Some updates for client manager

dsg
Dan Lake 2010-04-30 08:13:02 -07:00
parent 79327a6299
commit 2283b85bcf
15 changed files with 803 additions and 295 deletions

View File

@ -4901,33 +4901,39 @@ namespace OpenSim.Region.ClientStack.LindenUDP
int i = 0;
x.ToBytes(xb, ref i);
// If there was a previous update and this update is exactly the same, skip it
if (m_lastAgentUpdate != null && Enumerable.SequenceEqual(xb, m_lastAgentUpdate))
return true;
/*
// If there was a previous update and this update is exactly the same, skip it
if (m_scene.IsSyncedClient() && m_lastAgentUpdate != null && Enumerable.SequenceEqual(xb, m_lastAgentUpdate))
{
//m_log.Warn("LLClientView: HandleAgentUpdate (IDENTICAL TO LAST)");
return true;
}
// What is different?? (only interesting for client managers)
/*
if(m_scene.IsSyncedClient() && m_lastAgentUpdate != null)
{
AgentUpdatePacket.AgentDataBlock lastarg = new AgentUpdatePacket.AgentDataBlock();
i = 0;
lastarg.FromBytes(m_lastAgentUpdate, ref i);
if(x.BodyRotation != lastarg.BodyRotation) m_log.Warn("BodyRotation");
if(x.CameraAtAxis != lastarg.CameraAtAxis) m_log.Warn("CameraAtAxis");
if(x.CameraCenter != lastarg.CameraCenter) m_log.Warn("CameraCenter");
if(x.CameraLeftAxis != lastarg.CameraLeftAxis) m_log.Warn("CameraLeftAxis");
if(x.CameraUpAxis != lastarg.CameraUpAxis) m_log.Warn("CameraUpAxis");
if(x.ControlFlags != lastarg.ControlFlags) m_log.Warn("ControlFlags");
if(x.Far != lastarg.Far) m_log.Warn("Far");
if(x.Flags != lastarg.Flags) m_log.Warn("Flags");
if(x.State != lastarg.State) m_log.Warn("State");
if(x.HeadRotation != lastarg.HeadRotation) m_log.Warn("HeadRotation");
if(x.SessionID != lastarg.SessionID) m_log.Warn("SessionID");
if(x.AgentID != lastarg.AgentID) m_log.Warn("AgentID");
m_log.WarnFormat("LLClientView: HandleAgentUpdate |{0}{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}|",
(x.BodyRotation != lastarg.BodyRotation) ? "X" : " ",
(x.CameraAtAxis != lastarg.CameraAtAxis) ? "X" : " ",
(x.CameraCenter != lastarg.CameraCenter) ? "X" : " ",
(x.CameraLeftAxis != lastarg.CameraLeftAxis) ? "X" : " ",
(x.CameraUpAxis != lastarg.CameraUpAxis) ? "X" : " ",
(x.ControlFlags != lastarg.ControlFlags) ? "X" : " ",
(x.Far != lastarg.Far) ? "X" : " ",
(x.Flags != lastarg.Flags) ? "X" : " ",
(x.State != lastarg.State) ? "X" : " ",
(x.HeadRotation != lastarg.HeadRotation) ? "X" : " ",
(x.SessionID != lastarg.SessionID) ? "X" : " ",
(x.AgentID != lastarg.AgentID) ? "X" : " ");
}
* */
// save this set of arguments for next time
m_lastAgentUpdate = xb;

View File

@ -130,6 +130,7 @@ namespace OpenSim.Region.Examples.RegionSyncModule
public event Action<UUID> OnRemoveAvatar;
public event CreateNewInventoryItem OnCreateNewInventoryItem;
public event LinkInventoryItem OnLinkInventoryItem;
public event CreateInventoryFolder OnCreateNewInventoryFolder;
public event UpdateInventoryFolder OnUpdateInventoryFolder;
public event MoveInventoryFolder OnMoveInventoryFolder;

View File

