예제 #1
0
        static bool RayTrace(Game game, Vector3 origin, Vector3 dir, float reach,
                             PickedPos pos, bool clipMode)
        {
            t.SetVectors(origin, dir);
            float    reachSq = reach * reach;
            Vector3I pOrigin = Vector3I.Floor(origin);

            for (int i = 0; i < 10000; i++)
            {
                int x = t.X, y = t.Y, z = t.Z;
                t.Block = GetBlock(game.World, x, y, z, pOrigin);
                Vector3 min = new Vector3(x, y, z) + BlockInfo.RenderMinBB[t.Block];
                Vector3 max = new Vector3(x, y, z) + BlockInfo.RenderMaxBB[t.Block];

                float dx = Math.Min(Math.Abs(origin.X - min.X), Math.Abs(origin.X - max.X));
                float dy = Math.Min(Math.Abs(origin.Y - min.Y), Math.Abs(origin.Y - max.Y));
                float dz = Math.Min(Math.Abs(origin.Z - min.Z), Math.Abs(origin.Z - max.Z));
                if (dx * dx + dy * dy + dz * dz > reachSq)
                {
                    return(false);
                }

                t.Min = min; t.Max = max;
                bool intersect = clipMode ? CameraClip(game, pos) : PickBlock(game, pos);
                if (intersect)
                {
                    return(true);
                }
                t.Step();
            }

            throw new InvalidOperationException("did over 10000 iterations in CalculatePickedBlock(). " +
                                                "Something has gone wrong. (dir: " + dir + ")");
        }
예제 #2
0
        void FindReachableBlocks(ref int count, ref Vector3 size,
                                 out BoundingBox entityBB, out BoundingBox entityExtentBB)
        {
            Vector3 vel = Velocity;
            Vector3 pos = Position;

            entityBB = new BoundingBox(
                pos.X - size.X / 2, pos.Y, pos.Z - size.Z / 2,
                pos.X + size.X / 2, pos.Y + size.Y, pos.Z + size.Z / 2
                );

            // Exact maximum extent the entity can reach, and the equivalent map coordinates.
            entityExtentBB = new BoundingBox(
                vel.X < 0 ? entityBB.Min.X + vel.X : entityBB.Min.X,
                vel.Y < 0 ? entityBB.Min.Y + vel.Y : entityBB.Min.Y,
                vel.Z < 0 ? entityBB.Min.Z + vel.Z : entityBB.Min.Z,
                vel.X > 0 ? entityBB.Max.X + vel.X : entityBB.Max.X,
                vel.Y > 0 ? entityBB.Max.Y + vel.Y : entityBB.Max.Y,
                vel.Z > 0 ? entityBB.Max.Z + vel.Z : entityBB.Max.Z
                );
            Vector3I min = Vector3I.Floor(entityExtentBB.Min);
            Vector3I max = Vector3I.Floor(entityExtentBB.Max);

            int elements = (max.X + 1 - min.X) * (max.Y + 1 - min.Y) * (max.Z + 1 - min.Z);

            if (elements > stateCache.Length)
            {
                stateCache = new State[elements];
            }

            BoundingBox blockBB = default(BoundingBox);

            // Order loops so that we minimise cache misses
            for (int y = min.Y; y <= max.Y; y++)
            {
                for (int z = min.Z; z <= max.Z; z++)
                {
                    for (int x = min.X; x <= max.X; x++)
                    {
                        byte blockId = GetPhysicsBlockId(x, y, z);
                        if (!GetBoundingBox(blockId, x, y, z, ref blockBB))
                        {
                            continue;
                        }
                        if (!entityExtentBB.Intersects(blockBB))
                        {
                            continue;                                                 // necessary for non whole blocks. (slabs)
                        }
                        float tx = 0, ty = 0, tz = 0;
                        CalcTime(ref vel, ref entityBB, ref blockBB, out tx, out ty, out tz);
                        if (tx > 1 || ty > 1 || tz > 1)
                        {
                            continue;
                        }
                        float tSquared = tx * tx + ty * ty + tz * tz;
                        stateCache[count++] = new State(blockBB, blockId, tSquared);
                    }
                }
            }
        }
예제 #3
0
        /// <summary> Determines whether any of the blocks that intersect the
        /// given bounding box satisfy the given condition. </summary>
        public bool TouchesAny(BoundingBox bounds, Predicate <byte> condition)
        {
            Vector3I bbMin = Vector3I.Floor(bounds.Min);
            Vector3I bbMax = Vector3I.Floor(bounds.Max);

            // Order loops so that we minimise cache misses
            for (int y = bbMin.Y; y <= bbMax.Y; y++)
            {
                for (int z = bbMin.Z; z <= bbMax.Z; z++)
                {
                    for (int x = bbMin.X; x <= bbMax.X; x++)
                    {
                        if (!game.Map.IsValidPos(x, y, z))
                        {
                            continue;
                        }
                        byte    block = game.Map.GetBlock(x, y, z);
                        Vector3 min   = new Vector3(x, y, z) + info.MinBB[block];
                        Vector3 max   = new Vector3(x, y, z) + info.MaxBB[block];

                        BoundingBox blockBB = new BoundingBox(min, max);
                        if (!blockBB.Intersects(bounds))
                        {
                            continue;
                        }
                        if (condition(block))
                        {
                            return(true);
                        }
                    }
                }
            }
            return(false);
        }
