예제 #1
0
        private void PlaceElementsInZone(Collections.Hashtable elements)
        {
            Collections.DictionaryEntry currentEntry;
            ArrayList      currentList;
            SubNodeElement currentStartElement;
            SubNodeElement currentElement;

            IEnumerator entryEnumerator = elements.GetEntryEnumerator();

            while (entryEnumerator.MoveNext())
            {
                currentEntry        = (Collections.DictionaryEntry)entryEnumerator.Current;
                currentStartElement = (SubNodeElement)currentEntry.key;

                currentList = (ArrayList)currentEntry.value;

                lock (currentStartElement)
                {
                    for (int i = 0; i < currentList.Count; i++)
                    {
                        currentElement = (SubNodeElement)currentList[i];
                        currentStartElement.PushBack(currentElement);
                    }
                }
            }
        }
예제 #2
0
        private void PlaceElementsInOtherZones(Collections.Hashtable elements)
        {
            Collections.DictionaryEntry currentEntry;
            int            currentType;
            ArrayList      currentList;
            Zone           currentZone;
            SubNodeElement currentElement;

            IEnumerator entryEnumerator = elements.GetEntryEnumerator();

            while (entryEnumerator.MoveNext())
            {
                currentEntry = (Collections.DictionaryEntry)entryEnumerator.Current;
                currentType  = (int)currentEntry.key;
                currentList  = (ArrayList)currentEntry.value;

                for (int i = 0; i < currentList.Count; i++)
                {
                    currentElement = (SubNodeElement)currentList[i];
                    currentZone    = ZoneRegion.GetZone(currentElement.data.X, currentElement.data.Y);

                    currentZone?.ObjectEnterZone((eGameObjectType)currentType, currentElement);
                }
            }
        }
예제 #3
0
        private void UnsafeAddToListWithDistanceCheck(
            SubNodeElement startElement,
            int x,
            int y,
            int z,
            uint sqRadius,
            int typeIndex,
            int subZoneIndex,
            ArrayList partialList,
            Collections.Hashtable inZoneElements,
            Collections.Hashtable outOfZoneElements,
            bool ignoreZ)
        {
            // => check all distances for all objects in the subzone
            SubNodeElement currentElement = startElement.next;
            SubNodeElement elementToRemove;
            GameObject     currentObject;

            do
            {
                currentObject = currentElement.data;

                if (ShouldElementMove(currentElement, typeIndex, subZoneIndex, inZoneElements, outOfZoneElements))
                {
                    elementToRemove = currentElement;
                    currentElement  = currentElement.next;

                    elementToRemove.Remove();

                    if (log.IsDebugEnabled)
                    {
                        log.Debug($"Zone{ID}: {(currentObject != null ? $"object {currentObject.ObjectID}" : "ghost object")} removed for subzone");
                    }
                }
                else
                {
                    if (CheckSquareDistance(x, y, z, currentObject.X, currentObject.Y, currentObject.Z, sqRadius, ignoreZ) && !partialList.Contains(currentObject))
                    {
                        // the current object exists, is Active and still in the current subzone
                        // moreover it is in the right range and not yet in the result set
                        // => add it
                        partialList.Add(currentObject);
                    }

                    currentElement = currentElement.next;
                }
            } while (currentElement != startElement);
        }
예제 #4
0
        private bool ShouldElementMove(SubNodeElement currentElement, int typeIndex, int subZoneIndex, Collections.Hashtable inZoneElements, Collections.Hashtable outOfZoneElements)
        {
            if (!m_initialized)
            {
                InitializeZone();
            }

            bool       removeElement = true;
            GameObject currentObject = currentElement.data;

            if (currentObject != null &&
                (int)currentObject.ObjectState == (int)GameObject.eObjectState.Active &&
                currentObject.CurrentRegion == ZoneRegion)
            {
                // the current object exists, is Active and still in the Region where this Zone is located
                int currentElementSubzoneIndex = GetSubZoneIndex(currentObject.X, currentObject.Y);

                if (currentElementSubzoneIndex == -1)
                {
                    // the object has moved in another Zone in the same Region
                    ArrayList movedElements = (ArrayList)outOfZoneElements[typeIndex];

                    if (movedElements == null)
                    {
                        movedElements = new ArrayList();
                        outOfZoneElements[typeIndex] = movedElements;
                    }

                    movedElements.Add(currentElement);

                    Interlocked.Decrement(ref m_objectCount);
                }
                else
                {
                    // the object is still inside this Zone
                    if (removeElement = currentElementSubzoneIndex != subZoneIndex)
                    {
                        // it has changed of subzone
                        SubNodeElement newSubZoneStartElement = m_subZoneElements[currentElementSubzoneIndex][typeIndex];
                        ArrayList      movedElements          = (ArrayList)inZoneElements[newSubZoneStartElement];

                        if (movedElements == null)
                        {
                            movedElements = new ArrayList();
                            inZoneElements[newSubZoneStartElement] = movedElements;
                        }

                        // make it available for relocation
                        movedElements.Add(currentElement);
                    }
                }
            }
            else
            {
                // ghost object
                // => remove it
                Interlocked.Decrement(ref m_objectCount);
            }

            return(removeElement);
        }
