示例#1
0
        private bool IsInViewingFrustum(GameClient gameClient, EntityOffset offset, ChunkPos chunkPos)
        {
            /* Check if the bounding sphere of the chunk is in the viewing frustum. */

            var df = (double)GeometryConstants.ChunkSize;

            // Determine the chunk center relative to the viewer.
            double dx = (chunkPos.X + 0.5) * df - offset.X;
            double dy = (chunkPos.Y + 0.5) * df - offset.Y;
            double dz = (chunkPos.Z + 0.5) * df - offset.Z;

            double t0, t1;

            // Perform mouselook rotation
            double ha = gameClient.PositionData.Placement.Orientation.Horizontal;
            double hc = Math.Cos(ha), hs = Math.Sin(ha);

            t0 = dx * hc - dz * hs; t1 = dz * hc + dx * hs; dx = t0; dz = t1;

            double va = -gameClient.PositionData.Placement.Orientation.Vertical;
            double vc = Math.Cos(va), vs = Math.Sin(va);

            t0 = dz * vc - dy * vs; t1 = dy * vc + dz * vs; dz = t0; dy = t1;

            // Check if the chunk is behind the viewer.
            if (dz > ChunkRadius && dz > ChunkRadius)
            {
                return(false);
            }

            /* TODO: We can discard even more chunks by taking the left, right, top and bottom planes into account. */

            return(true);
        }
示例#2
0
 public override int GetHashCode()
 {
     unchecked
     {
         var hashCode = DocumentId.GetHashCode();
         hashCode = (hashCode * 397) ^ (Entity != null ? Entity.GetHashCode() : 0);
         hashCode = (hashCode * 397) ^ (EntityType != null ? EntityType.GetHashCode() : 0);
         hashCode = (hashCode * 397) ^ EntityOffset.GetHashCode();
         hashCode = (hashCode * 397) ^ EntityLength.GetHashCode();
         hashCode = (hashCode * 397) ^ Id.GetHashCode();
         return(hashCode);
     }
 }
示例#3
0
        private static void SetPositionFromCollisionPosition(PhysicsValues physicsValues, World world, PositionData positionData)
        {
            if (positionData.IsFalling)
            {
                positionData.Placement.Pos = positionData.InternalPos;
                return;
            }

            var entityPos = positionData.InternalPos;
            var blockPos  = (BlockPos)entityPos;

            /*
             * When standing on an edge, the entities bottom center might be hanging in the air.
             * Find the true floor position by iterating downward and looking for the floor.
             */
            if (world[blockPos] == 0 && world[blockPos - BlockOffset.UnitY] == 0)
            {
                blockPos  -= BlockOffset.UnitY;
                entityPos -= EntityOffset.UnitY;

                if (world[blockPos - new BlockOffset(0, 2, 0)] == 0)
                {
                    blockPos  -= BlockOffset.UnitY;
                    entityPos -= EntityOffset.UnitY;
                }
            }

            var entityOffset = entityPos - blockPos;

            double yOffset = 0;

            /*
             * Take the integral of all floor heights in a 2 by 2 area around the center.
             * Since the height is piecewise constant, this is a weighted sum of the heights around the entity position.
             */

            yOffset += (1 - entityOffset.X) * FindHeight(world, blockPos - BlockOffset.UnitX);
            yOffset += entityOffset.X * FindHeight(world, blockPos + BlockOffset.UnitX);
            yOffset += (1 - entityOffset.Z) * FindHeight(world, blockPos - BlockOffset.UnitZ);
            yOffset += entityOffset.Z * FindHeight(world, blockPos + BlockOffset.UnitZ);
            yOffset += (1 - entityOffset.X) * (1 - entityOffset.Z) * FindHeight(world, blockPos + new BlockOffset(-1, 0, -1));
            yOffset += (1 - entityOffset.X) * entityOffset.Z * FindHeight(world, blockPos + new BlockOffset(-1, 0, 1));
            yOffset += entityOffset.X * (1 - entityOffset.Z) * FindHeight(world, blockPos + new BlockOffset(1, 0, -1));
            yOffset += entityOffset.X * entityOffset.Z * FindHeight(world, blockPos + new BlockOffset(1, 0, 1));

            // Normalize.
            yOffset *= 0.25;

            entityPos += new EntityOffset(0, yOffset, 0);
            positionData.Placement.Pos = entityPos;
        }