예제 #4
0
        float LowestModifier(BoundingBox bounds, bool checkSolid)
        {
            Vector3I bbMin    = Vector3I.Floor(bounds.Min);
            Vector3I bbMax    = Vector3I.Floor(bounds.Max);
            float    modifier = float.PositiveInfinity;

            for (int y = bbMin.Y; y <= bbMax.Y; y++)
            {
                for (int z = bbMin.Z; z <= bbMax.Z; z++)
                {
                    for (int x = bbMin.X; x <= bbMax.X; x++)
                    {
                        byte block = game.Map.SafeGetBlock(x, y, z);
                        if (block == 0)
                        {
                            continue;
                        }
                        BlockCollideType type = info.CollideType[block];
                        if (type == BlockCollideType.Solid && !checkSolid)
                        {
                            continue;
                        }

                        modifier = Math.Min(modifier, info.SpeedMultiplier[block]);
                        if (block >= BlockInfo.CpeBlocksCount && type == BlockCollideType.SwimThrough)
                        {
                            useLiquidGravity = true;
                        }
                    }
                }
            }
            return(modifier == float.PositiveInfinity ? 1 : modifier);
        }
예제 #5
0
        bool CanSlideThrough(ref BoundingBox adjFinalBB)
        {
            Vector3I bbMin = Vector3I.Floor(adjFinalBB.Min);
            Vector3I bbMax = Vector3I.Floor(adjFinalBB.Max);

            for (int y = bbMin.Y; y <= bbMax.Y; y++)
            {
                for (int z = bbMin.Z; z <= bbMax.Z; z++)
                {
                    for (int x = bbMin.X; x <= bbMax.X; x++)
                    {
                        byte    block = GetPhysicsBlockId(x, y, z);
                        Vector3 min   = new Vector3(x, y, z) + info.MinBB[block];
                        Vector3 max   = new Vector3(x, y, z) + info.MaxBB[block];

                        BoundingBox blockBB = new BoundingBox(min, max);
                        if (!blockBB.Intersects(adjFinalBB))
                        {
                            continue;
                        }
                        if (info.CollideType[GetPhysicsBlockId(x, y, z)] == BlockCollideType.Solid)
                        {
                            return(false);
                        }
                    }
                }
            }
            return(true);
        }
예제 #6
0
        // http://www.xnawiki.com/index.php/Voxel_traversal
        // https://web.archive.org/web/20120113051728/http://www.xnawiki.com/index.php?title=Voxel_traversal
        /// <summary> Determines the picked block based on the given origin and direction vector.<br/>
        /// Marks pickedPos as invalid if a block could not be found due to going outside map boundaries
        /// or not being able to find a suitable candiate within the given reach distance. </summary>
        public static void CalculatePickedBlock(Game game, Vector3 origin, Vector3 dir, float reach, PickedPos pickedPos)
        {
            // Implementation based on: "A Fast Voxel Traversal Algorithm for Ray Tracing"
            // John Amanatides, Andrew Woo
            // http://www.cse.yorku.ca/~amana/research/grid.pdf
            // http://www.devmaster.net/articles/raytracing_series/A%20faster%20voxel%20traversal%20algorithm%20for%20ray%20tracing.pdf

            // The cell in which the ray starts.
            Vector3I start = Vector3I.Floor(origin);               // Rounds the position's X, Y and Z down to the nearest integer values.
            int      x = start.X, y = start.Y, z = start.Z;
            Vector3I step, cellBoundary;
            Vector3  tMax, tDelta;

            CalcVectors(origin, dir, out step, out cellBoundary, out tMax, out tDelta);

            Map       map          = game.Map;
            BlockInfo info         = game.BlockInfo;
            float     reachSquared = reach * reach;
            int       iterations   = 0;

            // For each step, determine which distance to the next voxel boundary is lowest (i.e.
            // which voxel boundary is nearest) and walk that way.
            while (iterations < 10000)
            {
                byte    block = GetBlock(map, x, y, z, origin);
                Vector3 min   = new Vector3(x, y, z) + info.MinBB[block];
                Vector3 max   = new Vector3(x, y, z) + info.MaxBB[block];

                float dx = Math.Min(Math.Abs(origin.X - min.X), Math.Abs(origin.X - max.X));
                float dy = Math.Min(Math.Abs(origin.Y - min.Y), Math.Abs(origin.Y - max.Y));
                float dz = Math.Min(Math.Abs(origin.Z - min.Z), Math.Abs(origin.Z - max.Z));

                if (dx * dx + dy * dy + dz * dz > reachSquared)
                {
                    pickedPos.SetAsInvalid();
                    return;
                }

                if (game.CanPick(block))
                {
                    // This cell falls on the path of the ray. Now perform an additional bounding box test,
                    // since some blocks do not occupy a whole cell.
                    float t0, t1;
                    if (Intersection.RayIntersectsBox(origin, dir, min, max, out t0, out t1))
                    {
                        Vector3 intersect = origin + dir * t0;
                        pickedPos.SetAsValid(x, y, z, min, max, block, intersect);
                        return;
                    }
                }
                Step(ref tMax, ref tDelta, ref step, ref x, ref y, ref z);
                iterations++;
            }
            throw new InvalidOperationException("did over 10000 iterations in CalculatePickedBlock(). " +
                                                "Something has gone wrong. (dir: " + dir + ")");
        }
예제 #7
0
        static bool PushbackPlace(Game game, AABB blockBB)
        {
            Vector3 newP = game.LocalPlayer.Position;
            Vector3 oldP = game.LocalPlayer.Position;

            // Offset position by the closest face
            PickedPos selected = game.SelectedPos;

            if (selected.Face == BlockFace.XMax)
            {
                newP.X = blockBB.Max.X + 0.5f;
            }
            else if (selected.Face == BlockFace.ZMax)
            {
                newP.Z = blockBB.Max.Z + 0.5f;
            }
            else if (selected.Face == BlockFace.XMin)
            {
                newP.X = blockBB.Min.X - 0.5f;
            }
            else if (selected.Face == BlockFace.ZMin)
            {
                newP.Z = blockBB.Min.Z - 0.5f;
            }
            else if (selected.Face == BlockFace.YMax)
            {
                newP.Y = blockBB.Min.Y + 1 + Entity.Adjustment;
            }
            else if (selected.Face == BlockFace.YMin)
            {
                newP.Y = blockBB.Min.Y - game.LocalPlayer.Size.Y - Entity.Adjustment;
            }

            Vector3I newLoc   = Vector3I.Floor(newP);
            bool     validPos = newLoc.X >= 0 && newLoc.Y >= 0 && newLoc.Z >= 0 &&
                                newLoc.X < game.World.Width && newP.Z < game.World.Length;

            if (!validPos)
            {
                return(false);
            }

            game.LocalPlayer.Position = newP;
            if (!game.LocalPlayer.Hacks.Noclip &&
                game.LocalPlayer.TouchesAny(b => game.BlockInfo.Collide[b] == CollideType.Solid))
            {
                game.LocalPlayer.Position = oldP;
                return(false);
            }

            game.LocalPlayer.Position = oldP;
            LocationUpdate update = LocationUpdate.MakePos(newP, false);

            game.LocalPlayer.SetLocation(update, false);
            return(true);
        }
