/// <summary> Mark this as not having a selected block. </summary>
 public void SetAsInvalid()
 {
     Valid = false;
     BlockPos = TranslatedPos = Vector3I.MinusOne;
     BlockFace = (CpeBlockFace)255;
     BlockType = 0;
 }
        public void SetRayData( Vector3 origin, Vector3 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.
            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;
        }
 void TestAxis( float dAxis, ref float dist, Vector3I nAxis, ref Vector3I normal, 
     CpeBlockFace fAxis)
 {
     dAxis = Math.Abs( dAxis );
     if( dAxis < dist ) {
         dist = dAxis;
         normal = nAxis;
         BlockFace = fAxis;
     }
 }
		private static void MakePlayerClick( byte button, bool buttonDown, float yaw, float pitch, byte targetEntity,
		                                    Vector3I targetPos, CpeBlockFace targetFace ) {
			WriteUInt8( (byte)PacketId.CpePlayerClick );
			WriteUInt8( button );
			WriteUInt8( buttonDown ? (byte)0 : (byte)1 );
			WriteInt16( (short)Utils.DegreesToPacked( yaw, 65536 ) );
			WriteInt16( (short)Utils.DegreesToPacked( pitch, 65536 ) );
			WriteUInt8( targetEntity );
			WriteInt16( (short)targetPos.X );
			WriteInt16( (short)targetPos.Y );
			WriteInt16( (short)targetPos.Z );
			WriteUInt8( (byte)targetFace );
		}
Beispiel #5
0
        public void SetAsValid( Vector3 min, Vector3 max, Vector3 intersect )
        {
            Min = min;
            Max = max;
            BlockPos = Vector3I.Truncate( Min );
            Valid = true;

            Vector3I normal = Vector3I.Zero;
            float dist = float.PositiveInfinity;
            TestAxis( intersect.X - Min.X, ref dist, -Vector3I.UnitX, ref normal, CpeBlockFace.XMin );
            TestAxis( intersect.X - Max.X, ref dist, Vector3I.UnitX, ref normal, CpeBlockFace.XMax );
            TestAxis( intersect.Y - Min.Y, ref dist, -Vector3I.UnitY, ref normal, CpeBlockFace.YMin );
            TestAxis( intersect.Y - Max.Y, ref dist, Vector3I.UnitY, ref normal, CpeBlockFace.YMax );
            TestAxis( intersect.Z - Min.Z, ref dist, -Vector3I.UnitZ, ref normal, CpeBlockFace.ZMin );
            TestAxis( intersect.Z - Max.Z, ref dist, Vector3I.UnitZ, ref normal, CpeBlockFace.ZMax );
            TranslatedPos = BlockPos + normal;
        }
        /// <summary> Mark this as having a selected block, and 
        /// calculates the closest block face of the selected position. </summary>
        public void SetAsValid( int x, int y, int z, Vector3 min, Vector3 max, 
            byte block, Vector3 intersect)
        {
            Min = min;
            Max = max;
            BlockPos = new Vector3I( x, y, z );
            Valid = true;
            BlockType = block;
            IntersectPoint = intersect;

            Vector3I normal = Vector3I.Zero;
            float dist = float.PositiveInfinity;
            TestAxis( intersect.X - Min.X, ref dist, -Vector3I.UnitX, ref normal, CpeBlockFace.XMin );
            TestAxis( intersect.X - Max.X, ref dist, Vector3I.UnitX, ref normal, CpeBlockFace.XMax );
            TestAxis( intersect.Y - Min.Y, ref dist, -Vector3I.UnitY, ref normal, CpeBlockFace.YMin );
            TestAxis( intersect.Y - Max.Y, ref dist, Vector3I.UnitY, ref normal, CpeBlockFace.YMax );
            TestAxis( intersect.Z - Min.Z, ref dist, -Vector3I.UnitZ, ref normal, CpeBlockFace.ZMin );
            TestAxis( intersect.Z - Max.Z, ref dist, Vector3I.UnitZ, ref normal, CpeBlockFace.ZMax );
            TranslatedPos = BlockPos + normal;
        }
