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()
{
TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure();
// TestHelpers.EnableLogging();
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
// there is some unidentified connection problem, not where we have issues due to deadlock
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;
}
IsActive = false;
CloseWithoutChecks();

View File

@ -1799,9 +1799,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (!client.SceneAgent.IsChildAgent)
client.Kick("Simulator logged you out due to connection timeout.");
client.CloseWithoutChecks();
}
m_scene.IncomingCloseAgent(client.AgentId, true);
}
private void IncomingPacketHandler()
@ -2142,7 +2142,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (!client.IsLoggingOut)
{
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()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
TestHelpers.EnableLogging();
IniConfigSource ics = new IniConfigSource();
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
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))
{
sp.DoNotCloseAfterTeleport = false;
@ -1081,14 +1091,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
if (!sp.DoNotCloseAfterTeleport)
{
// 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);
sp.CloseChildAgents(newRegionX, newRegionY);
m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Closing agent {0} in {1}", sp.Name, Scene.Name);
sp.Scene.IncomingCloseAgent(sp.UUID, false);
}
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;
}
}
@ -1863,10 +1871,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
List<ulong> newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles);
List<ulong> oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles);
//Dump("Current Neighbors", neighbourHandles);
//Dump("Previous Neighbours", previousRegionNeighbourHandles);
//Dump("New Neighbours", newRegions);
//Dump("Old Neighbours", oldRegions);
// Dump("Current Neighbors", neighbourHandles);
// Dump("Previous Neighbours", previousRegionNeighbourHandles);
// Dump("New Neighbours", newRegions);
// Dump("Old Neighbours", oldRegions);
/// Update the scene presence's known regions here on this region
sp.DropOldNeighbours(oldRegions);
@ -1874,8 +1882,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
/// Collect as many seeds as possible
Dictionary<ulong, string> seeds;
if (sp.Scene.CapsModule != null)
seeds
= new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID));
seeds = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID));
else
seeds = new Dictionary<ulong, string>();
@ -1945,6 +1952,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
newAgent = true;
else
newAgent = false;
// continue;
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))
{
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))
{
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))
{
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;
/// <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>
private object m_removeClientLock = new object();
@ -1312,7 +1312,7 @@ namespace OpenSim.Region.Framework.Scenes
Thread.Sleep(500);
// 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");
EventManager.TriggerSceneShuttingDown(this);
@ -2972,7 +2972,7 @@ namespace OpenSim.Region.Framework.Scenes
{
PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
sp.ControllingClient.Close();
IncomingCloseAgent(sp.UUID, false);
}
else
{
@ -3384,47 +3384,48 @@ namespace OpenSim.Region.Framework.Scenes
public override void RemoveClient(UUID agentID, bool closeChildAgents)
{
// CheckHeartbeat();
bool isChildAgent = false;
AgentCircuitData acd;
AgentCircuitData acd = m_authenticateHandler.GetAgentCircuitData(agentID);
lock (m_removeClientLock)
// 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)
{
acd = m_authenticateHandler.GetAgentCircuitData(agentID);
m_log.ErrorFormat(
"[SCENE]: No agent circuit found for {0} in {1}, aborting Scene.RemoveClient", agentID, Name);
if (acd == null)
{
m_log.ErrorFormat("[SCENE]: No agent circuit found for {0}, aborting Scene.RemoveClient", agentID);
return;
}
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);
}
return;
}
else
{
m_authenticateHandler.RemoveCircuit(agentID);
}
// TODO: Can we now remove this lock?
lock (acd)
{
{
bool isChildAgent = false;
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)
{
m_log.WarnFormat(
m_log.ErrorFormat(
"[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID);
return;
}
try
{
isChildAgent = avatar.IsChildAgent;
m_log.DebugFormat(
"[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
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
/// the LLUDP stack).
/// </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="requirePresenceLookup">True for normal presence. False for NPC
/// 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
/// 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 ||
(teleportFlags & (uint)TPFlags.ViaHGLogin) != 0);
@ -3613,15 +3614,15 @@ namespace OpenSim.Region.Framework.Scenes
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})",
RegionInfo.RegionName,
(agent.child ? "child" : "root"),
agent.firstname,
agent.lastname,
agent.AgentID,
agent.circuitcode,
agent.IPAddress,
agent.Viewer,
(acd.child ? "child" : "root"),
acd.firstname,
acd.lastname,
acd.AgentID,
acd.circuitcode,
acd.IPAddress,
acd.Viewer,
((TPFlags)teleportFlags).ToString(),
agent.startpos
acd.startpos
);
if (!LoginsEnabled)
@ -3639,7 +3640,7 @@ namespace OpenSim.Region.Framework.Scenes
{
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;
break;
@ -3656,7 +3657,7 @@ namespace OpenSim.Region.Framework.Scenes
{
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;
break;
@ -3668,61 +3669,112 @@ namespace OpenSim.Region.Framework.Scenes
{
m_log.DebugFormat(
"[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";
return false;
}
ILandObject land;
ScenePresence sp;
lock (agent)
lock (m_removeClientLock)
{
ScenePresence sp = GetScenePresence(agent.AgentID);
if (sp != null)
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)
{
if (!sp.IsChildAgent)
{
// We have a root agent. Is it in transit?
if (!EntityTransferModule.IsInTransit(sp.UUID))
{
// We have a zombie from a crashed session.
// Or the same user is trying to be root twice here, won't work.
// Kill it.
m_log.WarnFormat(
"[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.",
sp.Name, sp.UUID, RegionInfo.RegionName);
m_log.DebugFormat(
"[SCENE]: Reusing existing child scene presence for {0} in {1}", sp.Name, Name);
if (sp.ControllingClient != null)
sp.ControllingClient.Close(true);
sp = null;
}
//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);
}
else
// 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))
{
// We have a child agent here
m_log.DebugFormat(
"[SCENE]: Setting DoNotCloseAfterTeleport for child scene presence {0} in {1} because source will attempt close.",
sp.Name, Name);
sp.DoNotCloseAfterTeleport = true;
//m_log.WarnFormat("[SCENE]: Existing child scene presence for {0} {1} in {2}", sp.Name, sp.UUID, RegionInfo.RegionName);
}
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)
{
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?
if (!EntityTransferModule.IsInTransit(sp.UUID))
{
// We have a zombie from a crashed session.
// Or the same user is trying to be root twice here, won't work.
// Kill it.
m_log.WarnFormat(
"[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.",
sp.Name, sp.UUID, RegionInfo.RegionName);
if (sp.ControllingClient != null)
IncomingCloseAgent(sp.UUID, true);
sp = null;
}
//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);
}
// 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)
// If the checks fail, we remove the circuit.
agent.teleportFlags = teleportFlags;
m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent);
acd.teleportFlags = teleportFlags;
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
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;
}
}
@ -3733,9 +3785,9 @@ namespace OpenSim.Region.Framework.Scenes
{
try
{
if (!VerifyUserPresence(agent, out reason))
if (!VerifyUserPresence(acd, out reason))
{
m_authenticateHandler.RemoveCircuit(agent.circuitcode);
m_authenticateHandler.RemoveCircuit(acd.circuitcode);
return false;
}
}
@ -3744,16 +3796,16 @@ namespace OpenSim.Region.Framework.Scenes
m_log.ErrorFormat(
"[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace);
m_authenticateHandler.RemoveCircuit(agent.circuitcode);
m_authenticateHandler.RemoveCircuit(acd.circuitcode);
return false;
}
}
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;
}
}
@ -3762,19 +3814,19 @@ namespace OpenSim.Region.Framework.Scenes
m_log.ErrorFormat(
"[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace);
m_authenticateHandler.RemoveCircuit(agent.circuitcode);
m_authenticateHandler.RemoveCircuit(acd.circuitcode);
return false;
}
m_log.InfoFormat(
"[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,
agent.AgentID, agent.circuitcode);
Name, (acd.child ? "child" : "root"), acd.firstname, acd.lastname,
acd.AgentID, acd.circuitcode);
if (CapsModule != null)
{
CapsModule.SetAgentCapsSeeds(agent);
CapsModule.CreateCaps(agent.AgentID);
CapsModule.SetAgentCapsSeeds(acd);
CapsModule.CreateCaps(acd.AgentID);
}
}
else
@ -3787,14 +3839,14 @@ namespace OpenSim.Region.Framework.Scenes
{
m_log.DebugFormat(
"[SCENE]: Adjusting known seeds for existing agent {0} in {1}",
agent.AgentID, RegionInfo.RegionName);
acd.AgentID, RegionInfo.RegionName);
sp.AdjustKnownSeeds();
if (CapsModule != null)
{
CapsModule.SetAgentCapsSeeds(agent);
CapsModule.CreateCaps(agent.AgentID);
CapsModule.SetAgentCapsSeeds(acd);
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
// 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.
CacheUserName(null, agent);
CacheUserName(null, acd);
}
if (vialogin)
{
// CleanDroppedAttachments();
if (TestBorderCross(agent.startpos, Cardinals.E))
if (TestBorderCross(acd.startpos, Cardinals.E))
{
Border crossedBorder = GetCrossedBorder(agent.startpos, Cardinals.E);
agent.startpos.X = crossedBorder.BorderLine.Z - 1;
Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.E);
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);
agent.startpos.Y = crossedBorder.BorderLine.Z - 1;
Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.N);
acd.startpos.Y = crossedBorder.BorderLine.Z - 1;
}
//Mitigate http://opensimulator.org/mantis/view.php?id=3522
@ -3828,39 +3880,39 @@ namespace OpenSim.Region.Framework.Scenes
{
lock (EastBorders)
{
if (agent.startpos.X > EastBorders[0].BorderLine.Z)
if (acd.startpos.X > EastBorders[0].BorderLine.Z)
{
m_log.Warn("FIX AGENT POSITION");
agent.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
if (agent.startpos.Z > 720)
agent.startpos.Z = 720;
acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
if (acd.startpos.Z > 720)
acd.startpos.Z = 720;
}
}
lock (NorthBorders)
{
if (agent.startpos.Y > NorthBorders[0].BorderLine.Z)
if (acd.startpos.Y > NorthBorders[0].BorderLine.Z)
{
m_log.Warn("FIX Agent POSITION");
agent.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
if (agent.startpos.Z > 720)
agent.startpos.Z = 720;
acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
if (acd.startpos.Z > 720)
acd.startpos.Z = 720;
}
}
} else
{
if (agent.startpos.X > EastBorders[0].BorderLine.Z)
if (acd.startpos.X > EastBorders[0].BorderLine.Z)
{
m_log.Warn("FIX AGENT POSITION");
agent.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
if (agent.startpos.Z > 720)
agent.startpos.Z = 720;
acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
if (acd.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");
agent.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
if (agent.startpos.Z > 720)
agent.startpos.Z = 720;
acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
if (acd.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
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.GroupRotation
);
else
agent.startpos = spawnpoints[SpawnPoint()].GetLocation(
acd.startpos = spawnpoints[SpawnPoint()].GetLocation(
telehub.AbsolutePosition,
telehub.GroupRotation
);
@ -3889,7 +3941,7 @@ namespace OpenSim.Region.Framework.Scenes
else
{
// 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;
@ -3900,7 +3952,7 @@ namespace OpenSim.Region.Framework.Scenes
{
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>
public bool IncomingCloseAgent(UUID agentID, bool force)
{
//m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID);
ScenePresence presence = m_sceneGraph.GetScenePresence(agentID);
if (presence != null)
ScenePresence sp;
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;
}

View File

@ -74,6 +74,8 @@ namespace OpenSim.Region.Framework.Scenes
public class ScenePresence : EntityBase, IScenePresence
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
// ~ScenePresence()
// {
// m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name);
@ -85,10 +87,27 @@ namespace OpenSim.Region.Framework.Scenes
m_scene.EventManager.TriggerScenePresenceUpdated(this);
}
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
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 Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags));
private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f);
@ -766,7 +785,7 @@ namespace OpenSim.Region.Framework.Scenes
public ScenePresence(
IClientAPI client, Scene world, AvatarAppearance appearance, PresenceType type)
{
{
AttachmentsSyncLock = new Object();
AllowMovement = true;
IsChildAgent = true;
@ -811,6 +830,8 @@ namespace OpenSim.Region.Framework.Scenes
SetDirectionVectors();
Appearance = appearance;
m_stateMachine = new ScenePresenceStateMachine(this);
}
public void RegisterToEvents()
@ -879,7 +900,7 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary>
public void MakeRootAgent(Vector3 pos, bool isFlying)
{
m_log.DebugFormat(
m_log.InfoFormat(
"[SCENE]: Upgrading child to root agent for {0} in {1}",
Name, m_scene.RegionInfo.RegionName);
@ -887,6 +908,11 @@ namespace OpenSim.Region.Framework.Scenes
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>();
if (gm != null)
Grouptitle = gm.GetGroupTitle(m_uuid);
@ -3738,6 +3764,8 @@ namespace OpenSim.Region.Framework.Scenes
// m_reprioritizationTimer.Dispose();
RemoveFromPhysicalScene();
LifecycleState = ScenePresenceState.Removed;
}
public void AddAttachment(SceneObjectGroup gobj)