context: /*
   * DAWN OF LIGHT - The first free open source DAoC server emulator
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * as published by the Free Software Foundation; either version 2
   * of the License, or (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   *
   */
  using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.Collections.Concurrent;
  using System.Diagnostics;
  using System.Reflection;
  using System.Threading;
  using DOL.Database;
  using DOL.GS.PacketHandler;
  using DOL.Events;
  using DOL.GS.Keeps;
  using DOL.GS.Utils;
  using DOL.GS.ServerProperties;
  using log4net;
  
  namespace DOL.GS
  {
  	/// <summary>
  	/// This class represents a region in DAOC. A region is everything where you
  	/// need a loadingscreen to go there. Eg. whole Albion is one Region, Midgard and
  	/// Hibernia are just one region too. Darkness Falls is a region. Each dungeon, city
  	/// is a region ... you get the clue. Each Region can hold an arbitary number of
  	/// Zones! Camelot Hills is one Zone, Tir na Nog is one Zone (and one Region)...
  	/// </summary>
      public class Region
      {
          private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  
          #region Region Variables
  
          /// <summary>
          /// This is the minimumsize for object array that is allocated when
          /// the first object is added to the region must be dividable by 32 (optimization)
          /// </summary>
          public static readonly int MINIMUMSIZE = 256;
  
  
          /// <summary>
          /// This holds all objects inside this region. Their index = their id!
          /// </summary>
          protected GameObject[] m_objects;
  
  
          /// <summary>
          /// Object to lock when changing objects in the array
          /// </summary>
          public readonly object ObjectsSyncLock = new object();
  
          /// <summary>
          /// This holds a counter with the absolute count of all objects that are actually in this region
          /// </summary>
          protected int m_objectsInRegion;
  
          /// <summary>
          /// Total number of objects in this region
          /// </summary>
          public int TotalNumberOfObjects
          {
              get { return m_objectsInRegion; }
          }
  
          /// <summary>
          /// This array holds a bitarray
          /// Its used to know which slots in region object array are free and what allocated
          /// This is used to accelerate inserts a lot
          /// </summary>
          protected uint[] m_objectsAllocatedSlots;
  
          /// <summary>
          /// This holds the index of a possible next object slot
          /// but needs further checks (basically its lastaddedobjectIndex+1)
          /// </summary>
          protected int m_nextObjectSlot;
  
          /// <summary>
          /// This holds the gravestones in this region for fast access
          /// Player unique id(string) -> GameGraveStone
          /// </summary>
          protected readonly Hashtable m_graveStones;
  
          /// <summary>
          /// Holds all the Zones inside this Region
          /// </summary>
          protected readonly ReaderWriterList<Zone> m_zones;
  
          protected object m_lockAreas = new object();
  
          /// <summary>
          /// Holds all the Areas inside this Region
          /// 
          /// ZoneID, AreaID, Area
          ///
          /// Areas can be registed to a reagion via AddArea
          /// and events will be thrown if players/npcs/objects enter leave area
          /// </summary>
          private Dictionary<ushort, IArea> m_Areas;
  
          protected Dictionary<ushort, IArea> Areas
          {
              get { return m_Areas; }
          }
  
          /// <summary>
          /// Cache for zone area mapping to quickly access all areas within a certain zone
          /// </summary>
          protected ushort[][] m_ZoneAreas;
  
          /// <summary>
          /// /// Cache for number of items in m_ZoneAreas array.
          /// </summary>
          protected ushort[] m_ZoneAreasCount;
  
          /// <summary>
          /// How often shall we remove unused objects
          /// </summary>
          protected static readonly int CLEANUPTIMER = 60000;
  
          /// <summary>
          /// Contains the # of players in the region
          /// </summary>
          protected int m_numPlayer = 0;
  
          /// <summary>
          /// last relocation time
          /// </summary>
          private long m_lastRelocationTime = 0;
  
          /// <summary>
          /// The region time manager
          /// </summary>
          protected readonly GameTimer.TimeManager m_timeManager;
          
          /// <summary>
          /// The Region Mob's Respawn Timer Collection
          /// </summary>
          protected readonly ConcurrentDictionary<GameNPC, int> m_mobsRespawning = new ConcurrentDictionary<GameNPC, int>();
  
          #endregion
  
          #region Constructor
  
          private RegionData m_regionData;
          public RegionData RegionData
          {
              get { return m_regionData; }
              protected set { m_regionData = value; }
          }
  
          /// <summary>
          /// Factory method to create regions.  Will create a region of data.ClassType, or default to Region if 
          /// an error occurs or ClassType is not specified
          /// </summary>
          /// <param name="time"></param>
          /// <param name="data"></param>
          /// <returns></returns>
          public static Region Create(GameTimer.TimeManager time, RegionData data)
          {
              try
              {
                  Type t = typeof(Region);
  
                  if (string.IsNullOrEmpty(data.ClassType) == false)
                  {
                      t = Type.GetType(data.ClassType);
  
                      if (t == null)
                      {
                          t = ScriptMgr.GetType(data.ClassType);
                      }
  
                      if (t != null)
                      {
                          ConstructorInfo info = t.GetConstructor(new Type[] { typeof(GameTimer.TimeManager), typeof(RegionData) });
  
                          Region r = (Region)info.Invoke(new object[] { time, data });
  
                          if (r != null)
                          {
                              // Success with requested classtype
                              log.InfoFormat("Created Region {0} using ClassType '{1}'", r.ID, data.ClassType);
                              return r;
                          }
  
                          log.ErrorFormat("Failed to Invoke Region {0} using ClassType '{1}'", r.ID, data.ClassType);
                      }
                      else
                      {
                          log.ErrorFormat("Failed to find ClassType '{0}' for region {1}!", data.ClassType, data.Id);
                      }
                  }
              }
              catch (Exception ex)
              {
                  log.ErrorFormat("Failed to start region {0} with requested classtype: {1}.  Exception: {2}!", data.Id, data.ClassType, ex.Message);
              }
  
              // Create region using default type
              return new Region(time, data);
          }
  
          /// <summary>
          /// Constructs a new empty Region
          /// </summary>
          /// <param name="time">The time manager for this region</param>
          /// <param name="data">The region data</param>
          public Region(GameTimer.TimeManager time, RegionData data)
          {
              m_regionData = data;
              m_objects = new GameObject[0];
              m_objectsInRegion = 0;
              m_nextObjectSlot = 0;
              m_objectsAllocatedSlots = new uint[0];
  
              m_graveStones = new Hashtable();
  
              m_zones = new ReaderWriterList<Zone>(1);
              m_ZoneAreas = new ushort[64][];
              m_ZoneAreasCount = new ushort[64];
              for (int i = 0; i < 64; i++)
              {
                  m_ZoneAreas[i] = new ushort[AbstractArea.MAX_AREAS_PER_ZONE];
              }
  
              m_Areas = new Dictionary<ushort, IArea>();
  
              m_timeManager = time;
  
              List<string> list = null;
  
              if (ServerProperties.Properties.DEBUG_LOAD_REGIONS != string.Empty)
                  list = ServerProperties.Properties.DEBUG_LOAD_REGIONS.SplitCSV(true);
  
              if (list != null && list.Count > 0)
              {
                  m_loadObjects = false;
  
                  foreach (string region in list)
                  {
                      if (region.ToString() == ID.ToString())
                      {
                          m_loadObjects = true;
                          break;
                      }
                  }
              }
  
              list = ServerProperties.Properties.DISABLED_REGIONS.SplitCSV(true);
              foreach (string region in list)
              {
  
gt:                 if (region.ToString() == ID.ToString())