示例#4
0
        private void MovePlayer(GameDuration elapsedDuration)
        {
            var velocity = new EntityOffset(0, PositionData.Velocity.Y, 0);

            var moveOffset = PhysicsValues.PlayerMovementSpeed * (EntityOffset) new EntityOrientation(PositionData.Placement.Orientation.Horizontal, 0);

            bool isMovingAlong = false, isMovingSideways = false;

            if (_controller.IsKeyPressed(GameKey.Forwards))
            {
                isMovingAlong = true;
                velocity.X   += moveOffset.X;
                velocity.Z   += moveOffset.Z;
            }

            if (_controller.IsKeyPressed(GameKey.Left))
            {
                isMovingSideways = true;
                velocity.X      += moveOffset.Z;
                velocity.Z      -= moveOffset.X;
            }

            if (_controller.IsKeyPressed(GameKey.Backwards))
            {
                isMovingAlong = true;
                velocity.X   -= moveOffset.X;
                velocity.Z   -= moveOffset.Z;
            }

            if (_controller.IsKeyPressed(GameKey.Right))
            {
                isMovingSideways = true;
                velocity.X      -= moveOffset.Z;
                velocity.Z      += moveOffset.X;
            }

            if (isMovingAlong && isMovingSideways)
            {
                velocity.X *= _inverseSqrt2;
                velocity.Z *= _inverseSqrt2;
            }

            if (!PositionData.IsFalling && _controller.IsKeyPressed(GameKey.Jump))
            {
                velocity.Y += GetJumpingSpeed();
            }

            Movement.MoveEntity(PhysicsValues, World, PositionData, elapsedDuration, velocity);
        }
示例#5
0
        public RayCastResult CastRay(EntityPos entityPos, EntityOffset direction, double max)
        {
            long   x = entityPos.X, y = entityPos.Y, z = entityPos.Z;
            double dx = direction.X, dy = direction.Y, dz = direction.Z;

            int sdx = (int)Math.Sign(dx);
            int sdy = (int)Math.Sign(dy);
            int sdz = (int)Math.Sign(dz);

            if (sdx == 0 && sdy == 0 && sdz == 0)
            {
                return(null);
            }

            const long   edgeLength  = 1L << 32;
            const double oneOverEdge = 1.0 / edgeLength;

            var blockPos = (BlockPos)entityPos;

            if (this[blockPos] != 0)
            {
                return(new RayCastResult {
                    EntityPos = entityPos, BlockPos = blockPos
                });
            }

            while (max > 0 && IsNumber(max))
            {
                /* Check which edge of the current block is hit first */

                long edgeX;
                if (sdx > 0)
                {
                    edgeX = (x + edgeLength) & _upperMask;
                }
                else
                {
                    edgeX = (x - 1) & _upperMask;
                }

                double tx = (edgeX - x) * oneOverEdge / dx;

                long edgeY;
                if (sdy > 0)
                {
                    edgeY = (y + edgeLength) & _upperMask;
                }
                else
                {
                    edgeY = (y - 1) & _upperMask;
                }

                double ty = (edgeY - y) * oneOverEdge / dy;

                long edgeZ;
                if (sdz > 0)
                {
                    edgeZ = (z + edgeLength) & _upperMask;
                }
                else
                {
                    edgeZ = (z - 1) & _upperMask;
                }

                double tz = (edgeZ - z) * oneOverEdge / dz;

                if (Math.Abs(edgeX - x) > edgeLength || Math.Abs(edgeY - y) > edgeLength ||
                    Math.Abs(edgeZ - z) > edgeLength)
                {
                    // Shouldn't happen.
                    throw new Exception();
                }

                if (IsNumber(tx) && (tx <= ty || !IsNumber(ty)) && (tx <= tz || !IsNumber(tz)))
                {
                    x    = edgeX;
                    y   += (long)(tx * dy * edgeLength);
                    z   += (long)(tx * dz * edgeLength);
                    max -= tx;

                    blockPos.X += sdx;
                    if (max >= 0 && this[blockPos] != 0)
                    {
                        return(new RayCastResult {
                            EntityPos = new EntityPos(x, y, z), BlockPos = blockPos, Normal = new BlockOffset(-sdx, 0, 0)
                        });
                    }
                }
                else if (IsNumber(ty) && (ty <= tz || !IsNumber(tz)))
                {
                    x   += (long)(ty * dx * edgeLength);
                    y    = edgeY;
                    z   += (long)(ty * dz * edgeLength);
                    max -= ty;

                    blockPos.Y += sdy;
                    if (max >= 0 && this[blockPos] != 0)
                    {
                        return(new RayCastResult {
                            EntityPos = new EntityPos(x, y, z), BlockPos = blockPos, Normal = new BlockOffset(0, -sdy, 0)
                        });
                    }
                }
                else if (IsNumber(tz))
                {
                    x   += (long)(tz * dx * edgeLength);
                    y   += (long)(tz * dy * edgeLength);
                    z    = edgeZ;
                    max -= tz;

                    blockPos.Z += sdz;
                    if (max >= 0 && this[blockPos] != 0)
                    {
                        return(new RayCastResult {
                            EntityPos = new EntityPos(x, y, z), BlockPos = blockPos, Normal = new BlockOffset(0, 0, -sdz)
                        });
                    }
                }
                else
                {
                    // Shouldn't happen.
                    throw new Exception();
                }
            }

            return(null);
        }
