Beispiel #1
0
        /// <summary>
        /// Places or removes a block.
        /// </summary>
        /// <param name="place">True to place block</param>
        /// <param name="x">X coordinate of the placed/removed block</param>
        /// <param name="y">Y coordinate of the placed/removed block</param>
        /// <param name="z">Z coordinate of the placed/removed block</param>
        /// <param name="version">Current segment version</param>
        /// <returns>True if block has been placed/removed</returns>
        public bool PlaceOrRemoveBlock(bool place, out int x, out int y, out int z, out uint version)
        {
            x = -1;
             y = -1;
             z = -1;
             version = 0;

             if (!_CanPlaceBlocks)
             {
            return false;
             }

             // check closest intersection
             Point3D eyeLocation = new Point3D(Location, 0.0f, _EyeHeightFromCenter, 0.0f);
             Vector3D line = new Vector3D(eyeLocation, NewDirection);
             Intersection closest = new Intersection();
             List<Tuple<Box, int, int>> boxes = new List<Tuple<Box, int, int>>();

             // first add current segment's boxes which have 0 shift
             foreach (Box box in _CurrentSegment.GetBoxesSynchronized())
             {
            boxes.Add(Tuple.Create(box, 0, 0));
             }
             // now add other boxes and determine possible shift
             foreach (Segment neighbour in _CurrentSegmentNeighbours)
             {
            int shiftX = 0;
            if (_CurrentSegment.X - neighbour.X > WorldHelper.HalfSizeX)
            {
               shiftX = WorldHelper.SizeX;
            }
            else if (neighbour.X - _CurrentSegment.X > WorldHelper.HalfSizeX)
            {
               shiftX = -WorldHelper.SizeX;
            }

            int shiftZ = 0;
            if (_CurrentSegment.Z - neighbour.Z > WorldHelper.HalfSizeZ)
            {
               shiftZ = WorldHelper.SizeZ;
            }
            else if (neighbour.Z - _CurrentSegment.Z > WorldHelper.HalfSizeZ)
            {
               shiftZ = -WorldHelper.SizeZ;
            }

            foreach (Box box in neighbour.GetBoxesSynchronized())
            {
               boxes.Add(Tuple.Create(box, shiftX, shiftZ));
            }
             }

             if (eyeLocation.Y * eyeLocation.Y < BlockInteractionRange)
             {
            boxes.Add(Tuple.Create(Box.FloorBox, 0, 0));
             }

             int reverseShiftX = 0;
             int reverseShiftZ = 0;
             foreach (Tuple<Box, int, int> box in boxes)
             {
            Intersection intersection = box.Item1.GetIntersection(line, box.Item2, box.Item3);
            if (intersection.Distance < closest.Distance)
            {
               closest = intersection;
               reverseShiftX = -box.Item2;
               reverseShiftZ = -box.Item3;
            }
             }

             // check if there is a close intersection at all
             if (closest.IntersectionPoint == null || closest.Distance > BlockInteractionRange)
             {
            // not close enough or no point at all
            return false;
             }

             // adjust the reverse shift by accounting for reverse number truncating
             // when below 0
             if (closest.IntersectionPoint.X < 0 && closest.IntersectionPoint.X % 1 != 0)
             {
            reverseShiftX--;
             }
             if (closest.IntersectionPoint.Z < 0 && closest.IntersectionPoint.Z % 1 != 0)
             {
            reverseShiftZ--;
             }
             // calculate cube location without the shift
             x = Convert.ToInt32(Math.Truncate(closest.IntersectionPoint.X)) + reverseShiftX;
             y = Convert.ToInt32(Math.Truncate(closest.IntersectionPoint.Y));
             z = Convert.ToInt32(Math.Truncate(closest.IntersectionPoint.Z)) + reverseShiftZ;

             if (place)
             {
            // correct the location based on intersection side
            switch (closest.Side)
            {
               case Sides.FrontX:
                  x--;
                  break;
               case Sides.FrontY:
                  y--;
                  break;
               case Sides.FrontZ:
                  z--;
                  break;
            }
             }
             else
             {
            // correct the location based on intersection side
            switch (closest.Side)
            {
               case Sides.BackX:
                  x--;
                  break;
               case Sides.BackY:
                  y--;
                  break;
               case Sides.BackZ:
                  z--;
                  break;
            }
             }

             // check for floor/ceiling limits
             if (y < 0 || y > byte.MaxValue)
             {
            return false;
             }

             // adjust possible shift over the edge of the world after correction
             if (x < 0)
             {
            x += WorldHelper.SizeX;
             }
             else if (x >= WorldHelper.SizeX)
             {
            x -= WorldHelper.SizeX;
             }

             if (z < 0)
             {
            z += WorldHelper.SizeZ;
             }
             else if (z >= WorldHelper.SizeZ)
             {
            z -= WorldHelper.SizeZ;
             }

             // check if placing the block will clip into an entity
             if (place)
             {
            Box box = new Box(new Cube(x, y, z, 0), null);
            List<Entity> entities = WorldHelper.GetEntities(box.CenterPoint, BlockEntityCollisionSelectRange);

            bool collides = false;
            foreach (Entity entity in entities)
            {
               box.CheckSuffocation(entity.Location, ref entity._HalfSizeX, ref entity._HalfSizeY, ref collides);
               if (collides)
               {
                  // at least one entity collides with the newly placed box
                  return false;
               }
            }
             }

             // retrieve the destination segment and place or remove the block
             Segment destinationSegment = WorldHelper.GetSegment(x, y, z);
             version = destinationSegment.PlaceOrRemoveBlockAndUpdateVersion(place, x, y, z, GetSelectedMaterial());

             return true;
        }
