diff options
3 files changed, 332 insertions, 238 deletions
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 5d9d67f..7db2491 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | |||
@@ -46,35 +46,12 @@ using Nini.Config; | |||
46 | 46 | ||
47 | namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | 47 | namespace OpenSim.Region.CoreModules.Framework.EntityTransfer |
48 | { | 48 | { |
49 | /// <summary> | ||
50 | /// The possible states that an agent can be in when its being transferred between regions. | ||
51 | /// </summary> | ||
52 | /// <remarks> | ||
53 | /// This is a state machine. | ||
54 | /// | ||
55 | /// [Entry] => Preparing | ||
56 | /// Preparing => { Transferring || CleaningUp || [Exit] } | ||
57 | /// Transferring => { ReceivedAtDestination || CleaningUp } | ||
58 | /// ReceivedAtDestination => CleaningUp | ||
59 | /// CleaningUp => [Exit] | ||
60 | /// | ||
61 | /// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp | ||
62 | /// However, any state can transition to CleaningUp if the teleport has failed. | ||
63 | /// </remarks> | ||
64 | enum AgentTransferState | ||
65 | { | ||
66 | Preparing, // The agent is being prepared for transfer | ||
67 | Transferring, // The agent is in the process of being transferred to a destination | ||
68 | ReceivedAtDestination, // The destination has notified us that the agent has been successfully received | ||
69 | CleaningUp // The agent is being changed to child/removed after a transfer | ||
70 | } | ||
71 | |||
72 | public class EntityTransferModule : INonSharedRegionModule, IEntityTransferModule | 49 | public class EntityTransferModule : INonSharedRegionModule, IEntityTransferModule |
73 | { | 50 | { |
74 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 51 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
75 | 52 | ||
76 | public const int DefaultMaxTransferDistance = 4095; | 53 | public const int DefaultMaxTransferDistance = 4095; |
77 | public const bool EnableWaitForCallbackFromTeleportDestDefault = true; | 54 | public const bool WaitForAgentArrivedAtDestinationDefault = true; |
78 | 55 | ||
79 | /// <summary> | 56 | /// <summary> |
80 | /// The maximum distance, in standard region units (256m) that an agent is allowed to transfer. | 57 | /// 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 | |||
85 | /// If true then on a teleport, the source region waits for a callback from the destination region. If | 62 | /// If true then on a teleport, the source region waits for a callback from the destination region. If |
86 | /// a callback fails to arrive within a set time then the user is pulled back into the source region. | 63 | /// a callback fails to arrive within a set time then the user is pulled back into the source region. |
87 | /// </summary> | 64 | /// </summary> |
88 | public bool EnableWaitForCallbackFromTeleportDest { get; set; } | 65 | public bool WaitForAgentArrivedAtDestination { get; set; } |
89 | 66 | ||
90 | protected bool m_Enabled = false; | 67 | protected bool m_Enabled = false; |
91 | 68 | ||
92 | protected Scene m_scene; | 69 | public Scene Scene { get; private set; } |
93 | 70 | ||
94 | private Dictionary<UUID, AgentTransferState> m_agentsInTransit; | 71 | /// <summary> |
72 | /// Handles recording and manipulation of state for entities that are in transfer within or between regions | ||
73 | /// (cross or teleport). | ||
74 | /// </summary> | ||
75 | private EntityTransferStateMachine m_entityTransferStateMachine; | ||
95 | 76 | ||
96 | private ExpiringCache<UUID, ExpiringCache<ulong, DateTime>> m_bannedRegions = | 77 | private ExpiringCache<UUID, ExpiringCache<ulong, DateTime>> m_bannedRegions = |
97 | new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>(); | 78 | new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>(); |
@@ -133,8 +114,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
133 | IConfig transferConfig = source.Configs["EntityTransfer"]; | 114 | IConfig transferConfig = source.Configs["EntityTransfer"]; |
134 | if (transferConfig != null) | 115 | if (transferConfig != null) |
135 | { | 116 | { |
136 | EnableWaitForCallbackFromTeleportDest | 117 | WaitForAgentArrivedAtDestination |
137 | = transferConfig.GetBoolean("wait_for_callback", EnableWaitForCallbackFromTeleportDestDefault); | 118 | = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault); |
138 | 119 | ||
139 | MaxTransferDistance = transferConfig.GetInt("max_distance", DefaultMaxTransferDistance); | 120 | MaxTransferDistance = transferConfig.GetInt("max_distance", DefaultMaxTransferDistance); |
140 | } | 121 | } |
@@ -143,7 +124,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
143 | MaxTransferDistance = DefaultMaxTransferDistance; | 124 | MaxTransferDistance = DefaultMaxTransferDistance; |
144 | } | 125 | } |
145 | 126 | ||
146 | m_agentsInTransit = new Dictionary<UUID, AgentTransferState>(); | 127 | m_entityTransferStateMachine = new EntityTransferStateMachine(this); |
128 | |||
147 | m_Enabled = true; | 129 | m_Enabled = true; |
148 | } | 130 | } |
149 | 131 | ||
@@ -156,7 +138,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
156 | if (!m_Enabled) | 138 | if (!m_Enabled) |
157 | return; | 139 | return; |
158 | 140 | ||
159 | m_scene = scene; | 141 | Scene = scene; |
160 | 142 | ||
161 | scene.RegisterModuleInterface<IEntityTransferModule>(this); | 143 | scene.RegisterModuleInterface<IEntityTransferModule>(this); |
162 | scene.EventManager.OnNewClient += OnNewClient; | 144 | scene.EventManager.OnNewClient += OnNewClient; |
@@ -177,7 +159,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
177 | if (!m_Enabled) | 159 | if (!m_Enabled) |
178 | return; | 160 | return; |
179 | 161 | ||
180 | m_eqModule = m_scene.RequestModuleInterface<IEventQueue>(); | 162 | m_eqModule = Scene.RequestModuleInterface<IEventQueue>(); |
181 | } | 163 | } |
182 | 164 | ||
183 | #endregion | 165 | #endregion |
@@ -226,7 +208,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
226 | e.Message, e.StackTrace); | 208 | e.Message, e.StackTrace); |
227 | 209 | ||
228 | // Make sure that we clear the in-transit flag so that future teleport attempts don't always fail. | 210 | // Make sure that we clear the in-transit flag so that future teleport attempts don't always fail. |
229 | ResetFromTransit(sp.UUID); | 211 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); |
230 | 212 | ||
231 | sp.ControllingClient.SendTeleportFailed("Internal error"); | 213 | sp.ControllingClient.SendTeleportFailed("Internal error"); |
232 | } | 214 | } |
@@ -245,7 +227,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
245 | "[ENTITY TRANSFER MODULE]: Teleport for {0} to {1} within {2}", | 227 | "[ENTITY TRANSFER MODULE]: Teleport for {0} to {1} within {2}", |
246 | sp.Name, position, sp.Scene.RegionInfo.RegionName); | 228 | sp.Name, position, sp.Scene.RegionInfo.RegionName); |
247 | 229 | ||
248 | if (!SetInTransit(sp.UUID)) | 230 | if (!m_entityTransferStateMachine.SetInTransit(sp.UUID)) |
249 | { | 231 | { |
250 | m_log.DebugFormat( | 232 | m_log.DebugFormat( |
251 | "[ENTITY TRANSFER MODULE]: Ignoring within region teleport request of {0} {1} to {2} - agent is already in transit.", | 233 | "[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 | |||
282 | position.Z = newPosZ; | 264 | position.Z = newPosZ; |
283 | } | 265 | } |
284 | 266 | ||
285 | UpdateInTransit(sp.UUID, AgentTransferState.Transferring); | 267 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); |
286 | 268 | ||
287 | sp.ControllingClient.SendTeleportStart(teleportFlags); | 269 | sp.ControllingClient.SendTeleportStart(teleportFlags); |
288 | 270 | ||
@@ -291,15 +273,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
291 | sp.Velocity = Vector3.Zero; | 273 | sp.Velocity = Vector3.Zero; |
292 | sp.Teleport(position); | 274 | sp.Teleport(position); |
293 | 275 | ||
294 | UpdateInTransit(sp.UUID, AgentTransferState.ReceivedAtDestination); | 276 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.ReceivedAtDestination); |
295 | 277 | ||
296 | foreach (SceneObjectGroup grp in sp.GetAttachments()) | 278 | foreach (SceneObjectGroup grp in sp.GetAttachments()) |
297 | { | 279 | { |
298 | sp.Scene.EventManager.TriggerOnScriptChangedEvent(grp.LocalId, (uint)Changed.TELEPORT); | 280 | sp.Scene.EventManager.TriggerOnScriptChangedEvent(grp.LocalId, (uint)Changed.TELEPORT); |
299 | } | 281 | } |
300 | 282 | ||
301 | UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); | 283 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); |
302 | ResetFromTransit(sp.UUID); | 284 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); |
303 | } | 285 | } |
304 | 286 | ||
305 | /// <summary> | 287 | /// <summary> |
@@ -317,7 +299,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
317 | { | 299 | { |
318 | uint x = 0, y = 0; | 300 | uint x = 0, y = 0; |
319 | Utils.LongToUInts(regionHandle, out x, out y); | 301 | Utils.LongToUInts(regionHandle, out x, out y); |
320 | GridRegion reg = m_scene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y); | 302 | GridRegion reg = Scene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y); |
321 | 303 | ||
322 | if (reg != null) | 304 | if (reg != null) |
323 | { | 305 | { |
@@ -399,7 +381,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
399 | { | 381 | { |
400 | // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection | 382 | // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection |
401 | // of whether the destination region completes the teleport. | 383 | // of whether the destination region completes the teleport. |
402 | if (!SetInTransit(sp.UUID)) | 384 | if (!m_entityTransferStateMachine.SetInTransit(sp.UUID)) |
403 | { | 385 | { |
404 | m_log.DebugFormat( | 386 | m_log.DebugFormat( |
405 | "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2} ({3}) {4}/{5} - agent is already in transit.", | 387 | "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2} ({3}) {4}/{5} - agent is already in transit.", |
@@ -411,7 +393,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
411 | if (reg == null || finalDestination == null) | 393 | if (reg == null || finalDestination == null) |
412 | { | 394 | { |
413 | sp.ControllingClient.SendTeleportFailed("Unable to locate destination"); | 395 | sp.ControllingClient.SendTeleportFailed("Unable to locate destination"); |
414 | ResetFromTransit(sp.UUID); | 396 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); |
415 | 397 | ||
416 | return; | 398 | return; |
417 | } | 399 | } |
@@ -432,7 +414,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
432 | sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY, | 414 | sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY, |
433 | MaxTransferDistance)); | 415 | MaxTransferDistance)); |
434 | 416 | ||
435 | ResetFromTransit(sp.UUID); | 417 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); |
436 | 418 | ||
437 | return; | 419 | return; |
438 | } | 420 | } |
@@ -451,7 +433,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
451 | if (endPoint != null && endPoint.Address != null) | 433 | if (endPoint != null && endPoint.Address != null) |
452 | { | 434 | { |
453 | sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); | 435 | sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); |
454 | ResetFromTransit(sp.UUID); | 436 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); |
455 | 437 | ||
456 | return; | 438 | return; |
457 | } | 439 | } |
@@ -469,11 +451,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
469 | 451 | ||
470 | string reason; | 452 | string reason; |
471 | string version; | 453 | string version; |
472 | if (!m_scene.SimulationService.QueryAccess( | 454 | if (!Scene.SimulationService.QueryAccess( |
473 | finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out version, out reason)) | 455 | finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out version, out reason)) |
474 | { | 456 | { |
475 | sp.ControllingClient.SendTeleportFailed(reason); | 457 | sp.ControllingClient.SendTeleportFailed(reason); |
476 | ResetFromTransit(sp.UUID); | 458 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); |
477 | 459 | ||
478 | m_log.DebugFormat( | 460 | m_log.DebugFormat( |
479 | "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because {3}", | 461 | "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because {3}", |
@@ -527,7 +509,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
527 | if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) | 509 | if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) |
528 | { | 510 | { |
529 | sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason)); | 511 | sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason)); |
530 | ResetFromTransit(sp.UUID); | 512 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); |
531 | 513 | ||
532 | m_log.DebugFormat( | 514 | m_log.DebugFormat( |
533 | "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}", | 515 | "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}", |
@@ -537,7 +519,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
537 | } | 519 | } |
538 | 520 | ||
539 | // Past this point we have to attempt clean up if the teleport fails, so update transfer state. | 521 | // Past this point we have to attempt clean up if the teleport fails, so update transfer state. |
540 | UpdateInTransit(sp.UUID, AgentTransferState.Transferring); | 522 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); |
541 | 523 | ||
542 | // OK, it got this agent. Let's close some child agents | 524 | // OK, it got this agent. Let's close some child agents |
543 | sp.CloseChildAgents(newRegionX, newRegionY); | 525 | sp.CloseChildAgents(newRegionX, newRegionY); |
@@ -619,7 +601,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
619 | // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which | 601 | // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which |
620 | // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation | 602 | // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation |
621 | // that the client contacted the destination before we close things here. | 603 | // that the client contacted the destination before we close things here. |
622 | if (EnableWaitForCallbackFromTeleportDest && !WaitForCallback(sp.UUID)) | 604 | if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID)) |
623 | { | 605 | { |
624 | m_log.WarnFormat( | 606 | m_log.WarnFormat( |
625 | "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", | 607 | "[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 | |||
629 | return; | 611 | return; |
630 | } | 612 | } |
631 | 613 | ||
632 | UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); | 614 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); |
633 | 615 | ||
634 | // For backwards compatibility | 616 | // For backwards compatibility |
635 | if (version == "Unknown" || version == string.Empty) | 617 | if (version == "Unknown" || version == string.Empty) |
@@ -679,31 +661,34 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
679 | sp.UUID); | 661 | sp.UUID); |
680 | } | 662 | } |
681 | 663 | ||
682 | ResetFromTransit(sp.UUID); | 664 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); |
683 | } | 665 | } |
684 | 666 | ||
685 | protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout) | 667 | protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout) |
686 | { | 668 | { |
669 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); | ||
670 | |||
687 | // Client never contacted destination. Let's restore everything back | 671 | // Client never contacted destination. Let's restore everything back |
688 | sp.ControllingClient.SendTeleportFailed("Problems connecting to destination."); | 672 | sp.ControllingClient.SendTeleportFailed("Problems connecting to destination."); |
689 | 673 | ||
690 | // Fail. Reset it back | 674 | // Fail. Reset it back |
691 | sp.IsChildAgent = false; | 675 | sp.IsChildAgent = false; |
692 | ReInstantiateScripts(sp); | 676 | ReInstantiateScripts(sp); |
693 | ResetFromTransit(sp.UUID); | ||
694 | 677 | ||
695 | EnableChildAgents(sp); | 678 | EnableChildAgents(sp); |
696 | 679 | ||
697 | // Finally, kill the agent we just created at the destination. | 680 | // Finally, kill the agent we just created at the destination. |
698 | m_scene.SimulationService.CloseAgent(finalDestination, sp.UUID); | 681 | Scene.SimulationService.CloseAgent(finalDestination, sp.UUID); |
699 | 682 | ||
700 | sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout); | 683 | sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout); |
684 | |||
685 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); | ||
701 | } | 686 | } |
702 | 687 | ||
703 | protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout) | 688 | protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout) |
704 | { | 689 | { |
705 | logout = false; | 690 | logout = false; |
706 | bool success = m_scene.SimulationService.CreateAgent(finalDestination, agentCircuit, teleportFlags, out reason); | 691 | bool success = Scene.SimulationService.CreateAgent(finalDestination, agentCircuit, teleportFlags, out reason); |
707 | 692 | ||
708 | if (success) | 693 | if (success) |
709 | sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout); | 694 | sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout); |
@@ -713,7 +698,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
713 | 698 | ||
714 | protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent) | 699 | protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent) |
715 | { | 700 | { |
716 | return m_scene.SimulationService.UpdateAgent(finalDestination, agent); | 701 | return Scene.SimulationService.UpdateAgent(finalDestination, agent); |
717 | } | 702 | } |
718 | 703 | ||
719 | protected virtual void SetCallbackURL(AgentData agent, RegionInfo region) | 704 | protected virtual void SetCallbackURL(AgentData agent, RegionInfo region) |
@@ -776,7 +761,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
776 | /// <param name="position"></param> | 761 | /// <param name="position"></param> |
777 | public virtual void RequestTeleportLandmark(IClientAPI remoteClient, AssetLandmark lm) | 762 | public virtual void RequestTeleportLandmark(IClientAPI remoteClient, AssetLandmark lm) |
778 | { | 763 | { |
779 | GridRegion info = m_scene.GridService.GetRegionByUUID(UUID.Zero, lm.RegionID); | 764 | GridRegion info = Scene.GridService.GetRegionByUUID(UUID.Zero, lm.RegionID); |
780 | 765 | ||
781 | if (info == null) | 766 | if (info == null) |
782 | { | 767 | { |
@@ -802,8 +787,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
802 | m_log.DebugFormat( | 787 | m_log.DebugFormat( |
803 | "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId); | 788 | "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId); |
804 | 789 | ||
805 | //OpenSim.Services.Interfaces.PresenceInfo pinfo = m_scene.PresenceService.GetAgent(client.SessionId); | 790 | //OpenSim.Services.Interfaces.PresenceInfo pinfo = Scene.PresenceService.GetAgent(client.SessionId); |
806 | GridUserInfo uinfo = m_scene.GridUserService.GetGridUserInfo(client.AgentId.ToString()); | 791 | GridUserInfo uinfo = Scene.GridUserService.GetGridUserInfo(client.AgentId.ToString()); |
807 | 792 | ||
808 | if (uinfo != null) | 793 | if (uinfo != null) |
809 | { | 794 | { |
@@ -813,7 +798,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
813 | client.SendTeleportFailed("You don't have a home position set."); | 798 | client.SendTeleportFailed("You don't have a home position set."); |
814 | return false; | 799 | return false; |
815 | } | 800 | } |
816 | GridRegion regionInfo = m_scene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID); | 801 | GridRegion regionInfo = Scene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID); |
817 | if (regionInfo == null) | 802 | if (regionInfo == null) |
818 | { | 803 | { |
819 | // can't find the Home region: Tell viewer and abort | 804 | // can't find the Home region: Tell viewer and abort |
@@ -1063,7 +1048,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1063 | 1048 | ||
1064 | try | 1049 | try |
1065 | { | 1050 | { |
1066 | SetInTransit(agent.UUID); | 1051 | m_entityTransferStateMachine.SetInTransit(agent.UUID); |
1067 | 1052 | ||
1068 | ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize)); | 1053 | ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize)); |
1069 | 1054 | ||
@@ -1093,16 +1078,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1093 | cAgent.CallbackURI = String.Empty; | 1078 | cAgent.CallbackURI = String.Empty; |
1094 | 1079 | ||
1095 | // Beyond this point, extra cleanup is needed beyond removing transit state | 1080 | // Beyond this point, extra cleanup is needed beyond removing transit state |
1096 | UpdateInTransit(agent.UUID, AgentTransferState.Transferring); | 1081 | m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.Transferring); |
1097 | 1082 | ||
1098 | if (!m_scene.SimulationService.UpdateAgent(neighbourRegion, cAgent)) | 1083 | if (!m_scene.SimulationService.UpdateAgent(neighbourRegion, cAgent)) |
1099 | { | 1084 | { |
1100 | // region doesn't take it | 1085 | // region doesn't take it |
1101 | UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); | 1086 | m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); |
1102 | 1087 | ||
1103 | ReInstantiateScripts(agent); | 1088 | ReInstantiateScripts(agent); |
1104 | agent.AddToPhysicalScene(isFlying); | 1089 | agent.AddToPhysicalScene(isFlying); |
1105 | ResetFromTransit(agent.UUID); | 1090 | m_entityTransferStateMachine.ResetFromTransit(agent.UUID); |
1106 | 1091 | ||
1107 | return agent; | 1092 | return agent; |
1108 | } | 1093 | } |
@@ -1140,16 +1125,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1140 | } | 1125 | } |
1141 | 1126 | ||
1142 | // SUCCESS! | 1127 | // SUCCESS! |
1143 | UpdateInTransit(agent.UUID, AgentTransferState.ReceivedAtDestination); | 1128 | m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.ReceivedAtDestination); |
1144 | 1129 | ||
1145 | // Unlike a teleport, here we do not wait for the destination region to confirm the receipt. | 1130 | // Unlike a teleport, here we do not wait for the destination region to confirm the receipt. |
1146 | UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); | 1131 | m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); |
1147 | 1132 | ||
1148 | agent.MakeChildAgent(); | 1133 | agent.MakeChildAgent(); |
1149 | 1134 | ||
1150 | // FIXME: Possibly this should occur lower down after other commands to close other agents, | 1135 | // FIXME: Possibly this should occur lower down after other commands to close other agents, |
1151 | // but not sure yet what the side effects would be. | 1136 | // but not sure yet what the side effects would be. |
1152 | ResetFromTransit(agent.UUID); | 1137 | m_entityTransferStateMachine.ResetFromTransit(agent.UUID); |
1153 | 1138 | ||
1154 | // now we have a child agent in this region. Request all interesting data about other (root) agents | 1139 | // now we have a child agent in this region. Request all interesting data about other (root) agents |
1155 | agent.SendOtherAgentsAvatarDataToMe(); | 1140 | agent.SendOtherAgentsAvatarDataToMe(); |
@@ -1628,41 +1613,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1628 | 1613 | ||
1629 | #endregion | 1614 | #endregion |
1630 | 1615 | ||
1631 | |||
1632 | #region Agent Arrived | 1616 | #region Agent Arrived |
1617 | |||
1633 | public void AgentArrivedAtDestination(UUID id) | 1618 | public void AgentArrivedAtDestination(UUID id) |
1634 | { | 1619 | { |
1635 | lock (m_agentsInTransit) | 1620 | m_entityTransferStateMachine.SetAgentArrivedAtDestination(id); |
1636 | { | ||
1637 | if (!m_agentsInTransit.ContainsKey(id)) | ||
1638 | { | ||
1639 | m_log.WarnFormat( | ||
1640 | "[ENTITY TRANSFER MODULE]: Region {0} received notification of arrival in destination scene of agent {1} but no teleport request is active", | ||
1641 | m_scene.RegionInfo.RegionName, id); | ||
1642 | |||
1643 | return; | ||
1644 | } | ||
1645 | |||
1646 | AgentTransferState currentState = m_agentsInTransit[id]; | ||
1647 | |||
1648 | if (currentState == AgentTransferState.ReceivedAtDestination) | ||
1649 | { | ||
1650 | // An anomoly but don't make this an outright failure - destination region could be overzealous in sending notification. | ||
1651 | m_log.WarnFormat( | ||
1652 | "[ENTITY TRANSFER MODULE]: Region {0} received notification of arrival in destination scene of agent {1} but notification has already previously been received", | ||
1653 | m_scene.RegionInfo.RegionName, id); | ||
1654 | } | ||
1655 | else if (currentState != AgentTransferState.Transferring) | ||
1656 | { | ||
1657 | m_log.ErrorFormat( | ||
1658 | "[ENTITY TRANSFER MODULE]: Region {0} received notification of arrival in destination scene of agent {1} but agent is in transfer state {2}", | ||
1659 | m_scene.RegionInfo.RegionName, id, currentState); | ||
1660 | |||
1661 | return; | ||
1662 | } | ||
1663 | |||
1664 | m_agentsInTransit[id] = AgentTransferState.ReceivedAtDestination; | ||
1665 | } | ||
1666 | } | 1621 | } |
1667 | 1622 | ||
1668 | #endregion | 1623 | #endregion |
@@ -1933,8 +1888,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1933 | //// And the new channel... | 1888 | //// And the new channel... |
1934 | //if (m_interregionCommsOut != null) | 1889 | //if (m_interregionCommsOut != null) |
1935 | // successYN = m_interregionCommsOut.SendCreateObject(newRegionHandle, grp, true); | 1890 | // successYN = m_interregionCommsOut.SendCreateObject(newRegionHandle, grp, true); |
1936 | if (m_scene.SimulationService != null) | 1891 | if (Scene.SimulationService != null) |
1937 | successYN = m_scene.SimulationService.CreateObject(destination, newPosition, grp, true); | 1892 | successYN = Scene.SimulationService.CreateObject(destination, newPosition, grp, true); |
1938 | 1893 | ||
1939 | if (successYN) | 1894 | if (successYN) |
1940 | { | 1895 | { |
@@ -2013,139 +1968,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2013 | 1968 | ||
2014 | #region Misc | 1969 | #region Misc |
2015 | 1970 | ||
2016 | private bool WaitForCallback(UUID id) | ||
2017 | { | ||
2018 | lock (m_agentsInTransit) | ||
2019 | { | ||
2020 | if (!IsInTransit(id)) | ||
2021 | throw new Exception( | ||
2022 | string.Format( | ||
2023 | "Asked to wait for destination callback for agent with ID {0} but it is not in transit")); | ||
2024 | |||
2025 | AgentTransferState currentState = m_agentsInTransit[id]; | ||
2026 | |||
2027 | if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination) | ||
2028 | throw new Exception( | ||
2029 | string.Format( | ||
2030 | "Asked to wait for destination callback for agent with ID {0} but it is in state {1}", | ||
2031 | currentState)); | ||
2032 | } | ||
2033 | |||
2034 | int count = 200; | ||
2035 | |||
2036 | // There should be no race condition here since no other code should be removing the agent transfer or | ||
2037 | // changing the state to another other than Transferring => ReceivedAtDestination. | ||
2038 | while (m_agentsInTransit[id] != AgentTransferState.ReceivedAtDestination && count-- > 0) | ||
2039 | { | ||
2040 | // m_log.Debug(" >>> Waiting... " + count); | ||
2041 | Thread.Sleep(100); | ||
2042 | } | ||
2043 | |||
2044 | return count > 0; | ||
2045 | } | ||
2046 | |||
2047 | /// <summary> | ||
2048 | /// Set that an agent is in transit. | ||
2049 | /// </summary> | ||
2050 | /// <param name='id'>The ID of the agent being teleported</param> | ||
2051 | /// <returns>true if the agent was not already in transit, false if it was</returns> | ||
2052 | private bool SetInTransit(UUID id) | ||
2053 | { | ||
2054 | lock (m_agentsInTransit) | ||
2055 | { | ||
2056 | if (!m_agentsInTransit.ContainsKey(id)) | ||
2057 | { | ||
2058 | m_agentsInTransit[id] = AgentTransferState.Preparing; | ||
2059 | return true; | ||
2060 | } | ||
2061 | } | ||
2062 | |||
2063 | return false; | ||
2064 | } | ||
2065 | |||
2066 | /// <summary> | ||
2067 | /// Updates the state of an agent that is already in transit. | ||
2068 | /// </summary> | ||
2069 | /// <param name='id'></param> | ||
2070 | /// <param name='newState'></param> | ||
2071 | /// <returns></returns> | ||
2072 | /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception> | ||
2073 | private void UpdateInTransit(UUID id, AgentTransferState newState) | ||
2074 | { | ||
2075 | lock (m_agentsInTransit) | ||
2076 | { | ||
2077 | // Illegal to try and update an agent that's not actually in transit. | ||
2078 | if (!m_agentsInTransit.ContainsKey(id)) | ||
2079 | throw new Exception(string.Format("Agent with ID {0} is not registered as in transit", id)); | ||
2080 | |||
2081 | AgentTransferState oldState = m_agentsInTransit[id]; | ||
2082 | |||
2083 | bool transitionOkay = false; | ||
2084 | |||
2085 | if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) | ||
2086 | transitionOkay = true; | ||
2087 | else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing) | ||
2088 | transitionOkay = true; | ||
2089 | else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring) | ||
2090 | transitionOkay = true; | ||
2091 | |||
2092 | if (transitionOkay) | ||
2093 | m_agentsInTransit[id] = newState; | ||
2094 | else | ||
2095 | throw new Exception( | ||
2096 | string.Format( | ||
2097 | "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2}", | ||
2098 | id, oldState, newState)); | ||
2099 | } | ||
2100 | } | ||
2101 | |||
2102 | public bool IsInTransit(UUID id) | 1971 | public bool IsInTransit(UUID id) |
2103 | { | 1972 | { |
2104 | lock (m_agentsInTransit) | 1973 | return m_entityTransferStateMachine.IsInTransit(id); |
2105 | return m_agentsInTransit.ContainsKey(id); | ||
2106 | } | ||
2107 | |||
2108 | /// <summary> | ||
2109 | /// Removes an agent from the transit state machine. | ||
2110 | /// </summary> | ||
2111 | /// <param name='id'></param> | ||
2112 | /// <returns>true if the agent was flagged as being teleported when this method was called, false otherwise</returns> | ||
2113 | private bool ResetFromTransit(UUID id) | ||
2114 | { | ||
2115 | lock (m_agentsInTransit) | ||
2116 | { | ||
2117 | if (m_agentsInTransit.ContainsKey(id)) | ||
2118 | { | ||
2119 | AgentTransferState state = m_agentsInTransit[id]; | ||
2120 | |||
2121 | if (state == AgentTransferState.Transferring || state == AgentTransferState.ReceivedAtDestination) | ||
2122 | { | ||
2123 | // FIXME: For now, we allow exit from any state since a thrown exception in teleport is now guranteed | ||
2124 | // to be handled properly - ResetFromTransit() could be invoked at any step along the process | ||
2125 | m_log.WarnFormat( | ||
2126 | "[ENTITY TRANSFER MODULE]: Agent with ID should not exit directly from state {1}, should go to {2} state first", | ||
2127 | state, AgentTransferState.CleaningUp); | ||
2128 | |||
2129 | // throw new Exception( | ||
2130 | // "Agent with ID {0} cannot exit directly from state {1}, it must go to {2} state first", | ||
2131 | // state, AgentTransferState.CleaningUp); | ||
2132 | } | ||
2133 | |||
2134 | m_agentsInTransit.Remove(id); | ||
2135 | |||
2136 | m_log.DebugFormat( | ||
2137 | "[ENTITY TRANSFER MODULE]: Agent {0} cleared from transit in {1}", | ||
2138 | id, m_scene.RegionInfo.RegionName); | ||
2139 | |||
2140 | return true; | ||
2141 | } | ||
2142 | } | ||
2143 | |||
2144 | m_log.WarnFormat( | ||
2145 | "[ENTITY TRANSFER MODULE]: Agent {0} requested to clear from transit in {1} but was already cleared.", | ||
2146 | id, m_scene.RegionInfo.RegionName); | ||
2147 | |||
2148 | return false; | ||
2149 | } | 1974 | } |
2150 | 1975 | ||
2151 | protected void ReInstantiateScripts(ScenePresence sp) | 1976 | protected void ReInstantiateScripts(ScenePresence sp) |
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs new file mode 100644 index 0000000..d0cab49 --- /dev/null +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs | |||
@@ -0,0 +1,269 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Net; | ||
31 | using System.Reflection; | ||
32 | using System.Threading; | ||
33 | using OpenMetaverse; | ||
34 | using log4net; | ||
35 | using Nini.Config; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Framework.Capabilities; | ||
38 | using OpenSim.Framework.Client; | ||
39 | using OpenSim.Region.Framework.Interfaces; | ||
40 | using OpenSim.Region.Framework.Scenes; | ||
41 | using OpenSim.Region.Physics.Manager; | ||
42 | using OpenSim.Services.Interfaces; | ||
43 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
44 | |||
45 | namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | ||
46 | { | ||
47 | /// <summary> | ||
48 | /// The possible states that an agent can be in when its being transferred between regions. | ||
49 | /// </summary> | ||
50 | /// <remarks> | ||
51 | /// This is a state machine. | ||
52 | /// | ||
53 | /// [Entry] => Preparing | ||
54 | /// Preparing => { Transferring || CleaningUp || [Exit] } | ||
55 | /// Transferring => { ReceivedAtDestination || CleaningUp } | ||
56 | /// ReceivedAtDestination => CleaningUp | ||
57 | /// CleaningUp => [Exit] | ||
58 | /// | ||
59 | /// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp | ||
60 | /// However, any state can transition to CleaningUp if the teleport has failed. | ||
61 | /// </remarks> | ||
62 | enum AgentTransferState | ||
63 | { | ||
64 | Preparing, // The agent is being prepared for transfer | ||
65 | Transferring, // The agent is in the process of being transferred to a destination | ||
66 | ReceivedAtDestination, // The destination has notified us that the agent has been successfully received | ||
67 | CleaningUp // The agent is being changed to child/removed after a transfer | ||
68 | } | ||
69 | |||
70 | /// <summary> | ||
71 | /// Records the state of entities when they are in transfer within or between regions (cross or teleport). | ||
72 | /// </summary> | ||
73 | public class EntityTransferStateMachine | ||
74 | { | ||
75 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
76 | |||
77 | /// <summary> | ||
78 | /// If true then on a teleport, the source region waits for a callback from the destination region. If | ||
79 | /// a callback fails to arrive within a set time then the user is pulled back into the source region. | ||
80 | /// </summary> | ||
81 | public bool EnableWaitForAgentArrivedAtDestination { get; set; } | ||
82 | |||
83 | private EntityTransferModule m_mod; | ||
84 | |||
85 | private Dictionary<UUID, AgentTransferState> m_agentsInTransit = new Dictionary<UUID, AgentTransferState>(); | ||
86 | |||
87 | public EntityTransferStateMachine(EntityTransferModule module) | ||
88 | { | ||
89 | m_mod = module; | ||
90 | } | ||
91 | |||
92 | /// <summary> | ||
93 | /// Set that an agent is in transit. | ||
94 | /// </summary> | ||
95 | /// <param name='id'>The ID of the agent being teleported</param> | ||
96 | /// <returns>true if the agent was not already in transit, false if it was</returns> | ||
97 | internal bool SetInTransit(UUID id) | ||
98 | { | ||
99 | lock (m_agentsInTransit) | ||
100 | { | ||
101 | if (!m_agentsInTransit.ContainsKey(id)) | ||
102 | { | ||
103 | m_agentsInTransit[id] = AgentTransferState.Preparing; | ||
104 | return true; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | return false; | ||
109 | } | ||
110 | |||
111 | /// <summary> | ||
112 | /// Updates the state of an agent that is already in transit. | ||
113 | /// </summary> | ||
114 | /// <param name='id'></param> | ||
115 | /// <param name='newState'></param> | ||
116 | /// <returns></returns> | ||
117 | /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception> | ||
118 | internal void UpdateInTransit(UUID id, AgentTransferState newState) | ||
119 | { | ||
120 | lock (m_agentsInTransit) | ||
121 | { | ||
122 | // Illegal to try and update an agent that's not actually in transit. | ||
123 | if (!m_agentsInTransit.ContainsKey(id)) | ||
124 | throw new Exception( | ||
125 | string.Format( | ||
126 | "Agent with ID {0} is not registered as in transit in {1}", | ||
127 | id, m_mod.Scene.RegionInfo.RegionName)); | ||
128 | |||
129 | AgentTransferState oldState = m_agentsInTransit[id]; | ||
130 | |||
131 | bool transitionOkay = false; | ||
132 | |||
133 | if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) | ||
134 | transitionOkay = true; | ||
135 | else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing) | ||
136 | transitionOkay = true; | ||
137 | else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring) | ||
138 | transitionOkay = true; | ||
139 | |||
140 | if (transitionOkay) | ||
141 | m_agentsInTransit[id] = newState; | ||
142 | else | ||
143 | throw new Exception( | ||
144 | string.Format( | ||
145 | "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}", | ||
146 | id, oldState, newState, m_mod.Scene.RegionInfo.RegionName)); | ||
147 | } | ||
148 | } | ||
149 | |||
150 | internal bool IsInTransit(UUID id) | ||
151 | { | ||
152 | lock (m_agentsInTransit) | ||
153 | return m_agentsInTransit.ContainsKey(id); | ||
154 | } | ||
155 | |||
156 | /// <summary> | ||
157 | /// Removes an agent from the transit state machine. | ||
158 | /// </summary> | ||
159 | /// <param name='id'></param> | ||
160 | /// <returns>true if the agent was flagged as being teleported when this method was called, false otherwise</returns> | ||
161 | internal bool ResetFromTransit(UUID id) | ||
162 | { | ||
163 | lock (m_agentsInTransit) | ||
164 | { | ||
165 | if (m_agentsInTransit.ContainsKey(id)) | ||
166 | { | ||
167 | AgentTransferState state = m_agentsInTransit[id]; | ||
168 | |||
169 | if (state == AgentTransferState.Transferring || state == AgentTransferState.ReceivedAtDestination) | ||
170 | { | ||
171 | // FIXME: For now, we allow exit from any state since a thrown exception in teleport is now guranteed | ||
172 | // to be handled properly - ResetFromTransit() could be invoked at any step along the process | ||
173 | m_log.WarnFormat( | ||
174 | "[ENTITY TRANSFER STATE MACHINE]: Agent with ID {0} should not exit directly from state {1}, should go to {2} state first in {3}", | ||
175 | id, state, AgentTransferState.CleaningUp, m_mod.Scene.RegionInfo.RegionName); | ||
176 | |||
177 | // throw new Exception( | ||
178 | // "Agent with ID {0} cannot exit directly from state {1}, it must go to {2} state first", | ||
179 | // state, AgentTransferState.CleaningUp); | ||
180 | } | ||
181 | |||
182 | m_agentsInTransit.Remove(id); | ||
183 | |||
184 | m_log.DebugFormat( | ||
185 | "[ENTITY TRANSFER STATE MACHINE]: Agent {0} cleared from transit in {1}", | ||
186 | id, m_mod.Scene.RegionInfo.RegionName); | ||
187 | |||
188 | return true; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | m_log.WarnFormat( | ||
193 | "[ENTITY TRANSFER STATE MACHINE]: Agent {0} requested to clear from transit in {1} but was already cleared", | ||
194 | id, m_mod.Scene.RegionInfo.RegionName); | ||
195 | |||
196 | return false; | ||
197 | } | ||
198 | |||
199 | internal bool WaitForAgentArrivedAtDestination(UUID id) | ||
200 | { | ||
201 | if (!m_mod.WaitForAgentArrivedAtDestination) | ||
202 | return true; | ||
203 | |||
204 | lock (m_agentsInTransit) | ||
205 | { | ||
206 | if (!IsInTransit(id)) | ||
207 | throw new Exception( | ||
208 | string.Format( | ||
209 | "Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit", | ||
210 | id, m_mod.Scene.RegionInfo.RegionName)); | ||
211 | |||
212 | AgentTransferState currentState = m_agentsInTransit[id]; | ||
213 | |||
214 | if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination) | ||
215 | throw new Exception( | ||
216 | string.Format( | ||
217 | "Asked to wait for destination callback for agent with ID {0} in {1} but agent is in state {2}", | ||
218 | id, m_mod.Scene.RegionInfo.RegionName, currentState)); | ||
219 | } | ||
220 | |||
221 | int count = 200; | ||
222 | |||
223 | // There should be no race condition here since no other code should be removing the agent transfer or | ||
224 | // changing the state to another other than Transferring => ReceivedAtDestination. | ||
225 | while (m_agentsInTransit[id] != AgentTransferState.ReceivedAtDestination && count-- > 0) | ||
226 | { | ||
227 | // m_log.Debug(" >>> Waiting... " + count); | ||
228 | Thread.Sleep(100); | ||
229 | } | ||
230 | |||
231 | return count > 0; | ||
232 | } | ||
233 | |||
234 | internal void SetAgentArrivedAtDestination(UUID id) | ||
235 | { | ||
236 | lock (m_agentsInTransit) | ||
237 | { | ||
238 | if (!m_agentsInTransit.ContainsKey(id)) | ||
239 | { | ||
240 | m_log.WarnFormat( | ||
241 | "[ENTITY TRANSFER STATE MACHINE]: Region {0} received notification of arrival in destination of agent {1} but no teleport request is active", | ||
242 | m_mod.Scene.RegionInfo.RegionName, id); | ||
243 | |||
244 | return; | ||
245 | } | ||
246 | |||
247 | AgentTransferState currentState = m_agentsInTransit[id]; | ||
248 | |||
249 | if (currentState == AgentTransferState.ReceivedAtDestination) | ||
250 | { | ||
251 | // An anomoly but don't make this an outright failure - destination region could be overzealous in sending notification. | ||
252 | m_log.WarnFormat( | ||
253 | "[ENTITY TRANSFER STATE MACHINE]: Region {0} received notification of arrival in destination of agent {1} but notification has already previously been received", | ||
254 | m_mod.Scene.RegionInfo.RegionName, id); | ||
255 | } | ||
256 | else if (currentState != AgentTransferState.Transferring) | ||
257 | { | ||
258 | m_log.ErrorFormat( | ||
259 | "[ENTITY TRANSFER STATE MACHINE]: Region {0} received notification of arrival in destination of agent {1} but agent is in state {2}", | ||
260 | m_mod.Scene.RegionInfo.RegionName, id, currentState); | ||
261 | |||
262 | return; | ||
263 | } | ||
264 | |||
265 | m_agentsInTransit[id] = AgentTransferState.ReceivedAtDestination; | ||
266 | } | ||
267 | } | ||
268 | } | ||
269 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs index 44ea2b1..7e71fd1 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs | |||
@@ -117,7 +117,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
117 | 117 | ||
118 | protected override GridRegion GetFinalDestination(GridRegion region) | 118 | protected override GridRegion GetFinalDestination(GridRegion region) |
119 | { | 119 | { |
120 | int flags = m_scene.GridService.GetRegionFlags(m_scene.RegionInfo.ScopeID, region.RegionID); | 120 | int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID); |
121 | m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionID, flags); | 121 | m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionID, flags); |
122 | 122 | ||
123 | if ((flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) | 123 | if ((flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) |
@@ -139,7 +139,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
139 | if (base.NeedsClosing(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) | 139 | if (base.NeedsClosing(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) |
140 | return true; | 140 | return true; |
141 | 141 | ||
142 | int flags = m_scene.GridService.GetRegionFlags(m_scene.RegionInfo.ScopeID, reg.RegionID); | 142 | int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID); |
143 | if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) | 143 | if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) |
144 | return true; | 144 | return true; |
145 | 145 | ||
@@ -152,7 +152,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
152 | if (logout) | 152 | if (logout) |
153 | { | 153 | { |
154 | // Log them out of this grid | 154 | // Log them out of this grid |
155 | m_scene.PresenceService.LogoutAgent(sp.ControllingClient.SessionId); | 155 | Scene.PresenceService.LogoutAgent(sp.ControllingClient.SessionId); |
156 | } | 156 | } |
157 | } | 157 | } |
158 | 158 | ||
@@ -161,7 +161,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
161 | m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: CreateAgent {0} {1}", reg.ServerURI, finalDestination.ServerURI); | 161 | m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: CreateAgent {0} {1}", reg.ServerURI, finalDestination.ServerURI); |
162 | reason = string.Empty; | 162 | reason = string.Empty; |
163 | logout = false; | 163 | logout = false; |
164 | int flags = m_scene.GridService.GetRegionFlags(m_scene.RegionInfo.ScopeID, reg.RegionID); | 164 | int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID); |
165 | if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) | 165 | if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) |
166 | { | 166 | { |
167 | // this user is going to another grid | 167 | // this user is going to another grid |
@@ -206,7 +206,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
206 | "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId); | 206 | "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId); |
207 | 207 | ||
208 | // Let's find out if this is a foreign user or a local user | 208 | // Let's find out if this is a foreign user or a local user |
209 | IUserManagement uMan = m_scene.RequestModuleInterface<IUserManagement>(); | 209 | IUserManagement uMan = Scene.RequestModuleInterface<IUserManagement>(); |
210 | if (uMan != null && uMan.IsLocalGridUser(id)) | 210 | if (uMan != null && uMan.IsLocalGridUser(id)) |
211 | { | 211 | { |
212 | // local grid user | 212 | // local grid user |
@@ -268,7 +268,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
268 | return; | 268 | return; |
269 | } | 269 | } |
270 | 270 | ||
271 | GridRegion info = m_scene.GridService.GetRegionByUUID(UUID.Zero, lm.RegionID); | 271 | GridRegion info = Scene.GridService.GetRegionByUUID(UUID.Zero, lm.RegionID); |
272 | 272 | ||
273 | // Local region? | 273 | // Local region? |
274 | if (info != null) | 274 | if (info != null) |
@@ -338,8 +338,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
338 | } | 338 | } |
339 | 339 | ||
340 | // Let's find out if this is a foreign user or a local user | 340 | // Let's find out if this is a foreign user or a local user |
341 | IUserManagement uMan = m_scene.RequestModuleInterface<IUserManagement>(); | 341 | IUserManagement uMan = Scene.RequestModuleInterface<IUserManagement>(); |
342 | // UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, obj.AgentId); | 342 | // UserAccount account = Scene.UserAccountService.GetUserAccount(Scene.RegionInfo.ScopeID, obj.AgentId); |
343 | if (uMan != null && uMan.IsLocalGridUser(obj.AgentId)) | 343 | if (uMan != null && uMan.IsLocalGridUser(obj.AgentId)) |
344 | { | 344 | { |
345 | // local grid user | 345 | // local grid user |