@ -20,6 +20,16 @@ namespace OpenSim.Region.Examples.RegionSyncModule
// The RegionSyncClient has a receive thread to process messages from the RegionSyncServer.
public class RegionSyncClient
{
#region MsgHandlerStatus Enum
public enum MsgHandlerStatus
{
Success, // Everything went as expected
Trivial, // Minor issue, nothing to worry about
Warning, // Something went wrong, we can continue
Error // This should certainly not have happened! (A bug)
}
#endregion
#region RegionSyncClient members
// Set the addr and port of RegionSyncServer
@ -29,9 +39,15 @@ namespace OpenSim.Region.Examples.RegionSyncModule
// A reference to the local scene
private Scene m_scene;
// The avatars added to this client manager for clients on other client managers
Dictionary<UUID, RegionSyncAvatar> m_remoteAvatars = new Dictionary<UUID, RegionSyncAvatar>();
Dictionary<UUID, IClientAPI> m_localAvatars = new Dictionary<UUID, IClientAPI>();
// The logfile
private ILog m_log;
private string LogHeader = "[REGION SYNC CLIENT]";
// The listener and the thread which listens for connections from client managers
private Thread m_rcvLoop;
@ -46,7 +62,7 @@ namespace OpenSim.Region.Examples.RegionSyncModule
public RegionSyncClient(Scene scene, string addr, int port)
{
m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
m_log.Warn("[REGION SYNC CLIENT] Constructed");
m_log.WarnFormat("{0} Constructed", LogHeader);
m_scene = scene;
m_addr = IPAddress.Parse(addr);
m_port = port;
@ -61,40 +77,63 @@ namespace OpenSim.Region.Examples.RegionSyncModule
}
catch (Exception e)
{
m_log.WarnFormat("[REGION SYNC CLIENT] [Start] Could not connect to RegionSyncServer at {0}:{1}", m_addr, m_port);
m_log.WarnFormat("{0} [Start] Could not connect to RegionSyncServer at {1}:{2}", LogHeader, m_addr, m_port);
m_log.Warn(e.Message);
}
m_log.WarnFormat("[REGION SYNC CLIENT] Connected to RegionSyncServer at {0}:{1}", m_addr, m_port);
m_log.WarnFormat("{0} Connected to RegionSyncServer at {1}:{2}", LogHeader, m_addr, m_port);
m_rcvLoop = new Thread(new ThreadStart(ReceiveLoop));
m_rcvLoop.Name = "RegionSyncClient ReceiveLoop";
m_log.WarnFormat("[REGION SYNC CLIENT] Starting {0} thread", m_rcvLoop.Name);
m_log.WarnFormat("{0} Starting {1} thread", LogHeader, m_rcvLoop.Name);
m_rcvLoop.Start();
m_log.Warn("[REGION SYNC CLIENT] Started");
m_log.WarnFormat("{0} Started", LogHeader);
DoInitialSync();
}
// Disconnect from the RegionSyncServer and close the RegionSyncClient
public void Stop()
{
// Can't abort the TCP connection until we let the remote scene know we are going away.
// Or, the remote scene will remove the CM's avatars automatically when it disconnects
m_rcvLoop.Abort();
ShutdownClient();
}
private void ShutdownClient()
{
m_log.WarnFormat("[REGION SYNC CLIENT] Disconnected from RegionSyncServer. Shutting down.");
m_scene.ForEachClient(delegate(IClientAPI client) { client.OnAgentUpdateRaw -= HandleAgentUpdateRaw; });
m_log.WarnFormat("{0} Disconnected from RegionSyncServer. Shutting down.", LogHeader);
// Remove remote avatars from local scene
lock (m_remoteAvatars)
{
foreach (UUID id in m_remoteAvatars.Keys)
{
m_scene.RemoveClient(id);
}
}
// Remove local avatars from remote scene
lock (m_localAvatars)
{
foreach (KeyValuePair<UUID, IClientAPI> kvp in m_localAvatars)
{
// Tell the remote scene to remove this client
RemoveLocalClient(kvp.Key, m_scene);
// Remove the agent update handler from the client
kvp.Value.OnAgentUpdateRaw -= HandleAgentUpdateRaw;
}
}
// Close the connection
m_client.Client.Close();
m_client.Close();
}
// Listen for messages from a RegionSyncClient
// *** This is the main thread loop for each connected client
private void ReceiveLoop()
{
m_log.WarnFormat("[REGION SYNC CLIENT] Thread running: {0}", m_rcvLoop.Name);
m_log.WarnFormat("{0} Thread running: {1}", LogHeader, m_rcvLoop.Name);
while (true && m_client.Connected)
{
RegionSyncMessage msg;
@ -102,7 +141,7 @@ namespace OpenSim.Region.Examples.RegionSyncModule
try
{
msg = new RegionSyncMessage(m_client.GetStream());
//m_log.WarnFormat("[REGION SYNC CLIENT] Received: {0}", msg.ToString());
//m_log.WarnFormat("{0} Received: {1}", LogHeader, msg.ToString());
}
// If there is a problem reading from the client, shut 'er down.
catch
@ -113,16 +152,32 @@ namespace OpenSim.Region.Examples.RegionSyncModule
// Try handling the message
try
{
HandleMessage(msg);
string message;
MsgHandlerStatus status = HandleMessage(msg, out message);
switch (status)
{
case MsgHandlerStatus.Success:
//m_log.WarnFormat("{0} Handled {1}: {2}", LogHeader, msg.ToString(), message);
break;
case MsgHandlerStatus.Trivial:
m_log.WarnFormat("{0} Issue handling {1}: {2}", LogHeader, msg.ToString(), message);
break;
case MsgHandlerStatus.Warning:
m_log.WarnFormat("{0} Warning handling {1}: {2}", LogHeader, msg.ToString(), message);
break;
case MsgHandlerStatus.Error:
m_log.WarnFormat("{0} Error handling {1}: {2}", LogHeader, msg.ToString(), message);
break;
}
}
catch (Exception e)
{
m_log.WarnFormat("[REGION SYNC CLIENT] Encountered an exception: {0}", e.Message);
m_log.WarnFormat("{0} Encountered an exception: {1}", LogHeader, e.Message);
}
}
}
#region Send
#region SEND
// Send a message to a single connected RegionSyncClient
private void Send(string msg)
{
@ -133,7 +188,7 @@ namespace OpenSim.Region.Examples.RegionSyncModule
private void Send(RegionSyncMessage msg)
{
Send(msg.ToBytes());
//m_log.WarnFormat("[REGION SYNC CLIENT] Sent {0}", msg.ToString());
//m_log.WarnFormat("{0} Sent {1}", LogHeader, msg.ToString());
}
private void Send(byte[] data)
@ -154,58 +209,71 @@ namespace OpenSim.Region.Examples.RegionSyncModule
}
#endregion
// Send coarse locations to locally connected clients
// This is a highly optimized version for lots of local and remote clients
// 99.9% faster for 1000 clients!
public void SendCoarseLocations()
{
List<UUID> ids = new List<UUID>();
List<Vector3> locations = new List<Vector3>();
m_scene.GetCoarseLocations(out ids, out locations);
lock (m_localAvatars)
{
foreach (IClientAPI client in m_localAvatars.Values)
{
client.SendCoarseLocationUpdate(ids, locations);
}
}
}
HashSet<string> exceptions = new HashSet<string>();
private OSDMap DeserializeMessage(RegionSyncMessage msg)
{
OSDMap data = null;
try
{
data = OSDParser.DeserializeJson(Encoding.ASCII.GetString(msg.Data)) as OSDMap;
}
catch (Exception e)
{
lock (exceptions)
// If this is a new message, then print the underlying data that caused it
if (!exceptions.Contains(e.Message))
m_log.Error(LogHeader + " " + Encoding.ASCII.GetString(msg.Data));
data = null;
}
return data;
}
// Handle an incoming message
// Returns true if the message was processed
// TODO: This should not be synchronous with the receive!
// Instead, handle messages from the incoming Queue
private bool HandleMessage(RegionSyncMessage msg)
private MsgHandlerStatus HandleMessage(RegionSyncMessage msg, out string result)
{
switch (msg.Type)
{
case RegionSyncMessage.MsgType.Terrain:
{
m_scene.Heightmap.LoadFromXmlString(Encoding.ASCII.GetString(msg.Data));
return HandlerSuccess(msg, "Syncrhonized terrain");
result = "Synchronized terrain";
return MsgHandlerStatus.Success;
}
case RegionSyncMessage.MsgType.AddObject:
case RegionSyncMessage.MsgType.UpdateObject:
case RegionSyncMessage.MsgType.NewObject:
case RegionSyncMessage.MsgType.UpdatedObject:
{
SceneObjectGroup sog = SceneObjectSerializer.FromXml2Format(Encoding.ASCII.GetString(msg.Data));
if(sog.IsDeleted)
return HandlerFailure(msg, String.Format("Ignoring update on deleted LocalId {0}.", sog.LocalId.ToString()));
if (sog.IsDeleted)
{
result = String.Format("Ignoring update on deleted LocalId {0}.", sog.LocalId.ToString());
return MsgHandlerStatus.Trivial;
}
if (m_scene.AddNewSceneObject(sog, true))
{
result = String.Format("Object \"{0}\" ({1}) ({1}) updated.", sog.Name, sog.UUID.ToString(), sog.LocalId.ToString());
else
result = String.Format("Object \"{0}\" ({1}) ({1}) added.", sog.Name, sog.UUID.ToString(), sog.LocalId.ToString());
sog.ScheduleGroupForFullUpdate();
return HandlerSuccess(msg, String.Format("LocalId {0} added or updated.", sog.LocalId.ToString()));
}
return HandlerFailure(msg, String.Format("Could not add or update LocalId {0}.", sog.LocalId.ToString()));
}
case RegionSyncMessage.MsgType.UpdateAvatarTerse:
{
OSDMap data = OSDParser.DeserializeJson(Encoding.ASCII.GetString(msg.Data)) as OSDMap;
if( data != null )
{
UUID agentID = data["id"].AsUUID();
Vector3 pos = data["pos"].AsVector3();
Vector3 vel = data["vel"].AsVector3();
Quaternion rot = data["rot"].AsQuaternion();
// We get the UUID of the avatar to be updated, find it in the scene
if (agentID != UUID.Zero)
{
ScenePresence presence = m_scene.GetScenePresence(agentID);
if (presence != null)
{
presence.AbsolutePosition = pos;
presence.Velocity = vel;
presence.Rotation = rot;
presence.SendTerseUpdateToAllClients();
return HandlerSuccess(msg, String.Format("agentID {0} updated", agentID.ToString()));
}
}
return HandlerFailure(msg, String.Format("agentID {0} not found.", agentID.ToString()));
}
return HandlerFailure(msg, "Could not parse AgentUpdate parameters");
return MsgHandlerStatus.Success;
}
// return HandlerSuccess(msg, "Updated avatar");
/*
@ -228,9 +296,9 @@ namespace OpenSim.Region.Examples.RegionSyncModule
}
}
* */
case RegionSyncMessage.MsgType.RemoveObject:
case RegionSyncMessage.MsgType.RemovedObject:
{
OSDMap data = OSDParser.DeserializeJson(Encoding.ASCII.GetString(msg.Data)) as OSDMap;
OSDMap data = DeserializeMessage(msg);
if( data != null )
{
ulong regionHandle = data["regionHandle"].AsULong();
@ -245,15 +313,130 @@ namespace OpenSim.Region.Examples.RegionSyncModule
if (sog != null)
{
m_scene.DeleteSceneObject(sog, false);
return HandlerSuccess(msg, String.Format("localID {0} deleted.", localID.ToString()));
result = String.Format("localID {0} deleted.", localID.ToString());
return MsgHandlerStatus.Success;
}
}
return HandlerFailure(msg, String.Format("ignoring delete request for non-local regionHandle {0}.", regionHandle.ToString()));
result = String.Format("ignoring delete request for non-local regionHandle {0}.", regionHandle.ToString());
return MsgHandlerStatus.Trivial;
}
return HandlerFailure(msg, String.Format("localID {0} not found.", localID.ToString()));
result = String.Format("localID {0} not found.", localID.ToString());
return MsgHandlerStatus.Warning;
}
return HandlerFailure(msg, "Could not parse DeleteObject parameters");
result = "Could not deserialize JSON data.";
return MsgHandlerStatus.Error;
}
case RegionSyncMessage.MsgType.NewAvatar:
{
OSDMap data = DeserializeMessage(msg);
if (data != null)
{
UUID agentID = data["agentID"].AsUUID();
string first = data["first"].AsString();
string last = data["last"].AsString();
Vector3 startPos = data["startPos"].AsVector3();
if (agentID != null && first != null && last != null && startPos != null)
{
if (m_remoteAvatars.ContainsKey(agentID))
{
result = String.Format("Attempted to add duplicate avatar \"{0} {1}\" ({2})", first, last, agentID.ToString());
return MsgHandlerStatus.Warning;
}
ScenePresence sp;
if (m_scene.TryGetScenePresence(agentID, out sp))
{
result = String.Format("Confirmation of new avatar \"{0}\" ({1})", sp.Name, sp.UUID.ToString());
HandlerDebug(msg, result);
return MsgHandlerStatus.Success;
}
RegionSyncAvatar av = new RegionSyncAvatar(m_scene, agentID, first, last, startPos);
m_remoteAvatars.Add(agentID, av);
m_scene.AddNewClient(av);
result = String.Format("Handled NewAvatar for UUID {0}", agentID);
return MsgHandlerStatus.Success;
}
}
result = "Could not deserialize JSON data.";
return MsgHandlerStatus.Error;
}
case RegionSyncMessage.MsgType.UpdatedAvatar:
{
OSDMap data = DeserializeMessage(msg);
if (data != null)
{
UUID agentID = data["id"].AsUUID();
Vector3 pos = data["pos"].AsVector3();
Vector3 vel = data["vel"].AsVector3();
Quaternion rot = data["rot"].AsQuaternion();
bool flying = data["fly"].AsBoolean();
// We get the UUID of the avatar to be updated, find it in the scene
if (agentID != UUID.Zero)
{
ScenePresence presence;
if (m_scene.TryGetScenePresence(agentID, out presence))
{
presence.AbsolutePosition = pos;
presence.Velocity = vel;
presence.Rotation = rot;
presence.PhysicsActor.Flying = flying;
List<IClientAPI> locals;
lock (m_localAvatars)
locals = new List<IClientAPI>(m_localAvatars.Values);
presence.SendTerseUpdateToClientList(locals);
result = String.Format("Avatar \"{0}\" ({1}) ({2}) updated (pos:{3}, vel:{4}, rot:{5}, fly:{6})",
presence.Name, presence.UUID.ToString(), presence.LocalId.ToString(),
presence.AbsolutePosition.ToString(), presence.Velocity.ToString(),
presence.Rotation.ToString(), presence.PhysicsActor.Flying ? "Y" : "N");
return MsgHandlerStatus.Success;
}
}
result = String.Format("agentID {0} not found.", agentID.ToString());
return MsgHandlerStatus.Warning;
}
result = "Could not deserialize JSON data.";
return MsgHandlerStatus.Error;
}
case RegionSyncMessage.MsgType.RemovedAvatar:
{
OSDMap data = DeserializeMessage(msg);
if (data != null)
{
UUID agentID = data["agentID"].AsUUID();
// We get the UUID of the avatar to be removed, find it in the scene
if (agentID != UUID.Zero)
{
ScenePresence presence;
// If this is a synced remote avatar and it's in the scene, then remove it
if (m_remoteAvatars.ContainsKey(agentID))
{
if (m_scene.TryGetScenePresence(agentID, out presence))
{
m_scene.RemoveClient(agentID);
result = String.Format("Avatar \"{0}\" removed from scene", presence.Name);
return MsgHandlerStatus.Success;
}
else
{
result = String.Format("agentID {0} not found.", agentID.ToString());
return MsgHandlerStatus.Warning;
}
}
else
{
result = String.Format("agentID {0} is not a remote avatar.", agentID.ToString());
return MsgHandlerStatus.Warning;
}
}
result = String.Format("agentID {0} was UUID.Zero!", agentID.ToString());
return MsgHandlerStatus.Error;
}
result = "Could not deserialize JSON data.";
return MsgHandlerStatus.Error;
}
/*
case RegionSyncMessage.MsgType.UpdateObject:
{
@ -279,31 +462,27 @@ namespace OpenSim.Region.Examples.RegionSyncModule
* */
default:
{
m_log.WarnFormat("[REGION SYNC CLIENT] Unsupported message type");
return false;
result = String.Format("{0} Unsupported message type: {1}", LogHeader, ((int)msg.Type).ToString());
return MsgHandlerStatus.Error;
}
}
}
private bool HandlerSuccess(RegionSyncMessage msg, string handlerMessage)
private bool HandlerDebug(RegionSyncMessage msg, string handlerMessage)
{
//m_log.WarnFormat("[REGION SYNC CLIENT] Handled {0}: {1}", msg.ToString(), handlerMessage);
m_log.WarnFormat("{0} DBG ({1}): {2}", LogHeader, msg.ToString(), handlerMessage);
return true;
}
private bool HandlerFailure(RegionSyncMessage msg, string handlerMessage)
{
//m_log.WarnFormat("[REGION SYNC SERVER] Unable to handle {0}: {1}", msg.ToString(), handlerMessage);
return false;
}
private void DoInitialSync()
{
m_scene.DeleteAllSceneObjects();
Send(new RegionSyncMessage(RegionSyncMessage.MsgType.GetTerrain));
Send(new RegionSyncMessage(RegionSyncMessage.MsgType.GetObjects));
Send(new RegionSyncMessage(RegionSyncMessage.MsgType.GetAvatars));
// Register for events which will be forwarded to authoritative scene
m_scene.EventManager.OnNewClient += EventManager_OnNewClient;
m_scene.EventManager.OnClientClosed += new EventManager.ClientClosed(RemoveLocalClient);
}
public string GetServerAddressAndPort()
@ -311,11 +490,20 @@ namespace OpenSim.Region.Examples.RegionSyncModule
return m_addr.ToString() + ":" + m_port.ToString();
}
#region Event Handlers
#region MESSAGES SENT FROM CLIENT MANAGER TO SIM
public void EventManager_OnNewClient(IClientAPI client)
{
// If this client was added in response to NewAvatar message from a synced server,
// don't subscribe to events or send back to server
lock (m_remoteAvatars)
{
if (m_remoteAvatars.ContainsKey(client.AgentId))
return;
}
// Otherwise, it's a real local client connecting so track it locally
lock(m_localAvatars)
m_localAvatars.Add(client.AgentId, client);
m_log.WarnFormat("{0} New local client \"{1}\" ({2}) being added to remote scene.", LogHeader, client.Name, client.AgentId.ToString());
// Let the auth sim know that a new agent has connected
OSDMap data = new OSDMap(1);
data["agentID"] = OSD.FromUUID(client.AgentId);
@ -330,6 +518,16 @@ namespace OpenSim.Region.Examples.RegionSyncModule
client.OnChatFromClientRaw += HandleChatFromClientRaw;
}
void RemoveLocalClient(UUID clientID, Scene scene)
{
m_log.WarnFormat("{0} Local client ({1}) being removed from remote scene.", LogHeader, clientID.ToString());
m_localAvatars.Remove(clientID);
// Let the auth sim know that an agent has disconnected
OSDMap data = new OSDMap(1);
data["agentID"] = OSD.FromUUID(clientID);
Send(new RegionSyncMessage(RegionSyncMessage.MsgType.AgentRemove, OSDParser.SerializeJsonString(data)));
}
/// <summary>
/// This is the event handler for client movement. If a client is moving, this event is triggering.
/// </summary>
@ -342,8 +540,8 @@ namespace OpenSim.Region.Examples.RegionSyncModule
{
Send(new RegionSyncMessage(RegionSyncMessage.MsgType.ChatFromClient, chatData));
}
#endregion
/*
// Should be part of the RegionSyncClient
public string ReceiveMsg()

View File

@ -101,6 +101,11 @@ namespace OpenSim.Region.Examples.RegionSyncModule
#endregion
#region IRegionSyncClientModule members
public void SendCoarseLocations()
{
m_client.SendCoarseLocations();
}
public bool Active
{
get { return m_active; }
@ -126,6 +131,8 @@ namespace OpenSim.Region.Examples.RegionSyncModule
private ILog m_log;
private Object m_client_lock = new Object();
private RegionSyncClient m_client = null;
#endregion
#region Event Handlers

View File

@ -21,6 +21,13 @@ namespace OpenSim.Region.Examples.RegionSyncModule
public class RegionSyncClientView
{
#region RegionSyncClientView members
object stats = new object();
private long msgsIn;
private long msgsOut;
private long bytesIn;
private long bytesOut;
// The TcpClient this view uses to communicate with its RegionSyncClient
private TcpClient m_tcpclient;
// Set the addr and port for TcpListener
@ -32,15 +39,12 @@ namespace OpenSim.Region.Examples.RegionSyncModule
Dictionary<UUID, RegionSyncAvatar> m_syncedAvatars = new Dictionary<UUID, RegionSyncAvatar>();
// A queue for incoming and outgoing traffic
private Queue<string> m_inQ = new Queue<string>();
private Queue<string> m_outQ = new Queue<string>();
private OpenMetaverse.BlockingQueue<RegionSyncMessage> inbox = new OpenMetaverse.BlockingQueue<RegionSyncMessage>();
private ILog m_log;
private Thread m_receive_loop;
// The last time the entire region was sent to this RegionSyncClient
private long m_archive_time;
private Thread m_handler;
// A string of the format [REGION SYNC CLIENT VIEW #X] for use in log headers
private string LogHeader
@ -54,6 +58,12 @@ namespace OpenSim.Region.Examples.RegionSyncModule
get { return String.Format("RegionSyncClientView #{0}", m_connection_number); }
}
public string GetStats()
{
lock(stats)
return String.Format("{0},{1},{2},{3}", msgsIn, msgsOut, bytesIn, bytesOut);
}
// Check if the client is connected
public bool Connected
{ get { return m_tcpclient.Connected; } }
@ -96,12 +106,17 @@ namespace OpenSim.Region.Examples.RegionSyncModule
while (true)
{
RegionSyncMessage msg = GetMessage();
lock (stats)
{
msgsIn++;
bytesIn += msg.Length;
}
HandleMessage(msg);
}
}
catch (Exception e)
{
m_log.WarnFormat("{0} RegionSyncClient has disconnected.", LogHeader);
m_log.WarnFormat("{0} RegionSyncClient has disconnected: {1}", LogHeader, e.Message);
}
}
@ -110,10 +125,30 @@ namespace OpenSim.Region.Examples.RegionSyncModule
{
// Get a RegionSyncMessager from the incoming stream
RegionSyncMessage msg = new RegionSyncMessage(m_tcpclient.GetStream());
m_log.WarnFormat("{0} Received {1}", LogHeader, msg.ToString());
//m_log.WarnFormat("{0} Received {1}", LogHeader, msg.ToString());
return msg;
}
HashSet<string> exceptions = new HashSet<string>();
private OSDMap DeserializeMessage(RegionSyncMessage msg)
{
OSDMap data = null;
try
{
data = OSDParser.DeserializeJson(Encoding.ASCII.GetString(msg.Data)) as OSDMap;
}
catch(Exception e)
{
lock(exceptions)
// If this is a new message, then print the underlying data that caused it
if(!exceptions.Contains(e.Message))
m_log.Error(LogHeader + " " + Encoding.ASCII.GetString(msg.Data));
data = null;
}
return data;
}
// Handle an incoming message
// *** Perhaps this should not be synchronous with the receive
// We could handle messages from an incoming Queue
@ -122,6 +157,11 @@ namespace OpenSim.Region.Examples.RegionSyncModule
//string handlerMessage = "";
switch (msg.Type)
{
case RegionSyncMessage.MsgType.GetTerrain:
{
Send(new RegionSyncMessage(RegionSyncMessage.MsgType.Terrain, m_scene.Heightmap.SaveToXmlString()));
return HandlerSuccess(msg, "Terrain sent");
}
case RegionSyncMessage.MsgType.GetObjects:
{
List<EntityBase> entities = m_scene.GetEntities();
@ -130,19 +170,28 @@ namespace OpenSim.Region.Examples.RegionSyncModule
if (e is SceneObjectGroup)
{
string sogxml = SceneObjectSerializer.ToXml2Format((SceneObjectGroup)e);
Send(new RegionSyncMessage(RegionSyncMessage.MsgType.AddObject, sogxml));
Send(new RegionSyncMessage(RegionSyncMessage.MsgType.NewObject, sogxml));
}
}
return HandlerSuccess(msg, "Sent all scene objects");
}
case RegionSyncMessage.MsgType.GetTerrain:
case RegionSyncMessage.MsgType.GetAvatars:
{
Send(new RegionSyncMessage(RegionSyncMessage.MsgType.Terrain, m_scene.Heightmap.SaveToXmlString()));
return HandlerSuccess(msg, "Terrain sent");
m_scene.ForEachScenePresence(delegate(ScenePresence presence)
{
// Let the client managers know about this avatar
OSDMap data = new OSDMap(1);
data["agentID"] = OSD.FromUUID(presence.ControllingClient.AgentId);
data["first"] = OSD.FromString(presence.ControllingClient.FirstName);
data["last"] = OSD.FromString(presence.ControllingClient.LastName);
data["startPos"] = OSD.FromVector3(presence.ControllingClient.StartPos);
Send(new RegionSyncMessage(RegionSyncMessage.MsgType.NewAvatar, OSDParser.SerializeJsonString(data)));
});
return HandlerSuccess(msg, "Sent all scene avatars");
}
case RegionSyncMessage.MsgType.AgentAdd:
{
OSDMap data = OSDParser.DeserializeJson(Encoding.ASCII.GetString(msg.Data)) as OSDMap;
OSDMap data = DeserializeMessage(msg);
if (data != null)
{
UUID agentID = data["agentID"].AsUUID();
@ -165,7 +214,7 @@ namespace OpenSim.Region.Examples.RegionSyncModule
return HandlerSuccess(msg, String.Format("Handled AddAgent for UUID {0}", agentID));
}
}
return HandlerFailure(msg, "Could not parse AddAgent parameters");
return HandlerFailure(msg, "Could not deserialize JSON data.");
}
case RegionSyncMessage.MsgType.AgentUpdate:
@ -204,6 +253,42 @@ namespace OpenSim.Region.Examples.RegionSyncModule
else
return HandlerFailure(msg, String.Format("Could not handle AgentUpdate UUID {0}", agentID));
}
case RegionSyncMessage.MsgType.AgentRemove:
{
OSDMap data = DeserializeMessage(msg);
if (data != null)
{
UUID agentID = data["agentID"].AsUUID();
if (agentID != null && agentID != UUID.Zero)
{
lock (m_syncedAvatars)
{
if (m_syncedAvatars.ContainsKey(agentID))
{
m_syncedAvatars.Remove(agentID);
ScenePresence presence;
if (m_scene.TryGetScenePresence(agentID, out presence))
{
string name = presence.Name;
m_scene.RemoveClient(agentID);
return HandlerSuccess(msg, String.Format("Agent \"{0}\" ({1}) was removed from scene.", name, agentID));
}
else
{
return HandlerFailure(msg, String.Format("Agent {0} not found in the scene.", agentID));
}
}
else
{
return HandlerFailure(msg, String.Format("Agent {0} not in the list of synced avatars.", agentID));
}
}
}
}
return HandlerFailure(msg, "Could not deserialize JSON data.");
}
default:
{
m_log.WarnFormat("{0} Unable to handle unsupported message type", LogHeader);
@ -212,9 +297,15 @@ namespace OpenSim.Region.Examples.RegionSyncModule
}
}
private bool HandlerDebug(RegionSyncMessage msg, string handlerMessage)
{
m_log.WarnFormat("{0} DBG ({1}): {2}", LogHeader, msg.ToString(), handlerMessage);
return true;
}
private bool HandlerSuccess(RegionSyncMessage msg, string handlerMessage)
{
m_log.WarnFormat("{0} Handled {1}: {2}", LogHeader, msg.ToString(), handlerMessage);
//m_log.WarnFormat("{0} Handled {1}: {2}", LogHeader, msg.ToString(), handlerMessage);
return true;
}
@ -236,6 +327,11 @@ namespace OpenSim.Region.Examples.RegionSyncModule
{
try
{
lock (stats)
{
msgsOut++;
bytesOut += data.Length;
}
m_tcpclient.GetStream().Write(data, 0, data.Length);
}
catch (IOException e)

View File

@ -19,6 +19,7 @@ namespace OpenSim.Region.Examples.RegionSyncModule
// CM -> SIM
AgentAdd,
AgentUpdate,
AgentRemove,
GetTerrain,
GetObjects,
SubscribeObjects,
@ -27,12 +28,12 @@ namespace OpenSim.Region.Examples.RegionSyncModule
ChatFromClient,
// SIM -> CM
Terrain,
AddObject,
UpdateObject,
RemoveObject,
AddAvatarResponse,
UpdateAvatarTerse,
RemoveAvatar,
NewObject, // objects
UpdatedObject, // objects
RemovedObject, // objects
NewAvatar, // avatars
UpdatedAvatar, // avatars
RemovedAvatar, // avatars
ChatFromSim,
// BIDIR
EchoRequest,

View File

@ -20,6 +20,8 @@ namespace OpenSim.Region.Examples.RegionSyncModule
private IPAddress m_addr;
private Int32 m_port;
private int clientCounter;
// The local scene.
private Scene m_scene;
@ -36,27 +38,50 @@ namespace OpenSim.Region.Examples.RegionSyncModule
private Thread m_listenerThread;
// The list of clients and the threads handling IO for each client
// Lock should be used when client managers connect or disconnect
// while modifying the client list.
private Object clientLock = new Object();
private List<RegionSyncClientView> m_client_views = new List<RegionSyncClientView>();
// The list is read most of the time and only updated when a new client manager
// connects, so we just replace the list when it changes. Iterators on this
// list need to be able to handle if an element is shutting down.
private HashSet<RegionSyncClientView> m_client_views = new HashSet<RegionSyncClientView>();
// Check if any of the client views are in a connected state
public bool Synced
{
get
{
lock (clientLock)
return (m_client_views.Count > 0);
}
}
// Add the client view to the list and increment synced client counter
public void AddSyncedClient(RegionSyncClientView rscv)
{
foreach (RegionSyncClientView cv in m_client_views)
HashSet<RegionSyncClientView> newlist = new HashSet<RegionSyncClientView>(m_client_views);
newlist.Add(rscv);
// Threads holding the previous version of the list can keep using it since
// they will not hold it for long and get a new copy next time they need to iterate
Interlocked.Exchange<HashSet<RegionSyncClientView>>(ref m_client_views, newlist);
}
// Remove the client view from the list and decrement synced client counter
public void RemoveSyncedClient(RegionSyncClientView rscv)
{
if (cv.Connected)
return true;
}
return false;
HashSet<RegionSyncClientView> newlist = new HashSet<RegionSyncClientView>(m_client_views);
newlist.Remove(rscv);
// Threads holding the previous version of the list can keep using it since
// they will not hold it for long and get a new copy next time they need to iterate
Interlocked.Exchange<HashSet<RegionSyncClientView>>(ref m_client_views, newlist);
}
public void ReportStats()
{
// We should be able to safely iterate over our reference to the list since
// the only places which change it will replace it with an updated version
foreach (RegionSyncClientView rscv in m_client_views)
{
m_log.ErrorFormat("{0}: {1}", rscv.Description, rscv.GetStats());
}
}
#endregion
// Constructor
@ -81,20 +106,19 @@ namespace OpenSim.Region.Examples.RegionSyncModule
// Stop the server and disconnect all RegionSyncClients
public void Shutdown()
{
lock (clientLock)
{
// Stop the listener and listening thread so no new clients are accepted
m_listener.Stop();
m_listenerThread.Abort();
m_listenerThread = null;
// Stop all existing client views and clear client list
foreach (RegionSyncClientView cv in m_client_views)
HashSet<RegionSyncClientView> list = new HashSet<RegionSyncClientView>(m_client_views);
foreach (RegionSyncClientView rscv in list)
{
// Each client view will clean up after itself
cv.Shutdown();
}
m_client_views.Clear();
rscv.Shutdown();
RemoveSyncedClient(rscv);
}
}
@ -117,16 +141,13 @@ namespace OpenSim.Region.Examples.RegionSyncModule
TcpClient tcpclient = m_listener.AcceptTcpClient();
IPAddress addr = ((IPEndPoint)tcpclient.Client.RemoteEndPoint).Address;
int port = ((IPEndPoint)tcpclient.Client.RemoteEndPoint).Port;
lock (clientLock)
{
// Add the RegionSyncClientView to the list of clients
// *** Need to work on the timing order of starting the client view and adding to the server list
// so that messages coming from the scene do not get lost before the client view is added but
// not sent before it is ready to process them.
RegionSyncClientView rscv = new RegionSyncClientView(m_client_views.Count, m_scene, tcpclient);
RegionSyncClientView rscv = new RegionSyncClientView(++clientCounter, m_scene, tcpclient);
m_log.WarnFormat("[REGION SYNC SERVER] New connection from {0}", rscv.Description);
m_client_views.Add(rscv);
}
AddSyncedClient(rscv);
}
}
catch (SocketException e)
@ -138,23 +159,31 @@ namespace OpenSim.Region.Examples.RegionSyncModule
// Broadcast a message to all connected RegionSyncClients
public void Broadcast(RegionSyncMessage msg)
{
List<RegionSyncClientView> clients = new List<RegionSyncClientView>();
lock (clientLock)
{
foreach (RegionSyncClientView client in m_client_views)
{
if (client.Connected)
clients.Add(client);
}
}
if(clients.Count > 0 )
List<RegionSyncClientView> closed = null;
//lock (m_client_views)
{
//m_log.WarnFormat("[REGION SYNC SERVER] Broadcasting {0} to all connected RegionSyncClients", msg.ToString());
foreach( RegionSyncClientView client in clients)
foreach (RegionSyncClientView client in m_client_views)
{
// If connected, send the message.
if (client.Connected)
{
client.Send(msg);
}
// Else, remove the client view from the list
else
{
if (closed == null)
closed = new List<RegionSyncClientView>();
closed.Add(client);
}
}
if (closed != null)
{
foreach (RegionSyncClientView rscv in closed)
RemoveSyncedClient(rscv);
//m_client_views.Remove(rscv);
}
}
}
}

View File

@ -25,6 +25,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using Nini.Config;
@ -32,6 +33,7 @@ using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenSim.Framework;
using OpenSim.Framework.Client;
using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.Framework.Scenes.Serialization;
@ -42,7 +44,7 @@ using System.Threading;
namespace OpenSim.Region.Examples.RegionSyncModule
{
public class RegionSyncServerModule : IRegionModule, IRegionSyncServerModule
public class RegionSyncServerModule : IRegionModule, IRegionSyncServerModule, ICommandableModule
{
#region IRegionModule Members
public void Initialise(Scene scene, IConfigSource config)
@ -60,6 +62,11 @@ namespace OpenSim.Region.Examples.RegionSyncModule
m_serverport = syncConfig.GetInt("ServerPort", 13000);
m_scene = scene;
m_scene.RegisterModuleInterface<IRegionSyncServerModule>(this);
// Setup the command line interface
m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole;
InstallInterfaces();
m_log.Warn("[REGION SYNC SERVER MODULE] Initialised");
}
@ -69,12 +76,13 @@ namespace OpenSim.Region.Examples.RegionSyncModule
return;
//m_scene.EventManager.OnObjectBeingRemovedFromScene += new EventManager.ObjectBeingRemovedFromScene(EventManager_OnObjectBeingRemovedFromScene);
//m_scene.EventManager.OnNewClient +=new EventManager.OnNewClientDelegate(EventManager_OnNewClient);
//m_scene.EventManager.OnNewPresence +=new EventManager.OnNewPresenceDelegate(EventManager_OnNewPresence);
//m_scene.EventManager.OnAvatarEnteringNewParcel += new EventManager.AvatarEnteringNewParcel(EventManager_OnAvatarEnteringNewParcel);
//m_scene.EventManager.OnClientMovement += new EventManager.ClientMovement(EventManager_OnClientMovement);
//m_scene.EventManager.OnLandObjectAdded += new EventManager.LandObjectAdded(EventManager_OnLandObjectAdded);
//m_scene.EventManager.OnLandObjectRemoved += new EventManager.LandObjectRemoved(EventManager_OnLandObjectRemoved);
m_scene.EventManager.OnNewClient += new EventManager.OnNewClientDelegate(EventManager_OnNewClient);
//m_scene.EventManager.OnNewPresence += new EventManager.OnNewPresenceDelegate(EventManager_OnNewPresence);
m_scene.EventManager.OnRemovePresence += new EventManager.OnRemovePresenceDelegate(EventManager_OnRemovePresence);
m_scene.SceneGraph.OnObjectCreate += new ObjectCreateDelegate(SceneGraph_OnObjectCreate);
m_scene.SceneGraph.OnObjectDuplicate += new ObjectDuplicateDelegate(SceneGraph_OnObjectDuplicate);
@ -103,7 +111,15 @@ namespace OpenSim.Region.Examples.RegionSyncModule
{
get { return false; }
}
#endregion
#endregion
#region ICommandableModule Members
private readonly Commander m_commander = new Commander("sync");
public ICommander CommandInterface
{
get { return m_commander; }
}
#endregion
#region IRegionSyncServerModule members
// Lock is used to synchronize access to the update status and both update queues
@ -116,7 +132,7 @@ namespace OpenSim.Region.Examples.RegionSyncModule
{
if (!Active || !Synced)
return;
lock (m_primUpdates)
lock (m_updateLock)
{
m_primUpdates[part.ParentGroup.UUID] = part.ParentGroup;
}
@ -127,7 +143,7 @@ namespace OpenSim.Region.Examples.RegionSyncModule
{
if (!Active || !Synced)
return;
lock (m_presenceUpdates)
lock (m_updateLock)
{
m_presenceUpdates[presence.UUID] = presence;
}
@ -148,10 +164,14 @@ namespace OpenSim.Region.Examples.RegionSyncModule
List<SceneObjectGroup> primUpdates;
List<ScenePresence> presenceUpdates;
lock (m_updateLock)
{
primUpdates = new List<SceneObjectGroup>(m_primUpdates.Values);
presenceUpdates = new List<ScenePresence>(m_presenceUpdates.Values);
m_primUpdates.Clear();
m_presenceUpdates.Clear();
}
// This could be another thread for sending outgoing messages or just have the Queue functions
// create and queue the messages directly into the outgoing server thread.
@ -164,20 +184,27 @@ namespace OpenSim.Region.Examples.RegionSyncModule
if (!sog.IsDeleted)
{
string sogxml = SceneObjectSerializer.ToXml2Format(sog);
m_server.Broadcast(new RegionSyncMessage(RegionSyncMessage.MsgType.UpdateObject, sogxml));
m_server.Broadcast(new RegionSyncMessage(RegionSyncMessage.MsgType.UpdatedObject, sogxml));
}
}
foreach (ScenePresence presence in presenceUpdates)
{
if (!presence.IsDeleted)
{
OSDMap data = new OSDMap(4);
OSDMap data = new OSDMap(5);
data["id"] = OSD.FromUUID(presence.UUID);
// Do not include offset for appearance height. That will be handled by RegionSyncClient before sending to viewers
if(presence.AbsolutePosition.IsFinite())
data["pos"] = OSD.FromVector3(presence.AbsolutePosition);
else
data["pos"] = OSD.FromVector3(Vector3.Zero);
if(presence.Velocity.IsFinite())
data["vel"] = OSD.FromVector3(presence.Velocity);
else
data["vel"] = OSD.FromVector3(Vector3.Zero);
data["rot"] = OSD.FromQuaternion(presence.Rotation);
RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.UpdateAvatarTerse, OSDParser.SerializeJsonString(data));
data["fly"] = OSD.FromBoolean(presence.Flying);
RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.UpdatedAvatar, OSDParser.SerializeJsonString(data));
m_server.Broadcast(rsm);
}
}
@ -193,7 +220,7 @@ namespace OpenSim.Region.Examples.RegionSyncModule
OSDMap data = new OSDMap(2);
data["regionHandle"] = OSD.FromULong(regionHandle);
data["localID"] = OSD.FromUInteger(localID);
RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.RemoveObject, OSDParser.SerializeJsonString(data));
RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.RemovedObject, OSDParser.SerializeJsonString(data));
m_server.Broadcast(rsm);
}
@ -272,10 +299,12 @@ namespace OpenSim.Region.Examples.RegionSyncModule
#region Event Handlers
private void SceneGraph_OnObjectCreate(EntityBase entity)
{
if (!Synced)
return;
if (entity is SceneObjectGroup)
{
string sogxml = SceneObjectSerializer.ToXml2Format((SceneObjectGroup)entity);
RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.AddObject, sogxml);
RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.NewObject, sogxml);
m_server.Broadcast(rsm);
}
else
@ -286,10 +315,12 @@ namespace OpenSim.Region.Examples.RegionSyncModule
private void SceneGraph_OnObjectDuplicate(EntityBase original, EntityBase copy)
{
if (!Synced)
return;
if (original is SceneObjectGroup && copy is SceneObjectGroup)
{
string sogxml = SceneObjectSerializer.ToXml2Format((SceneObjectGroup)copy);
RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.AddObject, sogxml);
RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.NewObject, sogxml);
m_server.Broadcast(rsm);
}
else
@ -300,10 +331,12 @@ namespace OpenSim.Region.Examples.RegionSyncModule
private void SceneGraph_OnObjectRemove(EntityBase entity)
{
if (!Synced)
return;
if (entity is SceneObjectGroup)
{
// No reason to send the entire object, just send the UUID to be deleted
RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.RemoveObject, entity.UUID.ToString());
RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.RemovedObject, entity.UUID.ToString());
m_server.Broadcast(rsm);
}
else
@ -315,6 +348,8 @@ namespace OpenSim.Region.Examples.RegionSyncModule
// A ficticious event
public void Scene_AddNewPrim(SceneObjectGroup sog)
{
if (!Synced)
return;
}
/*
@ -385,47 +420,47 @@ namespace OpenSim.Region.Examples.RegionSyncModule
void EventManager_OnClientMovement(ScenePresence client)
{
m_moveCounter++;
if (m_moveCounter % 100 == 0)
{
string msg = (string.Format("EventManager_OnClientMovement - Event has been triggered 100 times"));
m_server.Broadcast(msg);
m_log.Warn("REGION SYNC SERVER MODULE] " + msg);
}
}
void EventManager_OnAvatarEnteringNewParcel(ScenePresence avatar, int localLandID, UUID regionID)
{
m_log.WarnFormat("[REGION SYNC SERVER MODULE] (OnAvatarEnteringNewParcel) Avatar \"{0}\" has joined the scene (1) {2} {3} {4}", avatar.Name, avatar.ControllingClient.AgentId.ToString(), avatar.UUID.ToString(), localLandID, regionID.ToString());
DebugSceneStats();
}
*/
private void EventManager_OnNewPresence(ScenePresence presence)
{
if (!Synced)
return;
m_log.WarnFormat("[REGION SYNC SERVER MODULE] (OneNewPresence) \"{0}\"", presence.Name);
}
private void EventManager_OnNewClient(IClientAPI client)
{
ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
if (presence != null)
{
m_log.WarnFormat("[REGION SYNC SERVER MODULE] (OnNewClient) \"{0}\"", presence.Name);
DebugSceneStats();
if (!Synced)
return;
m_log.WarnFormat("[REGION SYNC SERVER MODULE] Agent \"{0}\" (1) has joined the scene", client.FirstName + " " + client.LastName, client.AgentId.ToString());
// Let the client managers know that a new agent has connected
OSDMap data = new OSDMap(1);
data["agentID"] = OSD.FromUUID(client.AgentId);
data["first"] = OSD.FromString(client.FirstName);
data["last"] = OSD.FromString(client.LastName);
data["startPos"] = OSD.FromVector3(client.StartPos);
m_server.Broadcast(new RegionSyncMessage(RegionSyncMessage.MsgType.NewAvatar, OSDParser.SerializeJsonString(data)));
}
else
{
m_log.WarnFormat("[REGION SYNC SERVER MODULE] (OnNewClient) A new client connected but module could not get ScenePresence");
}
}
private void EventManager_OnNewPresence(ScenePresence presence)
{
m_log.WarnFormat("[REGION SYNC SERVER MODULE] Avatar \"{0}\" (1) {2} has joined the scene", presence.Firstname + " " + presence.Lastname, presence.ControllingClient.AgentId.ToString(), presence.UUID.ToString());
DebugSceneStats();
}
* */
private void EventManager_OnRemovePresence(UUID agentID)
{
if (!Synced)
return;
/*
ScenePresence avatar;
if (m_scene.TryGetScenePresence(agentID, out avatar))
{
@ -435,39 +470,61 @@ namespace OpenSim.Region.Examples.RegionSyncModule
{
m_log.WarnFormat("[REGION SYNC SERVER MODULE] Avatar \"unknown\" has left the scene");
}
OSDArray data = new OSDArray();
data.Add(OSD.FromULong(avatar.RegionHandle));
data.Add(OSD.FromUInteger(avatar.LocalId));
RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.RemoveAvatar, data.ToString());
m_server.Broadcast(rsm);
* */
OSDMap data = new OSDMap();
data["agentID"] = OSD.FromUUID(agentID);
m_server.Broadcast(new RegionSyncMessage(RegionSyncMessage.MsgType.RemovedAvatar, OSDParser.SerializeJsonString(data)));
}
#endregion
/*
private void DebugSceneStats()
#region Console Command Interface
private void InstallInterfaces()
{
List<ScenePresence> avatars = m_scene.GetAvatars();
List<EntityBase> entities = m_scene.GetEntities();
m_log.WarnFormat("There are {0} avatars and {1} entities in the scene", avatars.Count, entities.Count);
Command cmdSyncStats = new Command("stats", CommandIntentions.COMMAND_HAZARDOUS, SyncStats, "Reports stats for the RegionSyncServer.");
m_commander.RegisterCommand("stats", cmdSyncStats);
lock (m_scene)
{
// Add this to our scene so scripts can call these functions
m_scene.RegisterModuleCommander(m_commander);
}
}
public IClientAPI ClientAggregator
/// <summary>
/// Processes commandline input. Do not call directly.
/// </summary>
/// <param name="args">Commandline arguments</param>
private void EventManager_OnPluginConsole(string[] args)
{
get {return m_clientAggregator;}
if (args[0] == "sync")
{
if (args.Length == 1)
{
m_commander.ProcessConsoleCommand("help", new string[0]);
return;
}
private void AddAvatars()
{
for (int i = 0; i < 1; i++)
{
MyNpcCharacter m_character = new MyNpcCharacter(m_scene, this);
m_scene.AddNewClient(m_character);
string[] tmpArgs = new string[args.Length - 2];
int i;
for (i = 2; i < args.Length; i++)
tmpArgs[i - 2] = args[i];
m_scene.AgentCrossing(m_character.AgentId, m_character.StartPos, false);
m_commander.ProcessConsoleCommand(args[1], tmpArgs);
}
}
*/
private void SyncStats(Object[] args)
{
if (Synced)
m_server.ReportStats();
else if (m_server != null)
m_log.Error("No RegionSyncClients connected");
else
m_log.Error("The RegionSyncServer is not running!");
}
#endregion
}
}