Beispiel #7
0
        static BlockID GetBlock(World map, int x, int y, int z, Vector3I origin)
        {
            bool sides     = map.Env.SidesBlock != Block.Air;
            int  height    = Math.Max(1, map.Env.SidesHeight);
            bool insideMap = map.IsValidPos(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(Block.Air);
                }
                if (sides && y == -1 && origin.Y > 0)
                {
                    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(Block.Air);
            }
            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(Block.Air);
        }
Beispiel #8
0
        internal void Draw()
        {
            EntityShadow mode = game.Players.ShadowMode;
            Vector3      Position = entity.Position;
            float        posX = Position.X, posZ = Position.Z;
            int          posY = Math.Min((int)Position.Y, game.Map.Height - 1);
            int          index = 0, vb = 0;

            VertexPos3fTex2fCol4b[] verts = null;
            int         posCount = 0, dataCount = 0;
            Vector3I *  coords = stackalloc Vector3I[4];
            ShadowData *data = stackalloc ShadowData[4];

            for (int i = 0; i < 4; i++)
            {
                coords[i] = new Vector3I(int.MinValue);
                data[i]   = new ShadowData();
            }

            if (mode == EntityShadow.SnapToBlock)
            {
                vb = game.Graphics.texVb; verts = game.Graphics.texVerts;
                if (!GetBlocks(coords, ref posCount, posX, posZ, posY, data, ref dataCount))
                {
                    return;
                }

                float x1 = Utils.Floor(posX), z1 = Utils.Floor(posZ);
                DraqSquareShadow(verts, ref index, data[0].Y, 220, x1, z1);
            }
            else
            {
                vb = game.ModelCache.vb; verts = game.ModelCache.vertices;

                float x = posX - 7 / 16f, z = posZ - 7 / 16f;
                if (GetBlocks(coords, ref posCount, x, z, posY, data, ref dataCount) && data[0].A > 0)
                {
                    DrawCircle(verts, ref index, data, dataCount, x, z);
                }

                x = Math.Max(posX - 7 / 16f, Utils.Floor(posX + 7 / 16f));
                if (GetBlocks(coords, ref posCount, x, z, posY, data, ref dataCount) && data[0].A > 0)
                {
                    DrawCircle(verts, ref index, data, dataCount, x, z);
                }

                z = Math.Max(posZ - 7 / 16f, Utils.Floor(posZ + 7 / 16f));
                if (GetBlocks(coords, ref posCount, x, z, posY, data, ref dataCount) && data[0].A > 0)
                {
                    DrawCircle(verts, ref index, data, dataCount, x, z);
                }

                x = posX - 7 / 16f;
                if (GetBlocks(coords, ref posCount, x, z, posY, data, ref dataCount) && data[0].A > 0)
                {
                    DrawCircle(verts, ref index, data, dataCount, x, z);
                }
            }

            if (index == 0)
            {
                return;
            }
            CheckShadowTexture(game.Graphics);

            if (!boundShadowTex)
            {
                game.Graphics.BindTexture(shadowTex);
                boundShadowTex = true;
            }
            game.Graphics.UpdateDynamicIndexedVb(DrawMode.Triangles, vb, verts, index, index * 6 / 4);
        }
Beispiel #9
0
 public byte GetBlock( Vector3I p )
 {
     return mapData[( p.Y * Length + p.Z ) * Width + p.X];
 }
Beispiel #10
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 + ")");
        }
Beispiel #11
0
 public bool IsLit( Vector3I p )
 {
     if( !IsValidPos( p.X, p.Y, p.Z ) ) return true;
     return p.Y > heightmap[p.Z * Width + p.X];
 }
Beispiel #12
0
        bool CheckIsFree( Vector3I pos, byte newBlock )
        {
            float height = game.BlockInfo.Height[newBlock];
            BoundingBox blockBB = new BoundingBox( pos.X, pos.Y, pos.Z,
                                                  pos.X + 1, pos.Y + height, pos.Z + 1 );

            for( int id = 0; id < 255; id++ ) {
                Player player = game.Players[id];
                if( player == null ) continue;
                if( player.CollisionBounds.Intersects( blockBB ) ) return false;
            }

            BoundingBox localBB = game.LocalPlayer.CollisionBounds;
            if( localBB.Intersects( blockBB ) ) {
                localBB.Min.Y += 0.25f + Entity.Adjustment;
                if( localBB.Intersects( blockBB ) ) return false;

                // Push player up if they are jumping and trying to place a block underneath them.
                Vector3 p = game.LocalPlayer.Position;
                p.Y = pos.Y + height + Entity.Adjustment;
                LocationUpdate update = LocationUpdate.MakePos( p, false );
                game.LocalPlayer.SetLocation( update, false );
            }
            return true;
        }