예제 #8
0
        static bool PushbackPlace(Game game, AABB blockBB)
        {
            LocalPlayer p = game.LocalPlayer;
            Vector3     curPos = p.Position, adjPos = p.Position;

            // Offset position by the closest face
            PickedPos selected = game.SelectedPos;

            if (selected.Face == BlockFace.XMax)
            {
                adjPos.X = blockBB.Max.X + 0.5f;
            }
            else if (selected.Face == BlockFace.ZMax)
            {
                adjPos.Z = blockBB.Max.Z + 0.5f;
            }
            else if (selected.Face == BlockFace.XMin)
            {
                adjPos.X = blockBB.Min.X - 0.5f;
            }
            else if (selected.Face == BlockFace.ZMin)
            {
                adjPos.Z = blockBB.Min.Z - 0.5f;
            }
            else if (selected.Face == BlockFace.YMax)
            {
                adjPos.Y = blockBB.Min.Y + 1 + Entity.Adjustment;
            }
            else if (selected.Face == BlockFace.YMin)
            {
                adjPos.Y = blockBB.Min.Y - p.Size.Y - Entity.Adjustment;
            }

            Vector3I newLoc   = Vector3I.Floor(adjPos);
            bool     validPos = newLoc.X >= 0 && newLoc.Y >= 0 && newLoc.Z >= 0 &&
                                newLoc.X < game.World.Width && adjPos.Z < game.World.Length;

            if (!validPos)
            {
                return(false);
            }

            p.Position = adjPos;
            if (!p.Hacks.Noclip && p.TouchesAny(p.Bounds, touchesAnySolid))
            {
                p.Position = curPos;
                return(false);
            }

            p.Position = curPos;
            LocationUpdate update = LocationUpdate.MakePos(adjPos, false);

            p.SetLocation(update, false);
            return(true);
        }
예제 #9
0
        public void SetVectors(Vector3 origin, Vector3 dir)
        {
            Origin = origin; Dir = dir;

            Vector3I start = Vector3I.Floor(origin);             // Rounds the position's X, Y and Z down to the nearest integer values.

            // The cell in which the ray starts.
            X = start.X; Y = start.Y; Z = start.Z;

            // Determine which way we go.
            step.X = Math.Sign(dir.X); step.Y = Math.Sign(dir.Y); step.Z = Math.Sign(dir.Z);
            // Calculate cell boundaries. When the step (i.e. direction sign) is positive,
            // the next boundary is AFTER our current position, meaning that we have to add 1.
            // Otherwise, it is BEFORE our current position, in which case we add nothing.
            Vector3I cellBoundary;

            cellBoundary.X = start.X + (step.X > 0 ? 1 : 0);
            cellBoundary.Y = start.Y + (step.Y > 0 ? 1 : 0);
            cellBoundary.Z = start.Z + (step.Z > 0 ? 1 : 0);

            // NOTE: we want it so if dir.x = 0, tmax.x = positive infinity
            // Determine how far we can travel along the ray before we hit a voxel boundary.
            tMax = new Vector3(
                (cellBoundary.X - origin.X) / dir.X,                   // Boundary is a plane on the YZ axis.
                (cellBoundary.Y - origin.Y) / dir.Y,                   // Boundary is a plane on the XZ axis.
                (cellBoundary.Z - origin.Z) / dir.Z);                  // Boundary is a plane on the XY axis.
            if (Single.IsNaN(tMax.X) || Single.IsInfinity(tMax.X))
            {
                tMax.X = Single.PositiveInfinity;
            }
            if (Single.IsNaN(tMax.Y) || Single.IsInfinity(tMax.Y))
            {
                tMax.Y = Single.PositiveInfinity;
            }
            if (Single.IsNaN(tMax.Z) || Single.IsInfinity(tMax.Z))
            {
                tMax.Z = Single.PositiveInfinity;
            }

            // Determine how far we must travel along the ray before we have crossed a gridcell.
            tDelta = new Vector3(step.X / dir.X, step.Y / dir.Y, step.Z / dir.Z);
            if (Single.IsNaN(tDelta.X))
            {
                tDelta.X = Single.PositiveInfinity;
            }
            if (Single.IsNaN(tDelta.Y))
            {
                tDelta.Y = Single.PositiveInfinity;
            }
            if (Single.IsNaN(tDelta.Z))
            {
                tDelta.Z = Single.PositiveInfinity;
            }
        }