View File

@ -35,5 +35,6 @@ namespace OpenSim.Region.Framework.Interfaces
{
bool Active { get; }
bool Synced { get; }
void SendCoarseLocations();
}
}

View File

@ -1429,21 +1429,49 @@ namespace OpenSim.Region.Framework.Scenes
// Run through all ScenePresences looking for updates
// Presence updates and queued object updates for each presence are sent to clients
// If it's a synced client, just send prim updates
// 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
if (IsSyncedClient())
{
ForEachScenePresence(delegate(ScenePresence sp) { sp.SendPrimUpdates(); });
RegionSyncClientModule.SendCoarseLocations();
}
else
{
if (m_frame % m_update_presences == 0)
m_sceneGraph.UpdatePresences();
}
// REGION SYNC
// If this is a synced server, send updates to client managers at this time
// This batches updates, but the client manager will forward on to clients without
// additional delay
if (IsSyncedServer())
{
m_regionSyncServerModule.SendUpdates();
}
int tmpPhysicsMS2 = Util.EnvironmentTickCount();
// Do not simulate physics locally if this is a synced client
if (!IsSyncedClient())
{
if ((m_frame % m_update_physics == 0) && m_physics_enabled)
m_sceneGraph.UpdatePreparePhysics();
}
physicsMS2 = Util.EnvironmentTickCountSubtract(tmpPhysicsMS2);
// Do not simulate physics locally if this is a synced client
if (!IsSyncedClient())
{
if (m_frame % m_update_entitymovement == 0)
m_sceneGraph.UpdateScenePresenceMovement();
}
int tmpPhysicsMS = Util.EnvironmentTickCount();
// Do not simulate physics locally if this is a synced client
if (!IsSyncedClient())
{
if (m_frame % m_update_physics == 0)
{
if (m_physics_enabled)
@ -1451,6 +1479,7 @@ namespace OpenSim.Region.Framework.Scenes
if (SynchronizeScene != null)
SynchronizeScene(this);
}
}
physicsMS = Util.EnvironmentTickCountSubtract(tmpPhysicsMS);
// Delete temp-on-rez stuff
@ -1562,7 +1591,46 @@ namespace OpenSim.Region.Framework.Scenes
}
}
public void GetCoarseLocations(out List<UUID> ids, out List<Vector3> locations)
{
List<UUID> resultIds = new List<UUID>();
List<Vector3> resultLocations = new List<Vector3>();
ForEachScenePresence(delegate(ScenePresence sp)
{
if (sp.IsChildAgent)
return;
resultIds.Add(sp.UUID);
resultLocations.Add(sp.AbsolutePosition);
});
ids = resultIds;
locations = resultLocations;
/*
if (sp.ParentID != 0)
{
// sitting avatar
SceneObjectPart sop = GetSceneObjectPart(sp.ParentID);
if (sop != null)
{
locations.Add(sop.AbsolutePosition + sp.m_pos);
ids.Add(sp.UUID);
}
else
{
// we can't find the parent.. ! arg!
locations.Add(sp.m_pos);
ids.Add(sp.UUID);
}
}
else
{
locations.Add(sp.m_pos);
ids.Add(sp.UUID);
}
});
*/
}
public void AddGroupTarget(SceneObjectGroup grp)
{
@ -3233,9 +3301,9 @@ namespace OpenSim.Region.Framework.Scenes
m_eventManager.TriggerOnRemovePresence(agentID);
if(IsSyncedServer())
RegionSyncServerModule.DeleteObject(avatar.RegionHandle, avatar.LocalId);
else
// Don't try to send kills to clients if this is a synced server.
// The client closed event will trigger the broadcast to client managers
//if(!IsSyncedServer())
{
ForEachClient(
delegate(IClientAPI client)
@ -3325,11 +3393,11 @@ namespace OpenSim.Region.Framework.Scenes
}
}
ForEachClient(delegate(IClientAPI client) { client.SendKillObject(m_regionHandle, localID); });
// REGION SYNC
if( IsSyncedServer() )
RegionSyncServerModule.DeleteObject(m_regionHandle, localID);
else
ForEachClient(delegate(IClientAPI client) { client.SendKillObject(m_regionHandle, localID); });
}
#endregion
@ -4365,11 +4433,10 @@ namespace OpenSim.Region.Framework.Scenes
/// Performs action on all scene presences.
/// </summary>
/// <param name="action"></param>
static int s_ForEachPresenceCounter = 0;
public void ForEachScenePresence(Action<ScenePresence> action)
{
if (IsSyncedServer())
return;
//if (IsSyncedServer())
// return;
// We don't want to try to send messages if there are no avatars.
if (m_sceneGraph != null)
{
@ -4450,7 +4517,7 @@ namespace OpenSim.Region.Framework.Scenes
public void ForEachClient(Action<IClientAPI> action)
{
// REGION SYNC
if (IsSyncedServer())
if (false)//IsSyncedServer())
return;
m_clientManager.ForEachSync(action);
}

View File

@ -1272,7 +1272,7 @@ namespace OpenSim.Region.Framework.Scenes
if (Scene.IsSyncedServer())
{
Scene.RegionSyncServerModule.DeleteObject(part.RegionHandle, part.LocalId);
return;
//return;
}
Scene.ForEachScenePresence(delegate(ScenePresence avatar)
{

View File

@ -1259,13 +1259,13 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary>
public void AddFullUpdateToAllAvatars()
{
// REGION SYNC
if (m_parentGroup.Scene.IsSyncedServer())
m_parentGroup.Scene.RegionSyncServerModule.QueuePartForUpdate(this);
m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar)
{
avatar.SceneViewer.QueuePartForUpdate(this);
});
// REGION SYNC
if (m_parentGroup.Scene.IsSyncedServer())
m_parentGroup.Scene.RegionSyncServerModule.QueuePartForUpdate(this);
}
public void AddFullUpdateToAvatar(ScenePresence presence)
@ -1286,12 +1286,13 @@ namespace OpenSim.Region.Framework.Scenes
/// Terse updates
public void AddTerseUpdateToAllAvatars()
{
if (m_parentGroup.Scene.IsSyncedServer())
m_parentGroup.Scene.RegionSyncServerModule.QueuePartForUpdate(this);
m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar)
{
avatar.SceneViewer.QueuePartForUpdate(this);
});
// REGION SYNC
if (m_parentGroup.Scene.IsSyncedServer())
m_parentGroup.Scene.RegionSyncServerModule.QueuePartForUpdate(this);
}
public void AddTerseUpdateToAvatar(ScenePresence presence)

