PageRenderTime 53ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/OpenSim/Region/Framework/Scenes/SceneBase.cs

https://bitbucket.org/VirtualReality/taiga
C# | 514 lines | 309 code | 79 blank | 126 comment | 28 complexity | aa1a7b733c15d9ceaa8d8f2084c2abaf MD5 | raw file
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections.Generic;
  29. using System.Reflection;
  30. using System.Threading;
  31. using OpenMetaverse;
  32. using log4net;
  33. using Nini.Config;
  34. using OpenSim.Framework;
  35. using OpenSim.Framework.Console;
  36. using OpenSim.Framework.Communications.Cache;
  37. using OpenSim.Region.Framework.Interfaces;
  38. using GridRegion = OpenSim.Services.Interfaces.GridRegion;
  39. namespace OpenSim.Region.Framework.Scenes
  40. {
  41. public abstract class SceneBase : IScene
  42. {
  43. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  44. #region Events
  45. public event restart OnRestart;
  46. #endregion
  47. #region Fields
  48. public IConfigSource Config
  49. {
  50. get { return GetConfig(); }
  51. }
  52. protected virtual IConfigSource GetConfig()
  53. {
  54. return null;
  55. }
  56. /// <value>
  57. /// All the region modules attached to this scene.
  58. /// </value>
  59. public Dictionary<string, IRegionModule> Modules
  60. {
  61. get { return m_modules; }
  62. }
  63. protected Dictionary<string, IRegionModule> m_modules = new Dictionary<string, IRegionModule>();
  64. public Dictionary<string, IRegionModuleBase> RegionModules
  65. {
  66. get { return m_regionModules; }
  67. }
  68. private Dictionary<string, IRegionModuleBase> m_regionModules = new Dictionary<string, IRegionModuleBase>();
  69. /// <value>
  70. /// The module interfaces available from this scene.
  71. /// </value>
  72. protected Dictionary<Type, List<object>> ModuleInterfaces = new Dictionary<Type, List<object>>();
  73. protected Dictionary<string, object> ModuleAPIMethods = new Dictionary<string, object>();
  74. /// <value>
  75. /// The module commanders available from this scene
  76. /// </value>
  77. protected Dictionary<string, ICommander> m_moduleCommanders = new Dictionary<string, ICommander>();
  78. /// <value>
  79. /// Registered classes that are capable of creating entities.
  80. /// </value>
  81. protected Dictionary<PCode, IEntityCreator> m_entityCreators = new Dictionary<PCode, IEntityCreator>();
  82. /// <summary>
  83. /// The last allocated local prim id. When a new local id is requested, the next number in the sequence is
  84. /// dispensed.
  85. /// </summary>
  86. protected uint m_lastAllocatedLocalId = 720000;
  87. private readonly Mutex _primAllocateMutex = new Mutex(false);
  88. protected readonly ClientManager m_clientManager = new ClientManager();
  89. public float TimeDilation
  90. {
  91. get { return 1.0f; }
  92. }
  93. protected ulong m_regionHandle;
  94. protected string m_regionName;
  95. protected RegionInfo m_regInfo;
  96. public ITerrainChannel Heightmap;
  97. /// <value>
  98. /// Allows retrieval of land information for this scene.
  99. /// </value>
  100. public ILandChannel LandChannel;
  101. /// <value>
  102. /// Manage events that occur in this scene (avatar movement, script rez, etc.). Commonly used by region modules
  103. /// to subscribe to scene events.
  104. /// </value>
  105. public EventManager EventManager
  106. {
  107. get { return m_eventManager; }
  108. }
  109. protected EventManager m_eventManager;
  110. protected ScenePermissions m_permissions;
  111. public ScenePermissions Permissions
  112. {
  113. get { return m_permissions; }
  114. }
  115. protected string m_datastore;
  116. /* Used by the loadbalancer plugin on GForge */
  117. protected RegionStatus m_regStatus;
  118. public RegionStatus RegionStatus
  119. {
  120. get { return m_regStatus; }
  121. set { m_regStatus = value; }
  122. }
  123. #endregion
  124. #region Update Methods
  125. /// <summary>
  126. /// Normally called once every frame/tick to let the world preform anything required (like running the physics simulation)
  127. /// </summary>
  128. public abstract void Update();
  129. #endregion
  130. #region Terrain Methods
  131. /// <summary>
  132. /// Loads the World heightmap
  133. /// </summary>
  134. public abstract void LoadWorldMap();
  135. /// <summary>
  136. /// Send the region heightmap to the client
  137. /// </summary>
  138. /// <param name="RemoteClient">Client to send to</param>
  139. public virtual void SendLayerData(IClientAPI RemoteClient)
  140. {
  141. RemoteClient.SendLayerData(Heightmap.GetFloatsSerialised());
  142. }
  143. #endregion
  144. #region Add/Remove Agent/Avatar
  145. /// <summary>
  146. /// Register the new client with the scene. The client starts off as a child agent - the later agent crossing
  147. /// will promote it to a root agent during login.
  148. /// </summary>
  149. /// <param name="client"></param
  150. public abstract void AddNewClient(IClientAPI client);
  151. /// <summary>
  152. /// Remove a client from the scene
  153. /// </summary>
  154. /// <param name="agentID"></param>
  155. public abstract void RemoveClient(UUID agentID);
  156. #endregion
  157. /// <summary>
  158. ///
  159. /// </summary>
  160. /// <returns></returns>
  161. public virtual RegionInfo RegionInfo
  162. {
  163. get { return m_regInfo; }
  164. }
  165. #region admin stuff
  166. /// <summary>
  167. /// Region Restart - Seconds till restart.
  168. /// </summary>
  169. /// <param name="seconds"></param>
  170. public virtual void Restart(int seconds)
  171. {
  172. m_log.Error("[REGION]: passing Restart Message up the namespace");
  173. restart handlerPhysicsCrash = OnRestart;
  174. if (handlerPhysicsCrash != null)
  175. handlerPhysicsCrash(RegionInfo);
  176. }
  177. public virtual bool PresenceChildStatus(UUID avatarID)
  178. {
  179. return false;
  180. }
  181. public abstract void OtherRegionUp(GridRegion otherRegion);
  182. public virtual string GetSimulatorVersion()
  183. {
  184. return "OpenSimulator Server";
  185. }
  186. #endregion
  187. #region Shutdown
  188. /// <summary>
  189. /// Tidy before shutdown
  190. /// </summary>
  191. public virtual void Close()
  192. {
  193. // Shut down all non shared modules.
  194. foreach (IRegionModule module in Modules.Values)
  195. {
  196. if (!module.IsSharedModule)
  197. {
  198. module.Close();
  199. }
  200. }
  201. Modules.Clear();
  202. try
  203. {
  204. EventManager.TriggerShutdown();
  205. }
  206. catch (Exception e)
  207. {
  208. m_log.Error("[SCENE]: SceneBase.cs: Close() - Failed with exception " + e.ToString());
  209. }
  210. }
  211. #endregion
  212. /// <summary>
  213. /// Returns a new unallocated local ID
  214. /// </summary>
  215. /// <returns>A brand new local ID</returns>
  216. public uint AllocateLocalId()
  217. {
  218. uint myID;
  219. _primAllocateMutex.WaitOne();
  220. myID = ++m_lastAllocatedLocalId;
  221. _primAllocateMutex.ReleaseMutex();
  222. return myID;
  223. }
  224. #region Module Methods
  225. /// <summary>
  226. /// Add a module to this scene.
  227. /// </summary>
  228. /// <param name="name"></param>
  229. /// <param name="module"></param>
  230. public void AddModule(string name, IRegionModule module)
  231. {
  232. if (!Modules.ContainsKey(name))
  233. {
  234. Modules.Add(name, module);
  235. }
  236. }
  237. /// <summary>
  238. /// Add a region-module to this scene. TODO: This will replace AddModule in the future.
  239. /// </summary>
  240. /// <param name="name"></param>
  241. /// <param name="module"></param>
  242. public void AddRegionModule(string name, IRegionModuleBase module)
  243. {
  244. if (!RegionModules.ContainsKey(name))
  245. {
  246. RegionModules.Add(name, module);
  247. }
  248. }
  249. public void RemoveRegionModule(string name)
  250. {
  251. RegionModules.Remove(name);
  252. }
  253. /// <summary>
  254. /// Register a module commander.
  255. /// </summary>
  256. /// <param name="commander"></param>
  257. public void RegisterModuleCommander(ICommander commander)
  258. {
  259. lock (m_moduleCommanders)
  260. {
  261. m_moduleCommanders.Add(commander.Name, commander);
  262. }
  263. }
  264. /// <summary>
  265. /// Unregister a module commander and all its commands
  266. /// </summary>
  267. /// <param name="name"></param>
  268. public void UnregisterModuleCommander(string name)
  269. {
  270. lock (m_moduleCommanders)
  271. {
  272. ICommander commander;
  273. if (m_moduleCommanders.TryGetValue(name, out commander))
  274. m_moduleCommanders.Remove(name);
  275. }
  276. }
  277. /// <summary>
  278. /// Get a module commander
  279. /// </summary>
  280. /// <param name="name"></param>
  281. /// <returns>The module commander, null if no module commander with that name was found</returns>
  282. public ICommander GetCommander(string name)
  283. {
  284. lock (m_moduleCommanders)
  285. {
  286. if (m_moduleCommanders.ContainsKey(name))
  287. return m_moduleCommanders[name];
  288. }
  289. return null;
  290. }
  291. public Dictionary<string, ICommander> GetCommanders()
  292. {
  293. return m_moduleCommanders;
  294. }
  295. /// <summary>
  296. /// Register an interface to a region module. This allows module methods to be called directly as
  297. /// well as via events. If there is already a module registered for this interface, it is not replaced
  298. /// (is this the best behaviour?)
  299. /// </summary>
  300. /// <param name="mod"></param>
  301. public void RegisterModuleInterface<M>(M mod)
  302. {
  303. List<Object> l = null;
  304. if (!ModuleInterfaces.TryGetValue(typeof(M), out l))
  305. {
  306. l = new List<Object>();
  307. ModuleInterfaces.Add(typeof(M), l);
  308. }
  309. if (l.Count > 0)
  310. return;
  311. l.Add(mod);
  312. if (mod is IEntityCreator)
  313. {
  314. IEntityCreator entityCreator = (IEntityCreator)mod;
  315. foreach (PCode pcode in entityCreator.CreationCapabilities)
  316. {
  317. m_entityCreators[pcode] = entityCreator;
  318. }
  319. }
  320. }
  321. public void UnregisterModuleInterface<M>(M mod)
  322. {
  323. List<Object> l;
  324. if (ModuleInterfaces.TryGetValue(typeof(M), out l))
  325. {
  326. if (l.Remove(mod))
  327. {
  328. if (mod is IEntityCreator)
  329. {
  330. IEntityCreator entityCreator = (IEntityCreator)mod;
  331. foreach (PCode pcode in entityCreator.CreationCapabilities)
  332. {
  333. m_entityCreators[pcode] = null;
  334. }
  335. }
  336. }
  337. }
  338. }
  339. public void StackModuleInterface<M>(M mod)
  340. {
  341. List<Object> l;
  342. if (ModuleInterfaces.ContainsKey(typeof(M)))
  343. l = ModuleInterfaces[typeof(M)];
  344. else
  345. l = new List<Object>();
  346. if (l.Contains(mod))
  347. return;
  348. l.Add(mod);
  349. if (mod is IEntityCreator)
  350. {
  351. IEntityCreator entityCreator = (IEntityCreator)mod;
  352. foreach (PCode pcode in entityCreator.CreationCapabilities)
  353. {
  354. m_entityCreators[pcode] = entityCreator;
  355. }
  356. }
  357. ModuleInterfaces[typeof(M)] = l;
  358. }
  359. /// <summary>
  360. /// For the given interface, retrieve the region module which implements it.
  361. /// </summary>
  362. /// <returns>null if there is no registered module implementing that interface</returns>
  363. public T RequestModuleInterface<T>()
  364. {
  365. if (ModuleInterfaces.ContainsKey(typeof(T)) &&
  366. (ModuleInterfaces[typeof(T)].Count > 0))
  367. return (T)ModuleInterfaces[typeof(T)][0];
  368. else
  369. return default(T);
  370. }
  371. /// <summary>
  372. /// For the given interface, retrieve an array of region modules that implement it.
  373. /// </summary>
  374. /// <returns>an empty array if there are no registered modules implementing that interface</returns>
  375. public T[] RequestModuleInterfaces<T>()
  376. {
  377. if (ModuleInterfaces.ContainsKey(typeof(T)))
  378. {
  379. List<T> ret = new List<T>();
  380. foreach (Object o in ModuleInterfaces[typeof(T)])
  381. ret.Add((T)o);
  382. return ret.ToArray();
  383. }
  384. else
  385. {
  386. return new T[] { default(T) };
  387. }
  388. }
  389. #endregion
  390. /// <summary>
  391. /// Shows various details about the sim based on the parameters supplied by the console command in openSimMain.
  392. /// </summary>
  393. /// <param name="showParams">What to show</param>
  394. public virtual void Show(string[] showParams)
  395. {
  396. switch (showParams[0])
  397. {
  398. case "modules":
  399. m_log.Error("The currently loaded modules in " + RegionInfo.RegionName + " are:");
  400. foreach (IRegionModule module in Modules.Values)
  401. {
  402. if (!module.IsSharedModule)
  403. {
  404. m_log.Error("Region Module: " + module.Name);
  405. }
  406. }
  407. break;
  408. }
  409. }
  410. public void AddCommand(object mod, string command, string shorthelp, string longhelp, CommandDelegate callback)
  411. {
  412. if (MainConsole.Instance == null)
  413. return;
  414. string modulename = String.Empty;
  415. bool shared = false;
  416. if (mod != null)
  417. {
  418. if (mod is IRegionModule)
  419. {
  420. IRegionModule module = (IRegionModule)mod;
  421. modulename = module.Name;
  422. shared = module.IsSharedModule;
  423. }
  424. else if (mod is IRegionModuleBase)
  425. {
  426. IRegionModuleBase module = (IRegionModuleBase)mod;
  427. modulename = module.Name;
  428. shared = mod is ISharedRegionModule;
  429. }
  430. else throw new Exception("AddCommand module parameter must be IRegionModule or IRegionModuleBase");
  431. }
  432. MainConsole.Instance.Commands.AddCommand(modulename, shared, command, shorthelp, longhelp, callback);
  433. }
  434. }
  435. }