예제 #10
0
        bool PushbackPlace(PickedPos selected, BoundingBox blockBB)
        {
            Vector3 newP = game.LocalPlayer.Position;
            Vector3 oldP = game.LocalPlayer.Position;

            // Offset position by the closest face
            if (selected.BlockFace == CpeBlockFace.XMax)
            {
                newP.X = blockBB.Max.X + 0.5f;
            }
            else if (selected.BlockFace == CpeBlockFace.ZMax)
            {
                newP.Z = blockBB.Max.Z + 0.5f;
            }
            else if (selected.BlockFace == CpeBlockFace.XMin)
            {
                newP.X = blockBB.Min.X - 0.5f;
            }
            else if (selected.BlockFace == CpeBlockFace.ZMin)
            {
                newP.Z = blockBB.Min.Z - 0.5f;
            }
            else if (selected.BlockFace == CpeBlockFace.YMax)
            {
                newP.Y = blockBB.Min.Y + 1 + Entity.Adjustment;
            }
            else if (selected.BlockFace == CpeBlockFace.YMin)
            {
                newP.Y = blockBB.Min.Y - game.LocalPlayer.CollisionSize.Y - Entity.Adjustment;
            }

            Vector3I newLoc   = Vector3I.Floor(newP);
            bool     validPos = newLoc.X >= 0 && newLoc.Y >= 0 && newLoc.Z >= 0 &&
                                newLoc.X < game.Map.Width && newP.Z < game.Map.Length;

            if (!validPos)
            {
                return(false);
            }

            game.LocalPlayer.Position = newP;
            if (!game.LocalPlayer.noClip && game.LocalPlayer.TouchesAny(CannotPassThrough))
            {
                game.LocalPlayer.Position = oldP;
                return(false);
            }

            game.LocalPlayer.Position = oldP;
            LocationUpdate update = LocationUpdate.MakePos(newP, false);

            game.LocalPlayer.SetLocation(update, false);
            return(true);
        }
예제 #11
0
        void SimpleOcclusionCulling()           // TODO: still broken
        {
            Vector3  p      = game.LocalPlayer.EyePosition;
            Vector3I mapLoc = Vector3I.Floor(p);

            Utils.Clamp(ref mapLoc.X, 0, game.Map.Width - 1);
            Utils.Clamp(ref mapLoc.Y, 0, game.Map.Height - 1);
            Utils.Clamp(ref mapLoc.Z, 0, game.Map.Length - 1);

            int cx = mapLoc.X >> 4;
            int cy = mapLoc.Y >> 4;
            int cz = mapLoc.Z >> 4;

            ChunkInfo chunkIn = unsortedChunks[cx + chunksX * (cy + cz * chunksY)];
            byte      chunkInOcclusionFlags = chunkIn.OcclusionFlags;

            chunkIn.OcclusionFlags = 0;
            ChunkQueue queue = new ChunkQueue(chunksX * chunksY * chunksZ);

            for (int i = 0; i < chunks.Length; i++)
            {
                ChunkInfo chunk = chunks[i];
                chunk.Visited       = false;
                chunk.Occluded      = false;
                chunk.OccludedFlags = chunk.OcclusionFlags;
                chunk.DistanceFlags = 0;
            }

            chunkIn.Visited = true;
            mapLoc          = Vector3I.Floor(p);
            if (game.Map.IsValidPos(mapLoc))
            {
                chunkIn.DistanceFlags = flagX | flagY | flagZ;
            }
            else
            {
                chunkIn.OccludedFlags  = chunkIn.OcclusionFlags = chunkInOcclusionFlags;
                chunkIn.DistanceFlags |= (mapLoc.X < 0 || mapLoc.X >= game.Map.Width) ? flagX : (byte)0;
                chunkIn.DistanceFlags |= (mapLoc.Y < 0 || mapLoc.Y >= game.Map.Height) ? flagY : (byte)0;
                chunkIn.DistanceFlags |= (mapLoc.Z < 0 || mapLoc.Z >= game.Map.Length) ? flagZ : (byte)0;
            }

            Console.WriteLine("SRC    {0}", cx + "," + cy + "," + cz);
            QueueChunk(cx - 1, cy, cz, queue);
            QueueChunk(cx + 1, cy, cz, queue);
            QueueChunk(cx, cy - 1, cz, queue);
            QueueChunk(cx, cy + 1, cz, queue);
            QueueChunk(cx, cy, cz - 1, queue);
            QueueChunk(cx, cy, cz + 1, queue);
            ProcessQueue(queue);
            chunkIn.OcclusionFlags = chunkInOcclusionFlags;
        }
예제 #12
0
        static void CalcVectors(Vector3 origin, Vector3 dir, out Vector3I step,
                                out Vector3I cellBoundary, out Vector3 tMax, out Vector3 tDelta)
        {
            Vector3I start = Vector3I.Floor(origin);

            // Determine which way we go.
            step.X = Math.Sign(dir.X); step.Y = Math.Sign(dir.Y); step.Z = Math.Sign(dir.Z);
            // Calculate cell boundaries. When the step (i.e. direction sign) is positive,
            // the next boundary is AFTER our current position, meaning that we have to add 1.
            // Otherwise, it is BEFORE our current position, in which case we add nothing.
            cellBoundary = new Vector3I(
                start.X + (step.X > 0 ? 1 : 0),
                start.Y + (step.Y > 0 ? 1 : 0),
                start.Z + (step.Z > 0 ? 1 : 0));

            // NOTE: we want it so if dir.x = 0, tmax.x = positive infinity
            // Determine how far we can travel along the ray before we hit a voxel boundary.
            tMax = new Vector3(
                (cellBoundary.X - origin.X) / dir.X,                    // Boundary is a plane on the YZ axis.
                (cellBoundary.Y - origin.Y) / dir.Y,                    // Boundary is a plane on the XZ axis.
                (cellBoundary.Z - origin.Z) / dir.Z);                   // Boundary is a plane on the XY axis.
            if (Single.IsNaN(tMax.X) || Single.IsInfinity(tMax.X))
            {
                tMax.X = Single.PositiveInfinity;
            }
            if (Single.IsNaN(tMax.Y) || Single.IsInfinity(tMax.Y))
            {
                tMax.Y = Single.PositiveInfinity;
            }
            if (Single.IsNaN(tMax.Z) || Single.IsInfinity(tMax.Z))
            {
                tMax.Z = Single.PositiveInfinity;
            }

            // Determine how far we must travel along the ray before we have crossed a gridcell.
            tDelta = new Vector3(step.X / dir.X, step.Y / dir.Y, step.Z / dir.Z);
            if (Single.IsNaN(tDelta.X))
            {
                tDelta.X = Single.PositiveInfinity;
            }
            if (Single.IsNaN(tDelta.Y))
            {
                tDelta.Y = Single.PositiveInfinity;
            }
            if (Single.IsNaN(tDelta.Z))
            {
                tDelta.Z = Single.PositiveInfinity;
            }
        }
