/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the OpenSim Project nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ using System; using System.Collections.Generic; using System.Reflection; using System.Threading; using OpenMetaverse; using log4net; using OpenSim.Framework; using OpenSim.Framework.Communications.Cache; using OpenSim.Region.Framework.Interfaces; namespace OpenSim.Region.Framework.Scenes { public abstract class SceneBase : IScene { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); #region Events public event restart OnRestart; #endregion #region Fields /// /// All the region modules attached to this scene. /// public Dictionary Modules { get { return m_modules; } } protected Dictionary m_modules = new Dictionary(); /// /// The module interfaces available from this scene. /// protected Dictionary> ModuleInterfaces = new Dictionary>(); protected Dictionary ModuleAPIMethods = new Dictionary(); /// /// The module commanders available from this scene /// protected Dictionary m_moduleCommanders = new Dictionary(); /// /// The module commands available for this scene /// protected Dictionary m_moduleCommands = new Dictionary(); /// /// Registered classes that are capable of creating entities. /// protected Dictionary m_entityCreators = new Dictionary(); /// /// The last allocated local prim id. When a new local id is requested, the next number in the sequence is /// dispensed. /// protected uint m_lastAllocatedLocalId = 720000; private readonly Mutex _primAllocateMutex = new Mutex(false); private readonly ClientManager m_clientManager = new ClientManager(); public ClientManager ClientManager { get { return m_clientManager; } } protected ulong m_regionHandle; protected string m_regionName; protected RegionInfo m_regInfo; //public TerrainEngine Terrain; public ITerrainChannel Heightmap; /// /// Allows retrieval of land information for this scene. /// public ILandChannel LandChannel; /// /// Manage events that occur in this scene (avatar movement, script rez, etc.). Commonly used by region modules /// to subscribe to scene events. /// public EventManager EventManager { get { return m_eventManager; } } protected EventManager m_eventManager; protected ScenePermissions m_permissions; public ScenePermissions Permissions { get { return m_permissions; } } protected string m_datastore; private AssetCache m_assetCache; public AssetCache AssetCache { get { return m_assetCache; } set { m_assetCache = value; } } protected RegionStatus m_regStatus; public RegionStatus Region_Status { get { return m_regStatus; } set { m_regStatus = value; } } #endregion #region Update Methods /// /// Normally called once every frame/tick to let the world preform anything required (like running the physics simulation) /// public abstract void Update(); #endregion #region Terrain Methods /// /// Loads the World heightmap /// public abstract void LoadWorldMap(); /// /// Send the region heightmap to the client /// /// Client to send to public virtual void SendLayerData(IClientAPI RemoteClient) { RemoteClient.SendLayerData(Heightmap.GetFloatsSerialised()); } #endregion #region Add/Remove Agent/Avatar /// /// Register the new client with the scene. The client starts off as a child agent - the later agent crossing /// will promote it to a root agent during login. /// /// /// Remove a client from the scene /// /// public abstract void RemoveClient(UUID agentID); public abstract void CloseAllAgents(uint circuitcode); #endregion /// /// /// /// public virtual RegionInfo RegionInfo { get { return m_regInfo; } } #region admin stuff /// /// Region Restart - Seconds till restart. /// /// public virtual void Restart(int seconds) { m_log.Error("[REGION]: passing Restart Message up the namespace"); restart handlerPhysicsCrash = OnRestart; if (handlerPhysicsCrash != null) handlerPhysicsCrash(RegionInfo); } public virtual bool PresenceChildStatus(UUID avatarID) { return false; } public abstract bool OtherRegionUp(RegionInfo thisRegion); public virtual string GetSimulatorVersion() { return "OpenSimulator Server"; } #endregion #region Shutdown /// /// Tidy before shutdown /// public virtual void Close() { // Shut down all non shared modules. foreach (IRegionModule module in Modules.Values) { if (!module.IsSharedModule) { module.Close(); } } Modules.Clear(); try { EventManager.TriggerShutdown(); } catch (Exception e) { m_log.Error("[SCENE]: SceneBase.cs: Close() - Failed with exception " + e.ToString()); } } #endregion /// /// Returns a new unallocated local ID /// /// A brand new local ID protected internal uint AllocateLocalId() { uint myID; _primAllocateMutex.WaitOne(); myID = ++m_lastAllocatedLocalId; _primAllocateMutex.ReleaseMutex(); return myID; } #region Module Methods /// /// Add a module to this scene. /// /// /// public void AddModule(string name, IRegionModule module) { if (!Modules.ContainsKey(name)) { Modules.Add(name, module); } } /// /// Register a module commander. /// /// public void RegisterModuleCommander(ICommander commander) { lock (m_moduleCommanders) { m_moduleCommanders.Add(commander.Name, commander); lock (m_moduleCommands) { foreach (ICommand command in commander.Commands.Values) { if (m_moduleCommands.ContainsKey(command.Name)) { m_log.ErrorFormat( "[MODULES]: Module commander {0} tried to register the command {1} which has already been registered", commander.Name, command.Name); continue; } m_moduleCommands[command.Name] = command; } } } } /// /// Get an available module command /// /// /// The command if it was found, null if no command is available with that name public ICommand GetCommand(string commandName) { lock (m_moduleCommands) { if (m_moduleCommands.ContainsKey(commandName)) return m_moduleCommands[commandName]; else return null; } } /// /// Get a module commander /// /// /// The module commander, null if no module commander with that name was found public ICommander GetCommander(string name) { lock (m_moduleCommanders) { if (m_moduleCommanders.ContainsKey(name)) return m_moduleCommanders[name]; } return null; } public Dictionary GetCommanders() { return m_moduleCommanders; } /// /// Register an interface to a region module. This allows module methods to be called directly as /// well as via events. If there is already a module registered for this interface, it is not replaced /// (is this the best behaviour?) /// /// public void RegisterModuleInterface(M mod) { if (!ModuleInterfaces.ContainsKey(typeof(M))) { List l = new List(); l.Add(mod); ModuleInterfaces.Add(typeof(M), l); if (mod is IEntityCreator) { IEntityCreator entityCreator = (IEntityCreator)mod; foreach (PCode pcode in entityCreator.CreationCapabilities) { m_entityCreators[pcode] = entityCreator; } } } } public void StackModuleInterface(M mod) { List l; if (ModuleInterfaces.ContainsKey(typeof(M))) l = ModuleInterfaces[typeof(M)]; else l = new List(); if (l.Contains(mod)) return; l.Add(mod); if (mod is IEntityCreator) { IEntityCreator entityCreator = (IEntityCreator)mod; foreach (PCode pcode in entityCreator.CreationCapabilities) { m_entityCreators[pcode] = entityCreator; } } ModuleInterfaces[typeof(M)] = l; } /// /// For the given interface, retrieve the region module which implements it. /// /// null if there is no registered module implementing that interface public T RequestModuleInterface() { if (ModuleInterfaces.ContainsKey(typeof(T))) { return (T)ModuleInterfaces[typeof(T)][0]; } else { return default(T); } } /// /// For the given interface, retrieve an array of region modules that implement it. /// /// an empty array if there are no registered modules implementing that interface public T[] RequestModuleInterfaces() { if (ModuleInterfaces.ContainsKey(typeof(T))) { List ret = new List(); foreach (Object o in ModuleInterfaces[typeof(T)]) ret.Add((T)o); return ret.ToArray(); } else { return new T[] { default(T) }; } } #endregion /// /// Shows various details about the sim based on the parameters supplied by the console command in openSimMain. /// /// What to show public virtual void Show(string[] showParams) { switch (showParams[0]) { case "modules": m_log.Error("The currently loaded modules in " + RegionInfo.RegionName + " are:"); foreach (IRegionModule module in Modules.Values) { if (!module.IsSharedModule) { m_log.Error("Region Module: " + module.Name); } } break; } } } }