Merge branch 'TeleportWork'

0.7.6-extended
Justin Clark-Casey (justincc) 2013-08-09 17:52:29 +01:00
commit 97bcb59bee
8 changed files with 270 additions and 136 deletions

View File

@ -91,7 +91,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
public void RemoveForClient() public void RemoveForClient()
{ {
TestHelpers.InMethod(); TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure(); // TestHelpers.EnableLogging();
UUID spId = TestHelpers.ParseTail(0x1); UUID spId = TestHelpers.ParseTail(0x1);

View File

@ -512,7 +512,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// We still perform a force close inside the sync lock since this is intended to attempt close where // We still perform a force close inside the sync lock since this is intended to attempt close where
// there is some unidentified connection problem, not where we have issues due to deadlock // there is some unidentified connection problem, not where we have issues due to deadlock
if (!IsActive && !force) if (!IsActive && !force)
{
m_log.DebugFormat(
"[CLIENT]: Not attempting to close inactive client {0} in {1} since force flag is not set",
Name, m_scene.Name);
return; return;
}
IsActive = false; IsActive = false;
CloseWithoutChecks(); CloseWithoutChecks();

View File

@ -1799,9 +1799,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (!client.SceneAgent.IsChildAgent) if (!client.SceneAgent.IsChildAgent)
client.Kick("Simulator logged you out due to connection timeout."); client.Kick("Simulator logged you out due to connection timeout.");
client.CloseWithoutChecks();
} }
m_scene.IncomingCloseAgent(client.AgentId, true);
} }
private void IncomingPacketHandler() private void IncomingPacketHandler()
@ -2142,7 +2142,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (!client.IsLoggingOut) if (!client.IsLoggingOut)
{ {
client.IsLoggingOut = true; client.IsLoggingOut = true;
client.Close(); m_scene.IncomingCloseAgent(client.AgentId, false);
} }
} }
} }

View File

