Merge branch 'dev' into physics

dsg
Robert Adams 2011-01-03 15:25:31 -08:00
commit e68d9a25b1
19 changed files with 2961 additions and 42 deletions

View File

@ -411,6 +411,12 @@ namespace OpenSim
scene.StartTimer(); scene.StartTimer();
//SYMMETRIC SYNC
//For INonSharedRegionModule, there is no more PostInitialise(). So we trigger OnPostSceneCreation event here
//to let the Sync modules to do their work once all modules are loaded and scene has interfaces to all of them.
scene.EventManager.TriggerOnPostSceneCreation(scene);
//end of SYMMETRIC SYNC
return clientServer; return clientServer;
} }

View File

@ -79,7 +79,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
ActorID = syncConfig.GetString("ActorID", "ZZ"); ActorID = syncConfig.GetString("ActorID", "ZZ");
// If syncConfig does not indicate "server", do not start up server mode // If syncConfig does not indicate "server", do not start up server mode
string mode = syncConfig.GetString("Mode", "server").ToLower(); //string mode = syncConfig.GetString("Mode", "server").ToLower();
string mode = syncConfig.GetString("Mode", "").ToLower();
if(mode != "server") if(mode != "server")
{ {
scene.RegionSyncEnabled = false; scene.RegionSyncEnabled = false;

View File

@ -0,0 +1,169 @@
/*
* Copyright (c) Contributors: TO BE FILLED
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Client;
using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using log4net;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Mono.Addins;
namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
{
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AttachmentsModule")]
public class ClientManagerSyncModule : INonSharedRegionModule, IDSGActorSyncModule
{
#region INonSharedRegionModule
public void Initialise(IConfigSource config)
{
m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
IConfig syncConfig = config.Configs["RegionSyncModule"];
m_active = false;
if (syncConfig == null)
{
m_log.Warn(LogHeader + " No RegionSyncModule config section found. Shutting down.");
return;
}
else if (!syncConfig.GetBoolean("Enabled", false))
{
m_log.Warn(LogHeader + " RegionSyncModule is not enabled. Shutting down.");
return;
}
string actorType = syncConfig.GetString("DSGActorType", "").ToLower();
//Read in configuration, if the local actor is configured to be a client manager, load this module.
if (!actorType.Equals("client_manager"))
{
m_log.Warn(LogHeader + ": not configured as Scene Persistence Actor. Shut down.");
return;
}
m_actorID = syncConfig.GetString("ActorID", "");
if (m_actorID.Equals(""))
{
m_log.Warn(LogHeader + ": ActorID not specified in config file. Shutting down.");
return;
}
m_active = true;
m_log.Warn(LogHeader + " Initialised");
}
//Called after Initialise()
public void AddRegion(Scene scene)
{
if (!m_active)
return;
//connect with scene
m_scene = scene;
//register the module with SceneGraph. If needed, SceneGraph checks the module's ActorType to know what type of module it is.
m_scene.RegisterModuleInterface<IDSGActorSyncModule>(this);
// Setup the command line interface
//m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole;
//InstallInterfaces();
//Register for the OnPostSceneCreation event
//m_scene.EventManager.OnPostSceneCreation += OnPostSceneCreation;
//Register for Scene/SceneGraph events
m_scene.SceneGraph.OnObjectCreate += new ObjectCreateDelegate(ClientManager_OnObjectCreate);
m_scene.EventManager.OnSymmetricSyncStop += ClientManager_OnSymmetricSyncStop;
}
//Called after AddRegion() has been called for all region modules of the scene.
//NOTE::However, at this point, Scene may not have requested all the needed region module interfaces yet.
public void RegionLoaded(Scene scene)
{
if (!m_active)
return;
}
public void RemoveRegion(Scene scene)
{
}
public Type ReplaceableInterface
{
get { return null; }
}
public void Close()
{
m_scene = null;
}
public string Name
{
get { return "ClientManagerSyncModule"; }
}
#endregion //INonSharedRegionModule
#region IDSGActorSyncModule members and functions
private DSGActorTypes m_actorType = DSGActorTypes.ClientManager;
public DSGActorTypes ActorType
{
get { return m_actorType; }
}
private string m_actorID;
public string ActorID
{
get { return m_actorID; }
}
#endregion //IDSGActorSyncModule
#region ClientManagerSyncModule memebers and functions
private ILog m_log;
private bool m_active = false;
public bool Active
{
get { return m_active; }
}
private Scene m_scene;
private string LogHeader = "[ClientManagerSyncModule]";
/// <summary>
/// Script Engine's action upon an object is added to the local scene
/// </summary>
private void ClientManager_OnObjectCreate(EntityBase entity)
{
if (entity is SceneObjectGroup)
{
}
}
public void ClientManager_OnSymmetricSyncStop()
{
//remove all objects
m_scene.DeleteAllSceneObjects();
}
#endregion //ScriptEngineSyncModule
}
}

View File

@ -0,0 +1,169 @@
/*
* Copyright (c) Contributors: TO BE FILLED
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Client;
using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using log4net;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Mono.Addins;
namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
{
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AttachmentsModule")]
public class PhysicsEngineSyncModule : INonSharedRegionModule, IDSGActorSyncModule
{
#region INonSharedRegionModule
public void Initialise(IConfigSource config)
{
m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
IConfig syncConfig = config.Configs["RegionSyncModule"];
m_active = false;
if (syncConfig == null)
{
m_log.Warn(LogHeader + " No RegionSyncModule config section found. Shutting down.");
return;
}
else if (!syncConfig.GetBoolean("Enabled", false))
{
m_log.Warn(LogHeader + " RegionSyncModule is not enabled. Shutting down.");
return;
}
string actorType = syncConfig.GetString("DSGActorType", "").ToLower();
//Read in configuration, if the local actor is configured to be a client manager, load this module.
if (!actorType.Equals("physics_engine"))
{
m_log.Warn(LogHeader + ": not configured as Scene Persistence Actor. Shut down.");
return;
}
m_actorID = syncConfig.GetString("ActorID", "");
if (m_actorID.Equals(""))
{
m_log.Warn(LogHeader + ": ActorID not specified in config file. Shutting down.");
return;
}
m_active = true;
m_log.Warn(LogHeader + " Initialised");
}
//Called after Initialise()
public void AddRegion(Scene scene)
{
if (!m_active)
return;
//connect with scene
m_scene = scene;
//register the module with SceneGraph. If needed, SceneGraph checks the module's ActorType to know what type of module it is.
m_scene.RegisterModuleInterface<IDSGActorSyncModule>(this);
// Setup the command line interface
//m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole;
//InstallInterfaces();
//Register for the OnPostSceneCreation event
//m_scene.EventManager.OnPostSceneCreation += OnPostSceneCreation;
//Register for Scene/SceneGraph events
m_scene.SceneGraph.OnObjectCreate += new ObjectCreateDelegate(PhysicsEngine_OnObjectCreate);
m_scene.EventManager.OnSymmetricSyncStop += PhysicsEngine_OnSymmetricSyncStop;
}
//Called after AddRegion() has been called for all region modules of the scene.
//NOTE::However, at this point, Scene may not have requested all the needed region module interfaces yet.
public void RegionLoaded(Scene scene)
{
if (!m_active)
return;
}
public void RemoveRegion(Scene scene)
{
}
public Type ReplaceableInterface
{
get { return null; }
}
public void Close()
{
m_scene = null;
}
public string Name
{
get { return "PhysicsEngineSyncModule"; }
}
#endregion //INonSharedRegionModule
#region IDSGActorSyncModule members and functions
private DSGActorTypes m_actorType = DSGActorTypes.PhysicsEngine;
public DSGActorTypes ActorType
{
get { return m_actorType; }
}
private string m_actorID;
public string ActorID
{
get { return m_actorID; }
}
#endregion //IDSGActorSyncModule
#region PhysicsEngineSyncModule memebers and functions
private ILog m_log;
private bool m_active = false;
public bool Active
{
get { return m_active; }
}
private Scene m_scene;
private string LogHeader = "[PhysicsEngineSyncModule]";
/// <summary>
/// Script Engine's action upon an object is added to the local scene
/// </summary>
private void PhysicsEngine_OnObjectCreate(EntityBase entity)
{
if (entity is SceneObjectGroup)
{
}
}
public void PhysicsEngine_OnSymmetricSyncStop()
{
//remove all objects
m_scene.DeleteAllSceneObjects();
}
#endregion //ScriptEngineSyncModule
}
}

View File

@ -0,0 +1,174 @@
/*
* Copyright (c) Contributors: TO BE FILLED
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Client;
using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using log4net;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Mono.Addins;
namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
{
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AttachmentsModule")]
public class ScenePersistenceSyncModule : INonSharedRegionModule, IDSGActorSyncModule
{
#region INonSharedRegionModule
public void Initialise(IConfigSource config)
{
m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
IConfig syncConfig = config.Configs["RegionSyncModule"];
m_active = false;
if (syncConfig == null)
{
m_log.Warn(LogHeader + " No RegionSyncModule config section found. Shutting down.");
return;
}
else if (!syncConfig.GetBoolean("Enabled", false))
{
m_log.Warn(LogHeader + " RegionSyncModule is not enabled. Shutting down.");
return;
}
string actorType = syncConfig.GetString("DSGActorType", "").ToLower();
if (!actorType.Equals("scene_persistence"))
{
m_log.Warn(LogHeader + ": not configured as Scene Persistence Actor. Shutting down.");
return;
}
m_actorID = syncConfig.GetString("ActorID", "");
if (m_actorID.Equals(""))
{
m_log.Warn(LogHeader + ": ActorID not specified in config file. Shutting down.");
return;
}
m_active = true;
m_log.Warn(LogHeader+" Initialised");
}
//Called after Initialise()
public void AddRegion(Scene scene)
{
if (!m_active)
return;
m_log.Warn(LogHeader + " AddRegion() called");
//connect with scene
m_scene = scene;
//register the module with SceneGraph. If needed, SceneGraph checks the module's ActorType to know what type of module it is.
m_scene.RegisterModuleInterface<IDSGActorSyncModule>(this);
// Setup the command line interface
//m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole;
//InstallInterfaces();
//Register for the OnPostSceneCreation event
//m_scene.EventManager.OnPostSceneCreation += OnPostSceneCreation;
//Register for Scene/SceneGraph events
m_scene.SceneGraph.OnObjectCreate += new ObjectCreateDelegate(ScenePersistence_OnObjectCreate);
}
//Called after AddRegion() has been called for all region modules of the scene.
//NOTE::However, at this point, Scene may not have requested all the needed region module interfaces yet.
// So to try to access other region modules in RegionLoaded, e.g. RegionSyncModule, is not a good idea.
public void RegionLoaded(Scene scene)
{
if (!m_active)
return;
m_log.Warn(LogHeader + " RegionLoaded() called");
}
public void RemoveRegion(Scene scene)
{
}
public Type ReplaceableInterface
{
get { return null; }
}
public void Close()
{
m_scene = null;
}
public string Name
{
get { return "ScenePersistenceSyncModule"; }
}
#endregion //INonSharedRegionModule
#region IDSGActorSyncModule members and functions
private DSGActorTypes m_actorType = DSGActorTypes.ScenePersistence;
public DSGActorTypes ActorType
{
get { return m_actorType; }
}
private string m_actorID;
public string ActorID
{
get { return m_actorID; }
}
#endregion //IDSGActorSyncModule
#region ScenePersistenceSyncModule memebers and functions
private ILog m_log;
private bool m_active = false;
public bool Active
{
get { return m_active; }
}
private Scene m_scene;
private string LogHeader = "[ScenePersistenceSyncModule]";
public void OnPostSceneCreation(Scene createdScene)
{
//If this is the local scene the actor is working on, do something
if (createdScene == m_scene)
{
}
}
/// <summary>
/// ScenePersistence's actions upon an object is added to the local scene.
/// </summary>
private void ScenePersistence_OnObjectCreate(EntityBase entity)
{
if (entity is SceneObjectGroup)
{
m_log.Warn(LogHeader + ": link to backup for " + entity.UUID);
SceneObjectGroup sog = (SceneObjectGroup)entity;
sog.AttachToBackup();
}
}
#endregion //ScenePersistenceSyncModule
}
}

View File

@ -0,0 +1,184 @@
/*
* Copyright (c) Contributors: TO BE FILLED
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Client;
using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using log4net;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Mono.Addins;
namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
{
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AttachmentsModule")]
public class ScriptEngineSyncModule : INonSharedRegionModule, IDSGActorSyncModule
{
#region INonSharedRegionModule
public void Initialise(IConfigSource config)
{
m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
IConfig syncConfig = config.Configs["RegionSyncModule"];
m_active = false;
if (syncConfig == null)
{
m_log.Warn(LogHeader + " No RegionSyncModule config section found. Shutting down.");
return;
}
else if (!syncConfig.GetBoolean("Enabled", false))
{
m_log.Warn(LogHeader + " RegionSyncModule is not enabled. Shutting down.");
return;
}
string actorType = syncConfig.GetString("DSGActorType", "").ToLower();
if (!actorType.Equals("script_engine"))
{
m_log.Warn(LogHeader + ": not configured as Scene Persistence Actor. Shut down.");
return;
}
m_actorID = syncConfig.GetString("ActorID", "");
if (m_actorID.Equals(""))
{
m_log.Warn(LogHeader + ": ActorID not specified in config file. Shutting down.");
return;
}
m_active = true;
m_log.Warn(LogHeader + " Initialised");
}
//Called after Initialise()
public void AddRegion(Scene scene)
{
if (!m_active)
return;
m_log.Warn(LogHeader + " AddRegion() called");
//connect with scene
m_scene = scene;
//register the module with SceneGraph. If needed, SceneGraph checks the module's ActorType to know what type of module it is.
m_scene.RegisterModuleInterface<IDSGActorSyncModule>(this);
// Setup the command line interface
//m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole;
//InstallInterfaces();
//Register for the OnPostSceneCreation event
//m_scene.EventManager.OnPostSceneCreation += OnPostSceneCreation;
//Register for Scene/SceneGraph events
m_scene.SceneGraph.OnObjectCreate += new ObjectCreateDelegate(ScriptEngine_OnObjectCreate);
m_scene.EventManager.OnSymmetricSyncStop += ScriptEngine_OnSymmetricSyncStop;
}
//Called after AddRegion() has been called for all region modules of the scene.
//NOTE::However, at this point, Scene may not have requested all the needed region module interfaces yet.
public void RegionLoaded(Scene scene)
{
if (!m_active)
return;
}
public void RemoveRegion(Scene scene)
{
}
public Type ReplaceableInterface
{
get { return null; }
}
public void Close()
{
m_scene = null;
}
public string Name
{
get { return "ScriptEngineSyncModule"; }
}
#endregion //INonSharedRegionModule
#region IDSGActorSyncModule members and functions
private DSGActorTypes m_actorType = DSGActorTypes.ScriptEngine;
public DSGActorTypes ActorType
{
get { return m_actorType; }
}
private string m_actorID;
public string ActorID
{
get { return m_actorID; }
}
#endregion //IDSGActorSyncModule
#region ScriptEngineSyncModule memebers and functions
private ILog m_log;
private bool m_active = false;
public bool Active
{
get { return m_active; }
}
private Scene m_scene;
private string LogHeader = "[ScriptEngineSyncModule]";
public void OnPostSceneCreation(Scene createdScene)
{
//If this is the local scene the actor is working on, do something
if (createdScene == m_scene)
{
}
}
/// <summary>
/// Script Engine's action upon an object is added to the local scene
/// </summary>
private void ScriptEngine_OnObjectCreate(EntityBase entity)
{
if (entity is SceneObjectGroup)
{
m_log.Warn(LogHeader + ": start script for obj " + entity.UUID);
SceneObjectGroup sog = (SceneObjectGroup)entity;
sog.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, 0);
sog.ResumeScripts();
}
}
public void ScriptEngine_OnSymmetricSyncStop()
{
//Inform script engine to save script states and stop scripts
m_scene.EventManager.TriggerScriptEngineSyncStop();
//remove all objects
m_scene.DeleteAllSceneObjects();
}
#endregion //ScriptEngineSyncModule
}
}

View File

@ -0,0 +1,153 @@
/*
* Copyright (c) Contributors: TO BE FILLED
*/
using System;
using System.IO;
using OpenMetaverse;
using log4net;
namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
{
//Initial code in SymmetricSyncMessage copied from RegionSyncMessage.
/// <summary>
/// Types of symmetric sync messages among actors.
/// NOTE:: To enable message subscription, we may need to move the definition of MsgType to, say IRegionSyncModule, so that it can be exposed to other region modules.
/// </summary>
public class SymmetricSyncMessage
{
#region MsgType Enum
public enum MsgType
{
Null,
// Actor -> SIM(Scene)
GetTerrain,
GetObjects,
// SIM -> CM
Terrain,
NewObject, // objects
UpdatedObject, // objects
RemovedObject, // objects
// BIDIR
//EchoRequest,
//EchoResponse,
RegionName,
//RegionStatus,
ActorID,
}
#endregion
#region Member Data
private MsgType m_type;
private byte[] m_data;
static ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
#endregion
#region Constructors
public SymmetricSyncMessage(MsgType type, byte[] data)
{
m_type = type;
m_data = data;
}
public SymmetricSyncMessage(MsgType type, string msg)
{
m_type = type;
m_data = System.Text.Encoding.ASCII.GetBytes(msg);
}
public SymmetricSyncMessage(MsgType type)
{
m_type = type;
m_data = new byte[0];
}
public SymmetricSyncMessage(Stream stream)
{
//ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
//try
{
m_type = (MsgType)Utils.BytesToInt(GetBytesFromStream(stream, 4));
int length = Utils.BytesToInt(GetBytesFromStream(stream, 4));
m_data = GetBytesFromStream(stream, length);
//log.WarnFormat("RegionSyncMessage Constructed {0} ({1} bytes)", m_type.ToString(), length);
}
}
private byte[] GetBytesFromStream(Stream stream, int count)
{
// Loop to receive the message length
byte[] ret = new byte[count];
int i = 0;
while (i < count)
{
i += stream.Read(ret, i, count - i);
}
return ret;
}
#endregion
#region Accessors
public MsgType Type
{
get { return m_type; }
}
public int Length
{
get { return m_data.Length; }
}
public byte[] Data
{
get { return m_data; }
}
#endregion
#region Conversions
public byte[] ToBytes()
{
byte[] buf = new byte[m_data.Length + 8];
Utils.IntToBytes((int)m_type, buf, 0);
Utils.IntToBytes(m_data.Length, buf, 4);
Array.Copy(m_data, 0, buf, 8, m_data.Length);
return buf;
}
public override string ToString()
{
return String.Format("{0} ({1} bytes)", m_type.ToString(), m_data.Length.ToString());
}
#endregion
public static void HandleSuccess(string header, SymmetricSyncMessage msg, string message)
{
m_log.WarnFormat("{0} Handled {1}: {2}", header, msg.ToString(), message);
}
public static void HandleTrivial(string header, SymmetricSyncMessage msg, string message)
{
m_log.WarnFormat("{0} Issue handling {1}: {2}", header, msg.ToString(), message);
}
public static void HandleWarning(string header, SymmetricSyncMessage msg, string message)
{
m_log.WarnFormat("{0} Warning handling {1}: {2}", header, msg.ToString(), message);
}
public static void HandleError(string header, SymmetricSyncMessage msg, string message)
{
m_log.WarnFormat("{0} Error handling {1}: {2}", header, msg.ToString(), message);
}
public static bool HandlerDebug(string header, SymmetricSyncMessage msg, string message)
{
m_log.WarnFormat("{0} DBG ({1}): {2}", header, msg.ToString(), message);
return true;
}
}
}

View File

@ -0,0 +1,298 @@
/*
* Copyright (c) Contributors: TO BE FILLED
*/
using System;
using System.IO;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Threading;
using System.Text;
using log4net;
using OpenMetaverse;
namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
{
// For implementations, a lot was copied from RegionSyncClientView, especially the SendLoop/ReceiveLoop.
public class SyncConnector
{
private TcpClient m_tcpConnection = null;
private RegionSyncListenerInfo m_remoteListenerInfo = null;
private Thread m_rcvLoop;
private Thread m_send_loop;
private string LogHeader = "[SYNC CONNECTOR]";
// The logfile
private ILog m_log;
//members for in/out messages queueing
object stats = new object();
private long queuedUpdates=0;
private long dequeuedUpdates=0;
private long msgsIn=0;
private long msgsOut=0;
private long bytesIn=0;
private long bytesOut=0;
private int msgCount = 0;
// A queue for outgoing traffic.
private BlockingUpdateQueue m_outQ = new BlockingUpdateQueue();
private RegionSyncModule m_regionSyncModule = null;
private int m_connectorNum;
public int ConnectorNum
{
get { return m_connectorNum; }
}
//the actorID of the other end of the connection
private string m_syncOtherSideActorID;
public string OtherSideActorID
{
get { return m_syncOtherSideActorID; }
set { m_syncOtherSideActorID = value; }
}
//The region name of the other side of the connection
private string m_syncOtherSideRegionName="";
public string OtherSideRegionName
{
get { return m_syncOtherSideRegionName; }
}
// Check if the client is connected
public bool Connected
{ get { return (m_tcpConnection !=null && m_tcpConnection.Connected); } }
public string Description
{
get
{
if (m_syncOtherSideRegionName == null)
return String.Format("SyncConnector #{0}", m_connectorNum);
return String.Format("SyncConnector #{0} ({1:10})", m_connectorNum, m_syncOtherSideRegionName);
}
}
/// <summary>
/// The constructor that will be called when a SyncConnector is created passively: a remote SyncConnector has initiated the connection.
/// </summary>
/// <param name="connectorNum"></param>
/// <param name="tcpclient"></param>
public SyncConnector(int connectorNum, TcpClient tcpclient, RegionSyncModule syncModule)
{
m_tcpConnection = tcpclient;
m_connectorNum = connectorNum;
m_regionSyncModule = syncModule;
m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
}
/// <summary>
/// The constructor that will be called when a SyncConnector is created actively: it is created to send connection request to a remote listener
/// </summary>
/// <param name="connectorNum"></param>
/// <param name="listenerInfo"></param>
public SyncConnector(int connectorNum, RegionSyncListenerInfo listenerInfo, RegionSyncModule syncModule)
{
m_remoteListenerInfo = listenerInfo;
m_connectorNum = connectorNum;
m_regionSyncModule = syncModule;
m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
}
//Connect to the remote listener
public bool Connect()
{
m_tcpConnection = new TcpClient();
try
{
m_tcpConnection.Connect(m_remoteListenerInfo.Addr, m_remoteListenerInfo.Port);
}
catch (Exception e)
{
m_log.WarnFormat("{0} [Start] Could not connect to RegionSyncServer at {1}:{2}", LogHeader, m_remoteListenerInfo.Addr, m_remoteListenerInfo.Port);
m_log.Warn(e.Message);
return false;
}
return true;
}
/// <summary>
/// Start both the send and receive threads
/// </summary>
public void StartCommThreads()
{
// Create a thread for the receive loop
m_rcvLoop = new Thread(new ThreadStart(ReceiveLoop));
m_rcvLoop.Name = Description + " (ReceiveLoop)";
m_log.WarnFormat("{0} Starting {1} thread", Description, m_rcvLoop.Name);
m_rcvLoop.Start();
// Create a thread for the send loop
m_send_loop = new Thread(new ThreadStart(delegate() { SendLoop(); }));
m_send_loop.Name = Description + " (SendLoop)";
m_log.WarnFormat("{0} Starting {1} thread", Description, m_send_loop.Name);
m_send_loop.Start();
}
public void Shutdown()
{
m_log.Warn(LogHeader + " shutdown connection");
// Abort receive and send loop
m_rcvLoop.Abort();
m_send_loop.Abort();
// Close the connection
m_tcpConnection.Client.Close();
m_tcpConnection.Close();
}
///////////////////////////////////////////////////////////
// Sending messages out to the other side of the connection
///////////////////////////////////////////////////////////
// Send messages from the update Q as fast as we can DeQueue them
// *** This is the main send loop thread for each connected client
private void SendLoop()
{
try
{
while (true)
{
// Dequeue is thread safe
byte[] update = m_outQ.Dequeue();
lock (stats)
dequeuedUpdates++;
Send(update);
}
}
catch (Exception e)
{
m_log.ErrorFormat("{0} has disconnected: {1} (SendLoop)", Description, e.Message);
}
Shutdown();
}
/// <summary>
/// Enqueue update of an object/avatar into the outgoing queue, and return right away
/// </summary>
/// <param name="id">UUID of the object/avatar</param>
/// <param name="update">the update infomation in byte format</param>
public void EnqueueOutgoingUpdate(UUID id, byte[] update)
{
lock (stats)
queuedUpdates++;
// Enqueue is thread safe
m_outQ.Enqueue(id, update);
}
//Send out a messge directly. This should only by called for short messages that are not sent frequently.
//Don't call this function for sending out updates. Call EnqueueOutgoingUpdate instead
public void Send(SymmetricSyncMessage msg)
{
Send(msg.ToBytes());
}
private void Send(byte[] data)
{
if (m_tcpConnection.Connected)
{
try
{
lock (stats)
{
msgsOut++;
bytesOut += data.Length;
}
m_tcpConnection.GetStream().BeginWrite(data, 0, data.Length, ar =>
{
if (m_tcpConnection.Connected)
{
try
{
m_tcpConnection.GetStream().EndWrite(ar);
}
catch (Exception)
{ }
}
}, null);
}
catch (IOException)
{
m_log.WarnFormat("{0}:{1} has disconnected.", Description, m_connectorNum);
}
}
}
///////////////////////////////////////////////////////////
// Receiving messages from the other side ofthe connection
///////////////////////////////////////////////////////////
private void ReceiveLoop()
{
m_log.WarnFormat("{0} Thread running: {1}", LogHeader, m_rcvLoop.Name);
while (true && m_tcpConnection.Connected)
{
SymmetricSyncMessage msg;
// Try to get the message from the network stream
try
{
msg = new SymmetricSyncMessage(m_tcpConnection.GetStream());
//m_log.WarnFormat("{0} Received: {1}", LogHeader, msg.ToString());
}
// If there is a problem reading from the client, shut 'er down.
catch
{
//ShutdownClient();
m_log.WarnFormat("{0}:{1} has disconnected.", Description, m_connectorNum);
Shutdown();
return;
}
// Try handling the message
try
{
HandleMessage(msg);
}
catch (Exception e)
{
m_log.WarnFormat("{0} Encountered an exception: {1} (MSGTYPE = {2})", Description, e.Message, msg.ToString());
}
}
}
private void HandleMessage(SymmetricSyncMessage msg)
{
msgCount++;
switch (msg.Type)
{
case SymmetricSyncMessage.MsgType.RegionName:
{
m_syncOtherSideRegionName = Encoding.ASCII.GetString(msg.Data, 0, msg.Length);
if (m_regionSyncModule.IsSyncRelay)
{
SymmetricSyncMessage outMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.RegionName, m_regionSyncModule.LocalScene.RegionInfo.RegionName);
Send(outMsg);
}
m_log.DebugFormat("Syncing to region \"{0}\"", m_syncOtherSideRegionName);
return;
}
case SymmetricSyncMessage.MsgType.ActorID:
{
m_syncOtherSideActorID = Encoding.ASCII.GetString(msg.Data, 0, msg.Length);
if (m_regionSyncModule.IsSyncRelay)
{
SymmetricSyncMessage outMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.ActorID, m_regionSyncModule.ActorID);
Send(outMsg);
}
m_log.DebugFormat("Syncing to actor \"{0}\"", m_syncOtherSideActorID);
return;
}
default:
break;
}
//For any other messages, we simply deliver the message to RegionSyncModule for now.
//Later on, we may deliver messages to different modules, say sync message to RegionSyncModule and event message to ActorSyncModule.
m_regionSyncModule.HandleIncomingMessage(msg);
}
}
}