Beispiel #13
0
        public void PickBlocks(bool cooldown, bool left, bool middle, bool right)
        {
            DateTime now   = DateTime.UtcNow;
            double   delta = (now - lastClick).TotalMilliseconds;

            if (cooldown && delta < 250)
            {
                return;                                      // 4 times per second
            }
            lastClick = now;
            Inventory inv = game.Inventory;

            if (game.Server.UsingPlayerClick && !game.Gui.ActiveScreen.HandlesAllInput)
            {
                input.pickingId = -1;
                input.ButtonStateChanged(MouseButton.Left, left);
                input.ButtonStateChanged(MouseButton.Right, right);
                input.ButtonStateChanged(MouseButton.Middle, middle);
            }

            if (game.Gui.ActiveScreen.HandlesAllInput || !inv.CanPick)
            {
                return;
            }

            if (left)
            {
                if (game.Mode.PickingLeft())
                {
                    return;
                }
                Vector3I pos = game.SelectedPos.BlockPos;
                if (!game.SelectedPos.Valid || !game.World.IsValidPos(pos))
                {
                    return;
                }

                BlockID old = game.World.GetBlock(pos);
                if (BlockInfo.Draw[old] == DrawType.Gas || !BlockInfo.CanDelete[old])
                {
                    return;
                }
                game.Mode.PickLeft(old);
            }
            else if (right)
            {
                if (game.Mode.PickingRight())
                {
                    return;
                }
                Vector3I pos = game.SelectedPos.TranslatedPos;
                if (!game.SelectedPos.Valid || !game.World.IsValidPos(pos))
                {
                    return;
                }

                BlockID old   = game.World.GetBlock(pos);
                BlockID block = inv.Selected;
                if (game.AutoRotate)
                {
                    block = AutoRotate.RotateBlock(game, block);
                }

                if (game.CanPick(old) || !BlockInfo.CanPlace[block])
                {
                    return;
                }
                // air-ish blocks can only replace over other air-ish blocks
                if (BlockInfo.Draw[block] == DrawType.Gas && BlockInfo.Draw[old] != DrawType.Gas)
                {
                    return;
                }

                if (!PickingHandler.CheckIsFree(game, block))
                {
                    return;
                }
                game.Mode.PickRight(old, block);
            }
            else if (middle)
            {
                Vector3I pos = game.SelectedPos.BlockPos;
                if (!game.SelectedPos.Valid || !game.World.IsValidPos(pos))
                {
                    return;
                }

                BlockID old = game.World.GetBlock(pos);
                game.Mode.PickMiddle(old);
            }
        }
Beispiel #14
0
 public static Vector3I Min( Vector3I p1, Vector3I p2 )
 {
     return new Vector3I( Math.Min( p1.X, p2.X ), Math.Min( p1.Y, p2.Y ), Math.Min( p1.Z, p2.Z ) );
 }
Beispiel #15
0
 public bool IsValidPos( Vector3I p )
 {
     return p.X >= 0 && p.Y >= 0 && p.Z >= 0 &&
         p.X < Width && p.Y < Height && p.Z < Length;
 }
