/*
* 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.Console;
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