View File

@ -205,6 +205,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
public bool UpdateAgent(GridRegion destination, AgentPosition cAgentData) public bool UpdateAgent(GridRegion destination, AgentPosition cAgentData)
{ {
return false;
if (destination == null) if (destination == null)
return false; return false;

View File

@ -589,6 +589,56 @@ namespace OpenSim.Region.CoreModules.World.Terrain
client.OnUnackedTerrain += client_OnUnackedTerrain; client.OnUnackedTerrain += client_OnUnackedTerrain;
} }
//SYMMETRIC SYNC
private long m_lastUpdateTimeStamp = DateTime.Now.Ticks;
public long LastUpdateTimeStamp
{
get { return m_lastUpdateTimeStamp; }
set { m_lastUpdateTimeStamp = value; }
}
private string m_lastUpdateActorID;
public string LastUpdateActorID
{
get { return m_lastUpdateActorID; }
set { m_lastUpdateActorID = value; }
}
private void SyncInfoUpdate(long timeStamp, string actorID)
{
m_lastUpdateTimeStamp = timeStamp;
m_lastUpdateActorID = actorID;
}
/*
public void CheckForTerrainUpdatesBySynchronization(long timeStamp, string actorID)
{
SyncInfoUpdate(timeStamp, actorID);
CheckForTerrainUpdates(false);
}
* */
public void TaintTerrianBySynchronization(long timeStamp, string actorID)
{
SyncInfoUpdate(timeStamp, actorID);
CheckForTerrainUpdates(false, timeStamp, actorID);
}
public bool TerrianModifiedLocally(string localActorID)
{
if (localActorID == m_lastUpdateActorID)
return true;
return false;
}
public void GetSyncInfo(out long lastUpdateTimeStamp, out string lastUpdateActorID)
{
lastUpdateTimeStamp = m_lastUpdateTimeStamp;
lastUpdateActorID = m_lastUpdateActorID;
}
//end of SYMMETRIC SYNC
/// <summary> /// <summary>
/// Checks to see if the terrain has been modified since last check /// Checks to see if the terrain has been modified since last check
/// but won't attempt to limit those changes to the limits specified in the estate settings /// but won't attempt to limit those changes to the limits specified in the estate settings
@ -596,7 +646,21 @@ namespace OpenSim.Region.CoreModules.World.Terrain
/// </summary> /// </summary>
private void CheckForTerrainUpdates() private void CheckForTerrainUpdates()
{ {
CheckForTerrainUpdates(false); //SYMMETRIC SYNC
//Assumption: Thus function is only called when the terrain is updated by the local actor.
// Updating terrain during receiving sync messages from another actor will call CheckForTerrainUpdates.
//Update the timestamp to the current time tick, and set the LastUpdateActorID to be self
long currentTimeTick = DateTime.Now.Ticks;
string localActorID = m_scene.GetSyncActorID();
SyncInfoUpdate(currentTimeTick, localActorID);
//Check if the terrain has been modified and send out sync message if modified.
CheckForTerrainUpdates(false, currentTimeTick, localActorID);
//end of SYMMETRIC SYNC
//CheckForTerrainUpdates(false);
} }
/// <summary> /// <summary>
@ -607,7 +671,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain
/// currently invoked by client_OnModifyTerrain only and not the Commander interfaces /// currently invoked by client_OnModifyTerrain only and not the Commander interfaces
/// <param name="respectEstateSettings">should height map deltas be limited to the estate settings limits</param> /// <param name="respectEstateSettings">should height map deltas be limited to the estate settings limits</param>
/// </summary> /// </summary>
private void CheckForTerrainUpdates(bool respectEstateSettings) //private void CheckForTerrainUpdates(bool respectEstateSettings)
//SYMMETRIC SYNC: Change the interface, to input the right sync information for the most recent update
private void CheckForTerrainUpdates(bool respectEstateSettings, long lastUpdateTimeStamp, string lastUpdateActorID)
//end of SYMMETRIC SYNC
{ {
bool shouldTaint = false; bool shouldTaint = false;
float[] serialised = m_channel.GetFloatsSerialised(); float[] serialised = m_channel.GetFloatsSerialised();
@ -636,6 +703,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain
if (shouldTaint) if (shouldTaint)
{ {
m_tainted = true; m_tainted = true;
//SYMMETRIC SYNC
//Terrain has been modified, send out sync message if needed
if (m_scene.RegionSyncModule != null)
{
m_scene.RegionSyncModule.SendTerrainUpdates(m_lastUpdateActorID);
}
//end of SYMMETRIC SYNC
} }
} }
@ -748,7 +822,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain
m_painteffects[(StandardTerrainEffects) action].PaintEffect( m_painteffects[(StandardTerrainEffects) action].PaintEffect(
m_channel, allowMask, west, south, height, size, seconds); m_channel, allowMask, west, south, height, size, seconds);
CheckForTerrainUpdates(!god); //revert changes outside estate limits //CheckForTerrainUpdates(!god); //revert changes outside estate limits
//SYMMETRIC SYNC
CheckForTerrainUpdates(!god, DateTime.Now.Ticks, m_scene.GetSyncActorID());
//end of SYMMETRIC SYNC
} }
} }
else else
@ -789,7 +866,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain
m_floodeffects[(StandardTerrainEffects) action].FloodEffect( m_floodeffects[(StandardTerrainEffects) action].FloodEffect(
m_channel, fillArea, size); m_channel, fillArea, size);
CheckForTerrainUpdates(!god); //revert changes outside estate limits //CheckForTerrainUpdates(!god); //revert changes outside estate limits
//SYMMETRIC SYNC
CheckForTerrainUpdates(!god, DateTime.Now.Ticks, m_scene.GetSyncActorID());
//end of SYMMETRIC SYNC
} }
} }
else else