示例#6
0
        public static void MoveEntity(PhysicsValues physicsValues, World world, PositionData positionData, GameDuration elapsedDuration, EntityOffset offset)
        {
            offset.Y -= 0.5 * elapsedDuration.Seconds * physicsValues.Gravity;
            if (MoveY(physicsValues, world, positionData, offset.Y * elapsedDuration.Seconds))
            {
                positionData.IsFalling = false;
            }
            else
            {
                if (!positionData.IsFalling)
                {
                    /* Re-evaluate the fall from the apparent position. */
                    positionData.InternalPos = positionData.Placement.Pos;
                    MoveY(physicsValues, world, positionData, offset.Y * elapsedDuration.Seconds);
                    positionData.IsFalling = true;
                }
            }

            if (positionData.IsFalling)
            {
                offset.Y -= 0.5 * elapsedDuration.Seconds * physicsValues.Gravity;
            }
            else
            {
                if (Math.Abs(offset.Y) > Math.Sqrt(2 * physicsValues.Gravity * physicsValues.TerminalHeight))
                {
                    Respawn(positionData);
                }

                offset.Y = 0;
            }

            if (offset.X != 0 || offset.Z != 0)
            {
                long savedY = positionData.InternalPos.Y;
                if (!positionData.IsFalling && world[(BlockPos)positionData.InternalPos - BlockOffset.UnitY] != 0)
                {
                    // Temporarily move the character up a block so that it can climb up stairs.
                    MoveY(physicsValues, world, positionData, 1);
                }

                EntityPos positionBeforeMovement = positionData.InternalPos;
                double    moveX = offset.X * elapsedDuration.Seconds;
                double    moveZ = offset.Z * elapsedDuration.Seconds;

                if (offset.X > offset.Z)
                {
                    MoveX(physicsValues, world, positionData, moveX);
                    MoveZ(physicsValues, world, positionData, moveZ);
                }
                else
                {
                    MoveZ(physicsValues, world, positionData, moveZ);
                    MoveX(physicsValues, world, positionData, moveX);
                }

                var moveDelta = positionData.InternalPos - positionBeforeMovement;
                moveX -= moveDelta.X;
                moveZ -= moveDelta.Z;

                if (!positionData.IsFalling)
                {
                    // Attempt to move the character back down to the ground in case we didn't climb a stair.
                    MoveY(physicsValues, world, positionData, (savedY - positionData.InternalPos.Y) / (double)(1L << 32));

                    savedY = positionData.InternalPos.Y;

                    // Attempt to move the caracter down an additional block so that it can walk down stairs.
                    if (!MoveY(physicsValues, world, positionData, -((1L << 32) + 1) / (double)(1L << 32)))
                    {
                        positionData.InternalPos.Y = savedY;
                        positionData.IsFalling     = true;
                    }
                }

                // Attempt to continue movement at this new (lower) Y position.
                if (offset.X > offset.Z)
                {
                    if (MoveX(physicsValues, world, positionData, moveX))
                    {
                        offset.X = 0;
                    }
                    if (MoveZ(physicsValues, world, positionData, moveZ))
                    {
                        offset.Z = 0;
                    }
                }
                else
                {
                    if (MoveZ(physicsValues, world, positionData, moveZ))
                    {
                        offset.Z = 0;
                    }
                    if (MoveX(physicsValues, world, positionData, moveX))
                    {
                        offset.X = 0;
                    }
                }
            }

            positionData.Velocity = offset;
            SetPositionFromCollisionPosition(physicsValues, world, positionData);
        }