예제 #13
0
        /// <summary> Determines the picked block based on the given origin and direction vector.<br/>
        /// Marks pickedPos as invalid if a block could not be found due to going outside map boundaries
        /// or not being able to find a suitable candiate within the given reach distance. </summary>
        public static void CalculatePickedBlock(Game game, Vector3 origin, Vector3 dir, float reach, PickedPos pickedPos)
        {
            tracer.SetRayData(origin, dir);
            World     map          = game.World;
            BlockInfo info         = game.BlockInfo;
            float     reachSquared = reach * reach;
            int       iterations   = 0;
            Vector3I  pOrigin      = Vector3I.Floor(origin);

            while (iterations < 10000)
            {
                int     x = tracer.X, y = tracer.Y, z = tracer.Z;
                byte    block = GetBlock(map, x, y, z, pOrigin);
                Vector3 min   = new Vector3(x, y, z) + info.MinBB[block];
                Vector3 max   = new Vector3(x, y, z) + info.MaxBB[block];
                if (info.IsLiquid[block])
                {
                    min.Y -= 1.5f / 16; max.Y -= 1.5f / 16;
                }

                float dx = Math.Min(Math.Abs(origin.X - min.X), Math.Abs(origin.X - max.X));
                float dy = Math.Min(Math.Abs(origin.Y - min.Y), Math.Abs(origin.Y - max.Y));
                float dz = Math.Min(Math.Abs(origin.Z - min.Z), Math.Abs(origin.Z - max.Z));

                if (dx * dx + dy * dy + dz * dz > reachSquared)
                {
                    pickedPos.SetAsInvalid(); return;
                }

                if (game.CanPick(block))
                {
                    // This cell falls on the path of the ray. Now perform an additional bounding box test,
                    // since some blocks do not occupy a whole cell.
                    float t0, t1;
                    if (Intersection.RayIntersectsBox(origin, dir, min, max, out t0, out t1))
                    {
                        Vector3 intersect = origin + dir * t0;
                        pickedPos.SetAsValid(x, y, z, min, max, block, intersect);
                        return;
                    }
                }
                tracer.Step();
                iterations++;
            }
            throw new InvalidOperationException("did over 10000 iterations in CalculatePickedBlock(). " +
                                                "Something has gone wrong. (dir: " + dir + ")");
        }
예제 #14
0
        void UpdateSortOrder()
        {
            Vector3  cameraPos   = game.CurrentCameraPos;
            Vector3I newChunkPos = Vector3I.Floor(cameraPos);

            newChunkPos.X = (newChunkPos.X & ~0x0F) + 8;
            newChunkPos.Y = (newChunkPos.Y & ~0x0F) + 8;
            newChunkPos.Z = (newChunkPos.Z & ~0x0F) + 8;
            if (newChunkPos == chunkPos)
            {
                return;
            }

            chunkPos = newChunkPos;
            for (int i = 0; i < distances.Length; i++)
            {
                ChunkInfo info = chunks[i];
                distances[i] = Utils.DistanceSquared(info.CentreX, info.CentreY, info.CentreZ, chunkPos.X, chunkPos.Y, chunkPos.Z);
            }
            // NOTE: Over 5x faster compared to normal comparison of IComparer<ChunkInfo>.Compare
            if (distances.Length > 1)
            {
                //FastSorter<ChunkInfo>.QuickSort( distances, chunks, 0, chunks.Length - 1 );
                Array.Sort(distances, chunks, 0, chunks.Length - 1);
            }

            Vector3I pPos = newChunkPos;

            for (int i = 0; i < chunks.Length; i++)
            {
                ChunkInfo info = chunks[i];
                int       dX1 = (info.CentreX - 8) - pPos.X, dX2 = (info.CentreX + 8) - pPos.X;
                int       dY1 = (info.CentreY - 8) - pPos.Y, dY2 = (info.CentreY + 8) - pPos.Y;
                int       dZ1 = (info.CentreZ - 8) - pPos.Z, dZ2 = (info.CentreZ + 8) - pPos.Z;

                // Back face culling: make sure that the chunk is definitely entirely back facing.
                info.DrawLeft   = !(dX1 <= 0 && dX2 <= 0);
                info.DrawRight  = !(dX1 >= 0 && dX2 >= 0);
                info.DrawFront  = !(dZ1 <= 0 && dZ2 <= 0);
                info.DrawBack   = !(dZ1 >= 0 && dZ2 >= 0);
                info.DrawBottom = !(dY1 <= 0 && dY2 <= 0);
                info.DrawTop    = !(dY1 >= 0 && dY2 >= 0);
            }
            RecalcBooleans(false);
            //SimpleOcclusionCulling();
        }