View File

@ -64,5 +64,21 @@ namespace OpenSim.Region.Framework.Interfaces
void InstallPlugin(string name, ITerrainEffect plug); void InstallPlugin(string name, ITerrainEffect plug);
void UndoTerrain(ITerrainChannel channel); void UndoTerrain(ITerrainChannel channel);
//SYMMETRIC SYNC
void TaintTerrianBySynchronization(long timeStamp, string actorID);
/// <summary>
/// Return true if the most recent update on terrain is done locally (i.e. not by receiving a terrain-sync message).
/// </summary>
/// <param name="localActorID"></param>
/// <returns></returns>
bool TerrianModifiedLocally(string localActorID);
/// <summary>
/// Obtain the timestemp and actorID information for the most recent update on terrain.
/// </summary>
/// <param name="lastUpdateTimeStamp"></param>
/// <param name="lastUpdateActorID"></param>
void GetSyncInfo(out long lastUpdateTimeStamp, out string lastUpdateActorID);
//end of SYMMETRIC SYNC
} }
} }

View File

@ -376,7 +376,6 @@ namespace OpenSim.Region.Framework.Scenes
public delegate void RegionUp(GridRegion region); public delegate void RegionUp(GridRegion region);
public event RegionUp OnRegionUp; public event RegionUp OnRegionUp;
public class MoneyTransferArgs : EventArgs public class MoneyTransferArgs : EventArgs
{ {
public UUID sender; public UUID sender;
@ -2184,7 +2183,7 @@ namespace OpenSim.Region.Framework.Scenes
catch (Exception e) catch (Exception e)
{ {
m_log.ErrorFormat( m_log.ErrorFormat(
"[EVENT MANAGER]: Delegate for TriggerOnSceneObjectLoaded failed - continuing. {0} {1}", "[EVENT MANAGER]: Delegate for TriggerScriptEngineSyncStop failed - continuing. {0} {1}",
e.Message, e.StackTrace); e.Message, e.StackTrace);
} }
} }
@ -2243,5 +2242,55 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
#endregion #endregion
//SYMMETRIC SYNC
public event PostSceneCreation OnPostSceneCreation;
public delegate void PostSceneCreation(Scene createdScene);
public void TriggerOnPostSceneCreation(Scene createdScene)
{
PostSceneCreation handler = OnPostSceneCreation;
if (handler != null)
{
foreach (PostSceneCreation d in handler.GetInvocationList())
{
try
{
d(createdScene);
}
catch (Exception e)
{
m_log.ErrorFormat(
"[EVENT MANAGER]: Delegate for TriggerOnPostSceneCreation failed - continuing. {0} {1}",
e.Message, e.StackTrace);
}
}
}
}
public delegate void SymmetricSyncStop();
public event SymmetricSyncStop OnSymmetricSyncStop;
public void TriggerOnSymmetricSyncStop()
{
SymmetricSyncStop handlerSymmetricSyncStop = OnSymmetricSyncStop;
if (handlerSymmetricSyncStop != null)
{
foreach (SymmetricSyncStop d in handlerSymmetricSyncStop.GetInvocationList())
{
try
{
d();
}
catch (Exception e)
{
m_log.ErrorFormat(
"[EVENT MANAGER]: Delegate for TriggerOnSymmetricSyncStop failed - continuing. {0} {1}",
e.Message, e.StackTrace);
}
}
}
}
//end of SYMMETRIC SYNC
} }
} }

