예제 #1
0
        /// <summary>
        /// Initializes the base part of the world manager.
        /// </summary>
        protected WorldManager()
        {
            WorldHelper.SetGetEntitiesDelegate(GetEntities);
            WorldHelper.SetGetSegmentNeighboursDelegate(GetSegmentNeighboursForCollisions);

            // create cache dir if doesn't exist
            if (!Directory.Exists(WorldHelper.CachePath))
            {
                Directory.CreateDirectory(WorldHelper.CachePath);
            }
        }
예제 #2
0
        /// <summary>
        /// Resets the world instance.
        /// </summary>
        /// <param name="name">World name</param>
        /// <param name="dirName">Name in the world directory</param>
        public void Reset(string name, string dirName)
        {
            Console.WriteLine("Loading world...");

            _Initialized = false;

            _Name = name;
            _Path = Path.Combine(_WorldsPath, dirName);
            WorldHelper.SetWorldPath(_Path);

            if (_Areas != null)
            {
                _Areas.Clear();
            }
            _Areas = new Dictionary <int, TArea>();

            if (_Segments != null)
            {
                _Segments.Clear();
            }
            _Segments = new Dictionary <int, TSegment>();

            if (_Entities != null)
            {
                _Entities.Clear();
            }
            _Entities = new Dictionary <ushort, Entity>();

            if (_LoadThread != null)
            {
                _LoadThread.Abort();
                _LoadThread.Join();
            }
            _LoadThread          = new Thread(LoadWorker);
            _LoadThread.Priority = ThreadPriority.BelowNormal;
            _LoadThread.Start();

            StopAutoSave();

            if (_LoadQueue != null)
            {
                _LoadQueue.Clear();
            }
            _LoadQueue = new Queue <LoadRequest>();

            OnReset();
        }
예제 #3
0
        /// <summary>
        /// Lods the world from data files.
        /// </summary>
        /// <param name="server">Determines whether this is a server load</param>
        public void Load(bool server)
        {
            if (_Initialized)
            {
                throw new WorldAlreadyInitializedException();
            }

            // first load world info file
            string worldPath = GetFullWorldPath();

            string[] worldInfo = File.ReadAllLines(worldPath + WorldInfoFileName);

            _Name = worldInfo[WorldInfoNameLineIndex];
            WorldHelper.SetWorldSize(Convert.ToInt32(worldInfo[WorldInfoXSizeLineIndex]),
                                     Convert.ToInt32(worldInfo[WorldInfoZSizeLineIndex]));

            // load entities
            DirectoryInfo entityDir = new DirectoryInfo(GetFullEntitiesDirectoryPath());

            foreach (FileInfo entityFile in entityDir.GetFiles("*" + ExtensionEntity))
            {
                Entity entity = Entity.CreateFromByteArray(File.ReadAllBytes(entityFile.FullName));
                _Entities.Add(entity.ID, entity);
                if (!server)
                {
                    LoadEntityColumns(new LoadRequest()
                    {
                        MessageId = -entity.ID,
                        Entity    = entity
                    });
                    entity.InitializeTerrainDependencies();
                }
            }

            _Initialized = true;

            if (_Configuration.AutoSaveConfigurationNode.EnableAutoSave)
            {
                _AutoSaveWait.Reset();
                _AutoSaveThread = new Thread(AutoSaveWorker);
                _AutoSaveThread.Start();
            }
        }
예제 #4
0
파일: Area.cs 프로젝트: daxola123/Qbes
        /// <summary>
        /// Creates an area from binary data. Note that this will also load the
        /// segments and their boxes.
        /// </summary>
        /// <param name="data">Array with serialized data</param>
        /// <param name="offset">Offset</param>
        public void InitializeFromByteArray <TSegment, TBox>(byte[] data, ref int offset)
            where TSegment : Segment, new()
            where TBox : Box, new()
        {
            int length = BitConverter.ToInt32(data, offset);

            X = BitConverter.ToUInt16(data, offset + OffsetX) * 64;
            Y = data[offset + OffsetY] * 64;
            Z = BitConverter.ToUInt16(data, offset + OffsetZ) * 64;

            // read segments
            int segmentOffset = offset + OffsetSegmentData;
            int x             = 0;
            int y             = 0;
            int z             = 0;

            while (segmentOffset < offset + length)
            {
                TSegment segment = (TSegment)WorldHelper.GetPooledSegment();
                segment.InitializeFromByteArray <TBox>(ref data, ref segmentOffset, this, ref x, ref y, ref z);
                AddSegment(segment);

                z += 8;
                if (z == 64)
                {
                    z  = 0;
                    y += 8;
                    if (y == 64)
                    {
                        y  = 0;
                        x += 8;
                    }
                }
            }

            offset += length;

            InitializeFields(X, Y, Z);
        }
예제 #5
0
        /// <summary>
        /// Initializes this segment from binary data. Note that this will also
        /// load the segment's boxes.
        /// </summary>
        /// <param name="data">Array with serialized data</param>
        /// <param name="offset">Offset</param>
        /// <param name="area">Wrapping area</param>
        /// <param name="x">X diff coordinate</param>
        /// <param name="y">z diff coordinate</param>
        /// <param name="z">Z diff coordinate</param>
        internal void InitializeFromByteArray <TBox>(ref byte[] data, ref int offset, Area area, ref int x, ref int y, ref int z)
            where TBox : Box, new()
        {
            short dataLength = BitConverter.ToInt16(data, offset + OffsetDataLength);

            X        = x + area.X;
            Y        = y + area.Y;
            Z        = z + area.Z;
            _Version = BitConverter.ToUInt32(data, offset + OffsetVersion);

            InitializeFields(area);

            for (int i = OffsetBoxData; i < dataLength; i += Box.SerializedSize)
            {
                TBox box = (TBox)WorldHelper.GetPooledBox();
                box.InitializeFromByteArray(ref data, offset + i, this);
                AddBox(box);
            }

            offset += dataLength;

            OnInitialized();
        }
