Some updates for client manager
							parent
							
								
									79327a6299
								
							
						
					
					
						commit
						2283b85bcf
					
				|  | @ -4901,32 +4901,38 @@ 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)) | ||||
|                 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; | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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) | ||||
|  | @ -153,59 +208,72 @@ 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)) | ||||
|                         { | ||||
|                             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"); | ||||
|                             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 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() | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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, | ||||
|  |  | |||
|  | @ -19,6 +19,8 @@ namespace OpenSim.Region.Examples.RegionSyncModule | |||
|         // Set the addr and port for TcpListener | ||||
|         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) | ||||
|                 { | ||||
|                     foreach (RegionSyncClientView cv in m_client_views) | ||||
|                     { | ||||
|                         if (cv.Connected) | ||||
|                             return true; | ||||
|                     } | ||||
|                     return false; | ||||
|                 } | ||||
|                 return (m_client_views.Count > 0); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // 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 | ||||
| 
 | ||||
|         // Constructor | ||||
|  | @ -82,19 +107,18 @@ 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 | ||||
|             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 | ||||
|                 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) | ||||
|                 { | ||||
|                     // Each client view will clean up after itself | ||||
|                     cv.Shutdown(); | ||||
|                 } | ||||
|                 m_client_views.Clear(); | ||||
|                 // Each client view will clean up after itself | ||||
|                 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); | ||||
|                         m_log.WarnFormat("[REGION SYNC SERVER] New connection from {0}", rscv.Description); | ||||
|                         m_client_views.Add(rscv); | ||||
|                     } | ||||
|                     // 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(++clientCounter, m_scene, tcpclient); | ||||
|                     m_log.WarnFormat("[REGION SYNC SERVER] New connection from {0}", rscv.Description); | ||||
|                     AddSyncedClient(rscv); | ||||
|                 } | ||||
|             } | ||||
|             catch (SocketException e) | ||||
|  | @ -138,22 +159,30 @@ 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) | ||||
|                 { | ||||
|                     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); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  |  | |||
|  | @ -24,7 +24,8 @@ | |||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
|      | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Reflection; | ||||
| using 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"); | ||||
|         } | ||||
| 
 | ||||
|  | @ -67,20 +74,21 @@ namespace OpenSim.Region.Examples.RegionSyncModule | |||
|         { | ||||
|             if (!m_active) | ||||
|                 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); | ||||
|             //m_scene.SceneGraph.OnObjectRemove += new ObjectDeleteDelegate(SceneGraph_OnObjectRemove); | ||||
|             //m_scene.StatsReporter.OnSendStatsResult += new SimStatsReporter.SendStatResult(StatsReporter_OnSendStatsResult); | ||||
|              | ||||
| 
 | ||||
|             m_log.Warn("[REGION SYNC SERVER MODULE] Starting RegionSyncServer"); | ||||
|             // Start the server and listen for RegionSyncClients | ||||
|             m_server = new RegionSyncServer(m_scene, m_serveraddr, m_serverport); | ||||
|  | @ -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; | ||||
|             primUpdates = new List<SceneObjectGroup>(m_primUpdates.Values); | ||||
|             presenceUpdates = new List<ScenePresence>(m_presenceUpdates.Values); | ||||
|             m_primUpdates.Clear(); | ||||
|             m_presenceUpdates.Clear(); | ||||
| 
 | ||||
|             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 | ||||
|                         data["pos"] = OSD.FromVector3(presence.AbsolutePosition);  | ||||
|                         data["vel"] = OSD.FromVector3(presence.Velocity); | ||||
|                         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); | ||||
|         } | ||||
| 
 | ||||
|  | @ -255,7 +282,7 @@ namespace OpenSim.Region.Examples.RegionSyncModule | |||
|              * */ | ||||
|         } | ||||
| #endif | ||||
|         #endregion  | ||||
|         #endregion | ||||
|         #endregion | ||||
| 
 | ||||
|         #region RegionSyncServerModule members | ||||
|  | @ -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; | ||||
|         } | ||||
| 
 | ||||
|         /* | ||||
|  | @ -384,48 +419,48 @@ 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(); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 m_log.WarnFormat("[REGION SYNC SERVER MODULE] (OnNewClient) A new client connected but module could not get ScenePresence"); | ||||
|             } | ||||
|             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))); | ||||
|         } | ||||
| 
 | ||||
|         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); | ||||
| 
 | ||||
|         public IClientAPI ClientAggregator | ||||
|         { | ||||
|             get {return m_clientAggregator;} | ||||
|         } | ||||
| 
 | ||||
|         private void AddAvatars() | ||||
|         { | ||||
|             for (int i = 0; i < 1; i++) | ||||
|             lock (m_scene) | ||||
|             { | ||||
|                 MyNpcCharacter m_character = new MyNpcCharacter(m_scene, this); | ||||
|                 m_scene.AddNewClient(m_character); | ||||
|                  | ||||
|                 m_scene.AgentCrossing(m_character.AgentId, m_character.StartPos, false); | ||||
|                 // Add this to our scene so scripts can call these functions | ||||
|                 m_scene.RegisterModuleCommander(m_commander); | ||||
|             } | ||||
|         } | ||||
|          */ | ||||
| 
 | ||||
| 
 | ||||
|         /// <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 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -35,5 +35,6 @@ namespace OpenSim.Region.Framework.Interfaces | |||
|     { | ||||
|         bool Active { get; } | ||||
|         bool Synced { get; } | ||||
|         void SendCoarseLocations(); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1429,27 +1429,56 @@ 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 (m_frame % m_update_presences == 0) | ||||
|                         m_sceneGraph.UpdatePresences(); | ||||
|                     // 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(); | ||||
|                     if ((m_frame % m_update_physics == 0) && m_physics_enabled) | ||||
|                         m_sceneGraph.UpdatePreparePhysics(); | ||||
|                     // 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); | ||||
| 
 | ||||
|                     if (m_frame % m_update_entitymovement == 0) | ||||
|                         m_sceneGraph.UpdateScenePresenceMovement(); | ||||
|                     // 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(); | ||||
|                     if (m_frame % m_update_physics == 0) | ||||
|                     // Do not simulate physics locally if this is a synced client | ||||
|                     if (!IsSyncedClient()) | ||||
|                     { | ||||
|                         if (m_physics_enabled) | ||||
|                             physicsFPS = m_sceneGraph.UpdatePhysics(Math.Max(SinceLastFrame.TotalSeconds, m_timespan)); | ||||
|                         if (SynchronizeScene != null) | ||||
|                             SynchronizeScene(this); | ||||
|                         if (m_frame % m_update_physics == 0) | ||||
|                         { | ||||
|                             if (m_physics_enabled) | ||||
|                                 physicsFPS = m_sceneGraph.UpdatePhysics(Math.Max(SinceLastFrame.TotalSeconds, m_timespan)); | ||||
|                             if (SynchronizeScene != null) | ||||
|                                 SynchronizeScene(this); | ||||
|                         } | ||||
|                     } | ||||
|                     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) | ||||
|         { | ||||
|  | @ -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); | ||||
|         } | ||||
|  |  | |||
|  | @ -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) | ||||
|                     { | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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; | ||||
|             } | ||||
|             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)); | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -24,10 +24,12 @@ | |||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
|      | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Reflection; | ||||
| using 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) < | ||||
|  |  | |||
|  | @ -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); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Dan Lake
						Dan Lake