예제 #15
0
        internal bool HandleKeyDown(Key key)
        {
            KeyMap keys = game.InputHandler.Keys;

            if (key == keys[KeyBinding.Respawn] && CanRespawn && HacksEnabled)
            {
                Vector3I p = Vector3I.Floor(SpawnPoint);
                if (game.Map.IsValidPos(p))
                {
                    // Spawn player at highest valid position.
                    for (int y = p.Y; y <= game.Map.Height; y++)
                    {
                        byte block1 = GetPhysicsBlockId(p.X, y, p.Z);
                        byte block2 = GetPhysicsBlockId(p.X, y + 1, p.Z);
                        if (info.CollideType[block1] != BlockCollideType.Solid &&
                            info.CollideType[block2] != BlockCollideType.Solid)
                        {
                            p.Y = y;
                            break;
                        }
                    }
                }
                Vector3        spawn  = (Vector3)p + new Vector3(0.5f, 0.01f, 0.5f);
                LocationUpdate update = LocationUpdate.MakePos(spawn, false);
                SetLocation(update, false);
            }
            else if (key == keys[KeyBinding.SetSpawn] && CanRespawn && HacksEnabled)
            {
                SpawnPoint = Position;
            }
            else if (key == keys[KeyBinding.Fly] && CanFly && HacksEnabled)
            {
                flying = !flying;
            }
            else if (key == keys[KeyBinding.NoClip] && CanNoclip && HacksEnabled)
            {
                noClip = !noClip;
            }
            else
            {
                return(false);
            }
            return(true);
        }
        static bool RayTrace(Game game, Vector3 origin, Vector3 dir, float reach,
                             PickedPos pos, bool clipMode)
        {
            t.SetVectors(origin, dir);
            double   reachSq   = reach * reach;
            Vector3I pOrigin   = Vector3I.Floor(origin);
            bool     insideMap = game.World.IsValidPos(pOrigin);

            Vector3 coords;

            for (int i = 0; i < 10000; i++)
            {
                int x = t.X, y = t.Y, z = t.Z;
                coords.X = x; coords.Y = y; coords.Z = z;
                t.Block  = insideMap ?
                           InsideGetBlock(game.World, x, y, z) : OutsideGetBlock(game.World, x, y, z, pOrigin);

                Vector3I coords2 = new Vector3I(t.X, t.Y, t.Z);

                //Vector3 min = coords + BlockInfo.RenderMinBB[t.Block];
                //Vector3 max = coords + BlockInfo.RenderMaxBB[t.Block];
                Vector3 min = coords + BlockInfo.GetMinBB(game, t.Block, coords2);
                Vector3 max = coords + BlockInfo.GetMaxBB(game, t.Block, coords2);

                double dx = Math.Min(Math.Abs(origin.X - min.X), Math.Abs(origin.X - max.X));
                double dy = Math.Min(Math.Abs(origin.Y - min.Y), Math.Abs(origin.Y - max.Y));
                double dz = Math.Min(Math.Abs(origin.Z - min.Z), Math.Abs(origin.Z - max.Z));
                if (dx * dx + dy * dy + dz * dz > reachSq)
                {
                    return(false);
                }

                t.Min = min; t.Max = max;
                bool intersect = clipMode ? CameraClip(game, pos) : PickBlock(game, pos);
                if (intersect)
                {
                    return(true);
                }
                t.Step();
            }

            throw new InvalidOperationException("did over 10000 iterations in CalculatePickedBlock(). " +
                                                "Something has gone wrong. (dir: " + dir + ")");
        }
        float LowestModifier(BoundingBox bounds, bool checkSolid)
        {
            Vector3I bbMin    = Vector3I.Floor(bounds.Min);
            Vector3I bbMax    = Vector3I.Floor(bounds.Max);
            float    modifier = inf;

            for (int y = bbMin.Y; y <= bbMax.Y; y++)
            {
                for (int z = bbMin.Z; z <= bbMax.Z; z++)
                {
                    for (int x = bbMin.X; x <= bbMax.X; x++)
                    {
                        byte block = game.Map.SafeGetBlock(x, y, z);
                        if (block == 0)
                        {
                            continue;
                        }
                        BlockCollideType type = info.CollideType[block];
                        if (type == BlockCollideType.Solid && !checkSolid)
                        {
                            continue;
                        }

                        Vector3     min     = new Vector3(x, y, z) + info.MinBB[block];
                        Vector3     max     = new Vector3(x, y, z) + info.MaxBB[block];
                        BoundingBox blockBB = new BoundingBox(min, max);
                        if (!blockBB.Intersects(bounds))
                        {
                            continue;
                        }

                        modifier = Math.Min(modifier, info.SpeedMultiplier[block]);
                        if (block >= BlockInfo.CpeBlocksCount && type == BlockCollideType.SwimThrough)
                        {
                            useLiquidGravity = true;
                        }
                    }
                }
            }
            return(modifier);
        }
예제 #18
0
        void DrawPosition()
        {
            int        index = 0;
            TextureRec xy    = new TextureRec(2, posTexture.Y1, baseWidth, posTexture.Height);
            TextureRec uv    = new TextureRec(0, 0, posTexture.U2, posTexture.V2);

            IGraphicsApi.Make2DQuad(xy, uv, game.ModelCache.vertices, ref index);

            Vector3I pos = Vector3I.Floor(game.LocalPlayer.Position);

            curX = baseWidth + 2;
            AddChar(13, ref index);
            AddInt(pos.X, ref index, true);
            AddInt(pos.Y, ref index, true);
            AddInt(pos.Z, ref index, false);
            AddChar(14, ref index);

            graphicsApi.BindTexture(posTexture.ID);
            graphicsApi.UpdateDynamicIndexedVb(DrawMode.Triangles,
                                               game.ModelCache.vb, game.ModelCache.vertices, index, index * 6 / 4);
        }
