From f61e54892f2284b6f89bacf3069467c05b2eea11 Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Thu, 8 Dec 2011 18:34:23 +0000
Subject: On a new client circuit, send the initial reply ack to let the client
know it's live before sending other data.
This means that avatar/appearance data of other avatars and scene objects for a client will be sent after the ack rather than possibly before.
This may stop some avatars appearing grey on login.
This introduces a new OpenSim.Framework.ISceneAgent to accompany the existing OpenSim.Framework.ISceneObject and ISceneEntity
This allows IClientAPI to handle this as it can't reference OpenSim.Region.Framework.Interfaces
---
OpenSim/Framework/IClientAPI.cs | 6 ++
OpenSim/Framework/IScene.cs | 10 +++-
OpenSim/Framework/ISceneAgent.cs | 68 ++++++++++++++++++++++
.../Region/ClientStack/Linden/UDP/LLClientView.cs | 4 +-
.../Region/ClientStack/Linden/UDP/LLUDPServer.cs | 58 ++++++++++++------
.../ClientStack/Linden/UDP/Tests/MockScene.cs | 5 +-
.../Region/Framework/Interfaces/IScenePresence.cs | 22 +------
OpenSim/Region/Framework/Scenes/Scene.cs | 15 +----
OpenSim/Region/Framework/Scenes/SceneBase.cs | 2 +-
OpenSim/Region/Framework/Scenes/ScenePresence.cs | 39 ++++++++-----
.../Server/IRCClientView.cs | 8 ++-
.../Region/OptionalModules/World/NPC/NPCAvatar.cs | 5 +-
OpenSim/Tests/Common/Mock/TestClient.cs | 7 ++-
13 files changed, 171 insertions(+), 78 deletions(-)
create mode 100644 OpenSim/Framework/ISceneAgent.cs
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs
index 475fc01..a070aa6 100644
--- a/OpenSim/Framework/IClientAPI.cs
+++ b/OpenSim/Framework/IClientAPI.cs
@@ -702,6 +702,12 @@ namespace OpenSim.Framework
UUID AgentId { get; }
+ ///
+ /// The scene agent for this client. This will only be set if the client has an agent in a scene (i.e. if it
+ /// is connected).
+ ///
+ ISceneAgent SceneAgent { get; }
+
UUID SessionId { get; }
UUID SecureSessionId { get; }
diff --git a/OpenSim/Framework/IScene.cs b/OpenSim/Framework/IScene.cs
index 7b0fe37..6919c48 100644
--- a/OpenSim/Framework/IScene.cs
+++ b/OpenSim/Framework/IScene.cs
@@ -68,12 +68,16 @@ namespace OpenSim.Framework
event restart OnRestart;
///
- /// Register the new client with the scene. The client starts off as a child agent - the later agent crossing
- /// will promote it to a root agent.
+ /// Add a new client and create a presence for it. All clients except initial login clients will starts off as a child agent
+ /// - the later agent crossing will promote it to a root agent.
///
///
/// The type of agent to add.
- void AddNewClient(IClientAPI client, PresenceType type);
+ ///
+ /// The scene agent if the new client was added.
+ /// Null if the required scene agent already existed or no scene agent was added because the required client circuit doesn't exist.
+ ///
+ ISceneAgent AddNewClient(IClientAPI client, PresenceType type);
///
/// Remove the given client from the scene.
diff --git a/OpenSim/Framework/ISceneAgent.cs b/OpenSim/Framework/ISceneAgent.cs
new file mode 100644
index 0000000..69e91ed
--- /dev/null
+++ b/OpenSim/Framework/ISceneAgent.cs
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+
+namespace OpenSim.Framework
+{
+ ///
+ /// An agent in the scene.
+ ///
+ ///
+ /// Interface is a work in progress. Please feel free to add other required properties and methods.
+ ///
+ public interface ISceneAgent : ISceneEntity
+ {
+ ///
+ /// The client controlling this presence
+ ///
+ IClientAPI ControllingClient { get; }
+
+ ///
+ /// What type of presence is this? User, NPC, etc.
+ ///
+ PresenceType PresenceType { get; }
+
+ ///
+ /// Avatar appearance data.
+ ///
+ ///
+ // Because appearance setting is in a module, we actually need
+ // to give it access to our appearance directly, otherwise we
+ // get a synchronization issue.
+ ///
+ AvatarAppearance Appearance { get; set; }
+
+ ///
+ /// Send initial scene data to the client controlling this agent
+ ///
+ ///
+ /// This includes scene object data and the appearance data of other avatars.
+ ///
+ void SendInitialDataToMe();
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index 7d39ddc..f246637 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -379,6 +379,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
set { m_startpos = value; }
}
public UUID AgentId { get { return m_agentId; } }
+ public ISceneAgent SceneAgent { get; private set; }
public UUID ActiveGroupId { get { return m_activeGroupID; } }
public string ActiveGroupName { get { return m_activeGroupName; } }
public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } }
@@ -508,6 +509,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Remove ourselves from the scene
m_scene.RemoveClient(AgentId, true);
+ SceneAgent = null;
// We can't reach into other scenes and close the connection
// We need to do this over grid communications
@@ -687,7 +689,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public virtual void Start()
{
- m_scene.AddNewClient(this, PresenceType.User);
+ SceneAgent = m_scene.AddNewClient(this, PresenceType.User);
RefreshGroupMembership();
}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index ccad241..7db5f6b 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -894,11 +894,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
IPEndPoint remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint;
// Begin the process of adding the client to the simulator
- AddNewClient((UseCircuitCodePacket)packet, remoteEndPoint);
+ IClientAPI client = AddNewClient((UseCircuitCodePacket)packet, remoteEndPoint);
- // Send ack
+ // Send ack straight away to let the viewer know that the connection is active.
SendAckImmediate(remoteEndPoint, packet.Header.Sequence);
+ // FIXME: Nasty - this is the only way we currently know if Scene.AddNewClient() failed to find a
+ // circuit and bombed out early. That check might be pointless since authorization is established
+ // up here.
+ if (client != null && client.SceneAgent != null)
+ client.SceneAgent.SendInitialDataToMe();
+
// m_log.DebugFormat(
// "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms",
// buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds);
@@ -933,7 +939,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
return sessionInfo.Authorised;
}
- private void AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint)
+ ///
+ /// Add a new client.
+ ///
+ ///
+ ///
+ ///
+ /// The client that was added or null if the client failed authorization or already existed.
+ ///
+ private IClientAPI AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint)
{
UUID agentID = useCircuitCode.CircuitCode.ID;
UUID sessionID = useCircuitCode.CircuitCode.SessionID;
@@ -942,7 +956,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
AuthenticateResponse sessionInfo;
if (IsClientAuthorized(useCircuitCode, out sessionInfo))
{
- AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo);
+ return AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo);
}
else
{
@@ -950,38 +964,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_log.WarnFormat(
"[LLUDPSERVER]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}",
useCircuitCode.CircuitCode.ID, useCircuitCode.CircuitCode.Code, remoteEndPoint);
+
+ return null;
}
}
- protected virtual void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
+ ///
+ /// Add a client.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// The client if it was added. Null if the client already existed.
+ protected virtual IClientAPI AddClient(
+ uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
{
+ IClientAPI client = null;
+
// In priciple there shouldn't be more than one thread here, ever.
// But in case that happens, we need to synchronize this piece of code
// because it's too important
lock (this)
{
- IClientAPI existingClient;
-
- if (!m_scene.TryGetClient(agentID, out existingClient))
+ if (!m_scene.TryGetClient(agentID, out client))
{
- // Create the LLUDPClient
LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
- // Create the LLClientView
- LLClientView client = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
+
+ client = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
client.OnLogout += LogoutHandler;
- client.DisableFacelights = m_disableFacelights;
+ ((LLClientView)client).DisableFacelights = m_disableFacelights;
- // Start the IClientAPI
client.Start();
-
- }
- else
- {
- m_log.WarnFormat("[LLUDPSERVER]: Ignoring a repeated UseCircuitCode from {0} at {1} for circuit {2}",
- existingClient.AgentId, remoteEndPoint, circuitCode);
}
}
+
+ return client;
}
private void RemoveClient(LLUDPClient udpClient)
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs
index 737c654..fb94355 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs
@@ -53,9 +53,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
public override void Update() {}
public override void LoadWorldMap() {}
- public override void AddNewClient(IClientAPI client, PresenceType type)
+ public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type)
{
client.OnObjectName += RecordObjectNameCall;
+
+ // FIXME
+ return null;
}
public override void RemoveClient(UUID agentID, bool someReason) {}
diff --git a/OpenSim/Region/Framework/Interfaces/IScenePresence.cs b/OpenSim/Region/Framework/Interfaces/IScenePresence.cs
index ff39283..5e43843 100644
--- a/OpenSim/Region/Framework/Interfaces/IScenePresence.cs
+++ b/OpenSim/Region/Framework/Interfaces/IScenePresence.cs
@@ -38,28 +38,8 @@ namespace OpenSim.Region.Framework.Interfaces
///
/// Interface is a work in progress. Please feel free to add other required properties and methods.
///
- public interface IScenePresence : ISceneEntity
+ public interface IScenePresence : ISceneAgent
{
- ///
- /// The client controlling this presence
- ///
- IClientAPI ControllingClient { get; }
-
- ///
- /// What type of presence is this? User, NPC, etc.
- ///
- PresenceType PresenceType { get; }
-
- ///
- /// Avatar appearance data.
- ///
- ///
- // Because appearance setting is in a module, we actually need
- // to give it access to our appearance directly, otherwise we
- // get a synchronization issue.
- ///
- AvatarAppearance Appearance { get; set; }
-
///
/// The AttachmentsModule synchronizes on this to avoid race conditions between commands to add and remove attachments.
///
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 21c4a87..d47536a 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -2491,13 +2491,13 @@ namespace OpenSim.Region.Framework.Scenes
///
///
/// The type of agent to add.
- public override void AddNewClient(IClientAPI client, PresenceType type)
+ public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type)
{
AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode);
bool vialogin = false;
if (aCircuit == null) // no good, didn't pass NewUserConnection successfully
- return;
+ return null;
vialogin = (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0 ||
(aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0;
@@ -2552,16 +2552,7 @@ namespace OpenSim.Region.Framework.Scenes
if (vialogin)
EventManager.TriggerOnClientLogin(client);
- // Send all scene object to the new client
- Util.FireAndForget(delegate
- {
- EntityBase[] entities = Entities.GetEntities();
- foreach(EntityBase e in entities)
- {
- if (e != null && e is SceneObjectGroup)
- ((SceneObjectGroup)e).SendFullUpdateToClient(client);
- }
- });
+ return sp;
}
///
diff --git a/OpenSim/Region/Framework/Scenes/SceneBase.cs b/OpenSim/Region/Framework/Scenes/SceneBase.cs
index a633c72..da15491 100644
--- a/OpenSim/Region/Framework/Scenes/SceneBase.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneBase.cs
@@ -175,7 +175,7 @@ namespace OpenSim.Region.Framework.Scenes
#region Add/Remove Agent/Avatar
- public abstract void AddNewClient(IClientAPI client, PresenceType type);
+ public abstract ISceneAgent AddNewClient(IClientAPI client, PresenceType type);
public abstract void RemoveClient(UUID agentID, bool closeChildAgents);
public bool TryGetScenePresence(UUID agentID, out object scenePresence)
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 5b9438b..8e55996 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -782,15 +782,6 @@ namespace OpenSim.Region.Framework.Scenes
AdjustKnownSeeds();
- // we created a new ScenePresence (a new child agent) in a fresh region.
- // Request info about all the (root) agents in this region
- // Note: This won't send data *to* other clients in that region (children don't send)
-
-// MIC: This gets called again in CompleteMovement
- // SendInitialFullUpdateToAllClients();
- SendOtherAgentsAvatarDataToMe();
- SendOtherAgentsAppearanceToMe();
-
RegisterToEvents();
SetDirectionVectors();
@@ -1191,9 +1182,9 @@ namespace OpenSim.Region.Framework.Scenes
{
// DateTime startTime = DateTime.Now;
- m_log.DebugFormat(
- "[SCENE PRESENCE]: Completing movement of {0} into region {1}",
- client.Name, Scene.RegionInfo.RegionName);
+// m_log.DebugFormat(
+// "[SCENE PRESENCE]: Completing movement of {0} into region {1}",
+// client.Name, Scene.RegionInfo.RegionName);
Vector3 look = Velocity;
if ((look.X == 0) && (look.Y == 0) && (look.Z == 0))
@@ -1225,7 +1216,7 @@ namespace OpenSim.Region.Framework.Scenes
//m_log.DebugFormat("[SCENE PRESENCE] Completed movement");
ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look);
- SendInitialData();
+ ValidateAndSendAppearanceAndAgentData();
// Create child agents in neighbouring regions
if (openChildAgents && !IsChildAgent)
@@ -2512,11 +2503,31 @@ namespace OpenSim.Region.Framework.Scenes
ControllingClient.SendCoarseLocationUpdate(avatarUUIDs, coarseLocations);
}
+ public void SendInitialDataToMe()
+ {
+ // we created a new ScenePresence (a new child agent) in a fresh region.
+ // Request info about all the (root) agents in this region
+ // Note: This won't send data *to* other clients in that region (children don't send)
+ SendOtherAgentsAvatarDataToMe();
+ SendOtherAgentsAppearanceToMe();
+
+ // Send all scene object to the new client
+ Util.FireAndForget(delegate
+ {
+ EntityBase[] entities = Scene.Entities.GetEntities();
+ foreach(EntityBase e in entities)
+ {
+ if (e != null && e is SceneObjectGroup)
+ ((SceneObjectGroup)e).SendFullUpdateToClient(ControllingClient);
+ }
+ });
+ }
+
///
/// Do everything required once a client completes its movement into a region and becomes
/// a root agent.
///
- private void SendInitialData()
+ private void ValidateAndSendAppearanceAndAgentData()
{
//m_log.DebugFormat("[SCENE PRESENCE] SendInitialData: {0} ({1})", Name, UUID);
// Moved this into CompleteMovement to ensure that Appearance is initialized before
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
index 380570b..70326b7 100644
--- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
+++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
@@ -55,6 +55,8 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
private UUID m_agentID = UUID.Random();
+ public ISceneAgent SceneAgent { get; private set; }
+
private string m_username;
private string m_nick;
@@ -547,6 +549,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
m_connected = false;
m_client.Close();
+ SceneAgent = null;
}
public UUID SessionId
@@ -890,12 +893,11 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
public void Start()
{
- Scene.AddNewClient(this, PresenceType.User);
+ SceneAgent = m_scene.AddNewClient(this, PresenceType.User);
// Mimicking LLClientView which gets always set appearance from client.
- Scene scene = (Scene)Scene;
AvatarAppearance appearance;
- scene.GetAvatarAppearance(this, out appearance);
+ m_scene.GetAvatarAppearance(this, out appearance);
OnSetAppearance(this, appearance.Texture, (byte[])appearance.VisualParams.Clone());
}
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
index 152377a..ed60976 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
@@ -43,7 +43,6 @@ namespace OpenSim.Region.OptionalModules.World.NPC
private readonly UUID m_uuid = UUID.Random();
private readonly Scene m_scene;
-
public NPCAvatar(string firstname, string lastname, Vector3 position, Scene scene)
{
m_firstname = firstname;
@@ -57,6 +56,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC
get { return m_scene; }
}
+ public ISceneAgent SceneAgent { get { throw new NotImplementedException(); } }
+
public void Say(string message)
{
SendOnChatFromClient(message, ChatTypeEnum.Say);
@@ -841,6 +842,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC
public void Start()
{
+ // We never start the client, so always fail.
+ throw new NotImplementedException();
}
public void Stop()
diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs
index b83ef9b..4e17b04 100644
--- a/OpenSim/Tests/Common/Mock/TestClient.cs
+++ b/OpenSim/Tests/Common/Mock/TestClient.cs
@@ -54,7 +54,7 @@ namespace OpenSim.Tests.Common.Mock
public Scene TeleportTargetScene;
private TestClient TeleportSceneClient;
- private IScene m_scene;
+ private Scene m_scene;
// Properties so that we can get at received data for test purposes
public List ReceivedOfflineNotifications { get; private set; }
@@ -324,6 +324,8 @@ namespace OpenSim.Tests.Common.Mock
///
private UUID m_agentId;
+ public ISceneAgent SceneAgent { get { throw new NotImplementedException(); } }
+
///
/// The last caps seed url that this client was given.
///
@@ -437,7 +439,7 @@ namespace OpenSim.Tests.Common.Mock
///
///
///
- public TestClient(AgentCircuitData agentData, IScene scene)
+ public TestClient(AgentCircuitData agentData, Scene scene)
{
m_agentId = agentData.AgentID;
m_firstName = agentData.firstname;
@@ -899,6 +901,7 @@ namespace OpenSim.Tests.Common.Mock
public void Start()
{
+ throw new NotImplementedException();
}
public void Stop()
--
cgit v1.1