@ -200,7 +200,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
public void TestLogoutClientDueToAck() public void TestLogoutClientDueToAck()
{ {
TestHelpers.InMethod(); TestHelpers.InMethod();
// TestHelpers.EnableLogging(); TestHelpers.EnableLogging();
IniConfigSource ics = new IniConfigSource(); IniConfigSource ics = new IniConfigSource();
IConfig config = ics.AddConfig("ClientStack.LindenUDP"); IConfig config = ics.AddConfig("ClientStack.LindenUDP");

View File

@ -1064,8 +1064,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// Now let's make it officially a child agent // Now let's make it officially a child agent
sp.MakeChildAgent(); sp.MakeChildAgent();
// Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone // May still need to signal neighbours whether child agents may need closing irrespective of whether this
// one needed closing. Neighbour regions also contain logic to prevent a close if a subsequent move or
// teleport re-established the child connection.
//
// It may be possible to also close child agents after a pause but one needs to be very careful about
// race conditions between different regions on rapid teleporting (e.g. from A1 to a non-neighbour B, back
// to a neighbour A2 then off to a non-neighbour C. Also, closing child agents early may be more compatible
// with complicated scenarios where there a mixture of V1 and V2 teleports, though this is conjecture. It's
// easier to close immediately and greatly reduce the scope of race conditions if possible.
sp.CloseChildAgents(newRegionX, newRegionY);
// Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
{ {
sp.DoNotCloseAfterTeleport = false; sp.DoNotCloseAfterTeleport = false;
@ -1081,14 +1091,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
if (!sp.DoNotCloseAfterTeleport) if (!sp.DoNotCloseAfterTeleport)
{ {
// OK, it got this agent. Let's close everything // OK, it got this agent. Let's close everything
m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Closing in agent {0} in region {1}", sp.Name, Scene.Name); m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Closing agent {0} in {1}", sp.Name, Scene.Name);
sp.CloseChildAgents(newRegionX, newRegionY);
sp.Scene.IncomingCloseAgent(sp.UUID, false); sp.Scene.IncomingCloseAgent(sp.UUID, false);
} }
else else
{ {
m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Not closing agent {0}, user is back in {0}", sp.Name, Scene.Name); m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Not closing agent {0}, user is back in {1}", sp.Name, Scene.Name);
sp.DoNotCloseAfterTeleport = false; sp.DoNotCloseAfterTeleport = false;
} }
} }
@ -1863,10 +1871,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
List<ulong> newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles); List<ulong> newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles);
List<ulong> oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles); List<ulong> oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles);
//Dump("Current Neighbors", neighbourHandles); // Dump("Current Neighbors", neighbourHandles);
//Dump("Previous Neighbours", previousRegionNeighbourHandles); // Dump("Previous Neighbours", previousRegionNeighbourHandles);
//Dump("New Neighbours", newRegions); // Dump("New Neighbours", newRegions);
//Dump("Old Neighbours", oldRegions); // Dump("Old Neighbours", oldRegions);
/// Update the scene presence's known regions here on this region /// Update the scene presence's known regions here on this region
sp.DropOldNeighbours(oldRegions); sp.DropOldNeighbours(oldRegions);
@ -1874,8 +1882,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
/// Collect as many seeds as possible /// Collect as many seeds as possible
Dictionary<ulong, string> seeds; Dictionary<ulong, string> seeds;
if (sp.Scene.CapsModule != null) if (sp.Scene.CapsModule != null)
seeds seeds = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID));
= new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID));
else else
seeds = new Dictionary<ulong, string>(); seeds = new Dictionary<ulong, string>();
@ -1945,6 +1952,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
newAgent = true; newAgent = true;
else else
newAgent = false; newAgent = false;
// continue;
if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle) if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle)
{ {

View File

@ -562,7 +562,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
if (!Scene.TeleportClientHome(user, s.ControllingClient)) if (!Scene.TeleportClientHome(user, s.ControllingClient))
{ {
s.ControllingClient.Kick("Your access to the region was revoked and TP home failed - you have been logged out."); s.ControllingClient.Kick("Your access to the region was revoked and TP home failed - you have been logged out.");
s.ControllingClient.Close(); Scene.IncomingCloseAgent(s.UUID, false);
} }
} }
} }
@ -797,7 +797,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
if (!Scene.TeleportClientHome(prey, s.ControllingClient)) if (!Scene.TeleportClientHome(prey, s.ControllingClient))
{ {
s.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out."); s.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out.");
s.ControllingClient.Close(); Scene.IncomingCloseAgent(s.UUID, false);
} }
} }
} }
@ -820,7 +820,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
if (!Scene.TeleportClientHome(p.UUID, p.ControllingClient)) if (!Scene.TeleportClientHome(p.UUID, p.ControllingClient))
{ {
p.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out."); p.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out.");
p.ControllingClient.Close(); Scene.IncomingCloseAgent(p.UUID, false);
} }
} }
} }

View File

