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

View File

@ -130,6 +130,7 @@ namespace OpenSim.Region.Examples.RegionSyncModule
public event Action<UUID> OnRemoveAvatar; public event Action<UUID> OnRemoveAvatar;
public event CreateNewInventoryItem OnCreateNewInventoryItem; public event CreateNewInventoryItem OnCreateNewInventoryItem;
public event LinkInventoryItem OnLinkInventoryItem;
public event CreateInventoryFolder OnCreateNewInventoryFolder; public event CreateInventoryFolder OnCreateNewInventoryFolder;
public event UpdateInventoryFolder OnUpdateInventoryFolder; public event UpdateInventoryFolder OnUpdateInventoryFolder;
public event MoveInventoryFolder OnMoveInventoryFolder; 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. // The RegionSyncClient has a receive thread to process messages from the RegionSyncServer.
public class RegionSyncClient 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 #region RegionSyncClient members
// Set the addr and port of RegionSyncServer // Set the addr and port of RegionSyncServer
@ -29,9 +39,15 @@ namespace OpenSim.Region.Examples.RegionSyncModule
// A reference to the local scene // A reference to the local scene
private Scene m_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 // The logfile
private ILog m_log; private ILog m_log;
private string LogHeader = "[REGION SYNC CLIENT]";
// The listener and the thread which listens for connections from client managers // The listener and the thread which listens for connections from client managers
private Thread m_rcvLoop; private Thread m_rcvLoop;
@ -46,7 +62,7 @@ namespace OpenSim.Region.Examples.RegionSyncModule
public RegionSyncClient(Scene scene, string addr, int port) public RegionSyncClient(Scene scene, string addr, int port)
{ {
m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 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_scene = scene;
m_addr = IPAddress.Parse(addr); m_addr = IPAddress.Parse(addr);
m_port = port; m_port = port;
@ -61,40 +77,63 @@ namespace OpenSim.Region.Examples.RegionSyncModule
} }
catch (Exception e) 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.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 = new Thread(new ThreadStart(ReceiveLoop));
m_rcvLoop.Name = "RegionSyncClient 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_rcvLoop.Start();
m_log.Warn("[REGION SYNC CLIENT] Started"); m_log.WarnFormat("{0} Started", LogHeader);
DoInitialSync(); DoInitialSync();
} }
// Disconnect from the RegionSyncServer and close the RegionSyncClient // Disconnect from the RegionSyncServer and close the RegionSyncClient
public void Stop() 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(); m_rcvLoop.Abort();
ShutdownClient(); ShutdownClient();
} }
private void ShutdownClient() private void ShutdownClient()
{ {
m_log.WarnFormat("[REGION SYNC CLIENT] Disconnected from RegionSyncServer. Shutting down."); m_log.WarnFormat("{0} Disconnected from RegionSyncServer. Shutting down.", LogHeader);
m_scene.ForEachClient(delegate(IClientAPI client) { client.OnAgentUpdateRaw -= HandleAgentUpdateRaw; });
// 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.Client.Close();
m_client.Close(); m_client.Close();
} }
// Listen for messages from a RegionSyncClient // Listen for messages from a RegionSyncClient
// *** This is the main thread loop for each connected client // *** This is the main thread loop for each connected client
private void ReceiveLoop() 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) while (true && m_client.Connected)
{ {
RegionSyncMessage msg; RegionSyncMessage msg;
@ -102,7 +141,7 @@ namespace OpenSim.Region.Examples.RegionSyncModule
try try
{ {
msg = new RegionSyncMessage(m_client.GetStream()); 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. // If there is a problem reading from the client, shut 'er down.
catch catch
@ -113,16 +152,32 @@ namespace OpenSim.Region.Examples.RegionSyncModule
// Try handling the message // Try handling the message
try 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) 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 // Send a message to a single connected RegionSyncClient
private void Send(string msg) private void Send(string msg)
{ {
@ -133,7 +188,7 @@ namespace OpenSim.Region.Examples.RegionSyncModule
private void Send(RegionSyncMessage msg) private void Send(RegionSyncMessage msg)
{ {
Send(msg.ToBytes()); 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) private void Send(byte[] data)
@ -153,59 +208,72 @@ namespace OpenSim.Region.Examples.RegionSyncModule
} }
} }
#endregion #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 // Handle an incoming message
// Returns true if the message was processed
// TODO: This should not be synchronous with the receive! // TODO: This should not be synchronous with the receive!
// Instead, handle messages from the incoming Queue // Instead, handle messages from the incoming Queue
private bool HandleMessage(RegionSyncMessage msg) private MsgHandlerStatus HandleMessage(RegionSyncMessage msg, out string result)
{ {
switch (msg.Type) switch (msg.Type)
{ {
case RegionSyncMessage.MsgType.Terrain: case RegionSyncMessage.MsgType.Terrain:
{ {
m_scene.Heightmap.LoadFromXmlString(Encoding.ASCII.GetString(msg.Data)); 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.NewObject:
case RegionSyncMessage.MsgType.UpdateObject: case RegionSyncMessage.MsgType.UpdatedObject:
{ {
SceneObjectGroup sog = SceneObjectSerializer.FromXml2Format(Encoding.ASCII.GetString(msg.Data)); SceneObjectGroup sog = SceneObjectSerializer.FromXml2Format(Encoding.ASCII.GetString(msg.Data));
if(sog.IsDeleted) if (sog.IsDeleted)
return HandlerFailure(msg, String.Format("Ignoring update on deleted LocalId {0}.", sog.LocalId.ToString())); {
result = String.Format("Ignoring update on deleted LocalId {0}.", sog.LocalId.ToString());
return MsgHandlerStatus.Trivial;
}
if (m_scene.AddNewSceneObject(sog, true)) if (m_scene.AddNewSceneObject(sog, true))
{ result = String.Format("Object \"{0}\" ({1}) ({1}) updated.", sog.Name, sog.UUID.ToString(), sog.LocalId.ToString());
sog.ScheduleGroupForFullUpdate(); else
return HandlerSuccess(msg, String.Format("LocalId {0} added or updated.", sog.LocalId.ToString())); result = String.Format("Object \"{0}\" ({1}) ({1}) added.", sog.Name, sog.UUID.ToString(), sog.LocalId.ToString());
} sog.ScheduleGroupForFullUpdate();
return HandlerFailure(msg, String.Format("Could not add or update LocalId {0}.", sog.LocalId.ToString())); return MsgHandlerStatus.Success;
}
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 HandlerSuccess(msg, "Updated avatar"); // 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 ) if( data != null )
{ {
ulong regionHandle = data["regionHandle"].AsULong(); ulong regionHandle = data["regionHandle"].AsULong();
@ -245,15 +313,130 @@ namespace OpenSim.Region.Examples.RegionSyncModule
if (sog != null) if (sog != null)
{ {
m_scene.DeleteSceneObject(sog, false); 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: case RegionSyncMessage.MsgType.UpdateObject:
{ {
@ -279,31 +462,27 @@ namespace OpenSim.Region.Examples.RegionSyncModule
* */ * */
default: default:
{ {
m_log.WarnFormat("[REGION SYNC CLIENT] Unsupported message type"); result = String.Format("{0} Unsupported message type: {1}", LogHeader, ((int)msg.Type).ToString());
return false; 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; 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() private void DoInitialSync()
{ {
m_scene.DeleteAllSceneObjects(); m_scene.DeleteAllSceneObjects();
Send(new RegionSyncMessage(RegionSyncMessage.MsgType.GetTerrain)); Send(new RegionSyncMessage(RegionSyncMessage.MsgType.GetTerrain));
Send(new RegionSyncMessage(RegionSyncMessage.MsgType.GetObjects)); Send(new RegionSyncMessage(RegionSyncMessage.MsgType.GetObjects));
Send(new RegionSyncMessage(RegionSyncMessage.MsgType.GetAvatars));
// Register for events which will be forwarded to authoritative scene // Register for events which will be forwarded to authoritative scene
m_scene.EventManager.OnNewClient += EventManager_OnNewClient; m_scene.EventManager.OnNewClient += EventManager_OnNewClient;
m_scene.EventManager.OnClientClosed += new EventManager.ClientClosed(RemoveLocalClient);
} }
public string GetServerAddressAndPort() public string GetServerAddressAndPort()
@ -311,11 +490,20 @@ namespace OpenSim.Region.Examples.RegionSyncModule
return m_addr.ToString() + ":" + m_port.ToString(); return m_addr.ToString() + ":" + m_port.ToString();
} }
#region MESSAGES SENT FROM CLIENT MANAGER TO SIM
#region Event Handlers
public void EventManager_OnNewClient(IClientAPI client) 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 // Let the auth sim know that a new agent has connected
OSDMap data = new OSDMap(1); OSDMap data = new OSDMap(1);
data["agentID"] = OSD.FromUUID(client.AgentId); data["agentID"] = OSD.FromUUID(client.AgentId);
@ -330,6 +518,16 @@ namespace OpenSim.Region.Examples.RegionSyncModule
client.OnChatFromClientRaw += HandleChatFromClientRaw; 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> /// <summary>
/// This is the event handler for client movement. If a client is moving, this event is triggering. /// This is the event handler for client movement. If a client is moving, this event is triggering.
/// </summary> /// </summary>
@ -342,8 +540,8 @@ namespace OpenSim.Region.Examples.RegionSyncModule
{ {
Send(new RegionSyncMessage(RegionSyncMessage.MsgType.ChatFromClient, chatData)); Send(new RegionSyncMessage(RegionSyncMessage.MsgType.ChatFromClient, chatData));
} }
#endregion #endregion
/* /*
// Should be part of the RegionSyncClient // Should be part of the RegionSyncClient
public string ReceiveMsg() public string ReceiveMsg()

View File

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

View File

@ -21,6 +21,13 @@ namespace OpenSim.Region.Examples.RegionSyncModule
public class RegionSyncClientView public class RegionSyncClientView
{ {
#region RegionSyncClientView members #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 // The TcpClient this view uses to communicate with its RegionSyncClient
private TcpClient m_tcpclient; private TcpClient m_tcpclient;
// Set the addr and port for TcpListener // 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>(); Dictionary<UUID, RegionSyncAvatar> m_syncedAvatars = new Dictionary<UUID, RegionSyncAvatar>();
// A queue for incoming and outgoing traffic // A queue for incoming and outgoing traffic
private Queue<string> m_inQ = new Queue<string>(); private OpenMetaverse.BlockingQueue<RegionSyncMessage> inbox = new OpenMetaverse.BlockingQueue<RegionSyncMessage>();
private Queue<string> m_outQ = new Queue<string>();
private ILog m_log; private ILog m_log;
private Thread m_receive_loop; private Thread m_receive_loop;
private Thread m_handler;
// The last time the entire region was sent to this RegionSyncClient
private long m_archive_time;
// A string of the format [REGION SYNC CLIENT VIEW #X] for use in log headers // A string of the format [REGION SYNC CLIENT VIEW #X] for use in log headers
private string LogHeader private string LogHeader
@ -54,6 +58,12 @@ namespace OpenSim.Region.Examples.RegionSyncModule
get { return String.Format("RegionSyncClientView #{0}", m_connection_number); } 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 // Check if the client is connected
public bool Connected public bool Connected
{ get { return m_tcpclient.Connected; } } { get { return m_tcpclient.Connected; } }
@ -96,12 +106,17 @@ namespace OpenSim.Region.Examples.RegionSyncModule
while (true) while (true)
{ {
RegionSyncMessage msg = GetMessage(); RegionSyncMessage msg = GetMessage();
lock (stats)
{
msgsIn++;
bytesIn += msg.Length;
}
HandleMessage(msg); HandleMessage(msg);
} }
} }
catch (Exception e) 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 // Get a RegionSyncMessager from the incoming stream
RegionSyncMessage msg = new RegionSyncMessage(m_tcpclient.GetStream()); 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; 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 // Handle an incoming message
// *** Perhaps this should not be synchronous with the receive // *** Perhaps this should not be synchronous with the receive
// We could handle messages from an incoming Queue // We could handle messages from an incoming Queue
@ -122,6 +157,11 @@ namespace OpenSim.Region.Examples.RegionSyncModule
//string handlerMessage = ""; //string handlerMessage = "";
switch (msg.Type) 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: case RegionSyncMessage.MsgType.GetObjects:
{ {
List<EntityBase> entities = m_scene.GetEntities(); List<EntityBase> entities = m_scene.GetEntities();
@ -130,19 +170,28 @@ namespace OpenSim.Region.Examples.RegionSyncModule
if (e is SceneObjectGroup) if (e is SceneObjectGroup)
{ {
string sogxml = SceneObjectSerializer.ToXml2Format((SceneObjectGroup)e); 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"); 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())); m_scene.ForEachScenePresence(delegate(ScenePresence presence)
return HandlerSuccess(msg, "Terrain sent"); {
// 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: case RegionSyncMessage.MsgType.AgentAdd:
{ {
OSDMap data = OSDParser.DeserializeJson(Encoding.ASCII.GetString(msg.Data)) as OSDMap; OSDMap data = DeserializeMessage(msg);
if (data != null) if (data != null)
{ {
UUID agentID = data["agentID"].AsUUID(); 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 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: case RegionSyncMessage.MsgType.AgentUpdate:
@ -204,6 +253,42 @@ namespace OpenSim.Region.Examples.RegionSyncModule
else else
return HandlerFailure(msg, String.Format("Could not handle AgentUpdate UUID {0}", agentID)); 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: default:
{ {
m_log.WarnFormat("{0} Unable to handle unsupported message type", LogHeader); 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) 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; return true;
} }
@ -236,6 +327,11 @@ namespace OpenSim.Region.Examples.RegionSyncModule
{ {
try try
{ {
lock (stats)
{
msgsOut++;
bytesOut += data.Length;
}
m_tcpclient.GetStream().Write(data, 0, data.Length); m_tcpclient.GetStream().Write(data, 0, data.Length);
} }
catch (IOException e) catch (IOException e)

View File

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

View File

@ -19,6 +19,8 @@ namespace OpenSim.Region.Examples.RegionSyncModule
// Set the addr and port for TcpListener // Set the addr and port for TcpListener
private IPAddress m_addr; private IPAddress m_addr;
private Int32 m_port; private Int32 m_port;
private int clientCounter;
// The local scene. // The local scene.
private Scene m_scene; private Scene m_scene;
@ -36,27 +38,50 @@ namespace OpenSim.Region.Examples.RegionSyncModule
private Thread m_listenerThread; private Thread m_listenerThread;
// The list of clients and the threads handling IO for each client // The list of clients and the threads handling IO for each client
// Lock should be used when client managers connect or disconnect // The list is read most of the time and only updated when a new client manager
// while modifying the client list. // connects, so we just replace the list when it changes. Iterators on this
private Object clientLock = new Object(); // list need to be able to handle if an element is shutting down.
private List<RegionSyncClientView> m_client_views = new List<RegionSyncClientView>(); private HashSet<RegionSyncClientView> m_client_views = new HashSet<RegionSyncClientView>();
// Check if any of the client views are in a connected state // Check if any of the client views are in a connected state
public bool Synced public bool Synced
{ {
get get
{ {
lock (clientLock) return (m_client_views.Count > 0);
{
foreach (RegionSyncClientView cv in m_client_views)
{
if (cv.Connected)
return true;
}
return false;
}
} }
} }
// Add the client view to the list and increment synced client counter
public void AddSyncedClient(RegionSyncClientView rscv)
{
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)
{
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 #endregion
// Constructor // Constructor
@ -82,19 +107,18 @@ namespace OpenSim.Region.Examples.RegionSyncModule
// Stop the server and disconnect all RegionSyncClients // Stop the server and disconnect all RegionSyncClients
public void Shutdown() 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
HashSet<RegionSyncClientView> list = new HashSet<RegionSyncClientView>(m_client_views);
foreach (RegionSyncClientView rscv in list)
{ {
// Stop the listener and listening thread so no new clients are accepted // Each client view will clean up after itself
m_listener.Stop(); rscv.Shutdown();
m_listenerThread.Abort(); RemoveSyncedClient(rscv);
m_listenerThread = null;
// Stop all existing client views and clear client list
foreach (RegionSyncClientView cv in m_client_views)
{
// Each client view will clean up after itself
cv.Shutdown();
}
m_client_views.Clear();
} }
} }
@ -117,16 +141,13 @@ namespace OpenSim.Region.Examples.RegionSyncModule
TcpClient tcpclient = m_listener.AcceptTcpClient(); TcpClient tcpclient = m_listener.AcceptTcpClient();
IPAddress addr = ((IPEndPoint)tcpclient.Client.RemoteEndPoint).Address; IPAddress addr = ((IPEndPoint)tcpclient.Client.RemoteEndPoint).Address;
int port = ((IPEndPoint)tcpclient.Client.RemoteEndPoint).Port; 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
// Add the RegionSyncClientView to the list of clients // so that messages coming from the scene do not get lost before the client view is added but
// *** Need to work on the timing order of starting the client view and adding to the server list // not sent before it is ready to process them.
// so that messages coming from the scene do not get lost before the client view is added but RegionSyncClientView rscv = new RegionSyncClientView(++clientCounter, m_scene, tcpclient);
// not sent before it is ready to process them. m_log.WarnFormat("[REGION SYNC SERVER] New connection from {0}", rscv.Description);
RegionSyncClientView rscv = new RegionSyncClientView(m_client_views.Count, m_scene, tcpclient); AddSyncedClient(rscv);
m_log.WarnFormat("[REGION SYNC SERVER] New connection from {0}", rscv.Description);
m_client_views.Add(rscv);
}
} }
} }
catch (SocketException e) catch (SocketException e)
@ -138,22 +159,30 @@ namespace OpenSim.Region.Examples.RegionSyncModule
// Broadcast a message to all connected RegionSyncClients // Broadcast a message to all connected RegionSyncClients
public void Broadcast(RegionSyncMessage msg) public void Broadcast(RegionSyncMessage msg)
{ {
List<RegionSyncClientView> clients = new List<RegionSyncClientView>(); List<RegionSyncClientView> closed = null;
lock (clientLock) //lock (m_client_views)
{
foreach (RegionSyncClientView client in m_client_views)
{
if (client.Connected)
clients.Add(client);
}
}
if(clients.Count > 0 )
{ {
//m_log.WarnFormat("[REGION SYNC SERVER] Broadcasting {0} to all connected RegionSyncClients", msg.ToString()); //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)
{ {
client.Send(msg); // 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

@ -24,7 +24,8 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using Nini.Config; using Nini.Config;
@ -32,6 +33,7 @@ using OpenMetaverse;
using OpenMetaverse.StructuredData; using OpenMetaverse.StructuredData;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Framework.Client; using OpenSim.Framework.Client;
using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.Framework.Scenes.Serialization; using OpenSim.Region.Framework.Scenes.Serialization;
@ -42,7 +44,7 @@ using System.Threading;
namespace OpenSim.Region.Examples.RegionSyncModule namespace OpenSim.Region.Examples.RegionSyncModule
{ {
public class RegionSyncServerModule : IRegionModule, IRegionSyncServerModule public class RegionSyncServerModule : IRegionModule, IRegionSyncServerModule, ICommandableModule
{ {
#region IRegionModule Members #region IRegionModule Members
public void Initialise(Scene scene, IConfigSource config) public void Initialise(Scene scene, IConfigSource config)
@ -60,6 +62,11 @@ namespace OpenSim.Region.Examples.RegionSyncModule
m_serverport = syncConfig.GetInt("ServerPort", 13000); m_serverport = syncConfig.GetInt("ServerPort", 13000);
m_scene = scene; m_scene = scene;
m_scene.RegisterModuleInterface<IRegionSyncServerModule>(this); 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"); m_log.Warn("[REGION SYNC SERVER MODULE] Initialised");
} }
@ -67,20 +74,21 @@ namespace OpenSim.Region.Examples.RegionSyncModule
{ {
if (!m_active) if (!m_active)
return; return;
//m_scene.EventManager.OnObjectBeingRemovedFromScene += new EventManager.ObjectBeingRemovedFromScene(EventManager_OnObjectBeingRemovedFromScene); //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.OnAvatarEnteringNewParcel += new EventManager.AvatarEnteringNewParcel(EventManager_OnAvatarEnteringNewParcel);
//m_scene.EventManager.OnClientMovement += new EventManager.ClientMovement(EventManager_OnClientMovement); //m_scene.EventManager.OnClientMovement += new EventManager.ClientMovement(EventManager_OnClientMovement);
//m_scene.EventManager.OnLandObjectAdded += new EventManager.LandObjectAdded(EventManager_OnLandObjectAdded); //m_scene.EventManager.OnLandObjectAdded += new EventManager.LandObjectAdded(EventManager_OnLandObjectAdded);
//m_scene.EventManager.OnLandObjectRemoved += new EventManager.LandObjectRemoved(EventManager_OnLandObjectRemoved); //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.EventManager.OnRemovePresence += new EventManager.OnRemovePresenceDelegate(EventManager_OnRemovePresence);
m_scene.SceneGraph.OnObjectCreate += new ObjectCreateDelegate(SceneGraph_OnObjectCreate); m_scene.SceneGraph.OnObjectCreate += new ObjectCreateDelegate(SceneGraph_OnObjectCreate);
m_scene.SceneGraph.OnObjectDuplicate += new ObjectDuplicateDelegate(SceneGraph_OnObjectDuplicate); m_scene.SceneGraph.OnObjectDuplicate += new ObjectDuplicateDelegate(SceneGraph_OnObjectDuplicate);
//m_scene.SceneGraph.OnObjectRemove += new ObjectDeleteDelegate(SceneGraph_OnObjectRemove); //m_scene.SceneGraph.OnObjectRemove += new ObjectDeleteDelegate(SceneGraph_OnObjectRemove);
//m_scene.StatsReporter.OnSendStatsResult += new SimStatsReporter.SendStatResult(StatsReporter_OnSendStatsResult); //m_scene.StatsReporter.OnSendStatsResult += new SimStatsReporter.SendStatResult(StatsReporter_OnSendStatsResult);
m_log.Warn("[REGION SYNC SERVER MODULE] Starting RegionSyncServer"); m_log.Warn("[REGION SYNC SERVER MODULE] Starting RegionSyncServer");
// Start the server and listen for RegionSyncClients // Start the server and listen for RegionSyncClients
m_server = new RegionSyncServer(m_scene, m_serveraddr, m_serverport); m_server = new RegionSyncServer(m_scene, m_serveraddr, m_serverport);
@ -103,7 +111,15 @@ namespace OpenSim.Region.Examples.RegionSyncModule
{ {
get { return false; } 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 #region IRegionSyncServerModule members
// Lock is used to synchronize access to the update status and both update queues // 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) if (!Active || !Synced)
return; return;
lock (m_primUpdates) lock (m_updateLock)
{ {
m_primUpdates[part.ParentGroup.UUID] = part.ParentGroup; m_primUpdates[part.ParentGroup.UUID] = part.ParentGroup;
} }
@ -127,7 +143,7 @@ namespace OpenSim.Region.Examples.RegionSyncModule
{ {
if (!Active || !Synced) if (!Active || !Synced)
return; return;
lock (m_presenceUpdates) lock (m_updateLock)
{ {
m_presenceUpdates[presence.UUID] = presence; m_presenceUpdates[presence.UUID] = presence;
} }
@ -148,10 +164,14 @@ namespace OpenSim.Region.Examples.RegionSyncModule
List<SceneObjectGroup> primUpdates; List<SceneObjectGroup> primUpdates;
List<ScenePresence> presenceUpdates; List<ScenePresence> presenceUpdates;
primUpdates = new List<SceneObjectGroup>(m_primUpdates.Values);
presenceUpdates = new List<ScenePresence>(m_presenceUpdates.Values); lock (m_updateLock)
m_primUpdates.Clear(); {
m_presenceUpdates.Clear(); 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 // 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. // create and queue the messages directly into the outgoing server thread.
@ -164,20 +184,27 @@ namespace OpenSim.Region.Examples.RegionSyncModule
if (!sog.IsDeleted) if (!sog.IsDeleted)
{ {
string sogxml = SceneObjectSerializer.ToXml2Format(sog); 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) foreach (ScenePresence presence in presenceUpdates)
{ {
if (!presence.IsDeleted) if (!presence.IsDeleted)
{ {
OSDMap data = new OSDMap(4); OSDMap data = new OSDMap(5);
data["id"] = OSD.FromUUID(presence.UUID); data["id"] = OSD.FromUUID(presence.UUID);
// Do not include offset for appearance height. That will be handled by RegionSyncClient before sending to viewers // Do not include offset for appearance height. That will be handled by RegionSyncClient before sending to viewers
data["pos"] = OSD.FromVector3(presence.AbsolutePosition); if(presence.AbsolutePosition.IsFinite())
data["vel"] = OSD.FromVector3(presence.Velocity); 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); 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); m_server.Broadcast(rsm);
} }
} }
@ -193,7 +220,7 @@ namespace OpenSim.Region.Examples.RegionSyncModule
OSDMap data = new OSDMap(2); OSDMap data = new OSDMap(2);
data["regionHandle"] = OSD.FromULong(regionHandle); data["regionHandle"] = OSD.FromULong(regionHandle);
data["localID"] = OSD.FromUInteger(localID); 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); m_server.Broadcast(rsm);
} }
@ -255,7 +282,7 @@ namespace OpenSim.Region.Examples.RegionSyncModule
* */ * */
} }
#endif #endif
#endregion #endregion
#endregion #endregion
#region RegionSyncServerModule members #region RegionSyncServerModule members
@ -272,10 +299,12 @@ namespace OpenSim.Region.Examples.RegionSyncModule
#region Event Handlers #region Event Handlers
private void SceneGraph_OnObjectCreate(EntityBase entity) private void SceneGraph_OnObjectCreate(EntityBase entity)
{ {
if (!Synced)
return;
if (entity is SceneObjectGroup) if (entity is SceneObjectGroup)
{ {
string sogxml = SceneObjectSerializer.ToXml2Format((SceneObjectGroup)entity); 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); m_server.Broadcast(rsm);
} }
else else
@ -286,10 +315,12 @@ namespace OpenSim.Region.Examples.RegionSyncModule
private void SceneGraph_OnObjectDuplicate(EntityBase original, EntityBase copy) private void SceneGraph_OnObjectDuplicate(EntityBase original, EntityBase copy)
{ {
if (!Synced)
return;
if (original is SceneObjectGroup && copy is SceneObjectGroup) if (original is SceneObjectGroup && copy is SceneObjectGroup)
{ {
string sogxml = SceneObjectSerializer.ToXml2Format((SceneObjectGroup)copy); 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); m_server.Broadcast(rsm);
} }
else else
@ -300,10 +331,12 @@ namespace OpenSim.Region.Examples.RegionSyncModule
private void SceneGraph_OnObjectRemove(EntityBase entity) private void SceneGraph_OnObjectRemove(EntityBase entity)
{ {
if (!Synced)
return;
if (entity is SceneObjectGroup) if (entity is SceneObjectGroup)
{ {
// No reason to send the entire object, just send the UUID to be deleted // 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); m_server.Broadcast(rsm);
} }
else else
@ -315,6 +348,8 @@ namespace OpenSim.Region.Examples.RegionSyncModule
// A ficticious event // A ficticious event
public void Scene_AddNewPrim(SceneObjectGroup sog) public void Scene_AddNewPrim(SceneObjectGroup sog)
{ {
if (!Synced)
return;
} }
/* /*
@ -384,48 +419,48 @@ namespace OpenSim.Region.Examples.RegionSyncModule
} }
void EventManager_OnClientMovement(ScenePresence client) void EventManager_OnClientMovement(ScenePresence client)
{ {
m_moveCounter++; m_moveCounter++;
if (m_moveCounter % 100 == 0) if (m_moveCounter % 100 == 0)
{ {
string msg = (string.Format("EventManager_OnClientMovement - Event has been triggered 100 times"));
m_server.Broadcast(msg); m_server.Broadcast(msg);
m_log.Warn("REGION SYNC SERVER MODULE] " + msg); m_log.Warn("REGION SYNC SERVER MODULE] " + msg);
} }
} }
void EventManager_OnAvatarEnteringNewParcel(ScenePresence avatar, int localLandID, UUID regionID) 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()); 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(); 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) private void EventManager_OnNewClient(IClientAPI client)
{ {
ScenePresence presence = m_scene.GetScenePresence(client.AgentId); if (!Synced)
if (presence != null) return;
{ m_log.WarnFormat("[REGION SYNC SERVER MODULE] Agent \"{0}\" (1) has joined the scene", client.FirstName + " " + client.LastName, client.AgentId.ToString());
m_log.WarnFormat("[REGION SYNC SERVER MODULE] (OnNewClient) \"{0}\"", presence.Name); // Let the client managers know that a new agent has connected
DebugSceneStats(); OSDMap data = new OSDMap(1);
} data["agentID"] = OSD.FromUUID(client.AgentId);
else data["first"] = OSD.FromString(client.FirstName);
{ data["last"] = OSD.FromString(client.LastName);
m_log.WarnFormat("[REGION SYNC SERVER MODULE] (OnNewClient) A new client connected but module could not get ScenePresence"); data["startPos"] = OSD.FromVector3(client.StartPos);
} m_server.Broadcast(new RegionSyncMessage(RegionSyncMessage.MsgType.NewAvatar, OSDParser.SerializeJsonString(data)));
} }
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) private void EventManager_OnRemovePresence(UUID agentID)
{ {
if (!Synced)
return;
/*
ScenePresence avatar; ScenePresence avatar;
if (m_scene.TryGetScenePresence(agentID, out 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"); m_log.WarnFormat("[REGION SYNC SERVER MODULE] Avatar \"unknown\" has left the scene");
} }
OSDArray data = new OSDArray(); * */
data.Add(OSD.FromULong(avatar.RegionHandle)); OSDMap data = new OSDMap();
data.Add(OSD.FromUInteger(avatar.LocalId)); data["agentID"] = OSD.FromUUID(agentID);
RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.RemoveAvatar, data.ToString()); m_server.Broadcast(new RegionSyncMessage(RegionSyncMessage.MsgType.RemovedAvatar, OSDParser.SerializeJsonString(data)));
m_server.Broadcast(rsm);
} }
#endregion #endregion
#region Console Command Interface
/* private void InstallInterfaces()
private void DebugSceneStats()
{ {
List<ScenePresence> avatars = m_scene.GetAvatars(); Command cmdSyncStats = new Command("stats", CommandIntentions.COMMAND_HAZARDOUS, SyncStats, "Reports stats for the RegionSyncServer.");
List<EntityBase> entities = m_scene.GetEntities(); m_commander.RegisterCommand("stats", cmdSyncStats);
m_log.WarnFormat("There are {0} avatars and {1} entities in the scene", avatars.Count, entities.Count);
}
public IClientAPI ClientAggregator lock (m_scene)
{
get {return m_clientAggregator;}
}
private void AddAvatars()
{
for (int i = 0; i < 1; i++)
{ {
MyNpcCharacter m_character = new MyNpcCharacter(m_scene, this); // Add this to our scene so scripts can call these functions
m_scene.AddNewClient(m_character); m_scene.RegisterModuleCommander(m_commander);
m_scene.AgentCrossing(m_character.AgentId, m_character.StartPos, false);
} }
} }
*/
/// <summary>
/// Processes commandline input. Do not call directly.
/// </summary>
/// <param name="args">Commandline arguments</param>
private void EventManager_OnPluginConsole(string[] args)
{
if (args[0] == "sync")
{
if (args.Length == 1)
{
m_commander.ProcessConsoleCommand("help", new string[0]);
return;
}
string[] tmpArgs = new string[args.Length - 2];
int i;
for (i = 2; i < args.Length; i++)
tmpArgs[i - 2] = args[i];
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 Active { get; }
bool Synced { get; } bool Synced { get; }
void SendCoarseLocations();
} }
} }

View File

@ -1429,27 +1429,56 @@ namespace OpenSim.Region.Framework.Scenes
// Run through all ScenePresences looking for updates // Run through all ScenePresences looking for updates
// Presence updates and queued object updates for each presence are sent to clients // Presence updates and queued object updates for each presence are sent to clients
if (m_frame % m_update_presences == 0) // If it's a synced client, just send prim updates
m_sceneGraph.UpdatePresences(); // 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()) if (IsSyncedServer())
{
m_regionSyncServerModule.SendUpdates(); m_regionSyncServerModule.SendUpdates();
}
int tmpPhysicsMS2 = Util.EnvironmentTickCount(); int tmpPhysicsMS2 = Util.EnvironmentTickCount();
if ((m_frame % m_update_physics == 0) && m_physics_enabled) // Do not simulate physics locally if this is a synced client
m_sceneGraph.UpdatePreparePhysics(); if (!IsSyncedClient())
{
if ((m_frame % m_update_physics == 0) && m_physics_enabled)
m_sceneGraph.UpdatePreparePhysics();
}
physicsMS2 = Util.EnvironmentTickCountSubtract(tmpPhysicsMS2); physicsMS2 = Util.EnvironmentTickCountSubtract(tmpPhysicsMS2);
if (m_frame % m_update_entitymovement == 0) // Do not simulate physics locally if this is a synced client
m_sceneGraph.UpdateScenePresenceMovement(); if (!IsSyncedClient())
{
if (m_frame % m_update_entitymovement == 0)
m_sceneGraph.UpdateScenePresenceMovement();
}
int tmpPhysicsMS = Util.EnvironmentTickCount(); int tmpPhysicsMS = Util.EnvironmentTickCount();
if (m_frame % m_update_physics == 0) // Do not simulate physics locally if this is a synced client
if (!IsSyncedClient())
{ {
if (m_physics_enabled) if (m_frame % m_update_physics == 0)
physicsFPS = m_sceneGraph.UpdatePhysics(Math.Max(SinceLastFrame.TotalSeconds, m_timespan)); {
if (SynchronizeScene != null) if (m_physics_enabled)
SynchronizeScene(this); physicsFPS = m_sceneGraph.UpdatePhysics(Math.Max(SinceLastFrame.TotalSeconds, m_timespan));
if (SynchronizeScene != null)
SynchronizeScene(this);
}
} }
physicsMS = Util.EnvironmentTickCountSubtract(tmpPhysicsMS); physicsMS = Util.EnvironmentTickCountSubtract(tmpPhysicsMS);
@ -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) public void AddGroupTarget(SceneObjectGroup grp)
{ {
@ -3233,9 +3301,9 @@ namespace OpenSim.Region.Framework.Scenes
m_eventManager.TriggerOnRemovePresence(agentID); m_eventManager.TriggerOnRemovePresence(agentID);
if(IsSyncedServer()) // Don't try to send kills to clients if this is a synced server.
RegionSyncServerModule.DeleteObject(avatar.RegionHandle, avatar.LocalId); // The client closed event will trigger the broadcast to client managers
else //if(!IsSyncedServer())
{ {
ForEachClient( ForEachClient(
delegate(IClientAPI client) delegate(IClientAPI client)
@ -3325,11 +3393,11 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
ForEachClient(delegate(IClientAPI client) { client.SendKillObject(m_regionHandle, localID); });
// REGION SYNC // REGION SYNC
if( IsSyncedServer() ) if( IsSyncedServer() )
RegionSyncServerModule.DeleteObject(m_regionHandle, localID); RegionSyncServerModule.DeleteObject(m_regionHandle, localID);
else
ForEachClient(delegate(IClientAPI client) { client.SendKillObject(m_regionHandle, localID); });
} }
#endregion #endregion
@ -4365,11 +4433,10 @@ namespace OpenSim.Region.Framework.Scenes
/// Performs action on all scene presences. /// Performs action on all scene presences.
/// </summary> /// </summary>
/// <param name="action"></param> /// <param name="action"></param>
static int s_ForEachPresenceCounter = 0;
public void ForEachScenePresence(Action<ScenePresence> action) public void ForEachScenePresence(Action<ScenePresence> action)
{ {
if (IsSyncedServer()) //if (IsSyncedServer())
return; // return;
// We don't want to try to send messages if there are no avatars. // We don't want to try to send messages if there are no avatars.
if (m_sceneGraph != null) if (m_sceneGraph != null)
{ {
@ -4450,7 +4517,7 @@ namespace OpenSim.Region.Framework.Scenes
public void ForEachClient(Action<IClientAPI> action) public void ForEachClient(Action<IClientAPI> action)
{ {
// REGION SYNC // REGION SYNC
if (IsSyncedServer()) if (false)//IsSyncedServer())
return; return;
m_clientManager.ForEachSync(action); m_clientManager.ForEachSync(action);
} }

View File

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

View File

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

View File

@ -383,6 +383,18 @@ namespace OpenSim.Region.Framework.Scenes
set { m_allowMovement = value; } 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 public bool SetAlwaysRun
{ {
get get
@ -688,12 +700,9 @@ namespace OpenSim.Region.Framework.Scenes
AbsolutePosition = posLastSignificantMove = m_CameraCenter = AbsolutePosition = posLastSignificantMove = m_CameraCenter =
m_lastCameraCenter = m_controllingClient.StartPos; 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 = new Timer(world.ReprioritizationInterval); m_reprioritization_timer.AutoReset = false;
m_reprioritization_timer.Elapsed += new ElapsedEventHandler(Reprioritize);
m_reprioritization_timer.AutoReset = false;
}
AdjustKnownSeeds(); 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> /// <summary>
/// This is the event handler for client movement. If a client is moving, this event is triggering. /// This is the event handler for client movement. If a client is moving, this event is triggering.
/// </summary> /// </summary>
@ -2324,6 +2366,10 @@ namespace OpenSim.Region.Framework.Scenes
{ {
SendTerseUpdateToAllClients(); SendTerseUpdateToAllClients();
// REGION SYNC
if(m_scene.IsSyncedServer())
m_scene.RegionSyncServerModule.QueuePresenceForTerseUpdate(this);
// Update the "last" values // Update the "last" values
m_lastPosition = m_pos; m_lastPosition = m_pos;
m_lastRotation = m_bodyRot; m_lastRotation = m_bodyRot;
@ -2382,6 +2428,19 @@ namespace OpenSim.Region.Framework.Scenes
m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS)); 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() public void SendCoarseLocations()
{ {
SendCourseLocationsMethod d = m_sendCourseLocationsMethod; SendCourseLocationsMethod d = m_sendCourseLocationsMethod;
@ -2400,39 +2459,12 @@ namespace OpenSim.Region.Framework.Scenes
public void SendCoarseLocationsDefault(UUID sceneId, ScenePresence p) public void SendCoarseLocationsDefault(UUID sceneId, ScenePresence p)
{ {
m_perfMonMS = Util.EnvironmentTickCount(); m_perfMonMS = Util.EnvironmentTickCount();
List<Vector3> CoarseLocations = new List<Vector3>();
List<UUID> AvatarUUIDs = new List<UUID>(); List<UUID> AvatarUUIDs = new List<UUID>();
m_scene.ForEachScenePresence(delegate(ScenePresence sp) List<Vector3> CoarseLocations = new List<Vector3>();
{ // This is not cheap to compile this list of locations.
if (sp.IsChildAgent) // It should ideally be done once and then sent to every client rather than compiled for each client
return; m_scene.GetCoarseLocations(out AvatarUUIDs, out CoarseLocations);
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);
}
});
m_controllingClient.SendCoarseLocationUpdate(AvatarUUIDs, CoarseLocations); m_controllingClient.SendCoarseLocationUpdate(AvatarUUIDs, CoarseLocations);
m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS)); m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS));
} }

View File

@ -24,10 +24,12 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection;
using Nini.Config; using Nini.Config;
using log4net;
using OpenMetaverse; using OpenMetaverse;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Region.Physics.Manager; using OpenSim.Region.Physics.Manager;
@ -36,6 +38,8 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
{ {
public class BasicScene : PhysicsScene public class BasicScene : PhysicsScene
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private List<BasicActor> _actors = new List<BasicActor>(); private List<BasicActor> _actors = new List<BasicActor>();
private float[] _heightMap; private float[] _heightMap;
@ -129,7 +133,16 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
actorPosition.X = ((int)Constants.RegionSize - 0.1f); 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.Flying)
{ {
if (actor.Position.Z + (actor.Velocity.Z*timeStep) < 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); d.Vector3 localpos = d.BodyGetPosition(Body);
Vector3 localPos = new Vector3(localpos.X, localpos.Y, localpos.Z); 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 or out of bounds!");
m_log.Warn("[PHYSICS]: Avatar Position is non-finite!");
defects.Add(this); defects.Add(this);
// _parent_scene.RemoveCharacter(this); // _parent_scene.RemoveCharacter(this);