aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Framework/EntityTransfer
diff options
context:
space:
mode:
authorubit2013-04-28 20:40:11 +0200
committerubit2013-04-28 20:40:11 +0200
commit61ea7ee5a94e5e3d33fc77c1c316318850309c42 (patch)
tree1e589fc3b448b580d1cc25b52215ef5ce2d7ae78 /OpenSim/Region/CoreModules/Framework/EntityTransfer
parentMerge branch 'ubitwork' of ssh://3dhosting.de/var/git/careminster into ubitwork (diff)
parentController module for dynamic floaters (WIP) (diff)
downloadopensim-SC-61ea7ee5a94e5e3d33fc77c1c316318850309c42.zip
opensim-SC-61ea7ee5a94e5e3d33fc77c1c316318850309c42.tar.gz
opensim-SC-61ea7ee5a94e5e3d33fc77c1c316318850309c42.tar.bz2
opensim-SC-61ea7ee5a94e5e3d33fc77c1c316318850309c42.tar.xz
Merge branch 'ubitwork' of ssh://3dhosting.de/var/git/careminster into ubitwork
Conflicts: bin/Regions/Regions.ini.example
Diffstat (limited to 'OpenSim/Region/CoreModules/Framework/EntityTransfer')
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs536
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs141
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs6
3 files changed, 538 insertions, 145 deletions
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index ac4d93d..b70aeb7 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -33,6 +33,7 @@ using System.Threading;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Framework.Capabilities; 34using OpenSim.Framework.Capabilities;
35using OpenSim.Framework.Client; 35using OpenSim.Framework.Client;
36using OpenSim.Framework.Monitoring;
36using OpenSim.Region.Framework.Interfaces; 37using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes; 38using OpenSim.Region.Framework.Scenes;
38using OpenSim.Region.Physics.Manager; 39using OpenSim.Region.Physics.Manager;
@@ -66,6 +67,42 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
66 /// </summary> 67 /// </summary>
67 public bool WaitForAgentArrivedAtDestination { get; set; } 68 public bool WaitForAgentArrivedAtDestination { get; set; }
68 69
70 /// <summary>
71 /// If true then we ask the viewer to disable teleport cancellation and ignore teleport requests.
72 /// </summary>
73 /// <remarks>
74 /// This is useful in situations where teleport is very likely to always succeed and we want to avoid a
75 /// situation where avatars can be come 'stuck' due to a failed teleport cancellation. Unfortunately, the
76 /// nature of the teleport protocol makes it extremely difficult (maybe impossible) to make teleport
77 /// cancellation consistently suceed.
78 /// </remarks>
79 public bool DisableInterRegionTeleportCancellation { get; set; }
80
81 /// <summary>
82 /// Number of times inter-region teleport was attempted.
83 /// </summary>
84 private Stat m_interRegionTeleportAttempts;
85
86 /// <summary>
87 /// Number of times inter-region teleport was aborted (due to simultaneous client logout).
88 /// </summary>
89 private Stat m_interRegionTeleportAborts;
90
91 /// <summary>
92 /// Number of times inter-region teleport was successfully cancelled by the client.
93 /// </summary>
94 private Stat m_interRegionTeleportCancels;
95
96 /// <summary>
97 /// Number of times inter-region teleport failed due to server/client/network problems (e.g. viewer failed to
98 /// connect with destination region).
99 /// </summary>
100 /// <remarks>
101 /// This is not necessarily a problem for this simulator - in open-grid/hg conditions, viewer connectivity to
102 /// destination simulator is unknown.
103 /// </remarks>
104 private Stat m_interRegionTeleportFailures;
105
69 protected bool m_Enabled = false; 106 protected bool m_Enabled = false;
70 107
71 public Scene Scene { get; private set; } 108 public Scene Scene { get; private set; }
@@ -80,6 +117,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
80 new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>(); 117 new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>();
81 118
82 private IEventQueue m_eqModule; 119 private IEventQueue m_eqModule;
120 private IRegionCombinerModule m_regionCombinerModule;
83 121
84 #region ISharedRegionModule 122 #region ISharedRegionModule
85 123
@@ -116,6 +154,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
116 IConfig transferConfig = source.Configs["EntityTransfer"]; 154 IConfig transferConfig = source.Configs["EntityTransfer"];
117 if (transferConfig != null) 155 if (transferConfig != null)
118 { 156 {
157 DisableInterRegionTeleportCancellation
158 = transferConfig.GetBoolean("DisableInterRegionTeleportCancellation", false);
159
119 WaitForAgentArrivedAtDestination 160 WaitForAgentArrivedAtDestination
120 = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault); 161 = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault);
121 162
@@ -142,6 +183,60 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
142 183
143 Scene = scene; 184 Scene = scene;
144 185
186 m_interRegionTeleportAttempts =
187 new Stat(
188 "InterRegionTeleportAttempts",
189 "Number of inter-region teleports attempted.",
190 "This does not count attempts which failed due to pre-conditions (e.g. target simulator refused access).\n"
191 + "You can get successfully teleports by subtracting aborts, cancels and teleport failures from this figure.",
192 "",
193 "entitytransfer",
194 Scene.Name,
195 StatType.Push,
196 null,
197 StatVerbosity.Debug);
198
199 m_interRegionTeleportAborts =
200 new Stat(
201 "InterRegionTeleportAborts",
202 "Number of inter-region teleports aborted due to client actions.",
203 "The chief action is simultaneous logout whilst teleporting.",
204 "",
205 "entitytransfer",
206 Scene.Name,
207 StatType.Push,
208 null,
209 StatVerbosity.Debug);
210
211 m_interRegionTeleportCancels =
212 new Stat(
213 "InterRegionTeleportCancels",
214 "Number of inter-region teleports cancelled by the client.",
215 null,
216 "",
217 "entitytransfer",
218 Scene.Name,
219 StatType.Push,
220 null,
221 StatVerbosity.Debug);
222
223 m_interRegionTeleportFailures =
224 new Stat(
225 "InterRegionTeleportFailures",
226 "Number of inter-region teleports that failed due to server/client/network issues.",
227 "This number may not be very helpful in open-grid/hg situations as the network connectivity/quality of destinations is uncontrollable.",
228 "",
229 "entitytransfer",
230 Scene.Name,
231 StatType.Push,
232 null,
233 StatVerbosity.Debug);
234
235 StatsManager.RegisterStat(m_interRegionTeleportAttempts);
236 StatsManager.RegisterStat(m_interRegionTeleportAborts);
237 StatsManager.RegisterStat(m_interRegionTeleportCancels);
238 StatsManager.RegisterStat(m_interRegionTeleportFailures);
239
145 scene.RegisterModuleInterface<IEntityTransferModule>(this); 240 scene.RegisterModuleInterface<IEntityTransferModule>(this);
146 scene.EventManager.OnNewClient += OnNewClient; 241 scene.EventManager.OnNewClient += OnNewClient;
147 } 242 }
@@ -150,11 +245,25 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
150 { 245 {
151 client.OnTeleportHomeRequest += TriggerTeleportHome; 246 client.OnTeleportHomeRequest += TriggerTeleportHome;
152 client.OnTeleportLandmarkRequest += RequestTeleportLandmark; 247 client.OnTeleportLandmarkRequest += RequestTeleportLandmark;
248
249 if (!DisableInterRegionTeleportCancellation)
250 client.OnTeleportCancel += OnClientCancelTeleport;
251
252 client.OnConnectionClosed += OnConnectionClosed;
153 } 253 }
154 254
155 public virtual void Close() {} 255 public virtual void Close() {}
156 256
157 public virtual void RemoveRegion(Scene scene) {} 257 public virtual void RemoveRegion(Scene scene)
258 {
259 if (m_Enabled)
260 {
261 StatsManager.DeregisterStat(m_interRegionTeleportAttempts);
262 StatsManager.DeregisterStat(m_interRegionTeleportAborts);
263 StatsManager.DeregisterStat(m_interRegionTeleportCancels);
264 StatsManager.DeregisterStat(m_interRegionTeleportFailures);
265 }
266 }
158 267
159 public virtual void RegionLoaded(Scene scene) 268 public virtual void RegionLoaded(Scene scene)
160 { 269 {
@@ -162,12 +271,33 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
162 return; 271 return;
163 272
164 m_eqModule = Scene.RequestModuleInterface<IEventQueue>(); 273 m_eqModule = Scene.RequestModuleInterface<IEventQueue>();
274 m_regionCombinerModule = Scene.RequestModuleInterface<IRegionCombinerModule>();
165 } 275 }
166 276
167 #endregion 277 #endregion
168 278
169 #region Agent Teleports 279 #region Agent Teleports
170 280
281 private void OnConnectionClosed(IClientAPI client)
282 {
283 if (client.IsLoggingOut)
284 {
285 m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting);
286
287 m_log.DebugFormat(
288 "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout",
289 client.Name, Scene.Name);
290 }
291 }
292
293 private void OnClientCancelTeleport(IClientAPI client)
294 {
295 m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Cancelling);
296
297 m_log.DebugFormat(
298 "[ENTITY TRANSFER MODULE]: Received teleport cancel request from {0} in {1}", client.Name, Scene.Name);
299 }
300
171 public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) 301 public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags)
172 { 302 {
173 if (sp.Scene.Permissions.IsGridGod(sp.UUID)) 303 if (sp.Scene.Permissions.IsGridGod(sp.UUID))
@@ -179,13 +309,24 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
179 if (!sp.Scene.Permissions.CanTeleport(sp.UUID)) 309 if (!sp.Scene.Permissions.CanTeleport(sp.UUID))
180 return; 310 return;
181 311
182 // Reset animations; the viewer does that in teleports.
183 sp.Animator.ResetAnimations();
184
185 string destinationRegionName = "(not found)"; 312 string destinationRegionName = "(not found)";
186 313
314 // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection
315 // of whether the destination region completes the teleport.
316 if (!m_entityTransferStateMachine.SetInTransit(sp.UUID))
317 {
318 m_log.DebugFormat(
319 "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2}@{3} - agent is already in transit.",
320 sp.Name, sp.UUID, position, regionHandle);
321
322 return;
323 }
324
187 try 325 try
188 { 326 {
327 // Reset animations; the viewer does that in teleports.
328 sp.Animator.ResetAnimations();
329
189 if (regionHandle == sp.Scene.RegionInfo.RegionHandle) 330 if (regionHandle == sp.Scene.RegionInfo.RegionHandle)
190 { 331 {
191 destinationRegionName = sp.Scene.RegionInfo.RegionName; 332 destinationRegionName = sp.Scene.RegionInfo.RegionName;
@@ -194,12 +335,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
194 } 335 }
195 else // Another region possibly in another simulator 336 else // Another region possibly in another simulator
196 { 337 {
197 GridRegion finalDestination; 338 GridRegion finalDestination = null;
198 TeleportAgentToDifferentRegion( 339 try
199 sp, regionHandle, position, lookAt, teleportFlags, out finalDestination); 340 {
200 341 TeleportAgentToDifferentRegion(
201 if (finalDestination != null) 342 sp, regionHandle, position, lookAt, teleportFlags, out finalDestination);
202 destinationRegionName = finalDestination.RegionName; 343 }
344 finally
345 {
346 if (finalDestination != null)
347 destinationRegionName = finalDestination.RegionName;
348 }
203 } 349 }
204 } 350 }
205 catch (Exception e) 351 catch (Exception e)
@@ -209,11 +355,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
209 sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, destinationRegionName, 355 sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, destinationRegionName,
210 e.Message, e.StackTrace); 356 e.Message, e.StackTrace);
211 357
212 // Make sure that we clear the in-transit flag so that future teleport attempts don't always fail.
213 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
214
215 sp.ControllingClient.SendTeleportFailed("Internal error"); 358 sp.ControllingClient.SendTeleportFailed("Internal error");
216 } 359 }
360 finally
361 {
362 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
363 }
217 } 364 }
218 365
219 /// <summary> 366 /// <summary>
@@ -229,23 +376,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
229 "[ENTITY TRANSFER MODULE]: Teleport for {0} to {1} within {2}", 376 "[ENTITY TRANSFER MODULE]: Teleport for {0} to {1} within {2}",
230 sp.Name, position, sp.Scene.RegionInfo.RegionName); 377 sp.Name, position, sp.Scene.RegionInfo.RegionName);
231 378
232 if (!m_entityTransferStateMachine.SetInTransit(sp.UUID))
233 {
234 m_log.DebugFormat(
235 "[ENTITY TRANSFER MODULE]: Ignoring within region teleport request of {0} {1} to {2} - agent is already in transit.",
236 sp.Name, sp.UUID, position);
237
238 return;
239 }
240
241 // Teleport within the same region 379 // Teleport within the same region
242 if (IsOutsideRegion(sp.Scene, position) || position.Z < 0) 380 if (IsOutsideRegion(sp.Scene, position) || position.Z < 0)
243 { 381 {
244 Vector3 emergencyPos = new Vector3(128, 128, 128); 382 Vector3 emergencyPos = new Vector3(128, 128, 128);
245 383
246 m_log.WarnFormat( 384 m_log.WarnFormat(
247 "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}", 385 "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2} in {3}. Substituting {4}",
248 position, sp.Name, sp.UUID, emergencyPos); 386 position, sp.Name, sp.UUID, Scene.Name, emergencyPos);
249 387
250 position = emergencyPos; 388 position = emergencyPos;
251 } 389 }
@@ -286,7 +424,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
286 } 424 }
287 425
288 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); 426 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
289 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
290 } 427 }
291 428
292 /// <summary> 429 /// <summary>
@@ -340,7 +477,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
340 // 477 //
341 // This is it 478 // This is it
342 // 479 //
343 DoTeleport(sp, reg, finalDestination, position, lookAt, teleportFlags); 480 DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags);
344 // 481 //
345 // 482 //
346 // 483 //
@@ -395,27 +532,54 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
395 && Math.Abs(sourceRegion.RegionLocY - destRegion.RegionCoordY) <= MaxTransferDistance; 532 && Math.Abs(sourceRegion.RegionLocY - destRegion.RegionCoordY) <= MaxTransferDistance;
396 } 533 }
397 534
535 /// <summary>
536 /// Wraps DoTeleportInternal() and manages the transfer state.
537 /// </summary>
398 public void DoTeleport( 538 public void DoTeleport(
399 ScenePresence sp, GridRegion reg, GridRegion finalDestination, 539 ScenePresence sp, GridRegion reg, GridRegion finalDestination,
400 Vector3 position, Vector3 lookAt, uint teleportFlags) 540 Vector3 position, Vector3 lookAt, uint teleportFlags)
401 { 541 {
402 // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection 542 // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection
403 // of whether the destination region completes the teleport. 543 // of whether the destination region completes the teleport.
404 m_entityTransferStateMachine.SetInTransit(sp.UUID); 544 if (!m_entityTransferStateMachine.SetInTransit(sp.UUID))
405// if (!m_entityTransferStateMachine.SetInTransit(sp.UUID)) 545 {
406// { 546 m_log.DebugFormat(
407// m_log.DebugFormat( 547 "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2} ({3}) {4}/{5} - agent is already in transit.",
408// "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2} ({3}) {4}/{5} - agent is already in transit.", 548 sp.Name, sp.UUID, reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position);
409// sp.Name, sp.UUID, reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position);
410//
411// return;
412// }
413 549
414 if (reg == null || finalDestination == null) 550 return;
551 }
552
553 try
554 {
555 DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags);
556 }
557 catch (Exception e)
558 {
559 m_log.ErrorFormat(
560 "[ENTITY TRANSFER MODULE]: Exception on teleport of {0} from {1}@{2} to {3}@{4}: {5}{6}",
561 sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, finalDestination.RegionName,
562 e.Message, e.StackTrace);
563
564 sp.ControllingClient.SendTeleportFailed("Internal error");
565 }
566 finally
415 { 567 {
416 sp.ControllingClient.SendTeleportFailed("Unable to locate destination");
417 m_entityTransferStateMachine.ResetFromTransit(sp.UUID); 568 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
569 }
570 }
418 571
572 /// <summary>
573 /// Teleports the agent to another region.
574 /// This method doesn't manage the transfer state; the caller must do that.
575 /// </summary>
576 private void DoTeleportInternal(
577 ScenePresence sp, GridRegion reg, GridRegion finalDestination,
578 Vector3 position, Vector3 lookAt, uint teleportFlags)
579 {
580 if (reg == null || finalDestination == null)
581 {
582 sp.ControllingClient.SendTeleportFailed("Unable to locate destination");
419 return; 583 return;
420 } 584 }
421 585
@@ -435,8 +599,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
435 sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY, 599 sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY,
436 MaxTransferDistance)); 600 MaxTransferDistance));
437 601
438 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
439
440 return; 602 return;
441 } 603 }
442 604
@@ -454,7 +616,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
454 if (endPoint == null || endPoint.Address == null) 616 if (endPoint == null || endPoint.Address == null)
455 { 617 {
456 sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); 618 sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down");
457 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
458 619
459 return; 620 return;
460 } 621 }
@@ -464,19 +625,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
464 "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.", 625 "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.",
465 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName); 626 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName);
466 627
467// if (!sp.ValidateAttachments())
468// {
469// sp.ControllingClient.SendTeleportFailed("Inconsistent attachment state");
470// return;
471// }
472
473 string reason; 628 string reason;
474 string version; 629 string version;
475 if (!Scene.SimulationService.QueryAccess( 630 if (!Scene.SimulationService.QueryAccess(
476 finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out version, out reason)) 631 finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out version, out reason))
477 { 632 {
478 sp.ControllingClient.SendTeleportFailed(reason); 633 sp.ControllingClient.SendTeleportFailed(reason);
479 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
480 634
481 m_log.DebugFormat( 635 m_log.DebugFormat(
482 "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because {3}", 636 "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because {3}",
@@ -485,6 +639,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
485 return; 639 return;
486 } 640 }
487 641
642 // Before this point, teleport 'failure' is due to checkable pre-conditions such as whether the target
643 // simulator can be found and is explicitly prepared to allow access. Therefore, we will not count these
644 // as server attempts.
645 m_interRegionTeleportAttempts.Value++;
646
488 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version); 647 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version);
489 648
490 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from 649 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from
@@ -494,6 +653,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
494 else if (sp.Flying) 653 else if (sp.Flying)
495 teleportFlags |= (uint)TeleportFlags.IsFlying; 654 teleportFlags |= (uint)TeleportFlags.IsFlying;
496 655
656 if (DisableInterRegionTeleportCancellation)
657 teleportFlags |= (uint)TeleportFlags.DisableCancel;
658
497 // At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to 659 // At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to
498 // the viewer. However, it might mean that the viewer does not see the black teleport screen (untested). 660 // the viewer. However, it might mean that the viewer does not see the black teleport screen (untested).
499 sp.ControllingClient.SendTeleportStart(teleportFlags); 661 sp.ControllingClient.SendTeleportStart(teleportFlags);
@@ -530,11 +692,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
530 } 692 }
531 693
532 // Let's create an agent there if one doesn't exist yet. 694 // Let's create an agent there if one doesn't exist yet.
695 // NOTE: logout will always be false for a non-HG teleport.
533 bool logout = false; 696 bool logout = false;
534 if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) 697 if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout))
535 { 698 {
699 m_interRegionTeleportFailures.Value++;
700
536 sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason)); 701 sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason));
537 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
538 702
539 m_log.DebugFormat( 703 m_log.DebugFormat(
540 "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}", 704 "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}",
@@ -543,6 +707,27 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
543 return; 707 return;
544 } 708 }
545 709
710 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
711 {
712 m_interRegionTeleportCancels.Value++;
713
714 m_log.DebugFormat(
715 "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request",
716 sp.Name, finalDestination.RegionName, sp.Scene.Name);
717
718 return;
719 }
720 else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
721 {
722 m_interRegionTeleportAborts.Value++;
723
724 m_log.DebugFormat(
725 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.",
726 sp.Name, finalDestination.RegionName, sp.Scene.Name);
727
728 return;
729 }
730
546 // Past this point we have to attempt clean up if the teleport fails, so update transfer state. 731 // Past this point we have to attempt clean up if the teleport fails, so update transfer state.
547 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); 732 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
548 733
@@ -552,6 +737,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
552 IClientIPEndpoint ipepClient; 737 IClientIPEndpoint ipepClient;
553 if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) 738 if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY))
554 { 739 {
740 m_log.DebugFormat(
741 "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for incoming agent {3} from {4}",
742 finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name);
743
555 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); 744 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent...");
556 #region IP Translation for NAT 745 #region IP Translation for NAT
557 // Uses ipepClient above 746 // Uses ipepClient above
@@ -564,11 +753,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
564 753
565 if (m_eqModule != null) 754 if (m_eqModule != null)
566 { 755 {
756 // The EnableSimulator message makes the client establish a connection with the destination
757 // simulator by sending the initial UseCircuitCode UDP packet to the destination containing the
758 // correct circuit code.
567 m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID); 759 m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID);
568 760
569 // ES makes the client send a UseCircuitCode message to the destination, 761 // XXX: Is this wait necessary? We will always end up waiting on UpdateAgent for the destination
570 // which triggers a bunch of things there. 762 // simulator to confirm that it has established communication with the viewer.
571 // So let's wait
572 Thread.Sleep(200); 763 Thread.Sleep(200);
573 764
574 // At least on LL 3.3.4 for teleports between different regions on the same simulator this appears 765 // At least on LL 3.3.4 for teleports between different regions on the same simulator this appears
@@ -579,6 +770,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
579 } 770 }
580 else 771 else
581 { 772 {
773 // XXX: This is a little misleading since we're information the client of its avatar destination,
774 // which may or may not be a neighbour region of the source region. This path is probably little
775 // used anyway (with EQ being the one used). But it is currently being used for test code.
582 sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); 776 sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint);
583 } 777 }
584 } 778 }
@@ -596,23 +790,66 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
596 790
597 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent..."); 791 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent...");
598 792
793 // We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to
794 // establish th econnection to the destination which makes it return true.
795 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
796 {
797 m_interRegionTeleportAborts.Value++;
798
799 m_log.DebugFormat(
800 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} before UpdateAgent",
801 sp.Name, finalDestination.RegionName, sp.Scene.Name);
802
803 return;
804 }
805
806 // A common teleport failure occurs when we can send CreateAgent to the
807 // destination region but the viewer cannot establish the connection (e.g. due to network issues between
808 // the viewer and the destination). In this case, UpdateAgent timesout after 10 seconds, although then
809 // there's a further 10 second wait whilst we attempt to tell the destination to delete the agent in Fail().
599 if (!UpdateAgent(reg, finalDestination, agent, sp)) 810 if (!UpdateAgent(reg, finalDestination, agent, sp))
600 { 811 {
601 // Region doesn't take it 812 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
813 {
814 m_interRegionTeleportAborts.Value++;
815
816 m_log.DebugFormat(
817 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.",
818 sp.Name, finalDestination.RegionName, sp.Scene.Name);
819
820 return;
821 }
822
602 m_log.WarnFormat( 823 m_log.WarnFormat(
603 "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Returning avatar to source region.", 824 "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Keeping avatar in source region.",
604 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); 825 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName);
605 826
606 Fail(sp, finalDestination, logout); 827 Fail(sp, finalDestination, logout, "Connection between viewer and destination region could not be established.");
607 return; 828 return;
608 } 829 }
609 830
610 sp.ControllingClient.SendTeleportProgress(teleportFlags | (uint)TeleportFlags.DisableCancel, "sending_dest"); 831 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
832 {
833 m_interRegionTeleportCancels.Value++;
834
835 m_log.DebugFormat(
836 "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request",
837 sp.Name, finalDestination.RegionName, sp.Scene.Name);
838
839 CleanupFailedInterRegionTeleport(sp, finalDestination);
840
841 return;
842 }
611 843
612 m_log.DebugFormat( 844 m_log.DebugFormat(
613 "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", 845 "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}",
614 capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); 846 capsPath, sp.Scene.RegionInfo.RegionName, sp.Name);
615 847
848 // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator,
849 // where that neighbour simulator could otherwise request a child agent create on the source which then
850 // closes our existing agent which is still signalled as root.
851 sp.IsChildAgent = true;
852
616 if (m_eqModule != null) 853 if (m_eqModule != null)
617 { 854 {
618 m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); 855 m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID);
@@ -623,19 +860,28 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
623 teleportFlags, capsPath); 860 teleportFlags, capsPath);
624 } 861 }
625 862
626 // Let's set this to true tentatively. This does not trigger OnChildAgent
627 sp.IsChildAgent = true;
628
629 // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which 863 // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which
630 // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation 864 // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation
631 // that the client contacted the destination before we close things here. 865 // that the client contacted the destination before we close things here.
632 if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID)) 866 if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID))
633 { 867 {
868 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
869 {
870 m_interRegionTeleportAborts.Value++;
871
872 m_log.DebugFormat(
873 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after WaitForAgentArrivedAtDestination due to previous client close.",
874 sp.Name, finalDestination.RegionName, sp.Scene.Name);
875
876 return;
877 }
878
634 m_log.WarnFormat( 879 m_log.WarnFormat(
635 "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", 880 "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.",
636 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); 881 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName);
637 882
638 Fail(sp, finalDestination, logout); 883 Fail(sp, finalDestination, logout, "Destination region did not signal teleport completion.");
884
639 return; 885 return;
640 } 886 }
641 887
@@ -658,8 +904,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
658 // Now let's make it officially a child agent 904 // Now let's make it officially a child agent
659 sp.MakeChildAgent(); 905 sp.MakeChildAgent();
660 906
661// sp.Scene.CleanDroppedAttachments();
662
663 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone 907 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
664 908
665 if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) 909 if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
@@ -679,27 +923,21 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
679 // now we have a child agent in this region. 923 // now we have a child agent in this region.
680 sp.Reset(); 924 sp.Reset();
681 } 925 }
682
683 // Commented pending deletion since this method no longer appears to do anything at all
684// // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
685// if (sp.Scene.NeedSceneCacheClear(sp.UUID))
686// {
687// m_log.DebugFormat(
688// "[ENTITY TRANSFER MODULE]: User {0} is going to another region, profile cache removed",
689// sp.UUID);
690// }
691
692 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
693 } 926 }
694 927
695 protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout) 928 /// <summary>
929 /// Clean up an inter-region teleport that did not complete, either because of simulator failure or cancellation.
930 /// </summary>
931 /// <remarks>
932 /// All operations here must be idempotent so that we can call this method at any point in the teleport process
933 /// up until we send the TeleportFinish event quene event to the viewer.
934 /// <remarks>
935 /// <param name='sp'> </param>
936 /// <param name='finalDestination'></param>
937 protected virtual void CleanupFailedInterRegionTeleport(ScenePresence sp, GridRegion finalDestination)
696 { 938 {
697 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); 939 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
698 940
699 // Client never contacted destination. Let's restore everything back
700 sp.ControllingClient.SendTeleportFailed("Problems connecting to destination.");
701
702 // Fail. Reset it back
703 sp.IsChildAgent = false; 941 sp.IsChildAgent = false;
704 ReInstantiateScripts(sp); 942 ReInstantiateScripts(sp);
705 943
@@ -707,10 +945,26 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
707 945
708 // Finally, kill the agent we just created at the destination. 946 // Finally, kill the agent we just created at the destination.
709 Scene.SimulationService.CloseAgent(finalDestination, sp.UUID); 947 Scene.SimulationService.CloseAgent(finalDestination, sp.UUID);
948 }
710 949
711 sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout); 950 /// <summary>
951 /// Signal that the inter-region teleport failed and perform cleanup.
952 /// </summary>
953 /// <param name='sp'></param>
954 /// <param name='finalDestination'></param>
955 /// <param name='logout'></param>
956 /// <param name='reason'>Human readable reason for teleport failure. Will be sent to client.</param>
957 protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout, string reason)
958 {
959 CleanupFailedInterRegionTeleport(sp, finalDestination);
960
961 m_interRegionTeleportFailures.Value++;
962
963 sp.ControllingClient.SendTeleportFailed(
964 string.Format(
965 "Problems connecting to destination {0}, reason: {1}", finalDestination.RegionName, reason));
712 966
713 m_entityTransferStateMachine.ResetFromTransit(sp.UUID); 967 sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout);
714 } 968 }
715 969
716 protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout) 970 protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout)
@@ -761,7 +1015,21 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
761 1015
762 protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY) 1016 protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY)
763 { 1017 {
764 return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY); 1018 if (m_regionCombinerModule != null && m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID))
1019 {
1020 Vector2 swCorner, neCorner;
1021 GetMegaregionViewRange(out swCorner, out neCorner);
1022
1023 m_log.DebugFormat(
1024 "[ENTITY TRANSFER MODULE]: Megaregion view of {0} is from {1} to {2} with new agent check for {3},{4}",
1025 Scene.Name, swCorner, neCorner, newRegionX, newRegionY);
1026
1027 return !(newRegionX >= swCorner.X && newRegionX <= neCorner.X && newRegionY >= swCorner.Y && newRegionY <= neCorner.Y);
1028 }
1029 else
1030 {
1031 return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY);
1032 }
765 } 1033 }
766 1034
767 protected virtual bool NeedsClosing(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg) 1035 protected virtual bool NeedsClosing(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg)
@@ -865,6 +1133,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
865 { 1133 {
866 version = String.Empty; 1134 version = String.Empty;
867 newpos = new Vector3(pos.X, pos.Y, pos.Z); 1135 newpos = new Vector3(pos.X, pos.Y, pos.Z);
1136
1137// m_log.DebugFormat(
1138// "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name);
1139
868 uint neighbourx = scene.RegionInfo.RegionLocX; 1140 uint neighbourx = scene.RegionInfo.RegionLocX;
869 uint neighboury = scene.RegionInfo.RegionLocY; 1141 uint neighboury = scene.RegionInfo.RegionLocY;
870 const float boundaryDistance = 1.7f; 1142 const float boundaryDistance = 1.7f;
@@ -1017,16 +1289,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1017 } 1289 }
1018 1290
1019 1291
1020 public delegate void InformClientToInitateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY, 1292 public delegate void InformClientToInitiateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY,
1021 Vector3 position, 1293 Vector3 position,
1022 Scene initiatingScene); 1294 Scene initiatingScene);
1023 1295
1024 private void InformClientToInitateTeleportToLocation(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene) 1296 private void InformClientToInitiateTeleportToLocation(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene)
1025 { 1297 {
1026 1298
1027 // This assumes that we know what our neighbours are. 1299 // This assumes that we know what our neighbours are.
1028 1300
1029 InformClientToInitateTeleportToLocationDelegate d = InformClientToInitiateTeleportToLocationAsync; 1301 InformClientToInitiateTeleportToLocationDelegate d = InformClientToInitiateTeleportToLocationAsync;
1030 d.BeginInvoke(agent, regionX, regionY, position, initiatingScene, 1302 d.BeginInvoke(agent, regionX, regionY, position, initiatingScene,
1031 InformClientToInitiateTeleportToLocationCompleted, 1303 InformClientToInitiateTeleportToLocationCompleted,
1032 d); 1304 d);
@@ -1036,7 +1308,19 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1036 Scene initiatingScene) 1308 Scene initiatingScene)
1037 { 1309 {
1038 Thread.Sleep(10000); 1310 Thread.Sleep(10000);
1039 1311
1312 m_log.DebugFormat(
1313 "[ENTITY TRANSFER MODULE]: Auto-reteleporting {0} to correct megaregion location {1},{2},{3} from {4}",
1314 agent.Name, regionX, regionY, position, initiatingScene.Name);
1315
1316 agent.Scene.RequestTeleportLocation(
1317 agent.ControllingClient,
1318 Utils.UIntsToLong(regionX * (uint)Constants.RegionSize, regionY * (uint)Constants.RegionSize),
1319 position,
1320 agent.Lookat,
1321 (uint)Constants.TeleportFlags.ViaLocation);
1322
1323 /*
1040 IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>(); 1324 IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>();
1041 if (im != null) 1325 if (im != null)
1042 { 1326 {
@@ -1071,12 +1355,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1071 }); 1355 });
1072 1356
1073 } 1357 }
1358 */
1074 } 1359 }
1075 1360
1076 private void InformClientToInitiateTeleportToLocationCompleted(IAsyncResult iar) 1361 private void InformClientToInitiateTeleportToLocationCompleted(IAsyncResult iar)
1077 { 1362 {
1078 InformClientToInitateTeleportToLocationDelegate icon = 1363 InformClientToInitiateTeleportToLocationDelegate icon =
1079 (InformClientToInitateTeleportToLocationDelegate)iar.AsyncState; 1364 (InformClientToInitiateTeleportToLocationDelegate)iar.AsyncState;
1080 icon.EndInvoke(iar); 1365 icon.EndInvoke(iar);
1081 } 1366 }
1082 1367
@@ -1101,10 +1386,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1101 bool isFlying, string version) 1386 bool isFlying, string version)
1102 { 1387 {
1103 if (!CrossAgentToNewRegionPrep(agent, neighbourRegion)) 1388 if (!CrossAgentToNewRegionPrep(agent, neighbourRegion))
1389 {
1390 m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1104 return agent; 1391 return agent;
1392 }
1105 1393
1106 if (!CrossAgentIntoNewRegionMain(agent, pos, neighbourRegion, isFlying)) 1394 if (!CrossAgentIntoNewRegionMain(agent, pos, neighbourRegion, isFlying))
1395 {
1396 m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1107 return agent; 1397 return agent;
1398 }
1108 1399
1109 CrossAgentToNewRegionPost(agent, pos, neighbourRegion, isFlying, version); 1400 CrossAgentToNewRegionPost(agent, pos, neighbourRegion, isFlying, version);
1110 return agent; 1401 return agent;
@@ -1131,9 +1422,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1131 // region doesn't take it 1422 // region doesn't take it
1132 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); 1423 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp);
1133 1424
1425 m_log.WarnFormat(
1426 "[ENTITY TRANSFER MODULE]: Region {0} would not accept update for agent {1} on cross attempt. Returning to original region.",
1427 neighbourRegion.RegionName, agent.Name);
1428
1134 ReInstantiateScripts(agent); 1429 ReInstantiateScripts(agent);
1135 agent.AddToPhysicalScene(isFlying); 1430 agent.AddToPhysicalScene(isFlying);
1136 m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1137 1431
1138 return false; 1432 return false;
1139 } 1433 }
@@ -1570,6 +1864,37 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1570 } 1864 }
1571 1865
1572 /// <summary> 1866 /// <summary>
1867 /// Gets the range considered in view of this megaregion (assuming this is a megaregion).
1868 /// </summary>
1869 /// <remarks>Expressed in 256m units</remarks>
1870 /// <param name='swCorner'></param>
1871 /// <param name='neCorner'></param>
1872 private void GetMegaregionViewRange(out Vector2 swCorner, out Vector2 neCorner)
1873 {
1874 Border[] northBorders = Scene.NorthBorders.ToArray();
1875 Border[] eastBorders = Scene.EastBorders.ToArray();
1876
1877 Vector2 extent = Vector2.Zero;
1878 for (int i = 0; i < eastBorders.Length; i++)
1879 {
1880 extent.X = (eastBorders[i].BorderLine.Z > extent.X) ? eastBorders[i].BorderLine.Z : extent.X;
1881 }
1882 for (int i = 0; i < northBorders.Length; i++)
1883 {
1884 extent.Y = (northBorders[i].BorderLine.Z > extent.Y) ? northBorders[i].BorderLine.Z : extent.Y;
1885 }
1886
1887 // Loss of fraction on purpose
1888 extent.X = ((int)extent.X / (int)Constants.RegionSize);
1889 extent.Y = ((int)extent.Y / (int)Constants.RegionSize);
1890
1891 swCorner.X = Scene.RegionInfo.RegionLocX - 1;
1892 swCorner.Y = Scene.RegionInfo.RegionLocY - 1;
1893 neCorner.X = Scene.RegionInfo.RegionLocX + extent.X;
1894 neCorner.Y = Scene.RegionInfo.RegionLocY + extent.Y;
1895 }
1896
1897 /// <summary>
1573 /// Return the list of regions that are considered to be neighbours to the given scene. 1898 /// Return the list of regions that are considered to be neighbours to the given scene.
1574 /// </summary> 1899 /// </summary>
1575 /// <param name="pScene"></param> 1900 /// <param name="pScene"></param>
@@ -1581,15 +1906,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1581 Scene pScene = avatar.Scene; 1906 Scene pScene = avatar.Scene;
1582 RegionInfo m_regionInfo = pScene.RegionInfo; 1907 RegionInfo m_regionInfo = pScene.RegionInfo;
1583 1908
1584 Border[] northBorders = pScene.NorthBorders.ToArray();
1585 Border[] southBorders = pScene.SouthBorders.ToArray();
1586 Border[] eastBorders = pScene.EastBorders.ToArray();
1587 Border[] westBorders = pScene.WestBorders.ToArray();
1588
1589 // Leaving this as a "megaregions" computation vs "non-megaregions" computation; it isn't 1909 // Leaving this as a "megaregions" computation vs "non-megaregions" computation; it isn't
1590 // clear what should be done with a "far view" given that megaregions already extended the 1910 // clear what should be done with a "far view" given that megaregions already extended the
1591 // view to include everything in the megaregion 1911 // view to include everything in the megaregion
1592 if (northBorders.Length <= 1 && southBorders.Length <= 1 && eastBorders.Length <= 1 && westBorders.Length <= 1) 1912 if (m_regionCombinerModule == null || !m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID))
1593 { 1913 {
1594 int dd = avatar.DrawDistance < Constants.RegionSize ? (int)Constants.RegionSize : (int)avatar.DrawDistance; 1914 int dd = avatar.DrawDistance < Constants.RegionSize ? (int)Constants.RegionSize : (int)avatar.DrawDistance;
1595 1915
@@ -1607,27 +1927,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1607 } 1927 }
1608 else 1928 else
1609 { 1929 {
1610 Vector2 extent = Vector2.Zero; 1930 Vector2 swCorner, neCorner;
1611 for (int i = 0; i < eastBorders.Length; i++) 1931 GetMegaregionViewRange(out swCorner, out neCorner);
1612 {
1613 extent.X = (eastBorders[i].BorderLine.Z > extent.X) ? eastBorders[i].BorderLine.Z : extent.X;
1614 }
1615 for (int i = 0; i < northBorders.Length; i++)
1616 {
1617 extent.Y = (northBorders[i].BorderLine.Z > extent.Y) ? northBorders[i].BorderLine.Z : extent.Y;
1618 }
1619
1620 // Loss of fraction on purpose
1621 extent.X = ((int)extent.X / (int)Constants.RegionSize) + 1;
1622 extent.Y = ((int)extent.Y / (int)Constants.RegionSize) + 1;
1623
1624 int startX = (int)(pRegionLocX - 1) * (int)Constants.RegionSize;
1625 int startY = (int)(pRegionLocY - 1) * (int)Constants.RegionSize;
1626 1932
1627 int endX = ((int)pRegionLocX + (int)extent.X) * (int)Constants.RegionSize; 1933 List<GridRegion> neighbours
1628 int endY = ((int)pRegionLocY + (int)extent.Y) * (int)Constants.RegionSize; 1934 = pScene.GridService.GetRegionRange(
1935 m_regionInfo.ScopeID,
1936 (int)swCorner.X * (int)Constants.RegionSize,
1937 (int)neCorner.X * (int)Constants.RegionSize,
1938 (int)swCorner.Y * (int)Constants.RegionSize,
1939 (int)neCorner.Y * (int)Constants.RegionSize);
1629 1940
1630 List<GridRegion> neighbours = pScene.GridService.GetRegionRange(m_regionInfo.ScopeID, startX, endX, startY, endY);
1631 neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; }); 1941 neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; });
1632 1942
1633 return neighbours; 1943 return neighbours;
@@ -2048,7 +2358,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
2048 2358
2049 public bool IsInTransit(UUID id) 2359 public bool IsInTransit(UUID id)
2050 { 2360 {
2051 return m_entityTransferStateMachine.IsInTransit(id); 2361 return m_entityTransferStateMachine.GetAgentTransferState(id) != null;
2052 } 2362 }
2053 2363
2054 protected void ReInstantiateScripts(ScenePresence sp) 2364 protected void ReInstantiateScripts(ScenePresence sp)
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs
index 70dd1bc..e903383 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs
@@ -51,10 +51,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
51 /// This is a state machine. 51 /// This is a state machine.
52 /// 52 ///
53 /// [Entry] => Preparing 53 /// [Entry] => Preparing
54 /// Preparing => { Transferring || CleaningUp || [Exit] } 54 /// Preparing => { Transferring || Cancelling || CleaningUp || Aborting || [Exit] }
55 /// Transferring => { ReceivedAtDestination || CleaningUp } 55 /// Transferring => { ReceivedAtDestination || Cancelling || CleaningUp || Aborting }
56 /// ReceivedAtDestination => CleaningUp 56 /// Cancelling => CleaningUp || Aborting
57 /// ReceivedAtDestination => CleaningUp || Aborting
57 /// CleaningUp => [Exit] 58 /// CleaningUp => [Exit]
59 /// Aborting => [Exit]
58 /// 60 ///
59 /// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp 61 /// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp
60 /// However, any state can transition to CleaningUp if the teleport has failed. 62 /// However, any state can transition to CleaningUp if the teleport has failed.
@@ -64,7 +66,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
64 Preparing, // The agent is being prepared for transfer 66 Preparing, // The agent is being prepared for transfer
65 Transferring, // The agent is in the process of being transferred to a destination 67 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 68 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 69 CleaningUp, // The agent is being changed to child/removed after a transfer
70 Cancelling, // The user has cancelled the teleport but we have yet to act upon this.
71 Aborting // The transfer is aborting. Unlike Cancelling, no compensating actions should be performed
68 } 72 }
69 73
70 /// <summary> 74 /// <summary>
@@ -115,42 +119,114 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
115 /// <param name='newState'></param> 119 /// <param name='newState'></param>
116 /// <returns></returns> 120 /// <returns></returns>
117 /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception> 121 /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception>
118 internal void UpdateInTransit(UUID id, AgentTransferState newState) 122 internal bool UpdateInTransit(UUID id, AgentTransferState newState)
119 { 123 {
124 bool transitionOkay = false;
125
126 // We don't want to throw an exception on cancel since this can come it at any time.
127 bool failIfNotOkay = true;
128
129 // Should be a failure message if failure is not okay.
130 string failureMessage = null;
131
132 AgentTransferState? oldState = null;
133
120 lock (m_agentsInTransit) 134 lock (m_agentsInTransit)
121 { 135 {
122 // Illegal to try and update an agent that's not actually in transit. 136 // Illegal to try and update an agent that's not actually in transit.
123 if (!m_agentsInTransit.ContainsKey(id)) 137 if (!m_agentsInTransit.ContainsKey(id))
124 throw new Exception( 138 {
125 string.Format( 139 if (newState != AgentTransferState.Cancelling && newState != AgentTransferState.Aborting)
126 "Agent with ID {0} is not registered as in transit in {1}", 140 failureMessage = string.Format(
127 id, m_mod.Scene.RegionInfo.RegionName)); 141 "Agent with ID {0} is not registered as in transit in {1}",
128 142 id, m_mod.Scene.RegionInfo.RegionName);
129 AgentTransferState oldState = m_agentsInTransit[id]; 143 else
144 failIfNotOkay = false;
145 }
146 else
147 {
148 oldState = m_agentsInTransit[id];
130 149
131 bool transitionOkay = false; 150 if (newState == AgentTransferState.Aborting)
151 {
152 transitionOkay = true;
153 }
154 else if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp)
155 {
156 transitionOkay = true;
157 }
158 else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing)
159 {
160 transitionOkay = true;
161 }
162 else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring)
163 {
164 transitionOkay = true;
165 }
166 else
167 {
168 if (newState == AgentTransferState.Cancelling
169 && (oldState == AgentTransferState.Preparing || oldState == AgentTransferState.Transferring))
170 {
171 transitionOkay = true;
172 }
173 else
174 {
175 failIfNotOkay = false;
176 }
177 }
132 178
133 if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) 179 if (!transitionOkay)
134 transitionOkay = true; 180 failureMessage
135 else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing) 181 = string.Format(
136 transitionOkay = true; 182 "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}",
137 else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring) 183 id, oldState, newState, m_mod.Scene.RegionInfo.RegionName);
138 transitionOkay = true; 184 }
139 185
140 if (transitionOkay) 186 if (transitionOkay)
187 {
141 m_agentsInTransit[id] = newState; 188 m_agentsInTransit[id] = newState;
142 else 189
143 throw new Exception( 190// m_log.DebugFormat(
144 string.Format( 191// "[ENTITY TRANSFER STATE MACHINE]: Changed agent with id {0} from state {1} to {2} in {3}",
145 "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}", 192// id, oldState, newState, m_mod.Scene.Name);
146 id, oldState, newState, m_mod.Scene.RegionInfo.RegionName)); 193 }
194 else if (failIfNotOkay)
195 {
196 throw new Exception(failureMessage);
197 }
198// else
199// {
200// if (oldState != null)
201// m_log.DebugFormat(
202// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} from state {1} to {2} in {3}",
203// id, oldState, newState, m_mod.Scene.Name);
204// else
205// m_log.DebugFormat(
206// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} to state {1} in {2} since agent not in transit",
207// id, newState, m_mod.Scene.Name);
208// }
147 } 209 }
210
211 return transitionOkay;
148 } 212 }
149 213
150 internal bool IsInTransit(UUID id) 214 /// <summary>
215 /// Gets the current agent transfer state.
216 /// </summary>
217 /// <returns>Null if the agent is not in transit</returns>
218 /// <param name='id'>
219 /// Identifier.
220 /// </param>
221 internal AgentTransferState? GetAgentTransferState(UUID id)
151 { 222 {
152 lock (m_agentsInTransit) 223 lock (m_agentsInTransit)
153 return m_agentsInTransit.ContainsKey(id); 224 {
225 if (!m_agentsInTransit.ContainsKey(id))
226 return null;
227 else
228 return m_agentsInTransit[id];
229 }
154 } 230 }
155 231
156 /// <summary> 232 /// <summary>
@@ -203,14 +279,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
203 279
204 lock (m_agentsInTransit) 280 lock (m_agentsInTransit)
205 { 281 {
206 if (!IsInTransit(id)) 282 AgentTransferState? currentState = GetAgentTransferState(id);
283
284 if (currentState == null)
207 throw new Exception( 285 throw new Exception(
208 string.Format( 286 string.Format(
209 "Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit", 287 "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)); 288 id, m_mod.Scene.RegionInfo.RegionName));
211 289
212 AgentTransferState currentState = m_agentsInTransit[id];
213
214 if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination) 290 if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination)
215 throw new Exception( 291 throw new Exception(
216 string.Format( 292 string.Format(
@@ -222,8 +298,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
222 298
223 // There should be no race condition here since no other code should be removing the agent transfer or 299 // 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. 300 // changing the state to another other than Transferring => ReceivedAtDestination.
225 while (m_agentsInTransit[id] != AgentTransferState.ReceivedAtDestination && count-- > 0) 301
302 while (count-- > 0)
226 { 303 {
304 lock (m_agentsInTransit)
305 {
306 if (m_agentsInTransit[id] == AgentTransferState.ReceivedAtDestination)
307 break;
308 }
309
227// m_log.Debug(" >>> Waiting... " + count); 310// m_log.Debug(" >>> Waiting... " + count);
228 Thread.Sleep(100); 311 Thread.Sleep(100);
229 } 312 }
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
index f3a0b01..d372c0e 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
@@ -199,7 +199,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
199 199
200 public override void RemoveRegion(Scene scene) 200 public override void RemoveRegion(Scene scene)
201 { 201 {
202 base.AddRegion(scene); 202 base.RemoveRegion(scene);
203 203
204 if (m_Enabled) 204 if (m_Enabled)
205 scene.UnregisterModuleInterface<IUserAgentVerificationModule>(this); 205 scene.UnregisterModuleInterface<IUserAgentVerificationModule>(this);
@@ -212,11 +212,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
212 protected override GridRegion GetFinalDestination(GridRegion region) 212 protected override GridRegion GetFinalDestination(GridRegion region)
213 { 213 {
214 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID); 214 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID);
215 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionID, flags); 215 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionName, flags);
216 216
217 if ((flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0) 217 if ((flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
218 { 218 {
219 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region {0} is hyperlink", region.RegionID); 219 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region is hyperlink");
220 GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID); 220 GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID);
221 if (real_destination != null) 221 if (real_destination != null)
222 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: GetFinalDestination serveruri -> {0}", real_destination.ServerURI); 222 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: GetFinalDestination serveruri -> {0}", real_destination.ServerURI);