예제 #5
0
        internal void Relocate(object state)
        {
            if (!m_initialized)
            {
                return;
            }

            if (m_objectCount > 0)
            {
                SubNodeElement startElement;
                SubNodeElement currentElement;
                SubNodeElement elementToRemove;

                Collections.Hashtable outOfZoneElements = new Collections.Hashtable();
                Collections.Hashtable inZoneElements    = new Collections.Hashtable();

                for (int subZoneIndex = 0; subZoneIndex < m_subZoneElements.Length; subZoneIndex++)
                {
                    for (int typeIndex = 0; typeIndex < m_subZoneElements[subZoneIndex].Length; typeIndex++)
                    {
                        if (Environment.TickCount > m_subZoneTimestamps[(subZoneIndex << 2) | typeIndex])
                        {
                            // it is time to relocate some elements in this subzone
                            // => perform needed relocations of elements
                            startElement = m_subZoneElements[subZoneIndex][typeIndex];

                            lock (startElement)
                            {
                                if (startElement != startElement.next)
                                {
                                    // there are some elements in the list
                                    currentElement = startElement.next;

                                    do
                                    {
                                        if (ShouldElementMove(currentElement, typeIndex, subZoneIndex, inZoneElements, outOfZoneElements))
                                        {
                                            elementToRemove = currentElement;
                                            currentElement  = currentElement.next;

                                            elementToRemove.Remove();

                                            if (log.IsDebugEnabled)
                                            {
                                                log.Debug($"Zone{ID} object {elementToRemove.data.ObjectID} removed for subzone");
                                            }
                                        }
                                        else
                                        {
                                            currentElement = currentElement.next;
                                        }
                                    } while (currentElement != startElement);

                                    UnsafeUpdateSubZoneTimestamp(subZoneIndex, typeIndex);
                                }
                            }
                        }
                    }
                }

                if (inZoneElements.Count > 0)
                {
                    PlaceElementsInZone(inZoneElements);

                    if (log.IsDebugEnabled)
                    {
                        log.Debug($"Zone{ID} {inZoneElements.Count} objects moved inside zone");
                    }
                }

                if (outOfZoneElements.Count > 0)
                {
                    PlaceElementsInOtherZones(outOfZoneElements);

                    if (log.IsDebugEnabled)
                    {
                        log.Debug($"Zone{ID} {outOfZoneElements.Count} objects moved outside zone");
                    }
                }
            }
        }
예제 #6
0
        private void UnsafeAddToListWithoutDistanceCheck(SubNodeElement startElement, int typeIndex, int subZoneIndex, ArrayList partialList, Collections.Hashtable inZoneElements, Collections.Hashtable outOfZoneElements)
        {
            SubNodeElement currentElement = startElement.next;
            SubNodeElement elementToRemove;
            GameObject     currentObject;

            do
            {
                currentObject = currentElement.data;
                if (ShouldElementMove(currentElement, typeIndex, subZoneIndex, inZoneElements, outOfZoneElements))
                {
                    elementToRemove = currentElement;
                    currentElement  = currentElement.next;

                    elementToRemove.Remove();

                    if (log.IsDebugEnabled)
                    {
                        log.Debug($"Zone{ID}: {(currentObject != null ? $"object {currentObject.ObjectID}" : "ghost object")} removed for subzone");
                    }
                }
                else
                {
                    // the current object exists, is Active and still in the current subzone
                    // => add it
                    if (!partialList.Contains(currentObject))
                    {
                        partialList.Add(currentObject);
                    }

                    currentElement = currentElement.next;
                }
            } while (currentElement != startElement);
        }