View File

@ -408,7 +408,10 @@ namespace OpenSim.Region.Framework.Scenes
{ {
get { return m_AvatarFactory; } get { return m_AvatarFactory; }
} }
#region REGION SYNC
#region REGION SYNC -- Asymmetric sync, old style, depreciated ---------
protected IRegionSyncServerModule m_regionSyncServerModule; protected IRegionSyncServerModule m_regionSyncServerModule;
protected IRegionSyncClientModule m_regionSyncClientModule; protected IRegionSyncClientModule m_regionSyncClientModule;
@ -614,6 +617,100 @@ namespace OpenSim.Region.Framework.Scenes
// } // }
#endregion #endregion
#region SYMMETRIC SYNC
///////////////////////////////////////////////////////////////////////////////////////////////
//KittyL: 12/23/2010. SYMMETRIC SYNC: Implementation for the symmetric synchronization model.
///////////////////////////////////////////////////////////////////////////////////////////////
private IRegionSyncModule m_regionSyncModule = null;
public IRegionSyncModule RegionSyncModule
{
get { return m_regionSyncModule; }
//set { m_regionSyncModule = value; }
}
private IDSGActorSyncModule m_DSGActorSyncModule = null;
public IDSGActorSyncModule ActorSyncModule
{
get { return m_DSGActorSyncModule; }
}
//This enumeration would help to identify if after a NewObject/UpdatedObject message is received,
//the object is a new object and hence added to the scene graph, or it an object with some properties
//just updated, or the copy of the object in the UpdatedObject message is the same with local copy
//(before we add time-stamp to identify updates from different actors/scene, it could be possible the same
//update be forwarded, say from script engine to scene, and then back to script engine.
public enum ObjectUpdateResult
{
New, //the New/UpdatedObject message ends up adding a new object to local scene graph
Updated, //the object has some property updated after processing the New/UpdatedObject
Unchanged, //no property of the object has been changed after processing the New/UpdatedObject
//(it probably is the same update this end has sent out before
Error //Errors happen during processing the message, e.g. the entity with the given UUID is not of type SceneObjectGroup
}
public string GetSyncActorID()
{
if (m_DSGActorSyncModule != null)
{
return m_DSGActorSyncModule.ActorID;
}
return "";
}
//This function should only be called by an actor who's local Scene is just a cache of the authorative Scene.
//If the object already exists, use the new copy to replace it.
//Return true if added, false if just updated
public ObjectUpdateResult AddOrUpdateObjectBySynchronization(SceneObjectGroup sog)
{
return m_sceneGraph.AddOrUpdateObjectBySynchronization(sog);
}
//Similar to DeleteSceneObject, except that this does not change LastUpdateActorID and LastUpdateTimeStamp
public void DeleteSceneObjectBySynchronization(SceneObjectGroup group)
{
// m_log.DebugFormat("[SCENE]: Deleting scene object {0} {1}", group.Name, group.UUID);
//SceneObjectPart rootPart = group.GetChildPart(group.UUID);
// Serialise calls to RemoveScriptInstances to avoid
// deadlocking on m_parts inside SceneObjectGroup
lock (m_deleting_scene_object)
{
group.RemoveScriptInstances(true);
}
SceneObjectPart[] partList = group.Parts;
foreach (SceneObjectPart part in partList)
{
if (part.IsJoint() && ((part.Flags & PrimFlags.Physics) != 0))
{
PhysicsScene.RequestJointDeletion(part.Name); // FIXME: what if the name changed?
}
else if (part.PhysActor != null)
{
PhysicsScene.RemovePrim(part.PhysActor);
part.PhysActor = null;
}
}
if (UnlinkSceneObject(group, false))
{
EventManager.TriggerObjectBeingRemovedFromScene(group);
EventManager.TriggerParcelPrimCountTainted();
}
bool silent = false; //do not suppress broadcasting changes to other clients, for debugging with viewers
group.DeleteGroupFromScene(silent);
}
#endregion //SYMMETRIC SYNC
public ICapabilitiesModule CapsModule public ICapabilitiesModule CapsModule
{ {
get { return m_capsModule; } get { return m_capsModule; }
@ -1305,6 +1402,16 @@ namespace OpenSim.Region.Framework.Scenes
PhysEngineToSceneConnectorModule = RequestModuleInterface<IPhysEngineToSceneConnectorModule>(); PhysEngineToSceneConnectorModule = RequestModuleInterface<IPhysEngineToSceneConnectorModule>();
SceneToPhysEngineSyncServer = RequestModuleInterface<ISceneToPhysEngineServer>(); SceneToPhysEngineSyncServer = RequestModuleInterface<ISceneToPhysEngineServer>();
//////////////////////////////////////////////////////////////////////
//SYMMETRIC SYNC (KittyL: started 12/23/2010)
//////////////////////////////////////////////////////////////////////
m_regionSyncModule = RequestModuleInterface<IRegionSyncModule>();
m_DSGActorSyncModule = RequestModuleInterface<IDSGActorSyncModule>();
//////////////////////////////////////////////////////////////////////
//end of SYMMETRIC SYNC
//////////////////////////////////////////////////////////////////////
// Shoving this in here for now, because we have the needed // Shoving this in here for now, because we have the needed
// interfaces at this point // interfaces at this point
// //
@ -1456,7 +1563,7 @@ namespace OpenSim.Region.Framework.Scenes
// If it's a client manager, just send prim updates // If it's a client manager, just send prim updates
// This will get fixed later to only send to locally logged in presences rather than all presences // This will get fixed later to only send to locally logged in presences rather than all presences
// but requires pulling apart the concept of a client from the concept of a presence/avatar // but requires pulling apart the concept of a client from the concept of a presence/avatar
if (IsSyncedClient() || !RegionSyncEnabled) if (IsSyncedClient())
{ {
ForEachScenePresence(delegate(ScenePresence sp) { sp.SendPrimUpdates(); }); ForEachScenePresence(delegate(ScenePresence sp) { sp.SendPrimUpdates(); });
@ -1490,24 +1597,14 @@ namespace OpenSim.Region.Framework.Scenes
m_regionSyncServerModule.SendUpdates(); m_regionSyncServerModule.SendUpdates();
} }
/* //SYMMETRIC SYNC
// The authoritative sim should not try to send coarse locations
// Leave this up to the client managers //NOTE: If it is configured as symmetric sync in opensim.ini, the above IsSyncedServer() or IsSyncedClient() should all return false
if (!IsSyncedServer()) if (RegionSyncModule != null)
{ {
if (m_frame % m_update_coarse_locations == 0) RegionSyncModule.SendSceneUpdates();
{
List<Vector3> coarseLocations;
List<UUID> avatarUUIDs;
SceneGraph.GetCoarseLocations(out coarseLocations, out avatarUUIDs, 60);
// Send coarse locations to clients
ForEachScenePresence(delegate(ScenePresence presence)
{
presence.SendCoarseLocations(coarseLocations, avatarUUIDs);
});
} }
} //end of SYMMETRIC SYNC
* */
int tmpPhysicsMS2 = Util.EnvironmentTickCount(); int tmpPhysicsMS2 = Util.EnvironmentTickCount();
// Do not simulate physics locally if this is a synced client // Do not simulate physics locally if this is a synced client
@ -2357,6 +2454,15 @@ namespace OpenSim.Region.Framework.Scenes
group.DeleteGroupFromScene(silent); group.DeleteGroupFromScene(silent);
// m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID); // m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID);
//SYMMETRIC SYNC
//Set the ActorID and TimeStamp info for this latest update
foreach (SceneObjectPart part in group.Parts)
{
part.SyncInfoUpdate();
}
//end of SYMMETRIC SYNC
} }
/// <summary> /// <summary>

