diff options
author | Justin Clark-Casey (justincc) | 2012-05-28 23:06:00 +0100 |
---|---|---|
committer | Justin Clark-Casey (justincc) | 2012-05-28 23:06:00 +0100 |
commit | 79f3ce2e9f3563165ee640f917f944ec4b370ac7 (patch) | |
tree | bab16f99077a5145ca87d16e753d973b14527361 /OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | |
parent | If handling the failure of teleport, move agent state to CleaningUp when we s... (diff) | |
download | opensim-SC_OLD-79f3ce2e9f3563165ee640f917f944ec4b370ac7.zip opensim-SC_OLD-79f3ce2e9f3563165ee640f917f944ec4b370ac7.tar.gz opensim-SC_OLD-79f3ce2e9f3563165ee640f917f944ec4b370ac7.tar.bz2 opensim-SC_OLD-79f3ce2e9f3563165ee640f917f944ec4b370ac7.tar.xz |
refactor: factor out entity transfer state machine into a separate class to make code more analyzable
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | 284 |
1 files changed, 53 insertions, 231 deletions
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index ab1424d..f2926ea 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 | ||
@@ -290,15 +272,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
290 | sp.Velocity = Vector3.Zero; | 272 | sp.Velocity = Vector3.Zero; |
291 | sp.Teleport(position); | 273 | sp.Teleport(position); |
292 | 274 | ||
293 | UpdateInTransit(sp.UUID, AgentTransferState.ReceivedAtDestination); | 275 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.ReceivedAtDestination); |
294 | 276 | ||
295 | foreach (SceneObjectGroup grp in sp.GetAttachments()) | 277 | foreach (SceneObjectGroup grp in sp.GetAttachments()) |
296 | { | 278 | { |
297 | sp.Scene.EventManager.TriggerOnScriptChangedEvent(grp.LocalId, (uint)Changed.TELEPORT); | 279 | sp.Scene.EventManager.TriggerOnScriptChangedEvent(grp.LocalId, (uint)Changed.TELEPORT); |
298 | } | 280 | } |
299 | 281 | ||
300 | UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); | 282 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); |
301 | ResetFromTransit(sp.UUID); | 283 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); |
302 | } | 284 | } |
303 | 285 | ||
304 | /// <summary> | 286 | /// <summary> |
@@ -316,7 +298,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
316 | { | 298 | { |
317 | uint x = 0, y = 0; | 299 | uint x = 0, y = 0; |
318 | Utils.LongToUInts(regionHandle, out x, out y); | 300 | Utils.LongToUInts(regionHandle, out x, out y); |
319 | GridRegion reg = m_scene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y); | 301 | GridRegion reg = Scene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y); |
320 | 302 | ||
321 | if (reg != null) | 303 | if (reg != null) |
322 | { | 304 | { |
@@ -398,7 +380,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
398 | { | 380 | { |
399 | // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection | 381 | // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection |
400 | // of whether the destination region completes the teleport. | 382 | // of whether the destination region completes the teleport. |
401 | if (!SetInTransit(sp.UUID)) | 383 | if (!m_entityTransferStateMachine.SetInTransit(sp.UUID)) |
402 | { | 384 | { |
403 | m_log.DebugFormat( | 385 | m_log.DebugFormat( |
404 | "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2} ({3}) {4}/{5} - agent is already in transit.", | 386 | "[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 | |||
410 | if (reg == null || finalDestination == null) | 392 | if (reg == null || finalDestination == null) |
411 | { | 393 | { |
412 | sp.ControllingClient.SendTeleportFailed("Unable to locate destination"); | 394 | sp.ControllingClient.SendTeleportFailed("Unable to locate destination"); |
413 | ResetFromTransit(sp.UUID); | 395 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); |
414 | 396 | ||
415 | return; | 397 | return; |
416 | } | 398 | } |
@@ -431,7 +413,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
431 | sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY, | 413 | sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY, |
432 | MaxTransferDistance)); | 414 | MaxTransferDistance)); |
433 | 415 | ||
434 | ResetFromTransit(sp.UUID); | 416 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); |
435 | 417 | ||
436 | return; | 418 | return; |
437 | } | 419 | } |
@@ -451,7 +433,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
451 | if (endPoint.Address == null) | 433 | if (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,12 +661,12 @@ 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 | { |
687 | UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); | 669 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); |
688 | 670 | ||
689 | // Client never contacted destination. Let's restore everything back | 671 | // Client never contacted destination. Let's restore everything back |
690 | sp.ControllingClient.SendTeleportFailed("Problems connecting to destination."); | 672 | sp.ControllingClient.SendTeleportFailed("Problems connecting to destination."); |
@@ -696,17 +678,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
696 | EnableChildAgents(sp); | 678 | EnableChildAgents(sp); |
697 | 679 | ||
698 | // Finally, kill the agent we just created at the destination. | 680 | // Finally, kill the agent we just created at the destination. |
699 | m_scene.SimulationService.CloseAgent(finalDestination, sp.UUID); | 681 | Scene.SimulationService.CloseAgent(finalDestination, sp.UUID); |
700 | 682 | ||
701 | sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout); | 683 | sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout); |
702 | 684 | ||
703 | ResetFromTransit(sp.UUID); | 685 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); |
704 | } | 686 | } |
705 | 687 | ||
706 | 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) |
707 | { | 689 | { |
708 | logout = false; | 690 | logout = false; |
709 | bool success = m_scene.SimulationService.CreateAgent(finalDestination, agentCircuit, teleportFlags, out reason); | 691 | bool success = Scene.SimulationService.CreateAgent(finalDestination, agentCircuit, teleportFlags, out reason); |
710 | 692 | ||
711 | if (success) | 693 | if (success) |
712 | sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout); | 694 | sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout); |
@@ -716,7 +698,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
716 | 698 | ||
717 | protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent) | 699 | protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent) |
718 | { | 700 | { |
719 | return m_scene.SimulationService.UpdateAgent(finalDestination, agent); | 701 | return Scene.SimulationService.UpdateAgent(finalDestination, agent); |
720 | } | 702 | } |
721 | 703 | ||
722 | protected virtual void SetCallbackURL(AgentData agent, RegionInfo region) | 704 | protected virtual void SetCallbackURL(AgentData agent, RegionInfo region) |
@@ -779,7 +761,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
779 | /// <param name="position"></param> | 761 | /// <param name="position"></param> |
780 | public virtual void RequestTeleportLandmark(IClientAPI remoteClient, AssetLandmark lm) | 762 | public virtual void RequestTeleportLandmark(IClientAPI remoteClient, AssetLandmark lm) |
781 | { | 763 | { |
782 | GridRegion info = m_scene.GridService.GetRegionByUUID(UUID.Zero, lm.RegionID); | 764 | GridRegion info = Scene.GridService.GetRegionByUUID(UUID.Zero, lm.RegionID); |
783 | 765 | ||
784 | if (info == null) | 766 | if (info == null) |
785 | { | 767 | { |
@@ -800,12 +782,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
800 | m_log.DebugFormat( | 782 | m_log.DebugFormat( |
801 | "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId); | 783 | "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId); |
802 | 784 | ||
803 | //OpenSim.Services.Interfaces.PresenceInfo pinfo = m_scene.PresenceService.GetAgent(client.SessionId); | 785 | //OpenSim.Services.Interfaces.PresenceInfo pinfo = Scene.PresenceService.GetAgent(client.SessionId); |
804 | GridUserInfo uinfo = m_scene.GridUserService.GetGridUserInfo(client.AgentId.ToString()); | 786 | GridUserInfo uinfo = Scene.GridUserService.GetGridUserInfo(client.AgentId.ToString()); |
805 | 787 | ||
806 | if (uinfo != null) | 788 | if (uinfo != null) |
807 | { | 789 | { |
808 | GridRegion regionInfo = m_scene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID); | 790 | GridRegion regionInfo = Scene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID); |
809 | if (regionInfo == null) | 791 | if (regionInfo == null) |
810 | { | 792 | { |
811 | // can't find the Home region: Tell viewer and abort | 793 | // can't find the Home region: Tell viewer and abort |
@@ -1114,7 +1096,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1114 | 1096 | ||
1115 | try | 1097 | try |
1116 | { | 1098 | { |
1117 | SetInTransit(agent.UUID); | 1099 | m_entityTransferStateMachine.SetInTransit(agent.UUID); |
1118 | 1100 | ||
1119 | ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize)); | 1101 | ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize)); |
1120 | 1102 | ||
@@ -1144,16 +1126,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1144 | cAgent.CallbackURI = String.Empty; | 1126 | cAgent.CallbackURI = String.Empty; |
1145 | 1127 | ||
1146 | // Beyond this point, extra cleanup is needed beyond removing transit state | 1128 | // Beyond this point, extra cleanup is needed beyond removing transit state |
1147 | UpdateInTransit(agent.UUID, AgentTransferState.Transferring); | 1129 | m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.Transferring); |
1148 | 1130 | ||
1149 | if (!m_scene.SimulationService.UpdateAgent(neighbourRegion, cAgent)) | 1131 | if (!m_scene.SimulationService.UpdateAgent(neighbourRegion, cAgent)) |
1150 | { | 1132 | { |
1151 | // region doesn't take it | 1133 | // region doesn't take it |
1152 | UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); | 1134 | m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); |
1153 | 1135 | ||
1154 | ReInstantiateScripts(agent); | 1136 | ReInstantiateScripts(agent); |
1155 | agent.AddToPhysicalScene(isFlying); | 1137 | agent.AddToPhysicalScene(isFlying); |
1156 | ResetFromTransit(agent.UUID); | 1138 | m_entityTransferStateMachine.ResetFromTransit(agent.UUID); |
1157 | 1139 | ||
1158 | return agent; | 1140 | return agent; |
1159 | } | 1141 | } |
@@ -1191,16 +1173,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1191 | } | 1173 | } |
1192 | 1174 | ||
1193 | // SUCCESS! | 1175 | // SUCCESS! |
1194 | UpdateInTransit(agent.UUID, AgentTransferState.ReceivedAtDestination); | 1176 | m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.ReceivedAtDestination); |
1195 | 1177 | ||
1196 | // Unlike a teleport, here we do not wait for the destination region to confirm the receipt. | 1178 | // Unlike a teleport, here we do not wait for the destination region to confirm the receipt. |
1197 | UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); | 1179 | m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); |
1198 | 1180 | ||
1199 | agent.MakeChildAgent(); | 1181 | agent.MakeChildAgent(); |
1200 | 1182 | ||
1201 | // FIXME: Possibly this should occur lower down after other commands to close other agents, | 1183 | // FIXME: Possibly this should occur lower down after other commands to close other agents, |
1202 | // but not sure yet what the side effects would be. | 1184 | // but not sure yet what the side effects would be. |
1203 | ResetFromTransit(agent.UUID); | 1185 | m_entityTransferStateMachine.ResetFromTransit(agent.UUID); |
1204 | 1186 | ||
1205 | // now we have a child agent in this region. Request all interesting data about other (root) agents | 1187 | // now we have a child agent in this region. Request all interesting data about other (root) agents |
1206 | agent.SendOtherAgentsAvatarDataToMe(); | 1188 | agent.SendOtherAgentsAvatarDataToMe(); |
@@ -1675,41 +1657,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1675 | 1657 | ||
1676 | #endregion | 1658 | #endregion |
1677 | 1659 | ||
1678 | |||
1679 | #region Agent Arrived | 1660 | #region Agent Arrived |
1661 | |||
1680 | public void AgentArrivedAtDestination(UUID id) | 1662 | public void AgentArrivedAtDestination(UUID id) |
1681 | { | 1663 | { |
1682 | lock (m_agentsInTransit) | 1664 | m_entityTransferStateMachine.SetAgentArrivedAtDestination(id); |
1683 | { | ||
1684 | if (!m_agentsInTransit.ContainsKey(id)) | ||
1685 | { | ||
1686 | m_log.WarnFormat( | ||
1687 | "[ENTITY TRANSFER MODULE]: Region {0} received notification of arrival in destination scene of agent {1} but no teleport request is active", | ||
1688 | m_scene.RegionInfo.RegionName, id); | ||
1689 | |||
1690 | return; | ||
1691 | } | ||
1692 | |||
1693 | AgentTransferState currentState = m_agentsInTransit[id]; | ||
1694 | |||
1695 | if (currentState == AgentTransferState.ReceivedAtDestination) | ||
1696 | { | ||
1697 | // An anomoly but don't make this an outright failure - destination region could be overzealous in sending notification. | ||
1698 | m_log.WarnFormat( | ||
1699 | "[ENTITY TRANSFER MODULE]: Region {0} received notification of arrival in destination scene of agent {1} but notification has already previously been received", | ||
1700 | m_scene.RegionInfo.RegionName, id); | ||
1701 | } | ||
1702 | else if (currentState != AgentTransferState.Transferring) | ||
1703 | { | ||
1704 | m_log.ErrorFormat( | ||
1705 | "[ENTITY TRANSFER MODULE]: Region {0} received notification of arrival in destination scene of agent {1} but agent is in transfer state {2}", | ||
1706 | m_scene.RegionInfo.RegionName, id, currentState); | ||
1707 | |||
1708 | return; | ||
1709 | } | ||
1710 | |||
1711 | m_agentsInTransit[id] = AgentTransferState.ReceivedAtDestination; | ||
1712 | } | ||
1713 | } | 1665 | } |
1714 | 1666 | ||
1715 | #endregion | 1667 | #endregion |
@@ -1979,8 +1931,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1979 | //// And the new channel... | 1931 | //// And the new channel... |
1980 | //if (m_interregionCommsOut != null) | 1932 | //if (m_interregionCommsOut != null) |
1981 | // successYN = m_interregionCommsOut.SendCreateObject(newRegionHandle, grp, true); | 1933 | // successYN = m_interregionCommsOut.SendCreateObject(newRegionHandle, grp, true); |
1982 | if (m_scene.SimulationService != null) | 1934 | if (Scene.SimulationService != null) |
1983 | successYN = m_scene.SimulationService.CreateObject(destination, newPosition, grp, true); | 1935 | successYN = Scene.SimulationService.CreateObject(destination, newPosition, grp, true); |
1984 | 1936 | ||
1985 | if (successYN) | 1937 | if (successYN) |
1986 | { | 1938 | { |
@@ -2051,139 +2003,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2051 | 2003 | ||
2052 | #region Misc | 2004 | #region Misc |
2053 | 2005 | ||
2054 | private bool WaitForCallback(UUID id) | ||
2055 | { | ||
2056 | lock (m_agentsInTransit) | ||
2057 | { | ||
2058 | if (!IsInTransit(id)) | ||
2059 | throw new Exception( | ||
2060 | string.Format( | ||
2061 | "Asked to wait for destination callback for agent with ID {0} but it is not in transit")); | ||
2062 | |||
2063 | AgentTransferState currentState = m_agentsInTransit[id]; | ||
2064 | |||
2065 | if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination) | ||
2066 | throw new Exception( | ||
2067 | string.Format( | ||
2068 | "Asked to wait for destination callback for agent with ID {0} but it is in state {1}", | ||
2069 | currentState)); | ||
2070 | } | ||
2071 | |||
2072 | int count = 200; | ||
2073 | |||
2074 | // There should be no race condition here since no other code should be removing the agent transfer or | ||
2075 | // changing the state to another other than Transferring => ReceivedAtDestination. | ||
2076 | while (m_agentsInTransit[id] != AgentTransferState.ReceivedAtDestination && count-- > 0) | ||
2077 | { | ||
2078 | // m_log.Debug(" >>> Waiting... " + count); | ||
2079 | Thread.Sleep(100); | ||
2080 | } | ||
2081 | |||
2082 | return count > 0; | ||
2083 | } | ||
2084 | |||
2085 | /// <summary> | ||
2086 | /// Set that an agent is in transit. | ||
2087 | /// </summary> | ||
2088 | /// <param name='id'>The ID of the agent being teleported</param> | ||
2089 | /// <returns>true if the agent was not already in transit, false if it was</returns> | ||
2090 | private bool SetInTransit(UUID id) | ||
2091 | { | ||
2092 | lock (m_agentsInTransit) | ||
2093 | { | ||
2094 | if (!m_agentsInTransit.ContainsKey(id)) | ||
2095 | { | ||
2096 | m_agentsInTransit[id] = AgentTransferState.Preparing; | ||
2097 | return true; | ||
2098 | } | ||
2099 | } | ||
2100 | |||
2101 | return false; | ||
2102 | } | ||
2103 | |||
2104 | /// <summary> | ||
2105 | /// Updates the state of an agent that is already in transit. | ||
2106 | /// </summary> | ||
2107 | /// <param name='id'></param> | ||
2108 | /// <param name='newState'></param> | ||
2109 | /// <returns></returns> | ||
2110 | /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception> | ||
2111 | private void UpdateInTransit(UUID id, AgentTransferState newState) | ||
2112 | { | ||
2113 | lock (m_agentsInTransit) | ||
2114 | { | ||
2115 | // Illegal to try and update an agent that's not actually in transit. | ||
2116 | if (!m_agentsInTransit.ContainsKey(id)) | ||
2117 | throw new Exception(string.Format("Agent with ID {0} is not registered as in transit", id)); | ||
2118 | |||
2119 | AgentTransferState oldState = m_agentsInTransit[id]; | ||
2120 | |||
2121 | bool transitionOkay = false; | ||
2122 | |||
2123 | if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) | ||
2124 | transitionOkay = true; | ||
2125 | else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing) | ||
2126 | transitionOkay = true; | ||
2127 | else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring) | ||
2128 | transitionOkay = true; | ||
2129 | |||
2130 | if (transitionOkay) | ||
2131 | m_agentsInTransit[id] = newState; | ||
2132 | else | ||
2133 | throw new Exception( | ||
2134 | string.Format( | ||
2135 | "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2}", | ||
2136 | id, oldState, newState)); | ||
2137 | } | ||
2138 | } | ||
2139 | |||
2140 | public bool IsInTransit(UUID id) | 2006 | public bool IsInTransit(UUID id) |
2141 | { | 2007 | { |
2142 | lock (m_agentsInTransit) | 2008 | return m_entityTransferStateMachine.IsInTransit(id); |
2143 | return m_agentsInTransit.ContainsKey(id); | ||
2144 | } | ||
2145 | |||
2146 | /// <summary> | ||
2147 | /// Removes an agent from the transit state machine. | ||
2148 | /// </summary> | ||
2149 | /// <param name='id'></param> | ||
2150 | /// <returns>true if the agent was flagged as being teleported when this method was called, false otherwise</returns> | ||
2151 | private bool ResetFromTransit(UUID id) | ||
2152 | { | ||
2153 | lock (m_agentsInTransit) | ||
2154 | { | ||
2155 | if (m_agentsInTransit.ContainsKey(id)) | ||
2156 | { | ||
2157 | AgentTransferState state = m_agentsInTransit[id]; | ||
2158 | |||
2159 | if (state == AgentTransferState.Transferring || state == AgentTransferState.ReceivedAtDestination) | ||
2160 | { | ||
2161 | // FIXME: For now, we allow exit from any state since a thrown exception in teleport is now guranteed | ||
2162 | // to be handled properly - ResetFromTransit() could be invoked at any step along the process | ||
2163 | m_log.WarnFormat( | ||
2164 | "[ENTITY TRANSFER MODULE]: Agent with ID {0} should not exit directly from state {1}, should go to {2} state first", | ||
2165 | id, state, AgentTransferState.CleaningUp); | ||
2166 | |||
2167 | // throw new Exception( | ||
2168 | // "Agent with ID {0} cannot exit directly from state {1}, it must go to {2} state first", | ||
2169 | // state, AgentTransferState.CleaningUp); | ||
2170 | } | ||
2171 | |||
2172 | m_agentsInTransit.Remove(id); | ||
2173 | |||
2174 | m_log.DebugFormat( | ||
2175 | "[ENTITY TRANSFER MODULE]: Agent {0} cleared from transit in {1}", | ||
2176 | id, m_scene.RegionInfo.RegionName); | ||
2177 | |||
2178 | return true; | ||
2179 | } | ||
2180 | } | ||
2181 | |||
2182 | m_log.WarnFormat( | ||
2183 | "[ENTITY TRANSFER MODULE]: Agent {0} requested to clear from transit in {1} but was already cleared.", | ||
2184 | id, m_scene.RegionInfo.RegionName); | ||
2185 | |||
2186 | return false; | ||
2187 | } | 2009 | } |
2188 | 2010 | ||
2189 | protected void ReInstantiateScripts(ScenePresence sp) | 2011 | protected void ReInstantiateScripts(ScenePresence sp) |