예제 #7
0
        /// <summary>
        /// Gets the lists of objects, located in the current Zone and of the given type, that are at most at a 'radius' distance from (x,y,z)
        /// The found objects are appended to the given 'partialList'.
        /// </summary>
        /// <param name="type">the type of objects to look for</param>
        /// <param name="x">the x coordinate of the observation position</param>
        /// <param name="y">the y coordinate of the observation position</param>
        /// <param name="z">the z coordinate of the observation position</param>
        /// <param name="radius">the radius to check against</param>
        /// <param name="partialList">an initial (eventually empty but initialized, i.e. never null !!) list of objects</param>
        /// <returns>partialList augmented with the new objects verigying both type and radius in the current Zone</returns>
        internal ArrayList GetObjectsInRadius(eGameObjectType type, int x, int y, int z, ushort radius, ArrayList partialList, bool ignoreZ)
        {
            if (!m_initialized)
            {
                InitializeZone();
            }

            // initialise parameters
            uint sqRadius = radius * (uint)radius;
            int  referenceSubzoneIndex = GetSubZoneIndex(x, y);
            int  typeIndex             = (int)type;

            int xInZone = x - XOffset;                   // x in zone coordinates
            int yInZone = y - YOffset;                   // y in zone coordinates

            int cellNbr = (radius >> SUBZONE_SHIFT) + 1; // radius in terms of subzone number
            int xInCell = xInZone >> SUBZONE_SHIFT;      // xInZone in terms of subzone coord
            int yInCell = yInZone >> SUBZONE_SHIFT;      // yInZone in terms of subzone coord

            int minColumn = xInCell - cellNbr;

            if (minColumn < 0)
            {
                minColumn = 0;
            }

            int maxColumn = xInCell + cellNbr;

            if (maxColumn > (SUBZONE_NBR_ON_ZONE_SIDE - 1))
            {
                maxColumn = SUBZONE_NBR_ON_ZONE_SIDE - 1;
            }

            int minLine = yInCell - cellNbr;

            if (minLine < 0)
            {
                minLine = 0;
            }

            int maxLine = yInCell + cellNbr;

            if (maxLine > (SUBZONE_NBR_ON_ZONE_SIDE - 1))
            {
                maxLine = SUBZONE_NBR_ON_ZONE_SIDE - 1;
            }

            Collections.Hashtable inZoneElements    = new Collections.Hashtable();
            Collections.Hashtable outOfZoneElements = new Collections.Hashtable();

            for (int currentLine = minLine; currentLine <= maxLine; ++currentLine)
            {
                int            currentSubZoneIndex;
                SubNodeElement startElement;

                for (int currentColumn = minColumn; currentColumn <= maxColumn; ++currentColumn)
                {
                    currentSubZoneIndex = GetSubZoneOffset(currentLine, currentColumn);

                    // get the right list of objects
                    startElement = m_subZoneElements[currentSubZoneIndex][typeIndex];

                    if (startElement != startElement.next)
                    { // allow dirty read here to enable a more efficient and fine grained locking later...
                        // the current subzone contains some objects
                        if (currentSubZoneIndex == referenceSubzoneIndex)
                        {
                            lock (startElement)
                            {
                                // we are in the subzone of the observation point
                                // => check all distances for all objects in the subzone
                                UnsafeAddToListWithDistanceCheck(startElement, x, y, z, sqRadius, typeIndex, currentSubZoneIndex, partialList, inZoneElements, outOfZoneElements, ignoreZ);
                                UnsafeUpdateSubZoneTimestamp(currentSubZoneIndex, typeIndex);
                            }
                        }
                        else
                        {
                            int xLeft   = currentColumn << SUBZONE_SHIFT;
                            int xRight  = xLeft + SUBZONE_SIZE;
                            int yTop    = currentLine << SUBZONE_SHIFT;
                            int yBottom = yTop + SUBZONE_SIZE;

                            if (CheckMinDistance(xInZone, yInZone, xLeft, xRight, yTop, yBottom, sqRadius))
                            {
                                // the minimum distance is smaller than radius
                                if (CheckMaxDistance(xInZone, yInZone, xLeft, xRight, yTop, yBottom, sqRadius))
                                {
                                    // the current subzone is fully enclosed within the radius
                                    // => add all the objects of the current subzone
                                    lock (startElement)
                                    {
                                        UnsafeAddToListWithoutDistanceCheck(startElement, typeIndex, currentSubZoneIndex, partialList, inZoneElements, outOfZoneElements);
                                        UnsafeUpdateSubZoneTimestamp(currentSubZoneIndex, typeIndex);
                                    }
                                }
                                else
                                {
                                    // the current subzone is partially enclosed within the radius
                                    // => only add the objects within the right area
                                    lock (startElement)
                                    {
                                        UnsafeAddToListWithDistanceCheck(startElement, x, y, z, sqRadius, typeIndex, currentSubZoneIndex, partialList, inZoneElements, outOfZoneElements, ignoreZ);
                                        UnsafeUpdateSubZoneTimestamp(currentSubZoneIndex, typeIndex);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            //
            // perform needed relocations
            //
            if (inZoneElements.Count > 0)
            {
                PlaceElementsInZone(inZoneElements);

                if (log.IsDebugEnabled)
                {
                    log.Debug($"Zone{ID} {inZoneElements.Count} objects moved inside zone");
                }
            }

            if (outOfZoneElements.Count > 0)
            {
                PlaceElementsInOtherZones(outOfZoneElements);

                if (log.IsDebugEnabled)
                {
                    log.Debug($"Zone{ID} {outOfZoneElements.Count} objects moved outside zone");
                }
            }

            return(partialList);
        }