Beispiel #16
0
 protected Block GetBlock(Vector3 coords)
 {
     return((Block)game.Map.SafeGetBlock(Vector3I.Floor(coords)));
 }
 public static Vector3 GetMaxBB(Game game, BlockID block, Vector3I coords)
 {
                 #if ALPHA
     if (block == Block.Ladder)
     {
         Vector3 newMin = Vector3.Zero;
         Vector3 newMax = Vector3.One;
         byte    data   = game.World.ChunkHandler.GetDataSafe(coords.X, coords.Y, coords.Z);
         byte    flip   = 0;
         if (data == 0x3)
         {
             flip = 2;
         }
         if (data == 0x4)
         {
             flip = 1;
         }
         if (data == 0x5)
         {
             flip = 3;
         }
         Utils.FlipBounds(MinBB[block], MaxBB[block], out newMin, out newMax, flip);
         return(newMax);
     }
     else if (block == Block.Fence)
     {
         return(Vector3.One);
     }
     else if (block == Block.Torch ||
              block == Block.RedstoneTorchOff || block == Block.RedstoneTorchOn)
     {
         Vector3 newMin = Vector3.Zero;
         Vector3 newMax = Vector3.One;
         byte    data   = game.World.ChunkHandler.GetDataSafe(coords.X, coords.Y, coords.Z);
         byte    flip   = 0;
         if (data == 0x3)
         {
             flip = 2;
         }
         if (data == 0x2)
         {
             flip = 1;
         }
         if (data == 0x1)
         {
             flip = 3;
         }
         if (data >= 0x1 && data <= 0x4)
         {
             newMin = new Vector3(5.75f / 16f, 3.25f / 16f, 0f);
             newMax = new Vector3(10.25f / 16f, 12.75f / 16f, 4.75f / 16f);
             Utils.FlipBounds(newMin, newMax, out newMin, out newMax, flip);
         }
         else
         {
             newMax    = MaxBB[block];
             newMax.X += (2f / 3f) / 16f;
             newMax.Y -= (1f / 3f) / 16f;
             newMax.Z += (2f / 3f) / 16f;
         }
         return(newMax);
     }
                 #endif
     return(MaxBB[block]);
 }
Beispiel #18
0
 public bool Equals(Vector3I other)
 {
     return(X == other.X && Y == other.Y && Z == other.Z);
 }
Beispiel #19
0
 public static Vector3I Max(Vector3I p1, Vector3I p2)
 {
     return(new Vector3I(Math.Max(p1.X, p2.X), Math.Max(p1.Y, p2.Y), Math.Max(p1.Z, p2.Z)));
 }
 void OnNewMap( object sender, EventArgs e )
 {
     game.ChunkUpdates = 0;
     ClearChunkCache();
     chunks = null;
     unsortedChunks = null;
     chunkPos = new Vector3I( int.MaxValue, int.MaxValue, int.MaxValue );
     builder.OnNewMap();
 }
        void UpdateSortOrder()
        {
            Player p = game.LocalPlayer;
            Vector3 cameraPos = game.Camera.GetCameraPos( p.EyePosition );
            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
            Array.Sort( distances, chunks );

            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);
            }
            //SimpleOcclusionCulling();
        }
Beispiel #22
0
        public void PickBlocks(bool cooldown, bool left, bool middle, bool right)
        {
            DateTime now   = DateTime.UtcNow;
            double   delta = (now - lastClick).TotalMilliseconds;

            if (cooldown && delta < 250)
            {
                return;                                      // 4 times per second
            }
            lastClick = now;
            Inventory inv = game.Inventory;

            if (game.Server.UsingPlayerClick && !game.Gui.ActiveScreen.HandlesAllInput)
            {
                input.pickingId = -1;
                input.ButtonStateChanged(MouseButton.Left, left);
                input.ButtonStateChanged(MouseButton.Right, right);
                input.ButtonStateChanged(MouseButton.Middle, middle);
            }

            int btns = (left ? 1 : 0) + (right ? 1 : 0) + (middle ? 1 : 0);

            if (btns > 1 || game.Gui.ActiveScreen.HandlesAllInput || inv.Selected == Block.Invalid)
            {
                return;
            }

            // always play delete animations, even if we aren't picking a block.
            if (left)
            {
                game.HeldBlockRenderer.anim.SetClickAnim(true);
                byte id = game.Entities.GetClosetPlayer(game.LocalPlayer);
                if (id != EntityList.SelfID && game.Mode.PickEntity(id))
                {
                    return;
                }
            }
            if (!game.SelectedPos.Valid)
            {
                return;
            }

            if (middle)
            {
                Vector3I pos = game.SelectedPos.BlockPos;
                if (!game.World.IsValidPos(pos))
                {
                    return;
                }

                BlockID old = game.World.GetBlock(pos);
                game.Mode.PickMiddle(old);
            }
            else if (left)
            {
                Vector3I pos = game.SelectedPos.BlockPos;
                if (!game.World.IsValidPos(pos))
                {
                    return;
                }

                BlockID old = game.World.GetBlock(pos);
                if (game.BlockInfo.Draw[old] == DrawType.Gas || !inv.CanDelete[old])
                {
                    return;
                }
                game.Mode.PickLeft(old);
            }
            else if (right)
            {
                Vector3I pos = game.SelectedPos.TranslatedPos;
                if (!game.World.IsValidPos(pos))
                {
                    return;
                }

                BlockID old   = game.World.GetBlock(pos);
                BlockID block = inv.Selected;
                block = AutoRotate.RotateBlock(game, block);

                if (game.CanPick(old))
                {
                    return;
                }
                if (!inv.CanPlace[block] && game.SelectedPos.Block != Block.Chest1 && game.SelectedPos.Block != Block.Chest2 && game.SelectedPos.Block != Block.Chest3 && game.SelectedPos.Block != Block.Chest4)
                {
                    return;
                }
                if (!PickingHandler.CheckIsFree(game, block))
                {
                    return;
                }
                game.Mode.PickRight(old, block);
            }
        }
 public void Refresh()
 {
     if( chunks != null && !game.Map.IsNotLoaded ) {
         ClearChunkCache();
         CreateChunkCache();
     }
     chunkPos = new Vector3I( int.MaxValue, int.MaxValue, int.MaxValue );
 }