View File

@ -373,23 +373,13 @@ namespace OpenSim.Region.Framework.Scenes
sceneObject.AttachToScene(m_parentScene); sceneObject.AttachToScene(m_parentScene);
//KittyL: edited to support script engine actor
//if (sendClientUpdates)
// sceneObject.ScheduleGroupForFullUpdate();
if (sendClientUpdates) if (sendClientUpdates)
{
sceneObject.ScheduleGroupForFullUpdate(); sceneObject.ScheduleGroupForFullUpdate();
}
Entities.Add(sceneObject); Entities.Add(sceneObject);
//KittyL: edited to support script engine actor if (attachToBackup)
//if (attachToBackup)
// sceneObject.AttachToBackup();
if (attachToBackup && m_parentScene.IsAuthoritativeScene())
{
sceneObject.AttachToBackup(); sceneObject.AttachToBackup();
}
if (OnObjectCreate != null) if (OnObjectCreate != null)
OnObjectCreate(sceneObject); OnObjectCreate(sceneObject);
@ -465,7 +455,10 @@ namespace OpenSim.Region.Framework.Scenes
protected internal void AddToUpdateList(SceneObjectGroup obj) protected internal void AddToUpdateList(SceneObjectGroup obj)
{ {
lock (m_updateList) lock (m_updateList)
{
m_updateList[obj.UUID] = obj; m_updateList[obj.UUID] = obj;
m_log.Debug("added " + obj.UUID + " to m_updateList");
}
} }
/// <summary> /// <summary>
@ -484,6 +477,13 @@ namespace OpenSim.Region.Framework.Scenes
lock (m_updateList) lock (m_updateList)
{ {
updates = new List<SceneObjectGroup>(m_updateList.Values); updates = new List<SceneObjectGroup>(m_updateList.Values);
if (updates.Count > 0)
{
m_log.Debug("SceneGraph: " + updates.Count + " objects to send updates for");
}
m_updateList.Clear(); m_updateList.Clear();
} }
@ -1928,7 +1928,103 @@ namespace OpenSim.Region.Framework.Scenes
} }
#endregion #endregion // REGION SYNC
#region SYMMETRIC SYNC
public Scene.ObjectUpdateResult AddOrUpdateObjectBySynchronization(SceneObjectGroup updatedSog)
{
UUID sogID = updatedSog.UUID;
if (Entities.ContainsKey(sogID))
{
//update the object
EntityBase entity = Entities[sogID];
if (entity is SceneObjectGroup)
{
SceneObjectGroup localSog = (SceneObjectGroup)entity;
Scene.ObjectUpdateResult updateResult = localSog.UpdateObjectAllProperties(updatedSog);
return updateResult;
}
else
{
m_log.Warn("Entity with " + sogID + " is not of type SceneObjectGroup");
//return false;
return Scene.ObjectUpdateResult.Error;
}
}
else
{
m_log.Debug("AddSceneObjectByStateSynch to be called");
AddSceneObjectByStateSynch(updatedSog);
return Scene.ObjectUpdateResult.New;
}
}
//This is an object added due to receiving a state synchronization message from Scene or an actor. Do similar things as the original AddSceneObject(),
//but call ScheduleGroupForFullUpdate_TimeStampUnchanged() instead, so as not to modify the timestamp or actorID, since the object was not created
//locally.
protected bool AddSceneObjectByStateSynch(SceneObjectGroup sceneObject)
{
if (sceneObject == null || sceneObject.RootPart == null || sceneObject.RootPart.UUID == UUID.Zero)
return false;
if (Entities.ContainsKey(sceneObject.UUID))
return false;
SceneObjectPart[] children = sceneObject.Parts;
// Clamp child prim sizes and add child prims to the m_numPrim count
if (m_parentScene.m_clampPrimSize)
{
foreach (SceneObjectPart part in children)
{
Vector3 scale = part.Shape.Scale;
if (scale.X > m_parentScene.m_maxNonphys)
scale.X = m_parentScene.m_maxNonphys;
if (scale.Y > m_parentScene.m_maxNonphys)
scale.Y = m_parentScene.m_maxNonphys;
if (scale.Z > m_parentScene.m_maxNonphys)
scale.Z = m_parentScene.m_maxNonphys;
part.Shape.Scale = scale;
}
}
m_numPrim += children.Length;
sceneObject.AttachToScene(m_parentScene);
//SYMMETRIC SYNC,
sceneObject.ScheduleGroupForFullUpdate_SyncInfoUnchanged();
//end of SYMMETRIC SYNC,
Entities.Add(sceneObject);
//ScenePersistenceSyncModule will attach the object to backup when it catches the OnObjectCreate event.
//if (attachToBackup)
// sceneObject.AttachToBackup();
if (OnObjectCreate != null)
OnObjectCreate(sceneObject);
lock (SceneObjectGroupsByFullID)
{
SceneObjectGroupsByFullID[sceneObject.UUID] = sceneObject;
foreach (SceneObjectPart part in children)
SceneObjectGroupsByFullID[part.UUID] = sceneObject;
}
lock (SceneObjectGroupsByLocalID)
{
SceneObjectGroupsByLocalID[sceneObject.LocalId] = sceneObject;
foreach (SceneObjectPart part in children)
SceneObjectGroupsByLocalID[part.LocalId] = sceneObject;
}
return true;
}
#endregion //SYMMETRIC SYNC
} }
} }

