private void PlaceElementsInZone(DOL.GS.Collections.Hashtable elements) { DOL.GS.Collections.DictionaryEntry currentEntry = null; ArrayList currentList = null; SubNodeElement currentStartElement = null; SubNodeElement currentElement = null; IEnumerator entryEnumerator = elements.GetEntryEnumerator(); while (entryEnumerator.MoveNext()) { currentEntry = (DOL.GS.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); } } } }
/// <summary> /// Handles movement of objects from zone to zone /// </summary> /// <param name="objectType"></param> /// <param name="element"></param> private void ObjectEnterZone(eGameObjectType objectType, SubNodeElement element) { if (!m_initialized) { InitializeZone(); } int subZoneIndex = GetSubZoneIndex(element.data); if (log.IsDebugEnabled) { log.Debug("Object " + element.data.ObjectID + "(" + objectType + ") entering (inner) subzone " + subZoneIndex + " in zone " + this.ID + " in region " + m_Region.ID); } if ((subZoneIndex >= 0) && (subZoneIndex < SUBZONE_NBR)) { int type = (int)objectType; lock (m_subZoneElements[subZoneIndex][type]) { // add to subzone list m_subZoneElements[subZoneIndex][type].PushBack(element); } Interlocked.Increment(ref m_objectCount); } }
/// <summary> /// Insert a node before this one /// </summary> /// <param name="p_elem">The node to insert</param> public void PushBack(SubNodeElement p_elem) { p_elem.previous = this; p_elem.next = next; next.previous = p_elem; next = p_elem; }
private void PlaceElementsInOtherZones(DOL.GS.Collections.Hashtable elements) { DOL.GS.Collections.DictionaryEntry currentEntry = null; int currentType = 0; ArrayList currentList = null; Zone currentZone = null; SubNodeElement currentElement = null; IEnumerator entryEnumerator = elements.GetEntryEnumerator(); while (entryEnumerator.MoveNext()) { currentEntry = (DOL.GS.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.Position); if (currentZone != null) { currentZone.ObjectEnterZone((eGameObjectType)currentType, currentElement); } } } }
private void UnsafeAddToListWithoutDistanceCheck(SubNodeElement startElement, int typeIndex, int subZoneIndex, ArrayList partialList, DOL.GS.Collections.Hashtable inZoneElements, DOL.GS.Collections.Hashtable outOfZoneElements) { SubNodeElement currentElement = startElement.next; SubNodeElement elementToRemove = null; GameObject currentObject = null; 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); }
/// <summary> /// Remove this node from the list /// </summary> public void Remove() { if (previous != this) { previous.next = next; next.previous = previous; } previous = this; next = this; }
/// <summary> /// Handle a GameObject entering a zone /// </summary> /// <param name="p_Obj">The GameObject object</param> public void ObjectEnterZone(GameObject p_Obj) { if (!m_initialized) { InitializeZone(); } int subZoneIndex = GetSubZoneIndex(p_Obj); if ((subZoneIndex >= 0) && (subZoneIndex < SUBZONE_NBR)) { SubNodeElement element = new SubNodeElement(); element.data = p_Obj; int type = -1; // Only GamePlayer, GameNPC and GameStaticItem classes // are handled. if (p_Obj is GamePlayer) { type = (int)eGameObjectType.PLAYER; } else if (p_Obj is GameNPC) { type = (int)eGameObjectType.NPC; } else if (p_Obj is GameStaticItem) { type = (int)eGameObjectType.ITEM; } else if (p_Obj is IDoor) { type = (int)eGameObjectType.DOOR; } if (type == -1) { return; } if (log.IsDebugEnabled) { log.Debug($"Object {p_Obj.ObjectID} ({(eGameObjectType)type}) entering subzone {subZoneIndex} in zone {ID} in region {ZoneRegion.ID}"); } lock (m_subZoneElements[subZoneIndex][type]) { // add to subzone list m_subZoneElements[subZoneIndex][type].PushBack(element); } Interlocked.Increment(ref m_objectCount); } }
private void UnsafeAddToListWithDistanceCheck( SubNodeElement startElement, float x, float y, float z, uint sqRadius, int typeIndex, int subZoneIndex, ArrayList partialList, DOL.GS.Collections.Hashtable inZoneElements, DOL.GS.Collections.Hashtable outOfZoneElements, bool ignoreZ) { // => check all distances for all objects in the subzone SubNodeElement currentElement = startElement.next; SubNodeElement elementToRemove = null; GameObject currentObject = null; 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.Position.X, currentObject.Position.Y, currentObject.Position.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); }
private void InitializeZone() { if (m_initialized) { return; } for (int i = 0; i < SUBZONE_NBR; i++) { m_subZoneElements[i] = new SubNodeElement[4]; for (int k = 0; k < m_subZoneElements[i].Length; k++) { m_subZoneElements[i][k] = new SubNodeElement(); } } m_subZoneTimestamps = new int[SUBZONE_NBR << 2]; m_initialized = true; }
private void UnsafeAddToListWithDistanceCheck( SubNodeElement startElement, int x, int y, int z, uint sqRadius, int typeIndex, int subZoneIndex, ArrayList partialList, DOL.GS.Collections.Hashtable inZoneElements, DOL.GS.Collections.Hashtable outOfZoneElements, bool ignoreZ) { // => check all distances for all objects in the subzone SubNodeElement currentElement = startElement.next; SubNodeElement elementToRemove = null; GameObject currentObject = null; 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); }
private bool ShouldElementMove(SubNodeElement currentElement, int typeIndex, int subZoneIndex, DOL.GS.Collections.Hashtable inZoneElements, DOL.GS.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; }
/// <summary> /// Handles movement of objects from zone to zone /// </summary> /// <param name="objectType"></param> /// <param name="element"></param> private void ObjectEnterZone(eGameObjectType objectType, SubNodeElement element) { if (!m_initialized) InitializeZone(); int subZoneIndex = GetSubZoneIndex(element.data); if (log.IsDebugEnabled) { log.Debug("Object " + element.data.ObjectID + "(" + objectType + ") entering (inner) subzone " + subZoneIndex + " in zone " + this.ID + " in region " + m_Region.ID); } if ((subZoneIndex >= 0) && (subZoneIndex < SUBZONE_NBR)) { int type = (int)objectType; lock (m_subZoneElements[subZoneIndex][type]) { // add to subzone list m_subZoneElements[subZoneIndex][type].PushBack(element); } Interlocked.Increment(ref m_objectCount); } }
private void InitializeZone() { if (m_initialized) return; for (int i = 0; i < SUBZONE_NBR; i++) { m_subZoneElements[i] = new SubNodeElement[4]; for (int k = 0; k < m_subZoneElements[i].Length; k++) { m_subZoneElements[i][k] = new SubNodeElement(); } } m_subZoneTimestamps = new int[SUBZONE_NBR << 2]; m_initialized = true; }
/// <summary> /// Get NPCs of a zone given various parameters /// </summary> /// <param name="realms"></param> /// <param name="minLevel"></param> /// <param name="maxLevel"></param> /// <param name="compareLevel"></param> /// <param name="conLevel"></param> /// <param name="firstOnly"></param> /// <returns></returns> public List <GameNPC> GetNPCsOfZone(eRealm[] realms, int minLevel, int maxLevel, int compareLevel, int conLevel, bool firstOnly) { List <GameNPC> list = new List <GameNPC>(); try { if (!m_initialized) { InitializeZone(); } // select random starting subzone and iterate over all objects in subzone than in all subzone... int currentSubZoneIndex = Util.Random(SUBZONE_NBR); int startSubZoneIndex = currentSubZoneIndex; GameNPC currentNPC = null; bool stopSearching = false; do { SubNodeElement startElement = m_subZoneElements[currentSubZoneIndex][(int)eGameObjectType.NPC]; lock (startElement) { // if list is not empty if (startElement != startElement.next) { SubNodeElement curElement = startElement.next; do { currentNPC = (GameNPC)curElement.data; bool added = false; // Check for specified realms for (int i = 0; i < realms.Length; ++i) { eRealm realm = realms[i]; if (currentNPC.Realm == realm) { // Check for min-max level, if any specified bool addToList = true; if (compareLevel > 0 && conLevel > 0) { addToList = ((int)GameObject.GetConLevel(compareLevel, currentNPC.Level) == conLevel); } else { if (minLevel > 0 && currentNPC.Level < minLevel) { addToList = false; } if (maxLevel > 0 && currentNPC.Level > maxLevel) { addToList = false; } } if (addToList) { list.Add(currentNPC); added = true; break; } } } // If we have added and must return one only result, // then mark for stop searching if (firstOnly && added) { stopSearching = true; break; } curElement = curElement.next; } while (curElement != startElement); } } if (++currentSubZoneIndex >= SUBZONE_NBR) { currentSubZoneIndex = 0; } // If stop searching forced, then exit if (stopSearching) { break; } } while (currentSubZoneIndex != startSubZoneIndex); } catch (Exception ex) { log.Error("GetNPCsOfZone: Caught Exception for zone " + Description + ".", ex); } return(list); }
private bool ShouldElementMove(SubNodeElement currentElement, int typeIndex, int subZoneIndex, DOL.GS.Collections.Hashtable inZoneElements, DOL.GS.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.Position.X, currentObject.Position.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); }
public SubNodeElement() { next = this; previous = this; }
/// <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, float x, float y, float z, ushort radius, ArrayList partialList, bool ignoreZ) { if (!m_initialized) { InitializeZone(); } // initialise parameters uint sqRadius = (uint)radius * (uint)radius; int referenceSubzoneIndex = GetSubZoneIndex(x, y); int typeIndex = (int)type; int xInZone = (int)(x - m_XOffset); // x in zone coordinates int yInZone = (int)(y - m_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; } DOL.GS.Collections.Hashtable inZoneElements = new DOL.GS.Collections.Hashtable(); DOL.GS.Collections.Hashtable outOfZoneElements = new DOL.GS.Collections.Hashtable(); for (int currentLine = minLine; currentLine <= maxLine; ++currentLine) { int currentSubZoneIndex = 0; SubNodeElement startElement = null; 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); }
internal void Relocate(object state) { if (!m_initialized) { return; } if (m_objectCount > 0) { SubNodeElement startElement = null; SubNodeElement currentElement = null; SubNodeElement elementToRemove = null; DOL.GS.Collections.Hashtable outOfZoneElements = new DOL.GS.Collections.Hashtable(); DOL.GS.Collections.Hashtable inZoneElements = new DOL.GS.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"); } } } }
/// <summary> /// Handle a GameObject entering a zone /// </summary> /// <param name="p_Obj">The GameObject object</param> public void ObjectEnterZone(GameObject p_Obj) { if (!m_initialized) InitializeZone(); int subZoneIndex = GetSubZoneIndex(p_Obj); if ((subZoneIndex >= 0) && (subZoneIndex < SUBZONE_NBR)) { SubNodeElement element = new SubNodeElement(); element.data = p_Obj; int type = -1; //Only GamePlayer, GameNPC and GameStaticItem classes //are handled. if (p_Obj is GamePlayer) type = (int)eGameObjectType.PLAYER; else if (p_Obj is GameNPC) type = (int)eGameObjectType.NPC; else if (p_Obj is GameStaticItem) type = (int)eGameObjectType.ITEM; else if (p_Obj is IDoor) type = (int)eGameObjectType.DOOR; if (type == -1) return; if (log.IsDebugEnabled) { log.Debug("Object " + p_Obj.ObjectID + " (" + ((eGameObjectType)type) + ") entering subzone " + subZoneIndex + " in zone " + this.ID + " in region " + m_Region.ID); } lock (m_subZoneElements[subZoneIndex][type]) { // add to subzone list m_subZoneElements[subZoneIndex][type].PushBack(element); } Interlocked.Increment(ref m_objectCount); } }