Beispiel #24
0
        // http://www.xnawiki.com/index.php/Voxel_traversal
        public static void GetPickedBlockPos( Game window, Vector3 origin, Vector3 dir, float reach, PickedPos pickedPos )
        {
            // Implementation is 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

            // NOTES:
            // * This code assumes that the ray's position and direction are in 'cell coordinates', which means
            //   that one unit equals one cell in all directions.
            // * When the ray doesn't start within the voxel grid, calculate the first position at which the
            //   ray could enter the grid. If it never enters the grid, there is nothing more to do here.
            // * Also, it is important to test when the ray exits the voxel grid when the grid isn't infinite.
            // * The Point3D structure is a simple structure having three integer fields (X, Y and Z).

            // 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;
            int y = start.Y;
            int z = start.Z;

            // Determine which way we go.
            int stepX = Math.Sign( dir.X );
            int stepY = Math.Sign( dir.Y );
            int stepZ = 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 = new Vector3I(
                x + ( stepX > 0 ? 1 : 0 ),
                y + ( stepY > 0 ? 1 : 0 ),
                z + ( stepZ > 0 ? 1 : 0 ) );

            // NOTE: For the following calculations, the result will be Single.PositiveInfinity
            // when ray.Direction.X, Y or Z equals zero, which is OK. However, when the left-hand
            // value of the division also equals zero, the result is Single.NaN, which is not OK.

            // Determine how far we can travel along the ray before we hit a voxel boundary.
            Vector3 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.
            Vector3 tDelta = new Vector3(
                stepX / dir.X,     // Crossing the width of a cell.
                stepY / dir.Y,     // Crossing the height of a cell.
                stepZ / dir.Z );   // Crossing the depth of a cell.
            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;

            Map map = window.Map;
            BlockInfo info = window.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( window.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( min, max, block, intersect );
                        return;
                    }
                }

                if( tMax.X < tMax.Y && tMax.X < tMax.Z ) {
                    // tMax.X is the lowest, an YZ cell boundary plane is nearest.
                    x += stepX;
                    tMax.X += tDelta.X;
                } else if( tMax.Y < tMax.Z ) {
                    // tMax.Y is the lowest, an XZ cell boundary plane is nearest.
                    y += stepY;
                    tMax.Y += tDelta.Y;
                } else {
                    // tMax.Z is the lowest, an XY cell boundary plane is nearest.
                    z += stepZ;
                    tMax.Z += tDelta.Z;
                }
                iterations++;
            }
            throw new InvalidOperationException( "did over 10000 iterations in GetPickedBlockPos(). " +
                                                "Something has gone wrong. (dir: " + dir + ")" );
        }
        void ProcessQueue( ChunkInfo src, ChunkQueue queue )
        {
            Vector3I p = new Vector3I( src.CentreX, src.CentreY, src.CentreZ );
            while( queue.Size > 0 ) {
                ChunkInfo chunk = queue.Dequeue();
                chunk.VisibilityFlags = chunk.OcclusionFlags;
                int x1 = chunk.CentreX - 8, x2 = chunk.CentreX + 8;
                int y1 = chunk.CentreY - 8, y2 = chunk.CentreY + 8;
                int z1 = chunk.CentreZ - 8, z2 = chunk.CentreZ + 8;
                int cx = chunk.CentreX >> 4;
                int cy = chunk.CentreY >> 4;
                int cz = chunk.CentreZ >> 4;

                int xOffset, yOffset, zOffset;
                int dx = Math.Max( x1 - p.X, Math.Max( 0, p.X - x2 ) );
                int dy = Math.Max( y1 - p.Y, Math.Max( 0, p.Y - y2 ) );
                int dz = Math.Max( z1 - p.Z, Math.Max( 0, p.Z - z2 ) );
                int distX, distY, distZ;

                // X axis collisions
                int dxLeft = Math.Abs( x1 - p.X ), dxRight = Math.Abs( x2 - p.X );
                if( dxLeft < dxRight ) {
                    distX = dxLeft * dxLeft + dy * dy + dz * dz; xOffset = -1;
                } else {
                    distX = dxRight * dxRight + dy * dy + dz * dz; xOffset = 1;
                }

                // Z axis collisions
                int dxFront = Math.Abs( z1 - p.Z ), dxBack = Math.Abs( z2 - p.Z );
                if( dxFront < dxBack ) {
                    distZ = dx * dx + dy * dy + dxFront * dxFront; zOffset = -1;
                } else {
                    distZ = dx * dx + dy * dy + dxBack * dxBack; zOffset = 1;
                }

                // Y axis collisions
                int dxBottom = Math.Abs( y1 - p.Y ), dxTop = Math.Abs( y2 - p.Y );
                if( dxBottom < dxTop ) {
                    distY = dx * dx + dxBottom * dxBottom + dz * dz; yOffset = -1;
                } else {
                    distY = dx * dx + dxTop * dxTop + dz * dz; yOffset = 1;
                }

                int distMin = Math.Min( distX, Math.Min( distY, distZ ) );
                bool occlude = true;
                byte flags = 0;
                if( distMin == distX )
                    OccludeX( cx, cy, cz, xOffset, ref occlude, ref flags );
                if( distMin == distZ )
                    OccludeZ( cx, cy, cz, zOffset, ref occlude, ref flags );
                if( distMin == distY )
                    OccludeY( cx, cy, cz, yOffset, ref occlude, ref flags );

                if( occlude )
                    chunk.Occluded = true;
                chunk.VisibilityFlags = (byte)( flags | chunk.OcclusionFlags );
                QueueChunk( cx - 1, cy, cz, queue );
                QueueChunk( cx + 1, cy, cz, queue );
                QueueChunk( cx, cy, cz - 1, queue );
                QueueChunk( cx, cy, cz + 1, queue );
                QueueChunk( cx, cy - 1, cz, queue );
                QueueChunk( cx, cy + 1, cz, queue );
            }
            Console.WriteLine( "======================" );
        }