View File

@ -3455,6 +3455,145 @@ namespace OpenSim.Region.Framework.Scenes
this.m_locX = updatedSog.LocX; this.m_locX = updatedSog.LocX;
this.m_locY = updatedSog.LocY; this.m_locY = updatedSog.LocY;
} }
#endregion
#region SYMMETRIC SYNC
//update the existing copy of the object with updated properties in 'updatedSog'
//NOTE: updates on script content are handled seperately (e.g. user edited the script and saved it) -- SESyncServerOnUpdateScript(), a handler of EventManager.OnUpdateScript
//public void UpdateObjectProperties(SceneObjectGroup updatedSog)
/// <summary>
/// Update the existing copy of the object with updated properties in 'updatedSog'. For now we update
/// all properties. Later on this should be edited to allow only updating a bucket of properties.
/// </summary>
/// <param name="updatedSog"></param>
/// <returns></returns>
public Scene.ObjectUpdateResult UpdateObjectAllProperties(SceneObjectGroup updatedSog)
{
if (!this.GroupID.Equals(updatedSog.GroupID))
return Scene.ObjectUpdateResult.Error;
////////////////////////////////////////////////////////////////////////////////////////////////////
//NOTE!!!
//We do not want to simply call SceneObjectGroup.Copy here to clone the object:
//the prims (SceneObjectParts) in updatedSog are different instances than those in the local copy,
//and we want to preserve the references to the prims in this local copy, especially for scripts
//of each prim, where the scripts have references to the local copy. If the local copy is replaced,
//the prims (parts) will be replaces and we need to update all the references that were pointing to
//the previous prims.
////////////////////////////////////////////////////////////////////////////////////////////////////
Scene.ObjectUpdateResult groupUpdateResult = Scene.ObjectUpdateResult.Unchanged;
Dictionary<UUID, SceneObjectPart> updatedParts = new Dictionary<UUID, SceneObjectPart>();
bool partsRemoved = false; //has any old part been removed?
bool rootPartChanged = false; //has the rootpart be changed to a different prim?
lock (m_parts)
{
//update rootpart, if changed
if (m_rootPart.UUID != updatedSog.RootPart.UUID)
{
m_rootPart = updatedSog.RootPart;
rootPartChanged = true;
}
//foreach (KeyValuePair<UUID, SceneObjectPart> pair in updatedSog.Parts)
foreach (SceneObjectPart updatedPart in updatedSog.Parts)
{
UUID partUUID = updatedPart.UUID;
Scene.ObjectUpdateResult partUpdateResult = Scene.ObjectUpdateResult.Unchanged;
if (HasChildPrim(partUUID))
{
//update the existing part
SceneObjectPart oldPart = GetChildPart(partUUID);
partUpdateResult = oldPart.UpdateAllProperties(updatedPart);
updatedParts.Add(partUUID, updatedPart);
}
else
{
//a new part
//m_parts.Add(partUUID, updatedPart);
AddPart(updatedPart);
partUpdateResult = Scene.ObjectUpdateResult.New;
}
if (partUpdateResult != Scene.ObjectUpdateResult.Unchanged)
{
if (partUpdateResult == Scene.ObjectUpdateResult.New)
groupUpdateResult = Scene.ObjectUpdateResult.Updated;
else
groupUpdateResult = partUpdateResult; //Error or Updated
}
}
//For any parts that are not in the updatesParts (the old parts that are still in updatedSog), delete them.
foreach (SceneObjectPart oldPart in this.Parts)
{
if (!updatedParts.ContainsKey(oldPart.UUID))
{
m_parts.Remove(oldPart.UUID);
partsRemoved = true;
}
}
//Update the rootpart's ID in each non root parts
if (rootPartChanged)
{
UpdateParentIDs();
}
}
if (partsRemoved)
{
groupUpdateResult = Scene.ObjectUpdateResult.Updated;
}
/*
//update the authoritative scene that this object is located, which is identified by (LocX, LocY)
if (this.m_locX != updatedSog.LocX)
{
this.m_locX = updatedSog.LocX;
groupUpdateResult = Scene.ObjectUpdateResult.Updated;
}
if (this.m_locY != updatedSog.LocY)
{
this.m_locY = updatedSog.LocY;
groupUpdateResult = Scene.ObjectUpdateResult.Updated;
}
* */
//Schedule updates to be sent out, if the local copy has just been updated
//(1) if we are debugging the actor with a viewer attaching to it,
//we need to schedule updates to be sent to the viewer.
//(2) or if we are a relaying node to relay updates, we need to forward the updates.
//NOTE: LastUpdateTimeStamp and LastUpdateActorID should be kept the same as in the received copy of the object.
if (groupUpdateResult == Scene.ObjectUpdateResult.Updated)
{
ScheduleGroupForFullUpdate_SyncInfoUnchanged();
}
return groupUpdateResult;
}
public void ScheduleGroupForFullUpdate_SyncInfoUnchanged()
{
if (IsAttachment)
m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1}", Name, LocalId);
checkAtTargets();
RootPart.ScheduleFullUpdate_SyncInfoUnchanged();
lock (m_parts)
{
foreach (SceneObjectPart part in this.Parts)
{
if (part != RootPart)
part.ScheduleFullUpdate_SyncInfoUnchanged();
}
}
}
#endregion #endregion
} }
} }

