refactor: factor out entity transfer state machine into a separate class to make code more analyzable
parent
8f87f55d05
commit
79f3ce2e9f
|
@ -46,35 +46,12 @@ using Nini.Config;
|
||||||
|
|
||||||
namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// The possible states that an agent can be in when its being transferred between regions.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This is a state machine.
|
|
||||||
///
|
|
||||||
/// [Entry] => Preparing
|
|
||||||
/// Preparing => { Transferring || CleaningUp || [Exit] }
|
|
||||||
/// Transferring => { ReceivedAtDestination || CleaningUp }
|
|
||||||
/// ReceivedAtDestination => CleaningUp
|
|
||||||
/// CleaningUp => [Exit]
|
|
||||||
///
|
|
||||||
/// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp
|
|
||||||
/// However, any state can transition to CleaningUp if the teleport has failed.
|
|
||||||
/// </remarks>
|
|
||||||
enum AgentTransferState
|
|
||||||
{
|
|
||||||
Preparing, // The agent is being prepared for transfer
|
|
||||||
Transferring, // The agent is in the process of being transferred to a destination
|
|
||||||
ReceivedAtDestination, // The destination has notified us that the agent has been successfully received
|
|
||||||
CleaningUp // The agent is being changed to child/removed after a transfer
|
|
||||||
}
|
|
||||||
|
|
||||||
public class EntityTransferModule : INonSharedRegionModule, IEntityTransferModule
|
public class EntityTransferModule : INonSharedRegionModule, IEntityTransferModule
|
||||||
{
|
{
|
||||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
public const int DefaultMaxTransferDistance = 4095;
|
public const int DefaultMaxTransferDistance = 4095;
|
||||||
public const bool EnableWaitForCallbackFromTeleportDestDefault = true;
|
public const bool WaitForAgentArrivedAtDestinationDefault = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The maximum distance, in standard region units (256m) that an agent is allowed to transfer.
|
/// The maximum distance, in standard region units (256m) that an agent is allowed to transfer.
|
||||||
|
@ -85,13 +62,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
/// If true then on a teleport, the source region waits for a callback from the destination region. If
|
/// If true then on a teleport, the source region waits for a callback from the destination region. If
|
||||||
/// a callback fails to arrive within a set time then the user is pulled back into the source region.
|
/// a callback fails to arrive within a set time then the user is pulled back into the source region.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool EnableWaitForCallbackFromTeleportDest { get; set; }
|
public bool WaitForAgentArrivedAtDestination { get; set; }
|
||||||
|
|
||||||
protected bool m_Enabled = false;
|
protected bool m_Enabled = false;
|
||||||
|
|
||||||
protected Scene m_scene;
|
public Scene Scene { get; private set; }
|
||||||
|
|
||||||
private Dictionary<UUID, AgentTransferState> m_agentsInTransit;
|
/// <summary>
|
||||||
|
/// Handles recording and manipulation of state for entities that are in transfer within or between regions
|
||||||
|
/// (cross or teleport).
|
||||||
|
/// </summary>
|
||||||
|
private EntityTransferStateMachine m_entityTransferStateMachine;
|
||||||
|
|
||||||
private ExpiringCache<UUID, ExpiringCache<ulong, DateTime>> m_bannedRegions =
|
private ExpiringCache<UUID, ExpiringCache<ulong, DateTime>> m_bannedRegions =
|
||||||
new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>();
|
new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>();
|
||||||
|
@ -133,8 +114,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
IConfig transferConfig = source.Configs["EntityTransfer"];
|
IConfig transferConfig = source.Configs["EntityTransfer"];
|
||||||
if (transferConfig != null)
|
if (transferConfig != null)
|
||||||
{
|
{
|
||||||
EnableWaitForCallbackFromTeleportDest
|
WaitForAgentArrivedAtDestination
|
||||||
= transferConfig.GetBoolean("wait_for_callback", EnableWaitForCallbackFromTeleportDestDefault);
|
= transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault);
|
||||||
|
|
||||||
MaxTransferDistance = transferConfig.GetInt("max_distance", DefaultMaxTransferDistance);
|
MaxTransferDistance = transferConfig.GetInt("max_distance", DefaultMaxTransferDistance);
|
||||||
}
|
}
|
||||||
|
@ -143,7 +124,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
MaxTransferDistance = DefaultMaxTransferDistance;
|
MaxTransferDistance = DefaultMaxTransferDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_agentsInTransit = new Dictionary<UUID, AgentTransferState>();
|
m_entityTransferStateMachine = new EntityTransferStateMachine(this);
|
||||||
|
|
||||||
m_Enabled = true;
|
m_Enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +138,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
if (!m_Enabled)
|
if (!m_Enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_scene = scene;
|
Scene = scene;
|
||||||
|
|
||||||
scene.RegisterModuleInterface<IEntityTransferModule>(this);
|
scene.RegisterModuleInterface<IEntityTransferModule>(this);
|
||||||
scene.EventManager.OnNewClient += OnNewClient;
|
scene.EventManager.OnNewClient += OnNewClient;
|
||||||
|
@ -177,7 +159,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
if (!m_Enabled)
|
if (!m_Enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_eqModule = m_scene.RequestModuleInterface<IEventQueue>();
|
m_eqModule = Scene.RequestModuleInterface<IEventQueue>();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -226,7 +208,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
e.Message, e.StackTrace);
|
e.Message, e.StackTrace);
|
||||||
|
|
||||||
// Make sure that we clear the in-transit flag so that future teleport attempts don't always fail.
|
// Make sure that we clear the in-transit flag so that future teleport attempts don't always fail.
|
||||||
ResetFromTransit(sp.UUID);
|
m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
|
||||||
|
|
||||||
sp.ControllingClient.SendTeleportFailed("Internal error");
|
sp.ControllingClient.SendTeleportFailed("Internal error");
|
||||||
}
|
}
|
||||||
|
@ -245,7 +227,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
"[ENTITY TRANSFER MODULE]: Teleport for {0} to {1} within {2}",
|
"[ENTITY TRANSFER MODULE]: Teleport for {0} to {1} within {2}",
|
||||||
sp.Name, position, sp.Scene.RegionInfo.RegionName);
|
sp.Name, position, sp.Scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
if (!SetInTransit(sp.UUID))
|
if (!m_entityTransferStateMachine.SetInTransit(sp.UUID))
|
||||||
{
|
{
|
||||||
m_log.DebugFormat(
|
m_log.DebugFormat(
|
||||||
"[ENTITY TRANSFER MODULE]: Ignoring within region teleport request of {0} {1} to {2} - agent is already in transit.",
|
"[ENTITY TRANSFER MODULE]: Ignoring within region teleport request of {0} {1} to {2} - agent is already in transit.",
|
||||||
|
@ -282,7 +264,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
position.Z = newPosZ;
|
position.Z = newPosZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
|
m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
|
||||||
|
|
||||||
sp.ControllingClient.SendTeleportStart(teleportFlags);
|
sp.ControllingClient.SendTeleportStart(teleportFlags);
|
||||||
|
|
||||||
|
@ -290,15 +272,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
sp.Velocity = Vector3.Zero;
|
sp.Velocity = Vector3.Zero;
|
||||||
sp.Teleport(position);
|
sp.Teleport(position);
|
||||||
|
|
||||||
UpdateInTransit(sp.UUID, AgentTransferState.ReceivedAtDestination);
|
m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.ReceivedAtDestination);
|
||||||
|
|
||||||
foreach (SceneObjectGroup grp in sp.GetAttachments())
|
foreach (SceneObjectGroup grp in sp.GetAttachments())
|
||||||
{
|
{
|
||||||
sp.Scene.EventManager.TriggerOnScriptChangedEvent(grp.LocalId, (uint)Changed.TELEPORT);
|
sp.Scene.EventManager.TriggerOnScriptChangedEvent(grp.LocalId, (uint)Changed.TELEPORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
|
m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
|
||||||
ResetFromTransit(sp.UUID);
|
m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -316,7 +298,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
{
|
{
|
||||||
uint x = 0, y = 0;
|
uint x = 0, y = 0;
|
||||||
Utils.LongToUInts(regionHandle, out x, out y);
|
Utils.LongToUInts(regionHandle, out x, out y);
|
||||||
GridRegion reg = m_scene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y);
|
GridRegion reg = Scene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y);
|
||||||
|
|
||||||
if (reg != null)
|
if (reg != null)
|
||||||
{
|
{
|
||||||
|
@ -398,7 +380,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
{
|
{
|
||||||
// Record that this agent is in transit so that we can prevent simultaneous requests and do later detection
|
// Record that this agent is in transit so that we can prevent simultaneous requests and do later detection
|
||||||
// of whether the destination region completes the teleport.
|
// of whether the destination region completes the teleport.
|
||||||
if (!SetInTransit(sp.UUID))
|
if (!m_entityTransferStateMachine.SetInTransit(sp.UUID))
|
||||||
{
|
{
|
||||||
m_log.DebugFormat(
|
m_log.DebugFormat(
|
||||||
"[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2} ({3}) {4}/{5} - agent is already in transit.",
|
"[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2} ({3}) {4}/{5} - agent is already in transit.",
|
||||||
|
@ -410,7 +392,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
if (reg == null || finalDestination == null)
|
if (reg == null || finalDestination == null)
|
||||||
{
|
{
|
||||||
sp.ControllingClient.SendTeleportFailed("Unable to locate destination");
|
sp.ControllingClient.SendTeleportFailed("Unable to locate destination");
|
||||||
ResetFromTransit(sp.UUID);
|
m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -431,7 +413,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY,
|
sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY,
|
||||||
MaxTransferDistance));
|
MaxTransferDistance));
|
||||||
|
|
||||||
ResetFromTransit(sp.UUID);
|
m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -451,7 +433,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
if (endPoint.Address == null)
|
if (endPoint.Address == null)
|
||||||
{
|
{
|
||||||
sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down");
|
sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down");
|
||||||
ResetFromTransit(sp.UUID);
|
m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -469,11 +451,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
|
|
||||||
string reason;
|
string reason;
|
||||||
string version;
|
string version;
|
||||||
if (!m_scene.SimulationService.QueryAccess(
|
if (!Scene.SimulationService.QueryAccess(
|
||||||
finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out version, out reason))
|
finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out version, out reason))
|
||||||
{
|
{
|
||||||
sp.ControllingClient.SendTeleportFailed(reason);
|
sp.ControllingClient.SendTeleportFailed(reason);
|
||||||
ResetFromTransit(sp.UUID);
|
m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
|
||||||
|
|
||||||
m_log.DebugFormat(
|
m_log.DebugFormat(
|
||||||
"[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because {3}",
|
"[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because {3}",
|
||||||
|
@ -527,7 +509,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout))
|
if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout))
|
||||||
{
|
{
|
||||||
sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason));
|
sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason));
|
||||||
ResetFromTransit(sp.UUID);
|
m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
|
||||||
|
|
||||||
m_log.DebugFormat(
|
m_log.DebugFormat(
|
||||||
"[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}",
|
"[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}",
|
||||||
|
@ -537,7 +519,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Past this point we have to attempt clean up if the teleport fails, so update transfer state.
|
// Past this point we have to attempt clean up if the teleport fails, so update transfer state.
|
||||||
UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
|
m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
|
||||||
|
|
||||||
// OK, it got this agent. Let's close some child agents
|
// OK, it got this agent. Let's close some child agents
|
||||||
sp.CloseChildAgents(newRegionX, newRegionY);
|
sp.CloseChildAgents(newRegionX, newRegionY);
|
||||||
|
@ -619,7 +601,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
// TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which
|
// TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which
|
||||||
// trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation
|
// trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation
|
||||||
// that the client contacted the destination before we close things here.
|
// that the client contacted the destination before we close things here.
|
||||||
if (EnableWaitForCallbackFromTeleportDest && !WaitForCallback(sp.UUID))
|
if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID))
|
||||||
{
|
{
|
||||||
m_log.WarnFormat(
|
m_log.WarnFormat(
|
||||||
"[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.",
|
"[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.",
|
||||||
|
@ -629,7 +611,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
|
m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
|
||||||
|
|
||||||
// For backwards compatibility
|
// For backwards compatibility
|
||||||
if (version == "Unknown" || version == string.Empty)
|
if (version == "Unknown" || version == string.Empty)
|
||||||
|
@ -679,12 +661,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
sp.UUID);
|
sp.UUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResetFromTransit(sp.UUID);
|
m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout)
|
protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout)
|
||||||
{
|
{
|
||||||
UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
|
m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
|
||||||
|
|
||||||
// Client never contacted destination. Let's restore everything back
|
// Client never contacted destination. Let's restore everything back
|
||||||
sp.ControllingClient.SendTeleportFailed("Problems connecting to destination.");
|
sp.ControllingClient.SendTeleportFailed("Problems connecting to destination.");
|
||||||
|
@ -696,17 +678,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
EnableChildAgents(sp);
|
EnableChildAgents(sp);
|
||||||
|
|
||||||
// Finally, kill the agent we just created at the destination.
|
// Finally, kill the agent we just created at the destination.
|
||||||
m_scene.SimulationService.CloseAgent(finalDestination, sp.UUID);
|
Scene.SimulationService.CloseAgent(finalDestination, sp.UUID);
|
||||||
|
|
||||||
sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout);
|
sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout);
|
||||||
|
|
||||||
ResetFromTransit(sp.UUID);
|
m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout)
|
protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout)
|
||||||
{
|
{
|
||||||
logout = false;
|
logout = false;
|
||||||
bool success = m_scene.SimulationService.CreateAgent(finalDestination, agentCircuit, teleportFlags, out reason);
|
bool success = Scene.SimulationService.CreateAgent(finalDestination, agentCircuit, teleportFlags, out reason);
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout);
|
sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout);
|
||||||
|
@ -716,7 +698,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
|
|
||||||
protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent)
|
protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent)
|
||||||
{
|
{
|
||||||
return m_scene.SimulationService.UpdateAgent(finalDestination, agent);
|
return Scene.SimulationService.UpdateAgent(finalDestination, agent);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void SetCallbackURL(AgentData agent, RegionInfo region)
|
protected virtual void SetCallbackURL(AgentData agent, RegionInfo region)
|
||||||
|
@ -779,7 +761,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
/// <param name="position"></param>
|
/// <param name="position"></param>
|
||||||
public virtual void RequestTeleportLandmark(IClientAPI remoteClient, AssetLandmark lm)
|
public virtual void RequestTeleportLandmark(IClientAPI remoteClient, AssetLandmark lm)
|
||||||
{
|
{
|
||||||
GridRegion info = m_scene.GridService.GetRegionByUUID(UUID.Zero, lm.RegionID);
|
GridRegion info = Scene.GridService.GetRegionByUUID(UUID.Zero, lm.RegionID);
|
||||||
|
|
||||||
if (info == null)
|
if (info == null)
|
||||||
{
|
{
|
||||||
|
@ -800,12 +782,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
m_log.DebugFormat(
|
m_log.DebugFormat(
|
||||||
"[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId);
|
"[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId);
|
||||||
|
|
||||||
//OpenSim.Services.Interfaces.PresenceInfo pinfo = m_scene.PresenceService.GetAgent(client.SessionId);
|
//OpenSim.Services.Interfaces.PresenceInfo pinfo = Scene.PresenceService.GetAgent(client.SessionId);
|
||||||
GridUserInfo uinfo = m_scene.GridUserService.GetGridUserInfo(client.AgentId.ToString());
|
GridUserInfo uinfo = Scene.GridUserService.GetGridUserInfo(client.AgentId.ToString());
|
||||||
|
|
||||||
if (uinfo != null)
|
if (uinfo != null)
|
||||||
{
|
{
|
||||||
GridRegion regionInfo = m_scene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID);
|
GridRegion regionInfo = Scene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID);
|
||||||
if (regionInfo == null)
|
if (regionInfo == null)
|
||||||
{
|
{
|
||||||
// can't find the Home region: Tell viewer and abort
|
// can't find the Home region: Tell viewer and abort
|
||||||
|
@ -1114,7 +1096,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SetInTransit(agent.UUID);
|
m_entityTransferStateMachine.SetInTransit(agent.UUID);
|
||||||
|
|
||||||
ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize));
|
ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize));
|
||||||
|
|
||||||
|
@ -1144,16 +1126,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
cAgent.CallbackURI = String.Empty;
|
cAgent.CallbackURI = String.Empty;
|
||||||
|
|
||||||
// Beyond this point, extra cleanup is needed beyond removing transit state
|
// Beyond this point, extra cleanup is needed beyond removing transit state
|
||||||
UpdateInTransit(agent.UUID, AgentTransferState.Transferring);
|
m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.Transferring);
|
||||||
|
|
||||||
if (!m_scene.SimulationService.UpdateAgent(neighbourRegion, cAgent))
|
if (!m_scene.SimulationService.UpdateAgent(neighbourRegion, cAgent))
|
||||||
{
|
{
|
||||||
// region doesn't take it
|
// region doesn't take it
|
||||||
UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp);
|
m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp);
|
||||||
|
|
||||||
ReInstantiateScripts(agent);
|
ReInstantiateScripts(agent);
|
||||||
agent.AddToPhysicalScene(isFlying);
|
agent.AddToPhysicalScene(isFlying);
|
||||||
ResetFromTransit(agent.UUID);
|
m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
|
||||||
|
|
||||||
return agent;
|
return agent;
|
||||||
}
|
}
|
||||||
|
@ -1191,16 +1173,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
}
|
}
|
||||||
|
|
||||||
// SUCCESS!
|
// SUCCESS!
|
||||||
UpdateInTransit(agent.UUID, AgentTransferState.ReceivedAtDestination);
|
m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.ReceivedAtDestination);
|
||||||
|
|
||||||
// Unlike a teleport, here we do not wait for the destination region to confirm the receipt.
|
// Unlike a teleport, here we do not wait for the destination region to confirm the receipt.
|
||||||
UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp);
|
m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp);
|
||||||
|
|
||||||
agent.MakeChildAgent();
|
agent.MakeChildAgent();
|
||||||
|
|
||||||
// FIXME: Possibly this should occur lower down after other commands to close other agents,
|
// FIXME: Possibly this should occur lower down after other commands to close other agents,
|
||||||
// but not sure yet what the side effects would be.
|
// but not sure yet what the side effects would be.
|
||||||
ResetFromTransit(agent.UUID);
|
m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
|
||||||
|
|
||||||
// now we have a child agent in this region. Request all interesting data about other (root) agents
|
// now we have a child agent in this region. Request all interesting data about other (root) agents
|
||||||
agent.SendOtherAgentsAvatarDataToMe();
|
agent.SendOtherAgentsAvatarDataToMe();
|
||||||
|
@ -1675,41 +1657,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region Agent Arrived
|
#region Agent Arrived
|
||||||
|
|
||||||
public void AgentArrivedAtDestination(UUID id)
|
public void AgentArrivedAtDestination(UUID id)
|
||||||
{
|
{
|
||||||
lock (m_agentsInTransit)
|
m_entityTransferStateMachine.SetAgentArrivedAtDestination(id);
|
||||||
{
|
|
||||||
if (!m_agentsInTransit.ContainsKey(id))
|
|
||||||
{
|
|
||||||
m_log.WarnFormat(
|
|
||||||
"[ENTITY TRANSFER MODULE]: Region {0} received notification of arrival in destination scene of agent {1} but no teleport request is active",
|
|
||||||
m_scene.RegionInfo.RegionName, id);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
AgentTransferState currentState = m_agentsInTransit[id];
|
|
||||||
|
|
||||||
if (currentState == AgentTransferState.ReceivedAtDestination)
|
|
||||||
{
|
|
||||||
// An anomoly but don't make this an outright failure - destination region could be overzealous in sending notification.
|
|
||||||
m_log.WarnFormat(
|
|
||||||
"[ENTITY TRANSFER MODULE]: Region {0} received notification of arrival in destination scene of agent {1} but notification has already previously been received",
|
|
||||||
m_scene.RegionInfo.RegionName, id);
|
|
||||||
}
|
|
||||||
else if (currentState != AgentTransferState.Transferring)
|
|
||||||
{
|
|
||||||
m_log.ErrorFormat(
|
|
||||||
"[ENTITY TRANSFER MODULE]: Region {0} received notification of arrival in destination scene of agent {1} but agent is in transfer state {2}",
|
|
||||||
m_scene.RegionInfo.RegionName, id, currentState);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_agentsInTransit[id] = AgentTransferState.ReceivedAtDestination;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -1979,8 +1931,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
//// And the new channel...
|
//// And the new channel...
|
||||||
//if (m_interregionCommsOut != null)
|
//if (m_interregionCommsOut != null)
|
||||||
// successYN = m_interregionCommsOut.SendCreateObject(newRegionHandle, grp, true);
|
// successYN = m_interregionCommsOut.SendCreateObject(newRegionHandle, grp, true);
|
||||||
if (m_scene.SimulationService != null)
|
if (Scene.SimulationService != null)
|
||||||
successYN = m_scene.SimulationService.CreateObject(destination, newPosition, grp, true);
|
successYN = Scene.SimulationService.CreateObject(destination, newPosition, grp, true);
|
||||||
|
|
||||||
if (successYN)
|
if (successYN)
|
||||||
{
|
{
|
||||||
|
@ -2051,139 +2003,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
|
|
||||||
#region Misc
|
#region Misc
|
||||||
|
|
||||||
private bool WaitForCallback(UUID id)
|
|
||||||
{
|
|
||||||
lock (m_agentsInTransit)
|
|
||||||
{
|
|
||||||
if (!IsInTransit(id))
|
|
||||||
throw new Exception(
|
|
||||||
string.Format(
|
|
||||||
"Asked to wait for destination callback for agent with ID {0} but it is not in transit"));
|
|
||||||
|
|
||||||
AgentTransferState currentState = m_agentsInTransit[id];
|
|
||||||
|
|
||||||
if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination)
|
|
||||||
throw new Exception(
|
|
||||||
string.Format(
|
|
||||||
"Asked to wait for destination callback for agent with ID {0} but it is in state {1}",
|
|
||||||
currentState));
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = 200;
|
|
||||||
|
|
||||||
// There should be no race condition here since no other code should be removing the agent transfer or
|
|
||||||
// changing the state to another other than Transferring => ReceivedAtDestination.
|
|
||||||
while (m_agentsInTransit[id] != AgentTransferState.ReceivedAtDestination && count-- > 0)
|
|
||||||
{
|
|
||||||
// m_log.Debug(" >>> Waiting... " + count);
|
|
||||||
Thread.Sleep(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
return count > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set that an agent is in transit.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name='id'>The ID of the agent being teleported</param>
|
|
||||||
/// <returns>true if the agent was not already in transit, false if it was</returns>
|
|
||||||
private bool SetInTransit(UUID id)
|
|
||||||
{
|
|
||||||
lock (m_agentsInTransit)
|
|
||||||
{
|
|
||||||
if (!m_agentsInTransit.ContainsKey(id))
|
|
||||||
{
|
|
||||||
m_agentsInTransit[id] = AgentTransferState.Preparing;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the state of an agent that is already in transit.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name='id'></param>
|
|
||||||
/// <param name='newState'></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
/// <exception cref='Exception'>Illegal transitions will throw an Exception</exception>
|
|
||||||
private void UpdateInTransit(UUID id, AgentTransferState newState)
|
|
||||||
{
|
|
||||||
lock (m_agentsInTransit)
|
|
||||||
{
|
|
||||||
// Illegal to try and update an agent that's not actually in transit.
|
|
||||||
if (!m_agentsInTransit.ContainsKey(id))
|
|
||||||
throw new Exception(string.Format("Agent with ID {0} is not registered as in transit", id));
|
|
||||||
|
|
||||||
AgentTransferState oldState = m_agentsInTransit[id];
|
|
||||||
|
|
||||||
bool transitionOkay = false;
|
|
||||||
|
|
||||||
if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp)
|
|
||||||
transitionOkay = true;
|
|
||||||
else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing)
|
|
||||||
transitionOkay = true;
|
|
||||||
else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring)
|
|
||||||
transitionOkay = true;
|
|
||||||
|
|
||||||
if (transitionOkay)
|
|
||||||
m_agentsInTransit[id] = newState;
|
|
||||||
else
|
|
||||||
throw new Exception(
|
|
||||||
string.Format(
|
|
||||||
"Agent with ID {0} is not allowed to move from old transit state {1} to new state {2}",
|
|
||||||
id, oldState, newState));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsInTransit(UUID id)
|
public bool IsInTransit(UUID id)
|
||||||
{
|
{
|
||||||
lock (m_agentsInTransit)
|
return m_entityTransferStateMachine.IsInTransit(id);
|
||||||
return m_agentsInTransit.ContainsKey(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes an agent from the transit state machine.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name='id'></param>
|
|
||||||
/// <returns>true if the agent was flagged as being teleported when this method was called, false otherwise</returns>
|
|
||||||
private bool ResetFromTransit(UUID id)
|
|
||||||
{
|
|
||||||
lock (m_agentsInTransit)
|
|
||||||
{
|
|
||||||
if (m_agentsInTransit.ContainsKey(id))
|
|
||||||
{
|
|
||||||
AgentTransferState state = m_agentsInTransit[id];
|
|
||||||
|
|
||||||
if (state == AgentTransferState.Transferring || state == AgentTransferState.ReceivedAtDestination)
|
|
||||||
{
|
|
||||||
// FIXME: For now, we allow exit from any state since a thrown exception in teleport is now guranteed
|
|
||||||
// to be handled properly - ResetFromTransit() could be invoked at any step along the process
|
|
||||||
m_log.WarnFormat(
|
|
||||||
"[ENTITY TRANSFER MODULE]: Agent with ID {0} should not exit directly from state {1}, should go to {2} state first",
|
|
||||||
id, state, AgentTransferState.CleaningUp);
|
|
||||||
|
|
||||||
// throw new Exception(
|
|
||||||
// "Agent with ID {0} cannot exit directly from state {1}, it must go to {2} state first",
|
|
||||||
// state, AgentTransferState.CleaningUp);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_agentsInTransit.Remove(id);
|
|
||||||
|
|
||||||
m_log.DebugFormat(
|
|
||||||
"[ENTITY TRANSFER MODULE]: Agent {0} cleared from transit in {1}",
|
|
||||||
id, m_scene.RegionInfo.RegionName);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_log.WarnFormat(
|
|
||||||
"[ENTITY TRANSFER MODULE]: Agent {0} requested to clear from transit in {1} but was already cleared.",
|
|
||||||
id, m_scene.RegionInfo.RegionName);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ReInstantiateScripts(ScenePresence sp)
|
protected void ReInstantiateScripts(ScenePresence sp)
|
||||||
|
|
|
@ -0,0 +1,269 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using log4net;
|
||||||
|
using Nini.Config;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Framework.Capabilities;
|
||||||
|
using OpenSim.Framework.Client;
|
||||||
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
using OpenSim.Region.Physics.Manager;
|
||||||
|
using OpenSim.Services.Interfaces;
|
||||||
|
using GridRegion = OpenSim.Services.Interfaces.GridRegion;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The possible states that an agent can be in when its being transferred between regions.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is a state machine.
|
||||||
|
///
|
||||||
|
/// [Entry] => Preparing
|
||||||
|
/// Preparing => { Transferring || CleaningUp || [Exit] }
|
||||||
|
/// Transferring => { ReceivedAtDestination || CleaningUp }
|
||||||
|
/// ReceivedAtDestination => CleaningUp
|
||||||
|
/// CleaningUp => [Exit]
|
||||||
|
///
|
||||||
|
/// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp
|
||||||
|
/// However, any state can transition to CleaningUp if the teleport has failed.
|
||||||
|
/// </remarks>
|
||||||
|
enum AgentTransferState
|
||||||
|
{
|
||||||
|
Preparing, // The agent is being prepared for transfer
|
||||||
|
Transferring, // The agent is in the process of being transferred to a destination
|
||||||
|
ReceivedAtDestination, // The destination has notified us that the agent has been successfully received
|
||||||
|
CleaningUp // The agent is being changed to child/removed after a transfer
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Records the state of entities when they are in transfer within or between regions (cross or teleport).
|
||||||
|
/// </summary>
|
||||||
|
public class EntityTransferStateMachine
|
||||||
|
{
|
||||||
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If true then on a teleport, the source region waits for a callback from the destination region. If
|
||||||
|
/// a callback fails to arrive within a set time then the user is pulled back into the source region.
|
||||||
|
/// </summary>
|
||||||
|
public bool EnableWaitForAgentArrivedAtDestination { get; set; }
|
||||||
|
|
||||||
|
private EntityTransferModule m_mod;
|
||||||
|
|
||||||
|
private Dictionary<UUID, AgentTransferState> m_agentsInTransit = new Dictionary<UUID, AgentTransferState>();
|
||||||
|
|
||||||
|
public EntityTransferStateMachine(EntityTransferModule module)
|
||||||
|
{
|
||||||
|
m_mod = module;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set that an agent is in transit.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name='id'>The ID of the agent being teleported</param>
|
||||||
|
/// <returns>true if the agent was not already in transit, false if it was</returns>
|
||||||
|
internal bool SetInTransit(UUID id)
|
||||||
|
{
|
||||||
|
lock (m_agentsInTransit)
|
||||||
|
{
|
||||||
|
if (!m_agentsInTransit.ContainsKey(id))
|
||||||
|
{
|
||||||
|
m_agentsInTransit[id] = AgentTransferState.Preparing;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the state of an agent that is already in transit.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name='id'></param>
|
||||||
|
/// <param name='newState'></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref='Exception'>Illegal transitions will throw an Exception</exception>
|
||||||
|
internal void UpdateInTransit(UUID id, AgentTransferState newState)
|
||||||
|
{
|
||||||
|
lock (m_agentsInTransit)
|
||||||
|
{
|
||||||
|
// Illegal to try and update an agent that's not actually in transit.
|
||||||
|
if (!m_agentsInTransit.ContainsKey(id))
|
||||||
|
throw new Exception(
|
||||||
|
string.Format(
|
||||||
|
"Agent with ID {0} is not registered as in transit in {1}",
|
||||||
|
id, m_mod.Scene.RegionInfo.RegionName));
|
||||||
|
|
||||||
|
AgentTransferState oldState = m_agentsInTransit[id];
|
||||||
|
|
||||||
|
bool transitionOkay = false;
|
||||||
|
|
||||||
|
if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp)
|
||||||
|
transitionOkay = true;
|
||||||
|
else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing)
|
||||||
|
transitionOkay = true;
|
||||||
|
else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring)
|
||||||
|
transitionOkay = true;
|
||||||
|
|
||||||
|
if (transitionOkay)
|
||||||
|
m_agentsInTransit[id] = newState;
|
||||||
|
else
|
||||||
|
throw new Exception(
|
||||||
|
string.Format(
|
||||||
|
"Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}",
|
||||||
|
id, oldState, newState, m_mod.Scene.RegionInfo.RegionName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool IsInTransit(UUID id)
|
||||||
|
{
|
||||||
|
lock (m_agentsInTransit)
|
||||||
|
return m_agentsInTransit.ContainsKey(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes an agent from the transit state machine.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name='id'></param>
|
||||||
|
/// <returns>true if the agent was flagged as being teleported when this method was called, false otherwise</returns>
|
||||||
|
internal bool ResetFromTransit(UUID id)
|
||||||
|
{
|
||||||
|
lock (m_agentsInTransit)
|
||||||
|
{
|
||||||
|
if (m_agentsInTransit.ContainsKey(id))
|
||||||
|
{
|
||||||
|
AgentTransferState state = m_agentsInTransit[id];
|
||||||
|
|
||||||
|
if (state == AgentTransferState.Transferring || state == AgentTransferState.ReceivedAtDestination)
|
||||||
|
{
|
||||||
|
// FIXME: For now, we allow exit from any state since a thrown exception in teleport is now guranteed
|
||||||
|
// to be handled properly - ResetFromTransit() could be invoked at any step along the process
|
||||||
|
m_log.WarnFormat(
|
||||||
|
"[ENTITY TRANSFER STATE MACHINE]: Agent with ID {0} should not exit directly from state {1}, should go to {2} state first in {3}",
|
||||||
|
id, state, AgentTransferState.CleaningUp, m_mod.Scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
|
// throw new Exception(
|
||||||
|
// "Agent with ID {0} cannot exit directly from state {1}, it must go to {2} state first",
|
||||||
|
// state, AgentTransferState.CleaningUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_agentsInTransit.Remove(id);
|
||||||
|
|
||||||
|
m_log.DebugFormat(
|
||||||
|
"[ENTITY TRANSFER STATE MACHINE]: Agent {0} cleared from transit in {1}",
|
||||||
|
id, m_mod.Scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_log.WarnFormat(
|
||||||
|
"[ENTITY TRANSFER STATE MACHINE]: Agent {0} requested to clear from transit in {1} but was already cleared",
|
||||||
|
id, m_mod.Scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool WaitForAgentArrivedAtDestination(UUID id)
|
||||||
|
{
|
||||||
|
if (!m_mod.WaitForAgentArrivedAtDestination)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
lock (m_agentsInTransit)
|
||||||
|
{
|
||||||
|
if (!IsInTransit(id))
|
||||||
|
throw new Exception(
|
||||||
|
string.Format(
|
||||||
|
"Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit",
|
||||||
|
id, m_mod.Scene.RegionInfo.RegionName));
|
||||||
|
|
||||||
|
AgentTransferState currentState = m_agentsInTransit[id];
|
||||||
|
|
||||||
|
if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination)
|
||||||
|
throw new Exception(
|
||||||
|
string.Format(
|
||||||
|
"Asked to wait for destination callback for agent with ID {0} in {1} but agent is in state {2}",
|
||||||
|
id, m_mod.Scene.RegionInfo.RegionName, currentState));
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = 200;
|
||||||
|
|
||||||
|
// There should be no race condition here since no other code should be removing the agent transfer or
|
||||||
|
// changing the state to another other than Transferring => ReceivedAtDestination.
|
||||||
|
while (m_agentsInTransit[id] != AgentTransferState.ReceivedAtDestination && count-- > 0)
|
||||||
|
{
|
||||||
|
// m_log.Debug(" >>> Waiting... " + count);
|
||||||
|
Thread.Sleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
return count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void SetAgentArrivedAtDestination(UUID id)
|
||||||
|
{
|
||||||
|
lock (m_agentsInTransit)
|
||||||
|
{
|
||||||
|
if (!m_agentsInTransit.ContainsKey(id))
|
||||||
|
{
|
||||||
|
m_log.WarnFormat(
|
||||||
|
"[ENTITY TRANSFER STATE MACHINE]: Region {0} received notification of arrival in destination of agent {1} but no teleport request is active",
|
||||||
|
m_mod.Scene.RegionInfo.RegionName, id);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AgentTransferState currentState = m_agentsInTransit[id];
|
||||||
|
|
||||||
|
if (currentState == AgentTransferState.ReceivedAtDestination)
|
||||||
|
{
|
||||||
|
// An anomoly but don't make this an outright failure - destination region could be overzealous in sending notification.
|
||||||
|
m_log.WarnFormat(
|
||||||
|
"[ENTITY TRANSFER STATE MACHINE]: Region {0} received notification of arrival in destination of agent {1} but notification has already previously been received",
|
||||||
|
m_mod.Scene.RegionInfo.RegionName, id);
|
||||||
|
}
|
||||||
|
else if (currentState != AgentTransferState.Transferring)
|
||||||
|
{
|
||||||
|
m_log.ErrorFormat(
|
||||||
|
"[ENTITY TRANSFER STATE MACHINE]: Region {0} received notification of arrival in destination of agent {1} but agent is in state {2}",
|
||||||
|
m_mod.Scene.RegionInfo.RegionName, id, currentState);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_agentsInTransit[id] = AgentTransferState.ReceivedAtDestination;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -117,7 +117,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
|
|
||||||
protected override GridRegion GetFinalDestination(GridRegion region)
|
protected override GridRegion GetFinalDestination(GridRegion region)
|
||||||
{
|
{
|
||||||
int flags = m_scene.GridService.GetRegionFlags(m_scene.RegionInfo.ScopeID, region.RegionID);
|
int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID);
|
||||||
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionID, flags);
|
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionID, flags);
|
||||||
|
|
||||||
if ((flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0)
|
if ((flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0)
|
||||||
|
@ -139,7 +139,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
if (base.NeedsClosing(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
|
if (base.NeedsClosing(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
int flags = m_scene.GridService.GetRegionFlags(m_scene.RegionInfo.ScopeID, reg.RegionID);
|
int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
|
||||||
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0)
|
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
if (logout)
|
if (logout)
|
||||||
{
|
{
|
||||||
// Log them out of this grid
|
// Log them out of this grid
|
||||||
m_scene.PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
|
Scene.PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +161,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: CreateAgent {0} {1}", reg.ServerURI, finalDestination.ServerURI);
|
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: CreateAgent {0} {1}", reg.ServerURI, finalDestination.ServerURI);
|
||||||
reason = string.Empty;
|
reason = string.Empty;
|
||||||
logout = false;
|
logout = false;
|
||||||
int flags = m_scene.GridService.GetRegionFlags(m_scene.RegionInfo.ScopeID, reg.RegionID);
|
int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
|
||||||
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0)
|
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0)
|
||||||
{
|
{
|
||||||
// this user is going to another grid
|
// this user is going to another grid
|
||||||
|
@ -201,7 +201,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
"[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId);
|
"[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId);
|
||||||
|
|
||||||
// Let's find out if this is a foreign user or a local user
|
// Let's find out if this is a foreign user or a local user
|
||||||
IUserManagement uMan = m_scene.RequestModuleInterface<IUserManagement>();
|
IUserManagement uMan = Scene.RequestModuleInterface<IUserManagement>();
|
||||||
if (uMan != null && uMan.IsLocalGridUser(id))
|
if (uMan != null && uMan.IsLocalGridUser(id))
|
||||||
{
|
{
|
||||||
// local grid user
|
// local grid user
|
||||||
|
@ -265,7 +265,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GridRegion info = m_scene.GridService.GetRegionByUUID(UUID.Zero, lm.RegionID);
|
GridRegion info = Scene.GridService.GetRegionByUUID(UUID.Zero, lm.RegionID);
|
||||||
|
|
||||||
// Local region?
|
// Local region?
|
||||||
if (info != null)
|
if (info != null)
|
||||||
|
@ -335,8 +335,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let's find out if this is a foreign user or a local user
|
// Let's find out if this is a foreign user or a local user
|
||||||
IUserManagement uMan = m_scene.RequestModuleInterface<IUserManagement>();
|
IUserManagement uMan = Scene.RequestModuleInterface<IUserManagement>();
|
||||||
// UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, obj.AgentId);
|
// UserAccount account = Scene.UserAccountService.GetUserAccount(Scene.RegionInfo.ScopeID, obj.AgentId);
|
||||||
if (uMan != null && uMan.IsLocalGridUser(obj.AgentId))
|
if (uMan != null && uMan.IsLocalGridUser(obj.AgentId))
|
||||||
{
|
{
|
||||||
// local grid user
|
// local grid user
|
||||||
|
|
Loading…
Reference in New Issue