Beispiel #26
0
 public bool Equals( Vector3I other )
 {
     return X == other.X && Y == other.Y && Z == other.Z;
 }
Beispiel #27
0
 void OnNewMap(object sender, EventArgs e)
 {
     heightmap = null;
     lastPos   = new Vector3I(Int32.MaxValue);
 }
Beispiel #28
0
        static byte GetBlock( World map, int x, int y, int z, Vector3I origin )
        {
            bool sides = map.Env.SidesBlock != Block.Air;
            int height = Math.Max( 1, map.Env.SidesHeight );
            bool insideMap = map.IsValidPos( 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;
        }
Beispiel #29
0
        public void Render(double deltaTime)
        {
            Weather weather = map.Weather;

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

            graphics.Texturing = true;
            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.AlphaBlending = true;
            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.AlphaBlending = false;
            graphics.Texturing     = false;
            graphics.DepthWrite    = true;
        }
        bool IntersectsOtherPlayers( Vector3I pos, byte newType )
        {
            float height = game.BlockInfo.Height[newType];
            BoundingBox blockBB = new BoundingBox( pos.X, pos.Y, pos.Z,
                                                  pos.X + 1, pos.Y + height, pos.Z + 1 );

            for( int id = 0; id < 255; id++ ) {
                Player player = game.Players[id];
                if( player == null ) continue;
                if( player.CollisionBounds.Intersects( blockBB ) ) return true;
            }
            return false;
        }
Beispiel #31
0
 public void SetBlock( Vector3I p, byte blockId )
 {
     SetBlock( p.X, p.Y, p.Z, blockId );
 }