View File

@ -2892,6 +2892,13 @@ namespace OpenSim.Region.Framework.Scenes
// m_log.DebugFormat( // m_log.DebugFormat(
// "[SCENE OBJECT PART]: Scheduling full update for {0}, {1} at {2}", // "[SCENE OBJECT PART]: Scheduling full update for {0}, {1} at {2}",
// UUID, Name, TimeStampFull); // UUID, Name, TimeStampFull);
//SYMMETRIC SYNC
//update information (timestamp, actorID, etc) needed for synchronization across copies of Scene
SyncInfoUpdate();
//end of SYMMETRIC SYNC
} }
/// <summary> /// <summary>
@ -2913,6 +2920,13 @@ namespace OpenSim.Region.Framework.Scenes
// m_log.DebugFormat( // m_log.DebugFormat(
// "[SCENE OBJECT PART]: Scheduling terse update for {0}, {1} at {2}", // "[SCENE OBJECT PART]: Scheduling terse update for {0}, {1} at {2}",
// UUID, Name, TimeStampTerse); // UUID, Name, TimeStampTerse);
//SYMMETRIC SYNC
//update information (timestamp, actorID, etc) needed for synchronization across copies of Scene
SyncInfoUpdate();
//end of SYMMETRIC SYNC
} }
} }
@ -3130,6 +3144,12 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
ClearUpdateSchedule(); ClearUpdateSchedule();
//SYMMETRIC SYNC
m_parentGroup.Scene.RegionSyncModule.QueueSceneObjectPartForUpdate(this);
//end of SYMMETRIC SYNC
} }
/// <summary> /// <summary>
@ -4888,5 +4908,208 @@ namespace OpenSim.Region.Framework.Scenes
#endregion #endregion
#region SYMMETRIC SYNC
//Time stamp for the most recent update on this prim. We only have one time-stamp per prim for now.
//The goal is to evetually have time-stamp per property bucket for each prim.
private long m_lastUpdateTimeStamp = DateTime.Now.Ticks;
public long LastUpdateTimeStamp
{
get { return m_lastUpdateTimeStamp; }
set { m_lastUpdateTimeStamp = value; }
}
//The ID the identifies which actor has caused the most recent update to the prim.
//We use type "string" for the ID only to make it human-readable.
private string m_lastUpdateActorID;
public string LastUpdateActorID
{
get { return m_lastUpdateActorID; }
set { m_lastUpdateActorID = value; }
}
public void UpdateTimestamp()
{
m_lastUpdateTimeStamp = DateTime.Now.Ticks;
}
public void SetLastUpdateActorID()
{
if (m_parentGroup != null)
{
m_lastUpdateActorID = m_parentGroup.Scene.ActorSyncModule.ActorID;
}
else
{
m_log.Error("Prim " + UUID + " is not in a SceneObjectGroup yet");
}
}
public void SyncInfoUpdate()
{
//Trick: calling UpdateTimestamp here makes sure that when an object was received and de-serialized, before
// its parts are linked together, neither TimeStamp or ActorID will be modified. This is because during de-serialization,
// ScheduleFullUpdate() is called when m_parentGroup == null
if (m_parentGroup != null)
{
UpdateTimestamp();
m_lastUpdateActorID = m_parentGroup.Scene.ActorSyncModule.ActorID;
}
}
//!!!!!! -- TODO:
//!!!!!! -- We should call UpdateXXX functions to update each property, cause some of such updates involves sanity checking.
public Scene.ObjectUpdateResult UpdateAllProperties(SceneObjectPart updatedPart)
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//NOTE!!!: So far this function is written with Script Engine updating local Scene cache in mind.
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////Assumptions: ////////////////////
//(1) prim's UUID and LocalID shall not change (UUID is the unique identifies, LocalID is used to refer to the prim by, say scripts)
//(2) RegionHandle won't be updated -- each copy of Scene is hosted on a region with different region handle
//(3) ParentID won't be updated -- if the rootpart of the SceneObjectGroup changed, that will be updated in SceneObjectGroup.UpdateObjectProperties
////////////////////Furture enhancements:////////////////////
//For now, we only update the set of properties that are included in serialization.
//See SceneObjectSerializer for the properties that are included in a serialized SceneObjectPart.
//Later on, we may implement update functions that allow updating certain properties or certain buckets of properties.
if (updatedPart == null)
return Scene.ObjectUpdateResult.Error;
if (m_lastUpdateTimeStamp > updatedPart.LastUpdateTimeStamp)
{
//Our timestamp is more update to date, keep our values of the properties. Do not update anything.
return Scene.ObjectUpdateResult.Unchanged;
}
if (m_lastUpdateTimeStamp == updatedPart.LastUpdateTimeStamp)
{
//if (m_parentGroup.Scene.GetActorID() != updatedPart.LastUpdatedByActorID)
if (m_lastUpdateActorID != updatedPart.LastUpdateActorID)
{
m_log.Warn("Different actors modified SceneObjetPart " + UUID + " with the same TimeStamp, CONFLICT RESOLUTION TO BE IMPLEMENTED!!!!");
return Scene.ObjectUpdateResult.Unchanged;
}
//My own update was relayed back. Don't relay it.
return Scene.ObjectUpdateResult.Unchanged;
}
//Otherwise, our timestamp is less up to date, update the prim with the received copy
Scene.ObjectUpdateResult partUpdateResult = Scene.ObjectUpdateResult.Updated;
//See SceneObjectSerializer for the properties that are included in a serialized SceneObjectPart.
this.AllowedDrop = updatedPart.AllowedDrop;
this.CreatorID = updatedPart.CreatorID;
this.CreatorData = updatedPart.CreatorData;
this.FolderID = updatedPart.FolderID;
this.InventorySerial = updatedPart.InventorySerial;
this.TaskInventory = updatedPart.TaskInventory;
//Following two properties, UUID and LocalId, shall not be updated.
//this.UUID
//this.LocalId
this.Name = updatedPart.Name;
this.Material = updatedPart.Material;
this.PassTouches = updatedPart.PassTouches;
//RegionHandle shall not be copied, since updatedSog is sent by a different actor, which has a different local region
//this.RegionHandle
this.ScriptAccessPin = updatedPart.ScriptAccessPin;
this.GroupPosition = updatedPart.GroupPosition;
this.OffsetPosition = updatedPart.OffsetPosition;
this.RotationOffset = updatedPart.RotationOffset;
this.Velocity = updatedPart.Velocity;
this.AngularVelocity = updatedPart.AngularVelocity;
this.Acceleration = updatedPart.Acceleration;
this.Description = updatedPart.Description;
this.Color = updatedPart.Color;
this.Text = updatedPart.Text;
this.SitName = updatedPart.SitName;
this.TouchName = updatedPart.TouchName;
this.LinkNum = updatedPart.LinkNum;
this.ClickAction = updatedPart.ClickAction;
this.Shape = updatedPart.Shape;
this.Scale = updatedPart.Scale;
this.UpdateFlag = updatedPart.UpdateFlag;
this.SitTargetOrientation = updatedPart.SitTargetOrientation;
this.SitTargetPosition = updatedPart.SitTargetPosition;
this.SitTargetPositionLL = updatedPart.SitTargetPositionLL;
this.SitTargetOrientationLL = updatedPart.SitTargetOrientationLL;
//ParentID should still point to the rootpart in the local sog, do not update. If the root part changed, we will update it in SceneObjectGroup.UpdateObjectProperties()
//this.ParentID;
this.CreationDate = updatedPart.CreationDate;
this.Category = updatedPart.Category;
this.SalePrice = updatedPart.SalePrice;
this.ObjectSaleType = updatedPart.ObjectSaleType;
this.OwnershipCost = updatedPart.OwnershipCost;
this.GroupID = updatedPart.GroupID;
this.OwnerID = updatedPart.OwnerID;
this.LastOwnerID = updatedPart.LastOwnerID;
this.BaseMask = updatedPart.BaseMask;
this.OwnerMask = updatedPart.OwnerMask;
this.GroupMask = updatedPart.GroupMask;
this.EveryoneMask = updatedPart.EveryoneMask;
this.NextOwnerMask = updatedPart.NextOwnerMask;
this.Flags = updatedPart.Flags;
this.CollisionSound = updatedPart.CollisionSound;
this.CollisionSoundVolume = updatedPart.CollisionSoundVolume;
this.MediaUrl = updatedPart.MediaUrl;
this.TextureAnimation = updatedPart.TextureAnimation;
this.ParticleSystem = updatedPart.ParticleSystem;
//Update the timestamp and LastUpdatedByActorID first.
this.m_lastUpdateActorID = updatedPart.LastUpdateActorID;
this.m_lastUpdateTimeStamp = updatedPart.LastUpdateTimeStamp;
/*
this.m_inventory.Items = (TaskInventoryDictionary)updatedPart.m_inventory.Items.Clone();
//update shape information, for now, only update fileds in Shape whose set functions are defined in PrimitiveBaseShape
this.Shape = updatedPart.Shape.Copy();
this.Shape.TextureEntry = updatedPart.Shape.TextureEntry;
* */
return partUpdateResult;
}
/// <summary>
/// Schedules this prim for a full update, without changing the timestamp or actorID (info on when and who modified any property).
/// NOTE: this is the same as the original SceneObjectPart.ScheduleFullUpdate().
/// </summary>
public void ScheduleFullUpdate_SyncInfoUnchanged()
{
m_log.DebugFormat("[SCENE OBJECT PART]: ScheduleFullUpdate_SyncInfoUnchanged for {0} {1}", Name, LocalId);
if (m_parentGroup != null)
{
m_parentGroup.QueueForUpdateCheck();
}
int timeNow = Util.UnixTimeSinceEpoch();
// If multiple updates are scheduled on the same second, we still need to perform all of them
// So we'll force the issue by bumping up the timestamp so that later processing sees these need
// to be performed.
if (timeNow <= TimeStampFull)
{
TimeStampFull += 1;
}
else
{
TimeStampFull = (uint)timeNow;
}
m_updateFlag = 2;
// m_log.DebugFormat(
// "[SCENE OBJECT PART]: Scheduling full update for {0}, {1} at {2}",
// UUID, Name, TimeStampFull);
}
#endregion
} }
} }