예제 #19
0
        internal bool HandleKeyDown(Key key)
        {
            KeyMap keys = game.InputHandler.Keys;

            if (key == keys[KeyBinding.Respawn] && Hacks.CanRespawn)
            {
                Vector3I p = Vector3I.Floor(SpawnPoint);
                if (game.Map.IsValidPos(p))
                {
                    // Spawn player at highest valid position.
                    for (int y = p.Y; y <= game.Map.Height; y++)
                    {
                        byte block1 = physics.GetPhysicsBlockId(p.X, y, p.Z);
                        byte block2 = physics.GetPhysicsBlockId(p.X, y + 1, p.Z);
                        if (info.CollideType[block1] != BlockCollideType.Solid &&
                            info.CollideType[block2] != BlockCollideType.Solid)
                        {
                            p.Y = y;
                            break;
                        }
                    }
                }
                Vector3        spawn  = (Vector3)p + new Vector3(0.5f, 0.01f, 0.5f);
                LocationUpdate update = LocationUpdate.MakePosAndOri(spawn, SpawnYaw, SpawnPitch, false);
                SetLocation(update, false);
            }
            else if (key == keys[KeyBinding.SetSpawn] && Hacks.CanRespawn)
            {
                SpawnPoint = Position;
                SpawnYaw   = HeadYawDegrees;
                SpawnPitch = PitchDegrees;
            }
            else if (key == keys[KeyBinding.Fly] && Hacks.CanFly && Hacks.Enabled)
            {
                flying = !flying;
            }
            else if (key == keys[KeyBinding.NoClip] && Hacks.CanNoclip && Hacks.Enabled)
            {
                if (noClip)
                {
                    Velocity.Y = 0;
                }
                noClip = !noClip;
            }
            else if (key == keys[KeyBinding.Jump] && !onGround && !(flying || noClip))
            {
                if (!firstJump && Hacks.CanDoubleJump && Hacks.DoubleJump)
                {
                    DoNormalJump();
                    firstJump = true;
                }
                else if (!secondJump && Hacks.CanDoubleJump && Hacks.DoubleJump)
                {
                    DoNormalJump();
                    secondJump = true;
                }
            }
            else
            {
                return(false);
            }
            return(true);
        }
예제 #20
0
        public static void ClipCameraPos(Game game, Vector3 origin, Vector3 dir, float reach, PickedPos pickedPos)
        {
            if (!game.CameraClipping)
            {
                pickedPos.SetAsInvalid();
                pickedPos.IntersectPoint = origin + dir * reach;
                return;
            }
            tracer.SetRayData(origin, dir);
            World     map          = game.World;
            BlockInfo info         = game.BlockInfo;
            float     reachSquared = reach * reach;
            int       iterations   = 0;
            Vector3I  pOrigin      = Vector3I.Floor(origin);

            while (iterations < 10000)
            {
                int     x = tracer.X, y = tracer.Y, z = tracer.Z;
                byte    block = GetBlock(map, x, y, z, pOrigin);
                Vector3 min   = new Vector3(x, y, z) + info.MinBB[block];
                Vector3 max   = new Vector3(x, y, z) + info.MaxBB[block];
                if (info.IsLiquid[block])
                {
                    min.Y -= 1.5f / 16; max.Y -= 1.5f / 16;
                }

                float dx = Math.Min(Math.Abs(origin.X - min.X), Math.Abs(origin.X - max.X));
                float dy = Math.Min(Math.Abs(origin.Y - min.Y), Math.Abs(origin.Y - max.Y));
                float dz = Math.Min(Math.Abs(origin.Z - min.Z), Math.Abs(origin.Z - max.Z));

                if (dx * dx + dy * dy + dz * dz > reachSquared)
                {
                    pickedPos.SetAsInvalid();
                    pickedPos.IntersectPoint = origin + dir * reach;
                    return;
                }

                if (info.Collide[block] == CollideType.Solid && !info.IsAir[block])
                {
                    float       t0, t1;
                    const float adjust = 0.1f;
                    if (Intersection.RayIntersectsBox(origin, dir, min, max, out t0, out t1))
                    {
                        Vector3 intersect = origin + dir * t0;
                        pickedPos.SetAsValid(x, y, z, min, max, block, intersect);

                        switch (pickedPos.BlockFace)
                        {
                        case CpeBlockFace.XMin:
                            pickedPos.IntersectPoint.X -= adjust; break;

                        case CpeBlockFace.XMax:
                            pickedPos.IntersectPoint.X += adjust; break;

                        case CpeBlockFace.YMin:
                            pickedPos.IntersectPoint.Y -= adjust; break;

                        case CpeBlockFace.YMax:
                            pickedPos.IntersectPoint.Y += adjust; break;

                        case CpeBlockFace.ZMin:
                            pickedPos.IntersectPoint.Z -= adjust; break;

                        case CpeBlockFace.ZMax:
                            pickedPos.IntersectPoint.Z += adjust; break;
                        }
                        return;
                    }
                }
                tracer.Step();
                iterations++;
            }
            throw new InvalidOperationException("did over 10000 iterations in ClipCameraPos(). " +
                                                "Something has gone wrong. (dir: " + dir + ")");
        }