View File

@ -383,6 +383,18 @@ namespace OpenSim.Region.Framework.Scenes
set { m_allowMovement = value; }
}
// Added for region sync module.
// Should not rely on a physics actor like so many of these params seem to
public bool Flying
{
get
{
if (PhysicsActor != null)
return PhysicsActor.Flying;
return false;
}
}
public bool SetAlwaysRun
{
get
@ -688,12 +700,9 @@ namespace OpenSim.Region.Framework.Scenes
AbsolutePosition = posLastSignificantMove = m_CameraCenter =
m_lastCameraCenter = m_controllingClient.StartPos;
if (!m_scene.IsSyncedServer())
{
m_reprioritization_timer = new Timer(world.ReprioritizationInterval);
m_reprioritization_timer.Elapsed += new ElapsedEventHandler(Reprioritize);
m_reprioritization_timer.AutoReset = false;
}
AdjustKnownSeeds();
@ -1196,6 +1205,39 @@ namespace OpenSim.Region.Framework.Scenes
}
}
// Move the avatar to a specific position, velocity and rotation and mark it as changed
// Mostly copied from HandleAgentUpdate
public void MoveTo(Vector3 pos, Vector3 vel, Quaternion rot)
{
++m_movementUpdateCount;
if (m_movementUpdateCount < 1)
m_movementUpdateCount = 1;
#region Sanity Checking
// This is irritating. Really.
if (!AbsolutePosition.IsFinite())
{
RemoveFromPhysicalScene();
m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999902");
m_pos = m_LastFinitePos;
if (!m_pos.IsFinite())
{
m_pos.X = 127f;
m_pos.Y = 127f;
m_pos.Z = 127f;
m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999903");
}
AddToPhysicalScene(false);
}
else
{
m_LastFinitePos = m_pos;
}
#endregion Sanity Checking
}
/// <summary>
/// This is the event handler for client movement. If a client is moving, this event is triggering.
/// </summary>
@ -2324,6 +2366,10 @@ namespace OpenSim.Region.Framework.Scenes
{
SendTerseUpdateToAllClients();
// REGION SYNC
if(m_scene.IsSyncedServer())
m_scene.RegionSyncServerModule.QueuePresenceForTerseUpdate(this);
// Update the "last" values
m_lastPosition = m_pos;
m_lastRotation = m_bodyRot;
@ -2382,6 +2428,19 @@ namespace OpenSim.Region.Framework.Scenes
m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS));
}
/// <summary>
/// Send a location/velocity/accelleration update to all agents in a list
/// </summary>
public void SendTerseUpdateToClientList(List<IClientAPI> clients)
{
m_perfMonMS = Util.EnvironmentTickCount();
foreach( IClientAPI client in clients)
{
SendTerseUpdateToClient(client);
}
m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS));
}
public void SendCoarseLocations()
{
SendCourseLocationsMethod d = m_sendCourseLocationsMethod;
@ -2400,39 +2459,12 @@ namespace OpenSim.Region.Framework.Scenes
public void SendCoarseLocationsDefault(UUID sceneId, ScenePresence p)
{
m_perfMonMS = Util.EnvironmentTickCount();
List<Vector3> CoarseLocations = new List<Vector3>();
List<UUID> AvatarUUIDs = new List<UUID>();
m_scene.ForEachScenePresence(delegate(ScenePresence sp)
{
if (sp.IsChildAgent)
return;
if (sp.ParentID != 0)
{
// sitting avatar
SceneObjectPart sop = m_scene.GetSceneObjectPart(sp.ParentID);
if (sop != null)
{
CoarseLocations.Add(sop.AbsolutePosition + sp.m_pos);
AvatarUUIDs.Add(sp.UUID);
}
else
{
// we can't find the parent.. ! arg!
CoarseLocations.Add(sp.m_pos);
AvatarUUIDs.Add(sp.UUID);
}
}
else
{
CoarseLocations.Add(sp.m_pos);
AvatarUUIDs.Add(sp.UUID);
}
});
List<Vector3> CoarseLocations = new List<Vector3>();
// This is not cheap to compile this list of locations.
// It should ideally be done once and then sent to every client rather than compiled for each client
m_scene.GetCoarseLocations(out AvatarUUIDs, out CoarseLocations);
m_controllingClient.SendCoarseLocationUpdate(AvatarUUIDs, CoarseLocations);
m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS));
}