View File

@ -215,6 +215,10 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
sceneObject.AddPart(part); sceneObject.AddPart(part);
//SYMMETRIC SYNC
//KittyL: 12/27/2010, added ActorID for symmetric synch model
part.SetLastUpdateActorID();
// SceneObjectGroup.AddPart() tries to be smart and automatically set the LinkNum. // SceneObjectGroup.AddPart() tries to be smart and automatically set the LinkNum.
// We override that here // We override that here
if (originalLinkNum != 0) if (originalLinkNum != 0)
@ -324,6 +328,12 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
m_SOPXmlProcessors.Add("MediaUrl", ProcessMediaUrl); m_SOPXmlProcessors.Add("MediaUrl", ProcessMediaUrl);
m_SOPXmlProcessors.Add("TextureAnimation", ProcessTextureAnimation); m_SOPXmlProcessors.Add("TextureAnimation", ProcessTextureAnimation);
m_SOPXmlProcessors.Add("ParticleSystem", ProcessParticleSystem); m_SOPXmlProcessors.Add("ParticleSystem", ProcessParticleSystem);
//SYMMETRIC SYNC
m_SOPXmlProcessors.Add("LastUpdateTimeStamp", ProcessUpdateTimeStamp);
m_SOPXmlProcessors.Add("LastUpdateActorID", ProcessLastUpdateActorID);
//end of SYMMETRIC SYNC
#endregion #endregion
#region TaskInventoryXmlProcessors initialization #region TaskInventoryXmlProcessors initialization
@ -681,6 +691,19 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
{ {
obj.ParticleSystem = Convert.FromBase64String(reader.ReadElementContentAsString("ParticleSystem", String.Empty)); obj.ParticleSystem = Convert.FromBase64String(reader.ReadElementContentAsString("ParticleSystem", String.Empty));
} }
//SYMMETRIC SYNC
private static void ProcessUpdateTimeStamp(SceneObjectPart obj, XmlTextReader reader)
{
obj.LastUpdateTimeStamp = reader.ReadElementContentAsLong("LastUpdateTimeStamp", string.Empty);
}
private static void ProcessLastUpdateActorID(SceneObjectPart obj, XmlTextReader reader)
{
obj.LastUpdateActorID = reader.ReadElementContentAsString("LastUpdateActorID", string.Empty);
}
//end of SYMMETRIC SYNC
#endregion #endregion
#region TaskInventoryXmlProcessors #region TaskInventoryXmlProcessors
@ -1159,6 +1182,11 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
WriteBytes(writer, "TextureAnimation", sop.TextureAnimation); WriteBytes(writer, "TextureAnimation", sop.TextureAnimation);
WriteBytes(writer, "ParticleSystem", sop.ParticleSystem); WriteBytes(writer, "ParticleSystem", sop.ParticleSystem);
//SYMMETRIC SYNC
writer.WriteElementString("LastUpdateTimeStamp", sop.LastUpdateTimeStamp.ToString());
writer.WriteElementString("LastUpdateActorID", sop.LastUpdateActorID);
//end of SYMMETRIC SYNC
writer.WriteEndElement(); writer.WriteEndElement();
} }

View File

@ -65,7 +65,8 @@
AssetLoaderArgs = "assets/AssetSets.xml" AssetLoaderArgs = "assets/AssetSets.xml"
[Groups] [Groups]
Enabled = true ;Enabled = true
Enabled = false
Module = GroupsModule Module = GroupsModule
DebugEnabled = false DebugEnabled = false
NoticesEnabled = true NoticesEnabled = true