@ -151,7 +151,7 @@ namespace OpenSim.Region.Framework.Scenes
public SynchronizeSceneHandler SynchronizeScene; public SynchronizeSceneHandler SynchronizeScene;
/// <summary> /// <summary>
/// Used to prevent simultaneous calls to RemoveClient() for the same agent from interfering with each other. /// Used to prevent simultaneous calls to code that adds and removes agents.
/// </summary> /// </summary>
private object m_removeClientLock = new object(); private object m_removeClientLock = new object();
@ -1312,7 +1312,7 @@ namespace OpenSim.Region.Framework.Scenes
Thread.Sleep(500); Thread.Sleep(500);
// Stop all client threads. // Stop all client threads.
ForEachScenePresence(delegate(ScenePresence avatar) { avatar.ControllingClient.Close(); }); ForEachScenePresence(delegate(ScenePresence avatar) { IncomingCloseAgent(avatar.UUID, false); });
m_log.Debug("[SCENE]: Persisting changed objects"); m_log.Debug("[SCENE]: Persisting changed objects");
EventManager.TriggerSceneShuttingDown(this); EventManager.TriggerSceneShuttingDown(this);
@ -2972,7 +2972,7 @@ namespace OpenSim.Region.Framework.Scenes
{ {
PresenceService.LogoutAgent(sp.ControllingClient.SessionId); PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
sp.ControllingClient.Close(); IncomingCloseAgent(sp.UUID, false);
} }
else else
{ {
@ -3384,35 +3384,36 @@ namespace OpenSim.Region.Framework.Scenes
public override void RemoveClient(UUID agentID, bool closeChildAgents) public override void RemoveClient(UUID agentID, bool closeChildAgents)
{ {
// CheckHeartbeat(); AgentCircuitData acd = m_authenticateHandler.GetAgentCircuitData(agentID);
bool isChildAgent = false;
AgentCircuitData acd;
lock (m_removeClientLock)
{
acd = m_authenticateHandler.GetAgentCircuitData(agentID);
// Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which
// in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not
// However, will keep for now just in case.
if (acd == null) if (acd == null)
{ {
m_log.ErrorFormat("[SCENE]: No agent circuit found for {0}, aborting Scene.RemoveClient", agentID); m_log.ErrorFormat(
"[SCENE]: No agent circuit found for {0} in {1}, aborting Scene.RemoveClient", agentID, Name);
return; return;
} }
else else
{ {
// We remove the acd up here to avoid later race conditions if two RemoveClient() calls occurred
// simultaneously.
// We also need to remove by agent ID since NPCs will have no circuit code.
m_authenticateHandler.RemoveCircuit(agentID); m_authenticateHandler.RemoveCircuit(agentID);
} }
}
// TODO: Can we now remove this lock?
lock (acd) lock (acd)
{ {
bool isChildAgent = false;
ScenePresence avatar = GetScenePresence(agentID); ScenePresence avatar = GetScenePresence(agentID);
// Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which
// in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not
// However, will keep for now just in case.
if (avatar == null) if (avatar == null)
{ {
m_log.WarnFormat( m_log.ErrorFormat(
"[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID); "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID);
return; return;
@ -3424,7 +3425,7 @@ namespace OpenSim.Region.Framework.Scenes
m_log.DebugFormat( m_log.DebugFormat(
"[SCENE]: Removing {0} agent {1} {2} from {3}", "[SCENE]: Removing {0} agent {1} {2} from {3}",
(isChildAgent ? "child" : "root"), avatar.Name, agentID, RegionInfo.RegionName); isChildAgent ? "child" : "root", avatar.Name, agentID, Name);
// Don't do this to root agents, it's not nice for the viewer // Don't do this to root agents, it's not nice for the viewer
if (closeChildAgents && isChildAgent) if (closeChildAgents && isChildAgent)
@ -3587,13 +3588,13 @@ namespace OpenSim.Region.Framework.Scenes
/// is activated later when the viewer sends the initial UseCircuitCodePacket UDP packet (in the case of /// is activated later when the viewer sends the initial UseCircuitCodePacket UDP packet (in the case of
/// the LLUDP stack). /// the LLUDP stack).
/// </remarks> /// </remarks>
/// <param name="agent">CircuitData of the agent who is connecting</param> /// <param name="acd">CircuitData of the agent who is connecting</param>
/// <param name="reason">Outputs the reason for the false response on this string</param> /// <param name="reason">Outputs the reason for the false response on this string</param>
/// <param name="requirePresenceLookup">True for normal presence. False for NPC /// <param name="requirePresenceLookup">True for normal presence. False for NPC
/// or other applications where a full grid/Hypergrid presence may not be required.</param> /// or other applications where a full grid/Hypergrid presence may not be required.</param>
/// <returns>True if the region accepts this agent. False if it does not. False will /// <returns>True if the region accepts this agent. False if it does not. False will
/// also return a reason.</returns> /// also return a reason.</returns>
public bool NewUserConnection(AgentCircuitData agent, uint teleportFlags, out string reason, bool requirePresenceLookup) public bool NewUserConnection(AgentCircuitData acd, uint teleportFlags, out string reason, bool requirePresenceLookup)
{ {
bool vialogin = ((teleportFlags & (uint)TPFlags.ViaLogin) != 0 || bool vialogin = ((teleportFlags & (uint)TPFlags.ViaLogin) != 0 ||
(teleportFlags & (uint)TPFlags.ViaHGLogin) != 0); (teleportFlags & (uint)TPFlags.ViaHGLogin) != 0);
@ -3613,15 +3614,15 @@ namespace OpenSim.Region.Framework.Scenes
m_log.DebugFormat( m_log.DebugFormat(
"[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags ({8}), position {9})", "[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags ({8}), position {9})",
RegionInfo.RegionName, RegionInfo.RegionName,
(agent.child ? "child" : "root"), (acd.child ? "child" : "root"),
agent.firstname, acd.firstname,
agent.lastname, acd.lastname,
agent.AgentID, acd.AgentID,
agent.circuitcode, acd.circuitcode,
agent.IPAddress, acd.IPAddress,
agent.Viewer, acd.Viewer,
((TPFlags)teleportFlags).ToString(), ((TPFlags)teleportFlags).ToString(),
agent.startpos acd.startpos
); );
if (!LoginsEnabled) if (!LoginsEnabled)
@ -3639,7 +3640,7 @@ namespace OpenSim.Region.Framework.Scenes
{ {
foreach (string viewer in m_AllowedViewers) foreach (string viewer in m_AllowedViewers)
{ {
if (viewer == agent.Viewer.Substring(0, viewer.Length).Trim().ToLower()) if (viewer == acd.Viewer.Substring(0, viewer.Length).Trim().ToLower())
{ {
ViewerDenied = false; ViewerDenied = false;
break; break;
@ -3656,7 +3657,7 @@ namespace OpenSim.Region.Framework.Scenes
{ {
foreach (string viewer in m_BannedViewers) foreach (string viewer in m_BannedViewers)
{ {
if (viewer == agent.Viewer.Substring(0, viewer.Length).Trim().ToLower()) if (viewer == acd.Viewer.Substring(0, viewer.Length).Trim().ToLower())
{ {
ViewerDenied = true; ViewerDenied = true;
break; break;
@ -3668,20 +3669,78 @@ namespace OpenSim.Region.Framework.Scenes
{ {
m_log.DebugFormat( m_log.DebugFormat(
"[SCENE]: Access denied for {0} {1} using {2}", "[SCENE]: Access denied for {0} {1} using {2}",
agent.firstname, agent.lastname, agent.Viewer); acd.firstname, acd.lastname, acd.Viewer);
reason = "Access denied, your viewer is banned by the region owner"; reason = "Access denied, your viewer is banned by the region owner";
return false; return false;
} }
ILandObject land; ILandObject land;
ScenePresence sp;
lock (agent) lock (m_removeClientLock)
{ {
ScenePresence sp = GetScenePresence(agent.AgentID); sp = GetScenePresence(acd.AgentID);
// We need to ensure that we are not already removing the scene presence before we ask it not to be
// closed.
if (sp != null && sp.IsChildAgent && sp.LifecycleState == ScenePresenceState.Running)
{
m_log.DebugFormat(
"[SCENE]: Reusing existing child scene presence for {0} in {1}", sp.Name, Name);
// In the case where, for example, an A B C D region layout, an avatar may
// teleport from A -> D, but then -> C before A has asked B to close its old child agent. When C
// renews the lease on the child agent at B, we must make sure that the close from A does not succeed.
if (!acd.ChildrenCapSeeds.ContainsKey(RegionInfo.RegionHandle))
{
m_log.DebugFormat(
"[SCENE]: Setting DoNotCloseAfterTeleport for child scene presence {0} in {1} because source will attempt close.",
sp.Name, Name);
sp.DoNotCloseAfterTeleport = true;
}
else if (EntityTransferModule.IsInTransit(sp.UUID))
{
m_log.DebugFormat(
"[SCENE]: Setting DoNotCloseAfterTeleport for child scene presence {0} in {1} because this region will attempt previous end-of-teleport close.",
sp.Name, Name);
sp.DoNotCloseAfterTeleport = true;
}
}
}
// Need to poll here in case we are currently deleting an sp. Letting threads run over each other will
// allow unpredictable things to happen.
if (sp != null) if (sp != null)
{ {
if (!sp.IsChildAgent) const int polls = 10;
const int pollInterval = 1000;
int pollsLeft = polls;
while (sp.LifecycleState == ScenePresenceState.Removing && pollsLeft-- > 0)
Thread.Sleep(pollInterval);
if (sp.LifecycleState == ScenePresenceState.Removing)
{
m_log.WarnFormat(
"[SCENE]: Agent {0} in {1} was still being removed after {2}s. Aborting NewUserConnection.",
sp.Name, Name, polls * pollInterval / 1000);
return false;
}
else if (polls != pollsLeft)
{
m_log.DebugFormat(
"[SCENE]: NewUserConnection for agent {0} in {1} had to wait {2}s for in-progress removal to complete on an old presence.",
sp.Name, Name, polls * pollInterval / 1000);
}
}
// TODO: can we remove this lock?
lock (acd)
{
if (sp != null && !sp.IsChildAgent)
{ {
// We have a root agent. Is it in transit? // We have a root agent. Is it in transit?
if (!EntityTransferModule.IsInTransit(sp.UUID)) if (!EntityTransferModule.IsInTransit(sp.UUID))
@ -3694,35 +3753,28 @@ namespace OpenSim.Region.Framework.Scenes
sp.Name, sp.UUID, RegionInfo.RegionName); sp.Name, sp.UUID, RegionInfo.RegionName);
if (sp.ControllingClient != null) if (sp.ControllingClient != null)
sp.ControllingClient.Close(true); IncomingCloseAgent(sp.UUID, true);
sp = null; sp = null;
} }
//else //else
// m_log.WarnFormat("[SCENE]: Existing root scene presence for {0} {1} in {2}, but agent is in trasit", sp.Name, sp.UUID, RegionInfo.RegionName); // m_log.WarnFormat("[SCENE]: Existing root scene presence for {0} {1} in {2}, but agent is in trasit", sp.Name, sp.UUID, RegionInfo.RegionName);
} }
else
{
// We have a child agent here
sp.DoNotCloseAfterTeleport = true;
//m_log.WarnFormat("[SCENE]: Existing child scene presence for {0} {1} in {2}", sp.Name, sp.UUID, RegionInfo.RegionName);
}
}
// Optimistic: add or update the circuit data with the new agent circuit data and teleport flags. // Optimistic: add or update the circuit data with the new agent circuit data and teleport flags.
// We need the circuit data here for some of the subsequent checks. (groups, for example) // We need the circuit data here for some of the subsequent checks. (groups, for example)
// If the checks fail, we remove the circuit. // If the checks fail, we remove the circuit.
agent.teleportFlags = teleportFlags; acd.teleportFlags = teleportFlags;
m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent); m_authenticateHandler.AddNewCircuit(acd.circuitcode, acd);
land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y); land = LandChannel.GetLandObject(acd.startpos.X, acd.startpos.Y);
// On login test land permisions // On login test land permisions
if (vialogin) if (vialogin)
{ {
if (land != null && !TestLandRestrictions(agent.AgentID, out reason, ref agent.startpos.X, ref agent.startpos.Y)) if (land != null && !TestLandRestrictions(acd.AgentID, out reason, ref acd.startpos.X, ref acd.startpos.Y))
{ {
m_authenticateHandler.RemoveCircuit(agent.circuitcode); m_authenticateHandler.RemoveCircuit(acd.circuitcode);
return false; return false;
} }
} }
@ -3733,9 +3785,9 @@ namespace OpenSim.Region.Framework.Scenes
{ {
try try
{ {
if (!VerifyUserPresence(agent, out reason)) if (!VerifyUserPresence(acd, out reason))
{ {
m_authenticateHandler.RemoveCircuit(agent.circuitcode); m_authenticateHandler.RemoveCircuit(acd.circuitcode);
return false; return false;
} }
} }
@ -3744,16 +3796,16 @@ namespace OpenSim.Region.Framework.Scenes
m_log.ErrorFormat( m_log.ErrorFormat(
"[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace); "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace);
m_authenticateHandler.RemoveCircuit(agent.circuitcode); m_authenticateHandler.RemoveCircuit(acd.circuitcode);
return false; return false;
} }
} }
try try
{ {
if (!AuthorizeUser(agent, SeeIntoRegion, out reason)) if (!AuthorizeUser(acd, SeeIntoRegion, out reason))
{ {
m_authenticateHandler.RemoveCircuit(agent.circuitcode); m_authenticateHandler.RemoveCircuit(acd.circuitcode);
return false; return false;
} }
} }
@ -3762,19 +3814,19 @@ namespace OpenSim.Region.Framework.Scenes
m_log.ErrorFormat( m_log.ErrorFormat(
"[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace); "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace);
m_authenticateHandler.RemoveCircuit(agent.circuitcode); m_authenticateHandler.RemoveCircuit(acd.circuitcode);
return false; return false;
} }
m_log.InfoFormat( m_log.InfoFormat(
"[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})", "[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})",
RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname, Name, (acd.child ? "child" : "root"), acd.firstname, acd.lastname,
agent.AgentID, agent.circuitcode); acd.AgentID, acd.circuitcode);
if (CapsModule != null) if (CapsModule != null)
{ {
CapsModule.SetAgentCapsSeeds(agent); CapsModule.SetAgentCapsSeeds(acd);
CapsModule.CreateCaps(agent.AgentID); CapsModule.CreateCaps(acd.AgentID);
} }
} }
else else
@ -3787,14 +3839,14 @@ namespace OpenSim.Region.Framework.Scenes
{ {
m_log.DebugFormat( m_log.DebugFormat(
"[SCENE]: Adjusting known seeds for existing agent {0} in {1}", "[SCENE]: Adjusting known seeds for existing agent {0} in {1}",
agent.AgentID, RegionInfo.RegionName); acd.AgentID, RegionInfo.RegionName);
sp.AdjustKnownSeeds(); sp.AdjustKnownSeeds();
if (CapsModule != null) if (CapsModule != null)
{ {
CapsModule.SetAgentCapsSeeds(agent); CapsModule.SetAgentCapsSeeds(acd);
CapsModule.CreateCaps(agent.AgentID); CapsModule.CreateCaps(acd.AgentID);
} }
} }
} }
@ -3802,23 +3854,23 @@ namespace OpenSim.Region.Framework.Scenes
// Try caching an incoming user name much earlier on to see if this helps with an issue // Try caching an incoming user name much earlier on to see if this helps with an issue
// where HG users are occasionally seen by others as "Unknown User" because their UUIDName // where HG users are occasionally seen by others as "Unknown User" because their UUIDName
// request for the HG avatar appears to trigger before the user name is cached. // request for the HG avatar appears to trigger before the user name is cached.
CacheUserName(null, agent); CacheUserName(null, acd);
} }
if (vialogin) if (vialogin)
{ {
// CleanDroppedAttachments(); // CleanDroppedAttachments();
if (TestBorderCross(agent.startpos, Cardinals.E)) if (TestBorderCross(acd.startpos, Cardinals.E))
{ {
Border crossedBorder = GetCrossedBorder(agent.startpos, Cardinals.E); Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.E);
agent.startpos.X = crossedBorder.BorderLine.Z - 1; acd.startpos.X = crossedBorder.BorderLine.Z - 1;
} }
if (TestBorderCross(agent.startpos, Cardinals.N)) if (TestBorderCross(acd.startpos, Cardinals.N))
{ {
Border crossedBorder = GetCrossedBorder(agent.startpos, Cardinals.N); Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.N);
agent.startpos.Y = crossedBorder.BorderLine.Z - 1; acd.startpos.Y = crossedBorder.BorderLine.Z - 1;
} }
//Mitigate http://opensimulator.org/mantis/view.php?id=3522 //Mitigate http://opensimulator.org/mantis/view.php?id=3522
@ -3828,39 +3880,39 @@ namespace OpenSim.Region.Framework.Scenes
{ {
lock (EastBorders) lock (EastBorders)
{ {
if (agent.startpos.X > EastBorders[0].BorderLine.Z) if (acd.startpos.X > EastBorders[0].BorderLine.Z)
{ {
m_log.Warn("FIX AGENT POSITION"); m_log.Warn("FIX AGENT POSITION");
agent.startpos.X = EastBorders[0].BorderLine.Z * 0.5f; acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
if (agent.startpos.Z > 720) if (acd.startpos.Z > 720)
agent.startpos.Z = 720; acd.startpos.Z = 720;
} }
} }
lock (NorthBorders) lock (NorthBorders)
{ {
if (agent.startpos.Y > NorthBorders[0].BorderLine.Z) if (acd.startpos.Y > NorthBorders[0].BorderLine.Z)
{ {
m_log.Warn("FIX Agent POSITION"); m_log.Warn("FIX Agent POSITION");
agent.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f; acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
if (agent.startpos.Z > 720) if (acd.startpos.Z > 720)
agent.startpos.Z = 720; acd.startpos.Z = 720;
} }
} }
} else } else
{ {
if (agent.startpos.X > EastBorders[0].BorderLine.Z) if (acd.startpos.X > EastBorders[0].BorderLine.Z)
{ {
m_log.Warn("FIX AGENT POSITION"); m_log.Warn("FIX AGENT POSITION");
agent.startpos.X = EastBorders[0].BorderLine.Z * 0.5f; acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
if (agent.startpos.Z > 720) if (acd.startpos.Z > 720)
agent.startpos.Z = 720; acd.startpos.Z = 720;
} }
if (agent.startpos.Y > NorthBorders[0].BorderLine.Z) if (acd.startpos.Y > NorthBorders[0].BorderLine.Z)
{ {
m_log.Warn("FIX Agent POSITION"); m_log.Warn("FIX Agent POSITION");
agent.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f; acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
if (agent.startpos.Z > 720) if (acd.startpos.Z > 720)
agent.startpos.Z = 720; acd.startpos.Z = 720;
} }
} }
@ -3876,12 +3928,12 @@ namespace OpenSim.Region.Framework.Scenes
{ {
// We have multiple SpawnPoints, Route the agent to a random or sequential one // We have multiple SpawnPoints, Route the agent to a random or sequential one
if (SpawnPointRouting == "random") if (SpawnPointRouting == "random")
agent.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation( acd.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation(
telehub.AbsolutePosition, telehub.AbsolutePosition,
telehub.GroupRotation telehub.GroupRotation
); );
else else
agent.startpos = spawnpoints[SpawnPoint()].GetLocation( acd.startpos = spawnpoints[SpawnPoint()].GetLocation(
telehub.AbsolutePosition, telehub.AbsolutePosition,
telehub.GroupRotation telehub.GroupRotation
); );
@ -3889,7 +3941,7 @@ namespace OpenSim.Region.Framework.Scenes
else else
{ {
// We have a single SpawnPoint and will route the agent to it // We have a single SpawnPoint and will route the agent to it
agent.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); acd.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation);
} }
return true; return true;
@ -3900,7 +3952,7 @@ namespace OpenSim.Region.Framework.Scenes
{ {
if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero) if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero)
{ {
agent.startpos = land.LandData.UserLocation; acd.startpos = land.LandData.UserLocation;
} }
} }
} }
@ -4360,11 +4412,51 @@ namespace OpenSim.Region.Framework.Scenes
/// </param> /// </param>
public bool IncomingCloseAgent(UUID agentID, bool force) public bool IncomingCloseAgent(UUID agentID, bool force)
{ {
//m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID); ScenePresence sp;
ScenePresence presence = m_sceneGraph.GetScenePresence(agentID);
if (presence != null) lock (m_removeClientLock)
{ {
presence.ControllingClient.Close(force); sp = GetScenePresence(agentID);
if (sp == null)
{
m_log.DebugFormat(
"[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in {1}",
agentID, Name);
return false;
}
if (sp.LifecycleState != ScenePresenceState.Running)
{
m_log.DebugFormat(
"[SCENE]: Called RemoveClient() for {0} in {1} but presence is already in state {2}",
sp.Name, Name, sp.LifecycleState);
return false;
}
// We need to avoid a race condition where in, for example, an A B C D region layout, an avatar may
// teleport from A -> D, but then -> C before A has asked B to close its old child agent. We do not
// want to obey this close since C may have renewed the child agent lease on B.
if (sp.DoNotCloseAfterTeleport)
{
m_log.DebugFormat(
"[SCENE]: Not closing {0} agent {1} in {2} since another simulator has re-established the child connection",
sp.IsChildAgent ? "child" : "root", sp.Name, Name);
// Need to reset the flag so that a subsequent close after another teleport can succeed.
sp.DoNotCloseAfterTeleport = false;
return false;
}
sp.LifecycleState = ScenePresenceState.Removing;
}
if (sp != null)
{
sp.ControllingClient.Close(force);
return true; return true;
} }

View File

@ -74,6 +74,8 @@ namespace OpenSim.Region.Framework.Scenes
public class ScenePresence : EntityBase, IScenePresence public class ScenePresence : EntityBase, IScenePresence
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
// ~ScenePresence() // ~ScenePresence()
// { // {
// m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name); // m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name);
@ -85,10 +87,27 @@ namespace OpenSim.Region.Framework.Scenes
m_scene.EventManager.TriggerScenePresenceUpdated(this); m_scene.EventManager.TriggerScenePresenceUpdated(this);
} }
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public PresenceType PresenceType { get; private set; } public PresenceType PresenceType { get; private set; }
private ScenePresenceStateMachine m_stateMachine;
/// <summary>
/// The current state of this presence. Governs only the existence lifecycle. See ScenePresenceStateMachine
/// for more details.
/// </summary>
public ScenePresenceState LifecycleState
{
get
{
return m_stateMachine.GetState();
}
set
{
m_stateMachine.SetState(value);
}
}
// private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes(); // private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes();
private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags)); private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags));
private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f); private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f);
@ -811,6 +830,8 @@ namespace OpenSim.Region.Framework.Scenes
SetDirectionVectors(); SetDirectionVectors();
Appearance = appearance; Appearance = appearance;
m_stateMachine = new ScenePresenceStateMachine(this);
} }
public void RegisterToEvents() public void RegisterToEvents()
@ -879,7 +900,7 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary> /// </summary>
public void MakeRootAgent(Vector3 pos, bool isFlying) public void MakeRootAgent(Vector3 pos, bool isFlying)
{ {
m_log.DebugFormat( m_log.InfoFormat(
"[SCENE]: Upgrading child to root agent for {0} in {1}", "[SCENE]: Upgrading child to root agent for {0} in {1}",
Name, m_scene.RegionInfo.RegionName); Name, m_scene.RegionInfo.RegionName);
@ -887,6 +908,11 @@ namespace OpenSim.Region.Framework.Scenes
IsChildAgent = false; IsChildAgent = false;
// Must reset this here so that a teleport to a region next to an existing region does not keep the flag
// set and prevent the close of the connection on a subsequent re-teleport.
// Should not be needed if we are not trying to tell this region to close
// DoNotCloseAfterTeleport = false;
IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>(); IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>();
if (gm != null) if (gm != null)
Grouptitle = gm.GetGroupTitle(m_uuid); Grouptitle = gm.GetGroupTitle(m_uuid);
@ -3738,6 +3764,8 @@ namespace OpenSim.Region.Framework.Scenes
// m_reprioritizationTimer.Dispose(); // m_reprioritizationTimer.Dispose();
RemoveFromPhysicalScene(); RemoveFromPhysicalScene();
LifecycleState = ScenePresenceState.Removed;
} }
public void AddAttachment(SceneObjectGroup gobj) public void AddAttachment(SceneObjectGroup gobj)