View File

@ -27,7 +27,9 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Nini.Config;
using log4net;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.Physics.Manager;
@ -36,6 +38,8 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
{
public class BasicScene : PhysicsScene
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private List<BasicActor> _actors = new List<BasicActor>();
private float[] _heightMap;
@ -129,7 +133,16 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
actorPosition.X = ((int)Constants.RegionSize - 0.1f);
}
float height = _heightMap[(int)actor.Position.Y * Constants.RegionSize + (int)actor.Position.X] + actor.Size.Z;
float height = 25.0F;
try
{
height = _heightMap[(int)actor.Position.Y * Constants.RegionSize + (int)actor.Position.X] + actor.Size.Z;
}
catch (OverflowException)
{
m_log.WarnFormat("[BASICPHYSICS]: Actor out of range: {0}", actor.SOPName, actor.Position.ToString());
}
if (actor.Flying)
{
if (actor.Position.Z + (actor.Velocity.Z*timeStep) <

View File

@ -906,10 +906,9 @@ namespace OpenSim.Region.Physics.OdePlugin
d.Vector3 localpos = d.BodyGetPosition(Body);
Vector3 localPos = new Vector3(localpos.X, localpos.Y, localpos.Z);
if (!localPos.IsFinite())
if (!localPos.IsFinite() || localpos.X < 0.0 || localpos.X > 256.0 || localpos.Y < 0.0 || localpos.Y > 256.0 || localpos.Z < 0.0)
{
m_log.Warn("[PHYSICS]: Avatar Position is non-finite!");
m_log.Warn("[PHYSICS]: Avatar Position is non-finite or out of bounds!");
defects.Add(this);
// _parent_scene.RemoveCharacter(this);