/// <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> /// 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 = (uint)radius * (uint)radius; int referenceSubzoneIndex = GetSubZoneIndex(x, y); int typeIndex = (int)type; int xInZone = x - m_XOffset; // x in zone coordinates int yInZone = 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; }
/// <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> /// 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); }