Beispiel #2
0
        /// <summary>
        /// Places or removes a block.
        /// </summary>
        /// <param name="place">True to place block</param>
        /// <param name="x">X coordinate of the placed/removed block</param>
        /// <param name="y">Y coordinate of the placed/removed block</param>
        /// <param name="z">Z coordinate of the placed/removed block</param>
        /// <param name="version">Current segment version</param>
        /// <returns>True if block has been placed/removed</returns>
        public bool PlaceOrRemoveBlock(bool place, out int x, out int y, out int z, out uint version)
        {
            x       = -1;
            y       = -1;
            z       = -1;
            version = 0;

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

            // check closest intersection
            Point3D      eyeLocation            = new Point3D(Location, 0.0f, _EyeHeightFromCenter, 0.0f);
            Vector3D     line                   = new Vector3D(eyeLocation, NewDirection);
            Intersection closest                = new Intersection();
            List <Tuple <Box, int, int> > boxes = new List <Tuple <Box, int, int> >();

            // first add current segment's boxes which have 0 shift
            foreach (Box box in _CurrentSegment.GetBoxesSynchronized())
            {
                boxes.Add(Tuple.Create(box, 0, 0));
            }
            // now add other boxes and determine possible shift
            foreach (Segment neighbour in _CurrentSegmentNeighbours)
            {
                int shiftX = 0;
                if (_CurrentSegment.X - neighbour.X > WorldHelper.HalfSizeX)
                {
                    shiftX = WorldHelper.SizeX;
                }
                else if (neighbour.X - _CurrentSegment.X > WorldHelper.HalfSizeX)
                {
                    shiftX = -WorldHelper.SizeX;
                }

                int shiftZ = 0;
                if (_CurrentSegment.Z - neighbour.Z > WorldHelper.HalfSizeZ)
                {
                    shiftZ = WorldHelper.SizeZ;
                }
                else if (neighbour.Z - _CurrentSegment.Z > WorldHelper.HalfSizeZ)
                {
                    shiftZ = -WorldHelper.SizeZ;
                }

                foreach (Box box in neighbour.GetBoxesSynchronized())
                {
                    boxes.Add(Tuple.Create(box, shiftX, shiftZ));
                }
            }

            if (eyeLocation.Y * eyeLocation.Y < BlockInteractionRange)
            {
                boxes.Add(Tuple.Create(Box.FloorBox, 0, 0));
            }

            int reverseShiftX = 0;
            int reverseShiftZ = 0;

            foreach (Tuple <Box, int, int> box in boxes)
            {
                Intersection intersection = box.Item1.GetIntersection(line, box.Item2, box.Item3);
                if (intersection.Distance < closest.Distance)
                {
                    closest       = intersection;
                    reverseShiftX = -box.Item2;
                    reverseShiftZ = -box.Item3;
                }
            }

            // check if there is a close intersection at all
            if (closest.IntersectionPoint == null || closest.Distance > BlockInteractionRange)
            {
                // not close enough or no point at all
                return(false);
            }

            // adjust the reverse shift by accounting for reverse number truncating
            // when below 0
            if (closest.IntersectionPoint.X < 0 && closest.IntersectionPoint.X % 1 != 0)
            {
                reverseShiftX--;
            }
            if (closest.IntersectionPoint.Z < 0 && closest.IntersectionPoint.Z % 1 != 0)
            {
                reverseShiftZ--;
            }
            // calculate cube location without the shift
            x = Convert.ToInt32(Math.Truncate(closest.IntersectionPoint.X)) + reverseShiftX;
            y = Convert.ToInt32(Math.Truncate(closest.IntersectionPoint.Y));
            z = Convert.ToInt32(Math.Truncate(closest.IntersectionPoint.Z)) + reverseShiftZ;

            if (place)
            {
                // correct the location based on intersection side
                switch (closest.Side)
                {
                case Sides.FrontX:
                    x--;
                    break;

                case Sides.FrontY:
                    y--;
                    break;

                case Sides.FrontZ:
                    z--;
                    break;
                }
            }
            else
            {
                // correct the location based on intersection side
                switch (closest.Side)
                {
                case Sides.BackX:
                    x--;
                    break;

                case Sides.BackY:
                    y--;
                    break;

                case Sides.BackZ:
                    z--;
                    break;
                }
            }

            // check for floor/ceiling limits
            if (y < 0 || y > byte.MaxValue)
            {
                return(false);
            }

            // adjust possible shift over the edge of the world after correction
            if (x < 0)
            {
                x += WorldHelper.SizeX;
            }
            else if (x >= WorldHelper.SizeX)
            {
                x -= WorldHelper.SizeX;
            }

            if (z < 0)
            {
                z += WorldHelper.SizeZ;
            }
            else if (z >= WorldHelper.SizeZ)
            {
                z -= WorldHelper.SizeZ;
            }

            // check if placing the block will clip into an entity
            if (place)
            {
                Box           box      = new Box(new Cube(x, y, z, 0), null);
                List <Entity> entities = WorldHelper.GetEntities(box.CenterPoint, BlockEntityCollisionSelectRange);

                bool collides = false;
                foreach (Entity entity in entities)
                {
                    box.CheckSuffocation(entity.Location, ref entity._HalfSizeX, ref entity._HalfSizeY, ref collides);
                    if (collides)
                    {
                        // at least one entity collides with the newly placed box
                        return(false);
                    }
                }
            }

            // retrieve the destination segment and place or remove the block
            Segment destinationSegment = WorldHelper.GetSegment(x, y, z);

            version = destinationSegment.PlaceOrRemoveBlockAndUpdateVersion(place, x, y, z, GetSelectedMaterial());

            return(true);
        }