예제 #6
0
        internal List <CollisionWall> GetCollisionWalls()
        {
            lock (_Lock)
            {
                if (_CollisionWalls == null)
                {
                    _CollisionWalls = new List <CollisionWall>();
                    Segment neighbour = null;

                    for (int x = 0; x < 8; x++)
                    {
                        for (int y = 0; y < 8; y++)
                        {
                            for (int z = 0; z < 8; z++)
                            {
                                if (!_VisMatrix.Get(ref x, ref y, ref z))
                                {
                                    // skip empty space
                                    continue;
                                }

                                Box box = new Box(new Cube(X + x, Y + y, Z + z, 0), this);

                                // check front X wall
                                if (x == 0)
                                {
                                    neighbour = WorldHelper.GetSegment(X - 8, Y, Z);
                                    if (neighbour != null && !neighbour._VisMatrix.Get(7, y, z))
                                    {
                                        _CollisionWalls.Add(new CollisionWall(box, Sides.FrontX));
                                    }
                                }
                                else if (!_VisMatrix.Get(x - 1, y, z))
                                {
                                    _CollisionWalls.Add(new CollisionWall(box, Sides.FrontX));
                                }

                                // check back X wall
                                if (x == 7)
                                {
                                    neighbour = WorldHelper.GetSegment(X + 8, Y, Z);
                                    if (neighbour != null && !neighbour._VisMatrix.Get(0, y, z))
                                    {
                                        _CollisionWalls.Add(new CollisionWall(box, Sides.BackX));
                                    }
                                }
                                else if (!_VisMatrix.Get(x + 1, y, z))
                                {
                                    _CollisionWalls.Add(new CollisionWall(box, Sides.BackX));
                                }

                                // check front Z wall
                                if (z == 0)
                                {
                                    neighbour = WorldHelper.GetSegment(X, Y, Z - 8);
                                    if (neighbour != null && !neighbour._VisMatrix.Get(x, y, 7))
                                    {
                                        _CollisionWalls.Add(new CollisionWall(box, Sides.FrontZ));
                                    }
                                }
                                else if (!_VisMatrix.Get(x, y, z - 1))
                                {
                                    _CollisionWalls.Add(new CollisionWall(box, Sides.FrontZ));
                                }

                                // check back Z wall
                                if (z == 7)
                                {
                                    neighbour = WorldHelper.GetSegment(X, Y, Z + 8);
                                    if (neighbour != null && !neighbour._VisMatrix.Get(x, y, 0))
                                    {
                                        _CollisionWalls.Add(new CollisionWall(box, Sides.BackZ));
                                    }
                                }
                                else if (!_VisMatrix.Get(x, y, z + 1))
                                {
                                    _CollisionWalls.Add(new CollisionWall(box, Sides.BackZ));
                                }
                            }
                        }
                    }
                }

                return(_CollisionWalls);
            }
        }
예제 #7
0
파일: Entity.cs 프로젝트: daxola123/Qbes
        /// <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);
        }
예제 #8
0
파일: Entity.cs 프로젝트: daxola123/Qbes
        private void CheckSegmentChanged()
        {
            int segmentX = Convert.ToInt32(Math.Truncate(Location.X));

            segmentX -= segmentX % 8;
            if (segmentX >= WorldHelper.SizeX)
            {
                segmentX -= WorldHelper.SizeX;
            }
            else if (segmentX < 0)
            {
                segmentX += WorldHelper.SizeX;
            }
            int segmentY = Convert.ToInt32(Math.Truncate(Location.Y));

            segmentY -= segmentY % 8;
            int segmentZ = Convert.ToInt32(Math.Truncate(Location.Z));

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

            bool refreshNeighbours = false;

            // check if segment needs to be changed
            if (_CurrentSegment == null ||
                !(_CurrentSegment.X == segmentX &&
                  _CurrentSegment.Y == segmentY &&
                  _CurrentSegment.Z == segmentZ))
            {
                _CurrentSegment   = WorldHelper.GetSegment(segmentX, segmentY, segmentZ);
                refreshNeighbours = true;
            }

            Point3D inBorderCheckPoint = new Point3D(Location.X - _CurrentSegment.X,
                                                     Location.Y - _CurrentSegment.Y,
                                                     Location.Z - _CurrentSegment.Z);
            bool xRefresh = (inBorderCheckPoint.X < 4 != _PreviousCheckPoint.X < 4);
            bool yRefresh = (inBorderCheckPoint.Y < 4 != _PreviousCheckPoint.Y < 4);
            bool zRefresh = (inBorderCheckPoint.Z < 4 != _PreviousCheckPoint.Z < 4);

            // check if neighbours are to be refreshed
            if (refreshNeighbours || xRefresh || yRefresh || zRefresh)
            {
                _CurrentSegmentNeighbours = WorldHelper.GetSegmentNeighboursForCollisions(_CurrentSegment, Location);
            }

            _PreviousCheckPoint = inBorderCheckPoint;

            // check if column area isn't changed
            int x = Convert.ToInt32(Math.Truncate(Location.X));

            x -= x % 64;
            int z = Convert.ToInt32(Math.Truncate(Location.Z));

            z -= z % 64;

            if (CurrentColumnX != x || CurrentColumnZ != z)
            {
                _CurrentColumnX = x;
                _CurrentColumnZ = z;

                if (OnColumnChanged != null)
                {
                    OnColumnChanged(this, EventArgs.Empty);
                }
            }
        }