예제 #21
0
        public static void ClipCameraPos(Game game, Vector3 origin, Vector3 dir, float reach, PickedPos pickedPos)
        {
            if (!game.CameraClipping)
            {
                pickedPos.SetAsInvalid();
                pickedPos.IntersectPoint = origin + dir * reach;
                return;
            }
            Vector3I start = Vector3I.Floor(origin);
            int      x = start.X, y = start.Y, z = start.Z;
            Vector3I step, cellBoundary;
            Vector3  tMax, tDelta;

            CalcVectors(origin, dir, out step, out cellBoundary, out tMax, out tDelta);

            Map       map          = game.Map;
            BlockInfo info         = game.BlockInfo;
            float     reachSquared = reach * reach;
            int       iterations   = 0;

            while (iterations < 10000)
            {
                byte    block = GetBlock(map, x, y, z, origin);
                Vector3 min   = new Vector3(x, y, z) + info.MinBB[block];
                Vector3 max   = new Vector3(x, y, z) + info.MaxBB[block];

                float dx = Math.Min(Math.Abs(origin.X - min.X), Math.Abs(origin.X - max.X));
                float dy = Math.Min(Math.Abs(origin.Y - min.Y), Math.Abs(origin.Y - max.Y));
                float dz = Math.Min(Math.Abs(origin.Z - min.Z), Math.Abs(origin.Z - max.Z));

                if (dx * dx + dy * dy + dz * dz > reachSquared)
                {
                    pickedPos.SetAsInvalid();
                    pickedPos.IntersectPoint = origin + dir * reach;
                    return;
                }

                if (info.CollideType[block] == BlockCollideType.Solid && !info.IsAir[block])
                {
                    float       t0, t1;
                    const float adjust = 0.1f;
                    if (Intersection.RayIntersectsBox(origin, dir, min, max, out t0, out t1))
                    {
                        Vector3 intersect = origin + dir * t0;
                        pickedPos.SetAsValid(x, y, z, min, max, block, intersect);

                        switch (pickedPos.BlockFace)
                        {
                        case CpeBlockFace.XMin:
                            pickedPos.IntersectPoint.X -= adjust; break;

                        case CpeBlockFace.XMax:
                            pickedPos.IntersectPoint.X += adjust; break;

                        case CpeBlockFace.YMin:
                            pickedPos.IntersectPoint.Y -= adjust; break;

                        case CpeBlockFace.YMax:
                            pickedPos.IntersectPoint.Y += adjust; break;

                        case CpeBlockFace.ZMin:
                            pickedPos.IntersectPoint.Z -= adjust; break;

                        case CpeBlockFace.ZMax:
                            pickedPos.IntersectPoint.Z += adjust; break;
                        }
                        return;
                    }
                }
                Step(ref tMax, ref tDelta, ref step, ref x, ref y, ref z);
                iterations++;
            }
            throw new InvalidOperationException("did over 10000 iterations in ClipCameraPos(). " +
                                                "Something has gone wrong. (dir: " + dir + ")");
        }
예제 #22
0
        static byte GetBlock(Map map, int x, int y, int z, Vector3 origin)
        {
            bool sides     = map.SidesBlock != Block.Air;
            int  height    = Math.Max(1, map.SidesHeight);
            bool insideMap = map.IsValidPos(Vector3I.Floor(origin));

            // handling of blocks inside the map, above, and on borders
            if (x >= 0 && z >= 0 && x < map.Width && z < map.Length)
            {
                if (y >= map.Height)
                {
                    return(0);
                }
                if (sides && y == -1 && insideMap)
                {
                    return(border);
                }
                if (sides && y == 0 && origin.Y < 0)
                {
                    return(border);
                }

                if (sides && x == 0 && y >= 0 && y < height && origin.X < 0)
                {
                    return(border);
                }
                if (sides && z == 0 && y >= 0 && y < height && origin.Z < 0)
                {
                    return(border);
                }
                if (sides && x == (map.Width - 1) && y >= 0 && y < height && origin.X >= map.Width)
                {
                    return(border);
                }
                if (sides && z == (map.Length - 1) && y >= 0 && y < height && origin.Z >= map.Length)
                {
                    return(border);
                }
                if (y >= 0)
                {
                    return(map.GetBlock(x, y, z));
                }
            }

            // pick blocks on the map boundaries (when inside the map)
            if (!sides || !insideMap)
            {
                return(0);
            }
            if (y == 0 && origin.Y < 0)
            {
                return(border);
            }
            bool validX = (x == -1 || x == map.Width) && (z >= 0 && z < map.Length);
            bool validZ = (z == -1 || z == map.Length) && (x >= 0 && x < map.Width);

            if (y >= 0 && y < height && (validX || validZ))
            {
                return(border);
            }
            return(0);
        }
예제 #23
0
        public void Render(double deltaTime)
        {
            Weather weather = map.Weather;

            if (weather == Weather.Sunny)
            {
                return;
            }
            if (heightmap == null)
            {
                InitHeightmap();
            }

            graphics.BindTexture(weather == Weather.Rainy ? game.RainTexId : game.SnowTexId);
            Vector3  camPos = game.CurrentCameraPos;
            Vector3I pos    = Vector3I.Floor(camPos);
            bool     moved  = pos != lastPos;

            lastPos = pos;

            float speed = weather == Weather.Rainy ? 1f : 0.20f;

            vOffset  = -(float)game.accumulator * speed;
            rainAcc += deltaTime;
            bool particles = weather == Weather.Rainy;

            int index = 0;

            graphics.AlphaTest  = false;
            graphics.DepthWrite = false;
            FastColour col = game.Map.Sunlight;

            for (int dx = -extent; dx <= extent; dx++)
            {
                for (int dz = -extent; dz <= extent; dz++)
                {
                    float rainY  = GetRainHeight(pos.X + dx, pos.Z + dz);
                    float height = Math.Max(game.Map.Height, pos.Y + 64) - rainY;
                    if (height <= 0)
                    {
                        continue;
                    }

                    if (particles && (rainAcc >= 0.25 || moved))
                    {
                        game.ParticleManager.AddRainParticle(new Vector3(pos.X + dx, rainY, pos.Z + dz));
                    }
                    col.A = (byte)Math.Max(0, AlphaAt(dx * dx + dz * dz));
                    MakeRainForSquare(pos.X + dx, rainY, height, pos.Z + dz, col, ref index);
                }
            }
            if (particles && (rainAcc >= 0.25 || moved))
            {
                rainAcc = 0;
            }

            if (index > 0)
            {
                graphics.SetBatchFormat(VertexFormat.Pos3fTex2fCol4b);
                graphics.UpdateDynamicIndexedVb(DrawMode.Triangles, weatherVb, vertices, index, index * 6 / 4);
            }
            graphics.AlphaTest  = true;
            graphics.DepthWrite = true;
        }
예제 #24
0
 protected Block GetBlock(Vector3 coords)
 {
     return((Block)game.Map.SafeGetBlock(Vector3I.Floor(coords)));
 }