diff options
Diffstat (limited to 'OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs')
-rw-r--r-- | OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | 1709 |
1 files changed, 866 insertions, 843 deletions
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 1b4b5e6..2334e0b 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | |||
@@ -54,9 +54,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
54 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 54 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
55 | private static readonly string LogHeader = "[ENTITY TRANSFER MODULE]"; | 55 | private static readonly string LogHeader = "[ENTITY TRANSFER MODULE]"; |
56 | 56 | ||
57 | public const int DefaultMaxTransferDistance = 4095; | ||
57 | public const bool WaitForAgentArrivedAtDestinationDefault = true; | 58 | public const bool WaitForAgentArrivedAtDestinationDefault = true; |
58 | 59 | ||
59 | /// <summary> | 60 | /// <summary> |
61 | /// The maximum distance, in standard region units (256m) that an agent is allowed to transfer. | ||
62 | /// </summary> | ||
63 | public int MaxTransferDistance { get; set; } | ||
64 | |||
65 | /// <summary> | ||
60 | /// If true then on a teleport, the source region waits for a callback from the destination region. If | 66 | /// If true then on a teleport, the source region waits for a callback from the destination region. If |
61 | /// a callback fails to arrive within a set time then the user is pulled back into the source region. | 67 | /// a callback fails to arrive within a set time then the user is pulled back into the source region. |
62 | /// </summary> | 68 | /// </summary> |
@@ -66,9 +72,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
66 | /// If true then we ask the viewer to disable teleport cancellation and ignore teleport requests. | 72 | /// If true then we ask the viewer to disable teleport cancellation and ignore teleport requests. |
67 | /// </summary> | 73 | /// </summary> |
68 | /// <remarks> | 74 | /// <remarks> |
69 | /// This is useful in situations where teleport is very likely to always succeed and we want to avoid a | 75 | /// This is useful in situations where teleport is very likely to always succeed and we want to avoid a |
70 | /// situation where avatars can be come 'stuck' due to a failed teleport cancellation. Unfortunately, the | 76 | /// situation where avatars can be come 'stuck' due to a failed teleport cancellation. Unfortunately, the |
71 | /// nature of the teleport protocol makes it extremely difficult (maybe impossible) to make teleport | 77 | /// nature of the teleport protocol makes it extremely difficult (maybe impossible) to make teleport |
72 | /// cancellation consistently suceed. | 78 | /// cancellation consistently suceed. |
73 | /// </remarks> | 79 | /// </remarks> |
74 | public bool DisableInterRegionTeleportCancellation { get; set; } | 80 | public bool DisableInterRegionTeleportCancellation { get; set; } |
@@ -130,7 +136,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
130 | { | 136 | { |
131 | if (m_idCache.TryGetValue(pRegionHandle, out m_banUntil)) | 137 | if (m_idCache.TryGetValue(pRegionHandle, out m_banUntil)) |
132 | { | 138 | { |
133 | if (DateTime.Now < m_banUntil) | 139 | if (DateTime.UtcNow < m_banUntil) |
134 | { | 140 | { |
135 | ret = true; | 141 | ret = true; |
136 | } | 142 | } |
@@ -141,13 +147,19 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
141 | // Add this agent in this region as a banned person | 147 | // Add this agent in this region as a banned person |
142 | public void Add(ulong pRegionHandle, UUID pAgentID) | 148 | public void Add(ulong pRegionHandle, UUID pAgentID) |
143 | { | 149 | { |
150 | this.Add(pRegionHandle, pAgentID, 45, 15); | ||
151 | } | ||
152 | |||
153 | public void Add(ulong pRegionHandle, UUID pAgentID, double newTime, double extendTime) | ||
154 | { | ||
144 | if (!m_bannedRegions.TryGetValue(pAgentID, out m_idCache)) | 155 | if (!m_bannedRegions.TryGetValue(pAgentID, out m_idCache)) |
145 | { | 156 | { |
146 | m_idCache = new ExpiringCache<ulong, DateTime>(); | 157 | m_idCache = new ExpiringCache<ulong, DateTime>(); |
147 | m_bannedRegions.Add(pAgentID, m_idCache, TimeSpan.FromSeconds(45)); | 158 | m_bannedRegions.Add(pAgentID, m_idCache, TimeSpan.FromSeconds(newTime)); |
148 | } | 159 | } |
149 | m_idCache.Add(pRegionHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15)); | 160 | m_idCache.Add(pRegionHandle, DateTime.UtcNow + TimeSpan.FromSeconds(extendTime), extendTime); |
150 | } | 161 | } |
162 | |||
151 | // Remove the agent from the region's banned list | 163 | // Remove the agent from the region's banned list |
152 | public void Remove(ulong pRegionHandle, UUID pAgentID) | 164 | public void Remove(ulong pRegionHandle, UUID pAgentID) |
153 | { | 165 | { |
@@ -157,10 +169,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
157 | } | 169 | } |
158 | } | 170 | } |
159 | } | 171 | } |
172 | |||
160 | private BannedRegionCache m_bannedRegionCache = new BannedRegionCache(); | 173 | private BannedRegionCache m_bannedRegionCache = new BannedRegionCache(); |
161 | 174 | ||
162 | private IEventQueue m_eqModule; | 175 | private IEventQueue m_eqModule; |
163 | private IRegionCombinerModule m_regionCombinerModule; | ||
164 | 176 | ||
165 | #region ISharedRegionModule | 177 | #region ISharedRegionModule |
166 | 178 | ||
@@ -209,11 +221,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
209 | IConfig transferConfig = source.Configs["EntityTransfer"]; | 221 | IConfig transferConfig = source.Configs["EntityTransfer"]; |
210 | if (transferConfig != null) | 222 | if (transferConfig != null) |
211 | { | 223 | { |
212 | DisableInterRegionTeleportCancellation | 224 | DisableInterRegionTeleportCancellation |
213 | = transferConfig.GetBoolean("DisableInterRegionTeleportCancellation", false); | 225 | = transferConfig.GetBoolean("DisableInterRegionTeleportCancellation", false); |
214 | 226 | ||
215 | WaitForAgentArrivedAtDestination | 227 | WaitForAgentArrivedAtDestination |
216 | = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault); | 228 | = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault); |
229 | |||
230 | MaxTransferDistance = transferConfig.GetInt("max_distance", DefaultMaxTransferDistance); | ||
231 | } | ||
232 | else | ||
233 | { | ||
234 | MaxTransferDistance = DefaultMaxTransferDistance; | ||
217 | } | 235 | } |
218 | 236 | ||
219 | m_entityTransferStateMachine = new EntityTransferStateMachine(this); | 237 | m_entityTransferStateMachine = new EntityTransferStateMachine(this); |
@@ -232,7 +250,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
232 | 250 | ||
233 | Scene = scene; | 251 | Scene = scene; |
234 | 252 | ||
235 | m_interRegionTeleportAttempts = | 253 | m_interRegionTeleportAttempts = |
236 | new Stat( | 254 | new Stat( |
237 | "InterRegionTeleportAttempts", | 255 | "InterRegionTeleportAttempts", |
238 | "Number of inter-region teleports attempted.", | 256 | "Number of inter-region teleports attempted.", |
@@ -245,7 +263,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
245 | null, | 263 | null, |
246 | StatVerbosity.Debug); | 264 | StatVerbosity.Debug); |
247 | 265 | ||
248 | m_interRegionTeleportAborts = | 266 | m_interRegionTeleportAborts = |
249 | new Stat( | 267 | new Stat( |
250 | "InterRegionTeleportAborts", | 268 | "InterRegionTeleportAborts", |
251 | "Number of inter-region teleports aborted due to client actions.", | 269 | "Number of inter-region teleports aborted due to client actions.", |
@@ -257,7 +275,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
257 | null, | 275 | null, |
258 | StatVerbosity.Debug); | 276 | StatVerbosity.Debug); |
259 | 277 | ||
260 | m_interRegionTeleportCancels = | 278 | m_interRegionTeleportCancels = |
261 | new Stat( | 279 | new Stat( |
262 | "InterRegionTeleportCancels", | 280 | "InterRegionTeleportCancels", |
263 | "Number of inter-region teleports cancelled by the client.", | 281 | "Number of inter-region teleports cancelled by the client.", |
@@ -269,7 +287,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
269 | null, | 287 | null, |
270 | StatVerbosity.Debug); | 288 | StatVerbosity.Debug); |
271 | 289 | ||
272 | m_interRegionTeleportFailures = | 290 | m_interRegionTeleportFailures = |
273 | new Stat( | 291 | new Stat( |
274 | "InterRegionTeleportFailures", | 292 | "InterRegionTeleportFailures", |
275 | "Number of inter-region teleports that failed due to server/client/network issues.", | 293 | "Number of inter-region teleports that failed due to server/client/network issues.", |
@@ -303,7 +321,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
303 | 321 | ||
304 | public virtual void Close() {} | 322 | public virtual void Close() {} |
305 | 323 | ||
306 | public virtual void RemoveRegion(Scene scene) | 324 | public virtual void RemoveRegion(Scene scene) |
307 | { | 325 | { |
308 | if (m_Enabled) | 326 | if (m_Enabled) |
309 | { | 327 | { |
@@ -320,7 +338,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
320 | return; | 338 | return; |
321 | 339 | ||
322 | m_eqModule = Scene.RequestModuleInterface<IEventQueue>(); | 340 | m_eqModule = Scene.RequestModuleInterface<IEventQueue>(); |
323 | m_regionCombinerModule = Scene.RequestModuleInterface<IRegionCombinerModule>(); | ||
324 | } | 341 | } |
325 | 342 | ||
326 | #endregion | 343 | #endregion |
@@ -332,7 +349,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
332 | if (client.IsLoggingOut && m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting)) | 349 | if (client.IsLoggingOut && m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting)) |
333 | { | 350 | { |
334 | m_log.DebugFormat( | 351 | m_log.DebugFormat( |
335 | "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout", | 352 | "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout", |
336 | client.Name, Scene.Name); | 353 | client.Name, Scene.Name); |
337 | } | 354 | } |
338 | } | 355 | } |
@@ -354,7 +371,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
354 | teleportFlags |= (uint)TeleportFlags.Godlike; | 371 | teleportFlags |= (uint)TeleportFlags.Godlike; |
355 | } | 372 | } |
356 | 373 | ||
357 | if (!sp.Scene.Permissions.CanTeleport(sp.UUID)) | 374 | else if (!sp.Scene.Permissions.CanTeleport(sp.UUID)) |
358 | return; | 375 | return; |
359 | 376 | ||
360 | string destinationRegionName = "(not found)"; | 377 | string destinationRegionName = "(not found)"; |
@@ -374,17 +391,27 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
374 | 391 | ||
375 | try | 392 | try |
376 | { | 393 | { |
377 | // Reset animations; the viewer does that in teleports. | ||
378 | sp.Animator.ResetAnimations(); | ||
379 | 394 | ||
380 | if (regionHandle == sp.Scene.RegionInfo.RegionHandle) | 395 | if (regionHandle == sp.Scene.RegionInfo.RegionHandle) |
381 | { | 396 | { |
397 | if(!sp.AllowMovement) | ||
398 | { | ||
399 | sp.ControllingClient.SendTeleportFailed("You are frozen"); | ||
400 | m_entityTransferStateMachine.ResetFromTransit(sp.UUID); | ||
401 | return; | ||
402 | } | ||
403 | |||
404 | // Reset animations; the viewer does that in teleports. | ||
405 | sp.Animator.ResetAnimations(); | ||
382 | destinationRegionName = sp.Scene.RegionInfo.RegionName; | 406 | destinationRegionName = sp.Scene.RegionInfo.RegionName; |
383 | 407 | ||
384 | TeleportAgentWithinRegion(sp, position, lookAt, teleportFlags); | 408 | TeleportAgentWithinRegion(sp, position, lookAt, teleportFlags); |
385 | } | 409 | } |
386 | else // Another region possibly in another simulator | 410 | else // Another region possibly in another simulator |
387 | { | 411 | { |
412 | // Reset animations; the viewer does that in teleports. | ||
413 | sp.Animator.ResetAnimations(); | ||
414 | |||
388 | GridRegion finalDestination = null; | 415 | GridRegion finalDestination = null; |
389 | try | 416 | try |
390 | { | 417 | { |
@@ -400,12 +427,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
400 | } | 427 | } |
401 | catch (Exception e) | 428 | catch (Exception e) |
402 | { | 429 | { |
430 | |||
403 | m_log.ErrorFormat( | 431 | m_log.ErrorFormat( |
404 | "[ENTITY TRANSFER MODULE]: Exception on teleport of {0} from {1}@{2} to {3}@{4}: {5}{6}", | 432 | "[ENTITY TRANSFER MODULE]: Exception on teleport of {0} from {1}@{2} to {3}@{4}: {5}{6}", |
405 | sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, destinationRegionName, | 433 | sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, destinationRegionName, |
406 | e.Message, e.StackTrace); | 434 | e.Message, e.StackTrace); |
407 | 435 | if(sp != null && sp.ControllingClient != null && !sp.IsDeleted) | |
408 | sp.ControllingClient.SendTeleportFailed("Internal error"); | 436 | sp.ControllingClient.SendTeleportFailed("Internal error"); |
409 | } | 437 | } |
410 | finally | 438 | finally |
411 | { | 439 | { |
@@ -438,17 +466,25 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
438 | position = emergencyPos; | 466 | position = emergencyPos; |
439 | } | 467 | } |
440 | 468 | ||
469 | // Check Default Location (Also See ScenePresence.CompleteMovement) | ||
470 | if (position.X == 128f && position.Y == 128f && position.Z == 22.5f) | ||
471 | position = sp.Scene.RegionInfo.DefaultLandingPoint; | ||
472 | |||
441 | // TODO: Get proper AVG Height | 473 | // TODO: Get proper AVG Height |
442 | float localAVHeight = 1.56f; | 474 | float localHalfAVHeight = 0.8f; |
475 | if (sp.Appearance != null) | ||
476 | localHalfAVHeight = sp.Appearance.AvatarHeight / 2; | ||
477 | |||
443 | float posZLimit = 22; | 478 | float posZLimit = 22; |
444 | 479 | ||
445 | // TODO: Check other Scene HeightField | 480 | // TODO: Check other Scene HeightField |
446 | posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y]; | 481 | posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y]; |
447 | 482 | ||
448 | float newPosZ = posZLimit + localAVHeight; | 483 | posZLimit += localHalfAVHeight + 0.1f; |
449 | if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) | 484 | |
485 | if ((position.Z < posZLimit) && !(Single.IsInfinity(posZLimit) || Single.IsNaN(posZLimit))) | ||
450 | { | 486 | { |
451 | position.Z = newPosZ; | 487 | position.Z = posZLimit; |
452 | } | 488 | } |
453 | 489 | ||
454 | if (sp.Flying) | 490 | if (sp.Flying) |
@@ -457,9 +493,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
457 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); | 493 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); |
458 | 494 | ||
459 | sp.ControllingClient.SendTeleportStart(teleportFlags); | 495 | sp.ControllingClient.SendTeleportStart(teleportFlags); |
496 | lookAt.Z = 0f; | ||
497 | |||
498 | if(Math.Abs(lookAt.X) < 0.01f && Math.Abs(lookAt.Y) < 0.01f) | ||
499 | { | ||
500 | lookAt.X = 1.0f; | ||
501 | lookAt.Y = 0; | ||
502 | } | ||
460 | 503 | ||
461 | sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); | 504 | sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); |
462 | sp.TeleportFlags = (Constants.TeleportFlags)teleportFlags; | 505 | sp.TeleportFlags = (Constants.TeleportFlags)teleportFlags; |
506 | sp.RotateToLookAt(lookAt); | ||
463 | sp.Velocity = Vector3.Zero; | 507 | sp.Velocity = Vector3.Zero; |
464 | sp.Teleport(position); | 508 | sp.Teleport(position); |
465 | 509 | ||
@@ -494,15 +538,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
494 | { | 538 | { |
495 | string homeURI = Scene.GetAgentHomeURI(sp.ControllingClient.AgentId); | 539 | string homeURI = Scene.GetAgentHomeURI(sp.ControllingClient.AgentId); |
496 | 540 | ||
497 | string message; | 541 | string reason = String.Empty; |
498 | finalDestination = GetFinalDestination(reg, sp.ControllingClient.AgentId, homeURI, out message); | 542 | finalDestination = GetFinalDestination(reg, sp.ControllingClient.AgentId, homeURI, out reason); |
499 | 543 | ||
500 | if (finalDestination == null) | 544 | if (finalDestination == null) |
501 | { | 545 | { |
502 | m_log.WarnFormat( "{0} Final destination is having problems. Unable to teleport {1} {2}: {3}", | 546 | m_log.WarnFormat( "{0} Final destination is having problems. Unable to teleport {1} {2}: {3}", |
503 | LogHeader, sp.Name, sp.UUID, message); | 547 | LogHeader, sp.Name, sp.UUID, reason); |
504 | 548 | ||
505 | sp.ControllingClient.SendTeleportFailed(message); | 549 | sp.ControllingClient.SendTeleportFailed(reason); |
506 | return; | 550 | return; |
507 | } | 551 | } |
508 | 552 | ||
@@ -515,17 +559,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
515 | return; | 559 | return; |
516 | } | 560 | } |
517 | 561 | ||
518 | // Validate assorted conditions | ||
519 | string reason = string.Empty; | ||
520 | if (!ValidateGenericConditions(sp, reg, finalDestination, teleportFlags, out reason)) | 562 | if (!ValidateGenericConditions(sp, reg, finalDestination, teleportFlags, out reason)) |
521 | { | 563 | { |
522 | sp.ControllingClient.SendTeleportFailed(reason); | 564 | sp.ControllingClient.SendTeleportFailed(reason); |
523 | return; | 565 | return; |
524 | } | 566 | } |
525 | 567 | ||
526 | if (message != null) | ||
527 | sp.ControllingClient.SendAgentAlertMessage(message, true); | ||
528 | |||
529 | // | 568 | // |
530 | // This is it | 569 | // This is it |
531 | // | 570 | // |
@@ -547,9 +586,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
547 | Util.RegionHandleToRegionLoc(regionHandle, out regX, out regY); | 586 | Util.RegionHandleToRegionLoc(regionHandle, out regX, out regY); |
548 | 587 | ||
549 | MapBlockData block = new MapBlockData(); | 588 | MapBlockData block = new MapBlockData(); |
550 | block.X = (ushort)regX; | 589 | block.X = (ushort)(regX); |
551 | block.Y = (ushort)regY; | 590 | block.Y = (ushort)(regY); |
552 | block.Access = (byte)SimAccess.Down; | 591 | block.Access = (byte)SimAccess.Down; // == not there |
553 | 592 | ||
554 | List<MapBlockData> blocks = new List<MapBlockData>(); | 593 | List<MapBlockData> blocks = new List<MapBlockData>(); |
555 | blocks.Add(block); | 594 | blocks.Add(block); |
@@ -565,12 +604,22 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
565 | uint x = 0, y = 0; | 604 | uint x = 0, y = 0; |
566 | Util.RegionHandleToWorldLoc(regionHandle, out x, out y); | 605 | Util.RegionHandleToWorldLoc(regionHandle, out x, out y); |
567 | 606 | ||
607 | GridRegion reg; | ||
608 | |||
609 | // handle legacy HG. linked regions are mapped into y = 0 and have no size information | ||
610 | // so we can only search by base handle | ||
611 | if( y == 0) | ||
612 | { | ||
613 | reg = gridService.GetRegionByPosition(scope, (int)x, (int)y); | ||
614 | return reg; | ||
615 | } | ||
616 | |||
568 | // Compute the world location we're teleporting to | 617 | // Compute the world location we're teleporting to |
569 | double worldX = (double)x + position.X; | 618 | double worldX = (double)x + position.X; |
570 | double worldY = (double)y + position.Y; | 619 | double worldY = (double)y + position.Y; |
571 | 620 | ||
572 | // Find the region that contains the position | 621 | // Find the region that contains the position |
573 | GridRegion reg = GetRegionContainingWorldLocation(gridService, scope, worldX, worldY); | 622 | reg = GetRegionContainingWorldLocation(gridService, scope, worldX, worldY); |
574 | 623 | ||
575 | if (reg != null) | 624 | if (reg != null) |
576 | { | 625 | { |
@@ -589,6 +638,28 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
589 | return true; | 638 | return true; |
590 | } | 639 | } |
591 | 640 | ||
641 | /// <summary> | ||
642 | /// Determines whether this instance is within the max transfer distance. | ||
643 | /// </summary> | ||
644 | /// <param name="sourceRegion"></param> | ||
645 | /// <param name="destRegion"></param> | ||
646 | /// <returns> | ||
647 | /// <c>true</c> if this instance is within max transfer distance; otherwise, <c>false</c>. | ||
648 | /// </returns> | ||
649 | private bool IsWithinMaxTeleportDistance(RegionInfo sourceRegion, GridRegion destRegion) | ||
650 | { | ||
651 | if(MaxTransferDistance == 0) | ||
652 | return true; | ||
653 | |||
654 | // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Source co-ords are x={0} y={1}", curRegionX, curRegionY); | ||
655 | // | ||
656 | // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final dest is x={0} y={1} {2}@{3}", | ||
657 | // destRegionX, destRegionY, finalDestination.RegionID, finalDestination.ServerURI); | ||
658 | |||
659 | // Insanely, RegionLoc on RegionInfo is the 256m map co-ord whilst GridRegion.RegionLoc is the raw meters position. | ||
660 | return Math.Abs(sourceRegion.RegionLocX - destRegion.RegionCoordX) <= MaxTransferDistance | ||
661 | && Math.Abs(sourceRegion.RegionLocY - destRegion.RegionCoordY) <= MaxTransferDistance; | ||
662 | } | ||
592 | 663 | ||
593 | /// <summary> | 664 | /// <summary> |
594 | /// Wraps DoTeleportInternal() and manages the transfer state. | 665 | /// Wraps DoTeleportInternal() and manages the transfer state. |
@@ -607,7 +678,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
607 | sp.ControllingClient.SendTeleportFailed("Agent is already in transit."); | 678 | sp.ControllingClient.SendTeleportFailed("Agent is already in transit."); |
608 | return; | 679 | return; |
609 | } | 680 | } |
610 | 681 | ||
611 | try | 682 | try |
612 | { | 683 | { |
613 | DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags); | 684 | DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags); |
@@ -650,10 +721,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
650 | 721 | ||
651 | RegionInfo sourceRegion = sp.Scene.RegionInfo; | 722 | RegionInfo sourceRegion = sp.Scene.RegionInfo; |
652 | 723 | ||
724 | if (!IsWithinMaxTeleportDistance(sourceRegion, finalDestination)) | ||
725 | { | ||
726 | sp.ControllingClient.SendTeleportFailed( | ||
727 | string.Format( | ||
728 | "Can't teleport to {0} ({1},{2}) from {3} ({4},{5}), destination is more than {6} regions way", | ||
729 | finalDestination.RegionName, finalDestination.RegionCoordX, finalDestination.RegionCoordY, | ||
730 | sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY, | ||
731 | MaxTransferDistance)); | ||
653 | 732 | ||
654 | uint newRegionX, newRegionY, oldRegionX, oldRegionY; | 733 | return; |
655 | Util.RegionHandleToRegionLoc(reg.RegionHandle, out newRegionX, out newRegionY); | 734 | } |
656 | Util.RegionHandleToRegionLoc(sp.Scene.RegionInfo.RegionHandle, out oldRegionX, out oldRegionY); | ||
657 | 735 | ||
658 | ulong destinationHandle = finalDestination.RegionHandle; | 736 | ulong destinationHandle = finalDestination.RegionHandle; |
659 | 737 | ||
@@ -663,8 +741,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
663 | IPEndPoint endPoint = finalDestination.ExternalEndPoint; | 741 | IPEndPoint endPoint = finalDestination.ExternalEndPoint; |
664 | if (endPoint == null || endPoint.Address == null) | 742 | if (endPoint == null || endPoint.Address == null) |
665 | { | 743 | { |
666 | sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); | 744 | sp.ControllingClient.SendTeleportFailed("Could not resolve destination Address"); |
667 | |||
668 | return; | 745 | return; |
669 | } | 746 | } |
670 | 747 | ||
@@ -694,7 +771,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
694 | m_interRegionTeleportAttempts.Value++; | 771 | m_interRegionTeleportAttempts.Value++; |
695 | 772 | ||
696 | m_log.DebugFormat( | 773 | m_log.DebugFormat( |
697 | "[ENTITY TRANSFER MODULE]: {0} transfer protocol version to {1} is {2} / {3}", | 774 | "[ENTITY TRANSFER MODULE]: {0} transfer protocol version to {1} is {2} / {3}", |
698 | sp.Scene.Name, finalDestination.RegionName, ctx.OutboundVersion, ctx.InboundVersion); | 775 | sp.Scene.Name, finalDestination.RegionName, ctx.OutboundVersion, ctx.InboundVersion); |
699 | 776 | ||
700 | // Fixing a bug where teleporting while sitting results in the avatar ending up removed from | 777 | // Fixing a bug where teleporting while sitting results in the avatar ending up removed from |
@@ -704,27 +781,25 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
704 | else if (sp.Flying) | 781 | else if (sp.Flying) |
705 | teleportFlags |= (uint)TeleportFlags.IsFlying; | 782 | teleportFlags |= (uint)TeleportFlags.IsFlying; |
706 | 783 | ||
784 | sp.IsInLocalTransit = finalDestination.RegionLocY != 0; // HG | ||
785 | sp.IsInTransit = true; | ||
786 | |||
787 | |||
707 | if (DisableInterRegionTeleportCancellation) | 788 | if (DisableInterRegionTeleportCancellation) |
708 | teleportFlags |= (uint)TeleportFlags.DisableCancel; | 789 | teleportFlags |= (uint)TeleportFlags.DisableCancel; |
709 | 790 | ||
710 | // At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to | 791 | // At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to |
711 | // the viewer. However, it might mean that the viewer does not see the black teleport screen (untested). | 792 | // the viewer. However, it might mean that the viewer does not see the black teleport screen (untested). |
712 | sp.ControllingClient.SendTeleportStart(teleportFlags); | 793 | sp.ControllingClient.SendTeleportStart(teleportFlags); |
713 | 794 | ||
714 | // the avatar.Close below will clear the child region list. We need this below for (possibly) | ||
715 | // closing the child agents, so save it here (we need a copy as it is Clear()-ed). | ||
716 | //List<ulong> childRegions = avatar.KnownRegionHandles; | ||
717 | // Compared to ScenePresence.CrossToNewRegion(), there's no obvious code to handle a teleport | ||
718 | // failure at this point (unlike a border crossing failure). So perhaps this can never fail | ||
719 | // once we reach here... | ||
720 | //avatar.Scene.RemoveCapsHandler(avatar.UUID); | ||
721 | |||
722 | AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); | 795 | AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); |
723 | AgentCircuitData agentCircuit = sp.ControllingClient.RequestClientInfo(); | 796 | AgentCircuitData agentCircuit = sp.ControllingClient.RequestClientInfo(); |
724 | agentCircuit.startpos = position; | 797 | agentCircuit.startpos = position; |
725 | agentCircuit.child = true; | 798 | agentCircuit.child = true; |
799 | |||
726 | agentCircuit.Appearance = new AvatarAppearance(); | 800 | agentCircuit.Appearance = new AvatarAppearance(); |
727 | agentCircuit.Appearance.PackLegacyWearables = true; | 801 | agentCircuit.Appearance.AvatarHeight = sp.Appearance.AvatarHeight; |
802 | |||
728 | if (currentAgentCircuit != null) | 803 | if (currentAgentCircuit != null) |
729 | { | 804 | { |
730 | agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs; | 805 | agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs; |
@@ -735,36 +810,64 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
735 | agentCircuit.Id0 = currentAgentCircuit.Id0; | 810 | agentCircuit.Id0 = currentAgentCircuit.Id0; |
736 | } | 811 | } |
737 | 812 | ||
738 | // if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) | 813 | uint newRegionX, newRegionY, oldRegionX, oldRegionY; |
739 | float dist = (float)Math.Max(sp.Scene.DefaultDrawDistance, | 814 | Util.RegionHandleToRegionLoc(destinationHandle, out newRegionX, out newRegionY); |
740 | (float)Math.Max(sp.Scene.RegionInfo.RegionSizeX, sp.Scene.RegionInfo.RegionSizeY)); | 815 | Util.RegionHandleToRegionLoc(sourceRegion.RegionHandle, out oldRegionX, out oldRegionY); |
741 | if (NeedsNewAgent(dist, oldRegionX, newRegionX, oldRegionY, newRegionY)) | 816 | int oldSizeX = (int)sourceRegion.RegionSizeX; |
817 | int oldSizeY = (int)sourceRegion.RegionSizeY; | ||
818 | int newSizeX = finalDestination.RegionSizeX; | ||
819 | int newSizeY = finalDestination.RegionSizeY; | ||
820 | |||
821 | bool OutSideViewRange = NeedsNewAgent(sp.RegionViewDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, | ||
822 | oldSizeX, oldSizeY, newSizeX, newSizeY); | ||
823 | |||
824 | if (OutSideViewRange) | ||
742 | { | 825 | { |
743 | // brand new agent, let's create a new caps seed | 826 | m_log.DebugFormat( |
827 | "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} size {3},{4} needs new child agent for agent {5} from {6}", | ||
828 | finalDestination.RegionName, newRegionX, newRegionY,newSizeX, newSizeY, sp.Name, Scene.Name); | ||
829 | |||
830 | //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); | ||
744 | agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); | 831 | agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); |
745 | } | 832 | } |
833 | else | ||
834 | { | ||
835 | agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle); | ||
836 | if (agentCircuit.CapsPath == null) | ||
837 | agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); | ||
838 | } | ||
746 | 839 | ||
747 | // We're going to fallback to V1 if the destination gives us anything smaller than 0.2 | 840 | // We're going to fallback to V1 if the destination gives us anything smaller than 0.2 |
748 | if (ctx.OutboundVersion >= 0.2f) | 841 | if (ctx.OutboundVersion >= 0.2f) |
749 | TransferAgent_V2(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, ctx, out reason); | 842 | TransferAgent_V2(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, OutSideViewRange , ctx, out reason); |
750 | else | 843 | else |
751 | TransferAgent_V1(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, ctx, out reason); | 844 | TransferAgent_V1(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, OutSideViewRange, ctx, out reason); |
752 | } | 845 | } |
753 | 846 | ||
754 | private void TransferAgent_V1(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination, | 847 | private void TransferAgent_V1(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination, |
755 | IPEndPoint endPoint, uint teleportFlags, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, EntityTransferContext ctx, out string reason) | 848 | IPEndPoint endPoint, uint teleportFlags, bool OutSideViewRange, EntityTransferContext ctx, out string reason) |
756 | { | 849 | { |
757 | ulong destinationHandle = finalDestination.RegionHandle; | 850 | ulong destinationHandle = finalDestination.RegionHandle; |
758 | AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); | 851 | AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); |
759 | 852 | ||
760 | m_log.DebugFormat( | 853 | m_log.DebugFormat( |
761 | "[ENTITY TRANSFER MODULE]: Using TP V1 for {0} going from {1} to {2}", | 854 | "[ENTITY TRANSFER MODULE]: Using TP V1 for {0} going from {1} to {2}", |
762 | sp.Name, Scene.Name, finalDestination.RegionName); | 855 | sp.Name, Scene.Name, finalDestination.RegionName); |
763 | 856 | ||
764 | // Let's create an agent there if one doesn't exist yet. | 857 | string capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); |
858 | List<ulong> childRegionsToClose = sp.GetChildAgentsToClose(destinationHandle, finalDestination.RegionSizeX, finalDestination.RegionSizeY); | ||
859 | if(agentCircuit.ChildrenCapSeeds != null) | ||
860 | { | ||
861 | foreach(ulong handler in childRegionsToClose) | ||
862 | { | ||
863 | agentCircuit.ChildrenCapSeeds.Remove(handler); | ||
864 | } | ||
865 | } | ||
866 | |||
867 | // Let's create an agent there if one doesn't exist yet. | ||
765 | // NOTE: logout will always be false for a non-HG teleport. | 868 | // NOTE: logout will always be false for a non-HG teleport. |
766 | bool logout = false; | 869 | bool logout = false; |
767 | if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) | 870 | if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, ctx, out reason, out logout)) |
768 | { | 871 | { |
769 | m_interRegionTeleportFailures.Value++; | 872 | m_interRegionTeleportFailures.Value++; |
770 | 873 | ||
@@ -773,7 +876,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
773 | sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); | 876 | sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); |
774 | 877 | ||
775 | sp.ControllingClient.SendTeleportFailed(reason); | 878 | sp.ControllingClient.SendTeleportFailed(reason); |
776 | 879 | sp.IsInTransit = false; | |
777 | return; | 880 | return; |
778 | } | 881 | } |
779 | 882 | ||
@@ -784,7 +887,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
784 | m_log.DebugFormat( | 887 | m_log.DebugFormat( |
785 | "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request", | 888 | "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request", |
786 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | 889 | sp.Name, finalDestination.RegionName, sp.Scene.Name); |
787 | 890 | sp.IsInTransit = false; | |
788 | return; | 891 | return; |
789 | } | 892 | } |
790 | else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) | 893 | else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) |
@@ -794,7 +897,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
794 | m_log.DebugFormat( | 897 | m_log.DebugFormat( |
795 | "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.", | 898 | "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.", |
796 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | 899 | sp.Name, finalDestination.RegionName, sp.Scene.Name); |
797 | 900 | sp.IsInTransit = false; | |
798 | return; | 901 | return; |
799 | } | 902 | } |
800 | 903 | ||
@@ -802,28 +905,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
802 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); | 905 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); |
803 | 906 | ||
804 | // OK, it got this agent. Let's close some child agents | 907 | // OK, it got this agent. Let's close some child agents |
805 | sp.CloseChildAgents(newRegionX, newRegionY); | ||
806 | 908 | ||
807 | IClientIPEndpoint ipepClient; | 909 | if (OutSideViewRange) |
808 | string capsPath = String.Empty; | ||
809 | float dist = (float)Math.Max(sp.Scene.DefaultDrawDistance, | ||
810 | (float)Math.Max(sp.Scene.RegionInfo.RegionSizeX, sp.Scene.RegionInfo.RegionSizeY)); | ||
811 | if (NeedsNewAgent(dist, oldRegionX, newRegionX, oldRegionY, newRegionY)) | ||
812 | { | 910 | { |
813 | m_log.DebugFormat( | ||
814 | "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for incoming agent {3} from {4}", | ||
815 | finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name); | ||
816 | |||
817 | //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); | ||
818 | #region IP Translation for NAT | ||
819 | // Uses ipepClient above | ||
820 | if (sp.ClientView.TryGet(out ipepClient)) | ||
821 | { | ||
822 | endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); | ||
823 | } | ||
824 | #endregion | ||
825 | capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); | ||
826 | |||
827 | if (m_eqModule != null) | 911 | if (m_eqModule != null) |
828 | { | 912 | { |
829 | // The EnableSimulator message makes the client establish a connection with the destination | 913 | // The EnableSimulator message makes the client establish a connection with the destination |
@@ -853,22 +937,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
853 | sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); | 937 | sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); |
854 | } | 938 | } |
855 | } | 939 | } |
856 | else | ||
857 | { | ||
858 | agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle); | ||
859 | capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); | ||
860 | } | ||
861 | 940 | ||
862 | // Let's send a full update of the agent. This is a synchronous call. | 941 | // Let's send a full update of the agent. This is a synchronous call. |
863 | AgentData agent = new AgentData(); | 942 | AgentData agent = new AgentData(); |
864 | sp.CopyTo(agent); | 943 | sp.CopyTo(agent,false); |
865 | if (ctx.OutboundVersion < 0.5f) | 944 | |
866 | agent.Appearance.PackLegacyWearables = true; | 945 | if ((teleportFlags & (uint)TeleportFlags.IsFlying) != 0) |
946 | agent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY; | ||
947 | |||
867 | agent.Position = agentCircuit.startpos; | 948 | agent.Position = agentCircuit.startpos; |
868 | SetCallbackURL(agent, sp.Scene.RegionInfo); | 949 | SetCallbackURL(agent, sp.Scene.RegionInfo); |
869 | 950 | ||
870 | 951 | // We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to | |
871 | // We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to | ||
872 | // establish th econnection to the destination which makes it return true. | 952 | // establish th econnection to the destination which makes it return true. |
873 | if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) | 953 | if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) |
874 | { | 954 | { |
@@ -877,15 +957,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
877 | m_log.DebugFormat( | 957 | m_log.DebugFormat( |
878 | "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} before UpdateAgent", | 958 | "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} before UpdateAgent", |
879 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | 959 | sp.Name, finalDestination.RegionName, sp.Scene.Name); |
880 | 960 | sp.IsInTransit = false; | |
881 | return; | 961 | return; |
882 | } | 962 | } |
883 | 963 | ||
884 | // A common teleport failure occurs when we can send CreateAgent to the | 964 | // A common teleport failure occurs when we can send CreateAgent to the |
885 | // destination region but the viewer cannot establish the connection (e.g. due to network issues between | 965 | // destination region but the viewer cannot establish the connection (e.g. due to network issues between |
886 | // the viewer and the destination). In this case, UpdateAgent timesout after 10 seconds, although then | 966 | // the viewer and the destination). In this case, UpdateAgent timesout after 10 seconds, although then |
887 | // there's a further 10 second wait whilst we attempt to tell the destination to delete the agent in Fail(). | 967 | // there's a further 10 second wait whilst we attempt to tell the destination to delete the agent in Fail(). |
888 | if (!UpdateAgent(reg, finalDestination, agent, sp)) | 968 | if (!UpdateAgent(reg, finalDestination, agent, sp, ctx)) |
889 | { | 969 | { |
890 | if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) | 970 | if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) |
891 | { | 971 | { |
@@ -894,7 +974,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
894 | m_log.DebugFormat( | 974 | m_log.DebugFormat( |
895 | "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.", | 975 | "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.", |
896 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | 976 | sp.Name, finalDestination.RegionName, sp.Scene.Name); |
897 | 977 | sp.IsInTransit = false; | |
898 | return; | 978 | return; |
899 | } | 979 | } |
900 | 980 | ||
@@ -903,6 +983,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
903 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | 983 | sp.Name, finalDestination.RegionName, sp.Scene.Name); |
904 | 984 | ||
905 | Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); | 985 | Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); |
986 | sp.IsInTransit = false; | ||
906 | return; | 987 | return; |
907 | } | 988 | } |
908 | 989 | ||
@@ -915,7 +996,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
915 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | 996 | sp.Name, finalDestination.RegionName, sp.Scene.Name); |
916 | 997 | ||
917 | CleanupFailedInterRegionTeleport(sp, currentAgentCircuit.SessionID.ToString(), finalDestination); | 998 | CleanupFailedInterRegionTeleport(sp, currentAgentCircuit.SessionID.ToString(), finalDestination); |
918 | 999 | sp.IsInTransit = false; | |
919 | return; | 1000 | return; |
920 | } | 1001 | } |
921 | 1002 | ||
@@ -924,7 +1005,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
924 | capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); | 1005 | capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); |
925 | 1006 | ||
926 | // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator, | 1007 | // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator, |
927 | // where that neighbour simulator could otherwise request a child agent create on the source which then | 1008 | // where that neighbour simulator could otherwise request a child agent create on the source which then |
928 | // closes our existing agent which is still signalled as root. | 1009 | // closes our existing agent which is still signalled as root. |
929 | sp.IsChildAgent = true; | 1010 | sp.IsChildAgent = true; |
930 | 1011 | ||
@@ -952,7 +1033,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
952 | m_log.DebugFormat( | 1033 | m_log.DebugFormat( |
953 | "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after WaitForAgentArrivedAtDestination due to previous client close.", | 1034 | "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after WaitForAgentArrivedAtDestination due to previous client close.", |
954 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | 1035 | sp.Name, finalDestination.RegionName, sp.Scene.Name); |
955 | 1036 | sp.IsInTransit = false; | |
956 | return; | 1037 | return; |
957 | } | 1038 | } |
958 | 1039 | ||
@@ -961,12 +1042,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
961 | sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); | 1042 | sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); |
962 | 1043 | ||
963 | Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Destination region did not signal teleport completion."); | 1044 | Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Destination region did not signal teleport completion."); |
964 | 1045 | sp.IsInTransit = false; | |
965 | return; | 1046 | return; |
966 | } | 1047 | } |
967 | 1048 | ||
968 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); | ||
969 | |||
970 | /* | 1049 | /* |
971 | // TODO: This may be 0.6. Check if still needed | 1050 | // TODO: This may be 0.6. Check if still needed |
972 | // For backwards compatibility | 1051 | // For backwards compatibility |
@@ -978,18 +1057,26 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
978 | } | 1057 | } |
979 | */ | 1058 | */ |
980 | 1059 | ||
981 | // May need to logout or other cleanup | 1060 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); |
1061 | |||
1062 | if(logout) | ||
1063 | sp.closeAllChildAgents(); | ||
1064 | else | ||
1065 | sp.CloseChildAgents(childRegionsToClose); | ||
1066 | |||
1067 | // call HG hook | ||
982 | AgentHasMovedAway(sp, logout); | 1068 | AgentHasMovedAway(sp, logout); |
983 | 1069 | ||
984 | // Well, this is it. The agent is over there. | 1070 | sp.HasMovedAway(!(OutSideViewRange || logout)); |
985 | KillEntity(sp.Scene, sp.LocalId); | ||
986 | 1071 | ||
987 | // Now let's make it officially a child agent | 1072 | // ulong sourceRegionHandle = sp.RegionHandle; |
988 | sp.MakeChildAgent(); | 1073 | |
1074 | // Now let's make it officially a child agent | ||
1075 | sp.MakeChildAgent(destinationHandle); | ||
989 | 1076 | ||
990 | // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone | 1077 | // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone |
991 | 1078 | ||
992 | if (NeedsClosing(sp.Scene.DefaultDrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) | 1079 | if (NeedsClosing(reg, OutSideViewRange)) |
993 | { | 1080 | { |
994 | if (!sp.Scene.IncomingPreCloseClient(sp)) | 1081 | if (!sp.Scene.IncomingPreCloseClient(sp)) |
995 | return; | 1082 | return; |
@@ -1001,26 +1088,32 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1001 | // This sleep can be increased if necessary. However, whilst it's active, | 1088 | // This sleep can be increased if necessary. However, whilst it's active, |
1002 | // an agent cannot teleport back to this region if it has teleported away. | 1089 | // an agent cannot teleport back to this region if it has teleported away. |
1003 | Thread.Sleep(2000); | 1090 | Thread.Sleep(2000); |
1004 | |||
1005 | sp.Scene.CloseAgent(sp.UUID, false); | 1091 | sp.Scene.CloseAgent(sp.UUID, false); |
1006 | } | 1092 | } |
1007 | else | 1093 | sp.IsInTransit = false; |
1008 | { | ||
1009 | // now we have a child agent in this region. | ||
1010 | sp.Reset(); | ||
1011 | } | ||
1012 | } | 1094 | } |
1013 | 1095 | ||
1014 | private void TransferAgent_V2(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination, | 1096 | private void TransferAgent_V2(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination, |
1015 | IPEndPoint endPoint, uint teleportFlags, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, EntityTransferContext ctx, out string reason) | 1097 | IPEndPoint endPoint, uint teleportFlags, bool OutSideViewRange, EntityTransferContext ctx, out string reason) |
1016 | { | 1098 | { |
1017 | ulong destinationHandle = finalDestination.RegionHandle; | 1099 | ulong destinationHandle = finalDestination.RegionHandle; |
1018 | AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); | ||
1019 | 1100 | ||
1020 | // Let's create an agent there if one doesn't exist yet. | 1101 | List<ulong> childRegionsToClose = sp.GetChildAgentsToClose(destinationHandle, finalDestination.RegionSizeX, finalDestination.RegionSizeY); |
1102 | |||
1103 | if(agentCircuit.ChildrenCapSeeds != null) | ||
1104 | { | ||
1105 | foreach(ulong handler in childRegionsToClose) | ||
1106 | { | ||
1107 | agentCircuit.ChildrenCapSeeds.Remove(handler); | ||
1108 | } | ||
1109 | } | ||
1110 | |||
1111 | string capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);; | ||
1112 | |||
1113 | // Let's create an agent there if one doesn't exist yet. | ||
1021 | // NOTE: logout will always be false for a non-HG teleport. | 1114 | // NOTE: logout will always be false for a non-HG teleport. |
1022 | bool logout = false; | 1115 | bool logout = false; |
1023 | if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) | 1116 | if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, ctx, out reason, out logout)) |
1024 | { | 1117 | { |
1025 | m_interRegionTeleportFailures.Value++; | 1118 | m_interRegionTeleportFailures.Value++; |
1026 | 1119 | ||
@@ -1029,7 +1122,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1029 | sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); | 1122 | sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); |
1030 | 1123 | ||
1031 | sp.ControllingClient.SendTeleportFailed(reason); | 1124 | sp.ControllingClient.SendTeleportFailed(reason); |
1032 | 1125 | sp.IsInTransit = false; | |
1033 | return; | 1126 | return; |
1034 | } | 1127 | } |
1035 | 1128 | ||
@@ -1041,6 +1134,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1041 | "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request", | 1134 | "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request", |
1042 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | 1135 | sp.Name, finalDestination.RegionName, sp.Scene.Name); |
1043 | 1136 | ||
1137 | sp.IsInTransit = false; | ||
1044 | return; | 1138 | return; |
1045 | } | 1139 | } |
1046 | else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) | 1140 | else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) |
@@ -1051,40 +1145,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1051 | "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.", | 1145 | "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.", |
1052 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | 1146 | sp.Name, finalDestination.RegionName, sp.Scene.Name); |
1053 | 1147 | ||
1148 | sp.IsInTransit = false; | ||
1054 | return; | 1149 | return; |
1055 | } | 1150 | } |
1056 | 1151 | ||
1057 | // Past this point we have to attempt clean up if the teleport fails, so update transfer state. | 1152 | // Past this point we have to attempt clean up if the teleport fails, so update transfer state. |
1058 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); | 1153 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); |
1059 | 1154 | ||
1060 | IClientIPEndpoint ipepClient; | ||
1061 | string capsPath = String.Empty; | ||
1062 | float dist = (float)Math.Max(sp.Scene.DefaultDrawDistance, | ||
1063 | (float)Math.Max(sp.Scene.RegionInfo.RegionSizeX, sp.Scene.RegionInfo.RegionSizeY)); | ||
1064 | if (NeedsNewAgent(dist, oldRegionX, newRegionX, oldRegionY, newRegionY)) | ||
1065 | { | ||
1066 | m_log.DebugFormat( | ||
1067 | "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for agent {3} from {4}", | ||
1068 | finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name); | ||
1069 | |||
1070 | //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); | ||
1071 | #region IP Translation for NAT | ||
1072 | // Uses ipepClient above | ||
1073 | if (sp.ClientView.TryGet(out ipepClient)) | ||
1074 | { | ||
1075 | endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); | ||
1076 | } | ||
1077 | #endregion | ||
1078 | capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); | ||
1079 | } | ||
1080 | else | ||
1081 | { | ||
1082 | agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle); | ||
1083 | capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); | ||
1084 | } | ||
1085 | |||
1086 | // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator, | 1155 | // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator, |
1087 | // where that neighbour simulator could otherwise request a child agent create on the source which then | 1156 | // where that neighbour simulator could otherwise request a child agent create on the source which then |
1088 | // closes our existing agent which is still signalled as root. | 1157 | // closes our existing agent which is still signalled as root. |
1089 | //sp.IsChildAgent = true; | 1158 | //sp.IsChildAgent = true; |
1090 | 1159 | ||
@@ -1100,13 +1169,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1100 | "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", | 1169 | "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", |
1101 | capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); | 1170 | capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); |
1102 | 1171 | ||
1103 | // Let's send a full update of the agent. | 1172 | // Let's send a full update of the agent. |
1104 | AgentData agent = new AgentData(); | 1173 | AgentData agent = new AgentData(); |
1105 | sp.CopyTo(agent); | 1174 | sp.CopyTo(agent,false); |
1106 | if (ctx.OutboundVersion < 0.5f) | ||
1107 | agent.Appearance.PackLegacyWearables = true; | ||
1108 | agent.Position = agentCircuit.startpos; | 1175 | agent.Position = agentCircuit.startpos; |
1176 | |||
1177 | if ((teleportFlags & (uint)TeleportFlags.IsFlying) != 0) | ||
1178 | agent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY; | ||
1179 | |||
1109 | agent.SenderWantsToWaitForRoot = true; | 1180 | agent.SenderWantsToWaitForRoot = true; |
1181 | |||
1110 | //SetCallbackURL(agent, sp.Scene.RegionInfo); | 1182 | //SetCallbackURL(agent, sp.Scene.RegionInfo); |
1111 | 1183 | ||
1112 | // Reset the do not close flag. This must be done before the destination opens child connections (here | 1184 | // Reset the do not close flag. This must be done before the destination opens child connections (here |
@@ -1118,7 +1190,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1118 | // Send the Update. If this returns true, we know the client has contacted the destination | 1190 | // Send the Update. If this returns true, we know the client has contacted the destination |
1119 | // via CompleteMovementIntoRegion, so we can let go. | 1191 | // via CompleteMovementIntoRegion, so we can let go. |
1120 | // If it returns false, something went wrong, and we need to abort. | 1192 | // If it returns false, something went wrong, and we need to abort. |
1121 | if (!UpdateAgent(reg, finalDestination, agent, sp)) | 1193 | if (!UpdateAgent(reg, finalDestination, agent, sp, ctx)) |
1122 | { | 1194 | { |
1123 | if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) | 1195 | if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) |
1124 | { | 1196 | { |
@@ -1127,7 +1199,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1127 | m_log.DebugFormat( | 1199 | m_log.DebugFormat( |
1128 | "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.", | 1200 | "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.", |
1129 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | 1201 | sp.Name, finalDestination.RegionName, sp.Scene.Name); |
1130 | 1202 | sp.IsInTransit = false; | |
1131 | return; | 1203 | return; |
1132 | } | 1204 | } |
1133 | 1205 | ||
@@ -1135,31 +1207,31 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1135 | "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Keeping avatar in {2}", | 1207 | "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Keeping avatar in {2}", |
1136 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | 1208 | sp.Name, finalDestination.RegionName, sp.Scene.Name); |
1137 | 1209 | ||
1138 | Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); | 1210 | Fail(sp, finalDestination, logout, agentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); |
1211 | sp.IsInTransit = false; | ||
1139 | return; | 1212 | return; |
1140 | } | 1213 | } |
1141 | 1214 | ||
1142 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); | 1215 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); |
1143 | 1216 | ||
1144 | // Need to signal neighbours whether child agents may need closing irrespective of whether this | 1217 | if(logout) |
1145 | // one needed closing. We also need to close child agents as quickly as possible to avoid complicated | 1218 | sp.closeAllChildAgents(); |
1146 | // race conditions with rapid agent releporting (e.g. from A1 to a non-neighbour B, back | 1219 | else |
1147 | // to a neighbour A2 then off to a non-neighbour C). Closing child agents any later requires complex | 1220 | sp.CloseChildAgents(childRegionsToClose); |
1148 | // distributed checks to avoid problems in rapid reteleporting scenarios and where child agents are | ||
1149 | // abandoned without proper close by viewer but then re-used by an incoming connection. | ||
1150 | sp.CloseChildAgents(newRegionX, newRegionY); | ||
1151 | 1221 | ||
1152 | // May need to logout or other cleanup | 1222 | sp.HasMovedAway(!(OutSideViewRange || logout)); |
1223 | |||
1224 | //HG hook | ||
1153 | AgentHasMovedAway(sp, logout); | 1225 | AgentHasMovedAway(sp, logout); |
1154 | 1226 | ||
1155 | // Well, this is it. The agent is over there. | 1227 | // ulong sourceRegionHandle = sp.RegionHandle; |
1156 | KillEntity(sp.Scene, sp.LocalId); | ||
1157 | 1228 | ||
1158 | // Now let's make it officially a child agent | 1229 | // Now let's make it officially a child agent |
1159 | sp.MakeChildAgent(); | 1230 | sp.MakeChildAgent(destinationHandle); |
1160 | 1231 | ||
1161 | // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone | 1232 | // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone |
1162 | if (NeedsClosing(sp.Scene.DefaultDrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) | 1233 | // go by HG hook |
1234 | if (NeedsClosing(reg, OutSideViewRange)) | ||
1163 | { | 1235 | { |
1164 | if (!sp.Scene.IncomingPreCloseClient(sp)) | 1236 | if (!sp.Scene.IncomingPreCloseClient(sp)) |
1165 | return; | 1237 | return; |
@@ -1170,21 +1242,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1170 | // BEFORE THEY SETTLE IN THE NEW REGION. | 1242 | // BEFORE THEY SETTLE IN THE NEW REGION. |
1171 | // DECREASING THE WAIT TIME HERE WILL EITHER RESULT IN A VIEWER CRASH OR | 1243 | // DECREASING THE WAIT TIME HERE WILL EITHER RESULT IN A VIEWER CRASH OR |
1172 | // IN THE AVIE BEING PLACED IN INFINITY FOR A COUPLE OF SECONDS. | 1244 | // IN THE AVIE BEING PLACED IN INFINITY FOR A COUPLE OF SECONDS. |
1245 | |||
1173 | Thread.Sleep(15000); | 1246 | Thread.Sleep(15000); |
1174 | 1247 | ||
1175 | // OK, it got this agent. Let's close everything | 1248 | // OK, it got this agent. Let's close everything |
1176 | // If we shouldn't close the agent due to some other region renewing the connection | 1249 | // If we shouldn't close the agent due to some other region renewing the connection |
1177 | // then this will be handled in IncomingCloseAgent under lock conditions | 1250 | // then this will be handled in IncomingCloseAgent under lock conditions |
1178 | m_log.DebugFormat( | 1251 | m_log.DebugFormat( |
1179 | "[ENTITY TRANSFER MODULE]: Closing agent {0} in {1} after teleport", sp.Name, Scene.Name); | 1252 | "[ENTITY TRANSFER MODULE]: Closing agent {0} in {1} after teleport", sp.Name, Scene.Name); |
1180 | 1253 | ||
1181 | sp.Scene.CloseAgent(sp.UUID, false); | 1254 | sp.Scene.CloseAgent(sp.UUID, false); |
1182 | } | 1255 | } |
1183 | else | 1256 | sp.IsInTransit = false; |
1184 | { | ||
1185 | // now we have a child agent in this region. | ||
1186 | sp.Reset(); | ||
1187 | } | ||
1188 | } | 1257 | } |
1189 | 1258 | ||
1190 | /// <summary> | 1259 | /// <summary> |
@@ -1232,13 +1301,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1232 | sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout); | 1301 | sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout); |
1233 | } | 1302 | } |
1234 | 1303 | ||
1235 | protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout) | 1304 | protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, EntityTransferContext ctx, out string reason, out bool logout) |
1236 | { | 1305 | { |
1237 | GridRegion source = new GridRegion(Scene.RegionInfo); | 1306 | GridRegion source = new GridRegion(Scene.RegionInfo); |
1238 | source.RawServerURI = m_GatekeeperURI; | 1307 | source.RawServerURI = m_GatekeeperURI; |
1239 | 1308 | ||
1240 | logout = false; | 1309 | logout = false; |
1241 | bool success = Scene.SimulationService.CreateAgent(source, finalDestination, agentCircuit, teleportFlags, out reason); | 1310 | bool success = Scene.SimulationService.CreateAgent(source, finalDestination, agentCircuit, teleportFlags, ctx, out reason); |
1242 | 1311 | ||
1243 | if (success) | 1312 | if (success) |
1244 | sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout); | 1313 | sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout); |
@@ -1246,9 +1315,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1246 | return success; | 1315 | return success; |
1247 | } | 1316 | } |
1248 | 1317 | ||
1249 | protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent, ScenePresence sp) | 1318 | protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent, ScenePresence sp, EntityTransferContext ctx) |
1250 | { | 1319 | { |
1251 | return Scene.SimulationService.UpdateAgent(finalDestination, agent); | 1320 | return Scene.SimulationService.UpdateAgent(finalDestination, agent, ctx); |
1252 | } | 1321 | } |
1253 | 1322 | ||
1254 | protected virtual void SetCallbackURL(AgentData agent, RegionInfo region) | 1323 | protected virtual void SetCallbackURL(AgentData agent, RegionInfo region) |
@@ -1265,10 +1334,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1265 | /// </summary> | 1334 | /// </summary> |
1266 | /// <param name='sp'></param> | 1335 | /// <param name='sp'></param> |
1267 | /// <param name='logout'></param> | 1336 | /// <param name='logout'></param> |
1337 | /// | ||
1338 | /// now just a HG hook | ||
1268 | protected virtual void AgentHasMovedAway(ScenePresence sp, bool logout) | 1339 | protected virtual void AgentHasMovedAway(ScenePresence sp, bool logout) |
1269 | { | 1340 | { |
1270 | if (sp.Scene.AttachmentsModule != null) | 1341 | // if (sp.Scene.AttachmentsModule != null) |
1271 | sp.Scene.AttachmentsModule.DeleteAttachmentsFromScene(sp, true); | 1342 | // sp.Scene.AttachmentsModule.DeleteAttachmentsFromScene(sp, logout); |
1272 | } | 1343 | } |
1273 | 1344 | ||
1274 | protected void KillEntity(Scene scene, uint localID) | 1345 | protected void KillEntity(Scene scene, uint localID) |
@@ -1276,6 +1347,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1276 | scene.SendKillObject(new List<uint> { localID }); | 1347 | scene.SendKillObject(new List<uint> { localID }); |
1277 | } | 1348 | } |
1278 | 1349 | ||
1350 | // HG hook | ||
1279 | protected virtual GridRegion GetFinalDestination(GridRegion region, UUID agentID, string agentHomeURI, out string message) | 1351 | protected virtual GridRegion GetFinalDestination(GridRegion region, UUID agentID, string agentHomeURI, out string message) |
1280 | { | 1352 | { |
1281 | message = null; | 1353 | message = null; |
@@ -1285,28 +1357,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1285 | // This returns 'true' if the new region already has a child agent for our | 1357 | // This returns 'true' if the new region already has a child agent for our |
1286 | // incoming agent. The implication is that, if 'false', we have to create the | 1358 | // incoming agent. The implication is that, if 'false', we have to create the |
1287 | // child and then teleport into the region. | 1359 | // child and then teleport into the region. |
1288 | protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY) | 1360 | protected virtual bool NeedsNewAgent(float viewdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, |
1361 | int oldsizeX, int oldsizeY, int newsizeX, int newsizeY) | ||
1289 | { | 1362 | { |
1290 | if (m_regionCombinerModule != null && m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID)) | 1363 | return Util.IsOutsideView(viewdist, oldRegionX, newRegionX, oldRegionY, newRegionY, |
1291 | { | 1364 | oldsizeX, oldsizeY, newsizeX, newsizeY); |
1292 | Vector2 swCorner, neCorner; | ||
1293 | GetMegaregionViewRange(out swCorner, out neCorner); | ||
1294 | |||
1295 | m_log.DebugFormat( | ||
1296 | "[ENTITY TRANSFER MODULE]: Megaregion view of {0} is from {1} to {2} with new agent check for {3},{4}", | ||
1297 | Scene.Name, swCorner, neCorner, newRegionX, newRegionY); | ||
1298 | |||
1299 | return !(newRegionX >= swCorner.X && newRegionX <= neCorner.X && newRegionY >= swCorner.Y && newRegionY <= neCorner.Y); | ||
1300 | } | ||
1301 | else | ||
1302 | { | ||
1303 | return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY); | ||
1304 | } | ||
1305 | } | 1365 | } |
1306 | 1366 | ||
1307 | protected virtual bool NeedsClosing(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg) | 1367 | // HG Hook |
1368 | protected virtual bool NeedsClosing(GridRegion reg, bool OutViewRange) | ||
1369 | |||
1308 | { | 1370 | { |
1309 | return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY); | 1371 | return OutViewRange; |
1310 | } | 1372 | } |
1311 | 1373 | ||
1312 | #endregion | 1374 | #endregion |
@@ -1328,11 +1390,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1328 | remoteClient.SendTeleportFailed("The teleport destination could not be found."); | 1390 | remoteClient.SendTeleportFailed("The teleport destination could not be found."); |
1329 | return; | 1391 | return; |
1330 | } | 1392 | } |
1331 | ((Scene)(remoteClient.Scene)).RequestTeleportLocation(remoteClient, info.RegionHandle, lm.Position, | 1393 | ((Scene)(remoteClient.Scene)).RequestTeleportLocation(remoteClient, info.RegionHandle, lm.Position, |
1332 | Vector3.Zero, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark)); | 1394 | Vector3.Zero, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark)); |
1333 | } | 1395 | } |
1334 | 1396 | ||
1335 | #endregion | 1397 | #endregion |
1336 | 1398 | ||
1337 | #region Teleport Home | 1399 | #region Teleport Home |
1338 | 1400 | ||
@@ -1366,7 +1428,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1366 | client.SendTeleportFailed("Your home region could not be found."); | 1428 | client.SendTeleportFailed("Your home region could not be found."); |
1367 | return false; | 1429 | return false; |
1368 | } | 1430 | } |
1369 | 1431 | ||
1370 | m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Home region of {0} is {1} ({2}-{3})", | 1432 | m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Home region of {0} is {1} ({2}-{3})", |
1371 | client.Name, regionInfo.RegionName, regionInfo.RegionCoordX, regionInfo.RegionCoordY); | 1433 | client.Name, regionInfo.RegionName, regionInfo.RegionCoordX, regionInfo.RegionCoordY); |
1372 | 1434 | ||
@@ -1389,105 +1451,146 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1389 | 1451 | ||
1390 | #region Agent Crossings | 1452 | #region Agent Crossings |
1391 | 1453 | ||
1392 | // Given a position relative to the current region (which has previously been tested to | 1454 | public bool checkAgentAccessToRegion(ScenePresence agent, GridRegion destiny, Vector3 position, |
1393 | // see that it is actually outside the current region), find the new region that the | 1455 | EntityTransferContext ctx, out string reason) |
1394 | // point is actually in. | 1456 | { |
1395 | // Returns the coordinates and information of the new region or 'null' of it doesn't exist. | 1457 | reason = String.Empty; |
1458 | |||
1459 | UUID agentID = agent.UUID; | ||
1460 | ulong destinyHandle = destiny.RegionHandle; | ||
1461 | |||
1462 | if (m_bannedRegionCache.IfBanned(destinyHandle, agentID)) | ||
1463 | { | ||
1464 | return false; | ||
1465 | } | ||
1466 | |||
1467 | Scene ascene = agent.Scene; | ||
1468 | string homeURI = ascene.GetAgentHomeURI(agentID); | ||
1469 | |||
1470 | |||
1471 | if (!ascene.SimulationService.QueryAccess(destiny, agentID, homeURI, false, position, | ||
1472 | agent.Scene.GetFormatsOffered(), ctx, out reason)) | ||
1473 | { | ||
1474 | m_bannedRegionCache.Add(destinyHandle, agentID, 30.0, 30.0); | ||
1475 | return false; | ||
1476 | } | ||
1477 | return true; | ||
1478 | } | ||
1479 | |||
1480 | |||
1481 | // Given a position relative to the current region and outside of it | ||
1482 | // find the new region that the point is actually in. | ||
1483 | // returns 'null' if new region not found or if information | ||
1484 | // and new position relative to it | ||
1485 | // now only works for crossings | ||
1486 | |||
1396 | public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, | 1487 | public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, |
1397 | EntityTransferContext ctx, out Vector3 newpos, out string failureReason) | 1488 | EntityTransferContext ctx, out Vector3 newpos, out string failureReason) |
1398 | { | 1489 | { |
1399 | newpos = pos; | 1490 | newpos = pos; |
1400 | failureReason = string.Empty; | 1491 | failureReason = string.Empty; |
1401 | string homeURI = scene.GetAgentHomeURI(agentID); | ||
1402 | 1492 | ||
1403 | // m_log.DebugFormat( | 1493 | // m_log.DebugFormat( |
1404 | // "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name); | 1494 | // "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name); |
1405 | 1495 | ||
1406 | // Compute world location of the object's position | 1496 | // Compute world location of the agent's position |
1407 | double presenceWorldX = (double)scene.RegionInfo.WorldLocX + pos.X; | 1497 | double presenceWorldX = (double)scene.RegionInfo.WorldLocX + pos.X; |
1408 | double presenceWorldY = (double)scene.RegionInfo.WorldLocY + pos.Y; | 1498 | double presenceWorldY = (double)scene.RegionInfo.WorldLocY + pos.Y; |
1409 | 1499 | ||
1410 | // Call the grid service to lookup the region containing the new position. | 1500 | // Call the grid service to lookup the region containing the new position. |
1411 | GridRegion neighbourRegion = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID, | 1501 | GridRegion neighbourRegion = GetRegionContainingWorldLocation( |
1412 | presenceWorldX, presenceWorldY, | 1502 | scene.GridService, scene.RegionInfo.ScopeID, |
1413 | Math.Max(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY)); | 1503 | presenceWorldX, presenceWorldY, |
1504 | Math.Max(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY)); | ||
1505 | |||
1506 | if (neighbourRegion == null) | ||
1507 | return null; | ||
1414 | 1508 | ||
1415 | if (neighbourRegion != null) | 1509 | if (m_bannedRegionCache.IfBanned(neighbourRegion.RegionHandle, agentID)) |
1416 | { | 1510 | { |
1417 | // Compute the entity's position relative to the new region | 1511 | failureReason = "Access Denied or Temporary not possible"; |
1418 | newpos = new Vector3((float)(presenceWorldX - (double)neighbourRegion.RegionLocX), | 1512 | return null; |
1513 | } | ||
1514 | |||
1515 | m_bannedRegionCache.Remove(neighbourRegion.RegionHandle, agentID); | ||
1516 | |||
1517 | // Compute the entity's position relative to the new region | ||
1518 | newpos = new Vector3((float)(presenceWorldX - (double)neighbourRegion.RegionLocX), | ||
1419 | (float)(presenceWorldY - (double)neighbourRegion.RegionLocY), | 1519 | (float)(presenceWorldY - (double)neighbourRegion.RegionLocY), |
1420 | pos.Z); | 1520 | pos.Z); |
1421 | 1521 | ||
1422 | if (m_bannedRegionCache.IfBanned(neighbourRegion.RegionHandle, agentID)) | 1522 | string homeURI = scene.GetAgentHomeURI(agentID); |
1423 | { | 1523 | |
1424 | failureReason = "Cannot region cross into banned parcel"; | 1524 | if (!scene.SimulationService.QueryAccess( |
1425 | neighbourRegion = null; | 1525 | neighbourRegion, agentID, homeURI, false, newpos, |
1426 | } | 1526 | scene.GetFormatsOffered(), ctx, out failureReason)) |
1427 | else | 1527 | { |
1428 | { | 1528 | // remember the fail |
1429 | // If not banned, make sure this agent is not in the list. | 1529 | m_bannedRegionCache.Add(neighbourRegion.RegionHandle, agentID); |
1430 | m_bannedRegionCache.Remove(neighbourRegion.RegionHandle, agentID); | 1530 | if(String.IsNullOrWhiteSpace(failureReason)) |
1431 | } | 1531 | failureReason = "Access Denied"; |
1432 | 1532 | return null; | |
1433 | // Check to see if we have access to the target region. | ||
1434 | if (neighbourRegion != null | ||
1435 | && !scene.SimulationService.QueryAccess(neighbourRegion, agentID, homeURI, false, newpos, scene.GetFormatsOffered(), ctx, out failureReason)) | ||
1436 | { | ||
1437 | // remember banned | ||
1438 | m_bannedRegionCache.Add(neighbourRegion.RegionHandle, agentID); | ||
1439 | neighbourRegion = null; | ||
1440 | } | ||
1441 | } | 1533 | } |
1442 | else | 1534 | |
1535 | return neighbourRegion; | ||
1536 | } | ||
1537 | |||
1538 | public bool Cross(ScenePresence agent, bool isFlying) | ||
1539 | { | ||
1540 | agent.IsInLocalTransit = true; | ||
1541 | agent.IsInTransit = true; | ||
1542 | CrossAsyncDelegate d = CrossAsync; | ||
1543 | d.BeginInvoke(agent, isFlying, CrossCompleted, d); | ||
1544 | return true; | ||
1545 | } | ||
1546 | |||
1547 | private void CrossCompleted(IAsyncResult iar) | ||
1548 | { | ||
1549 | CrossAsyncDelegate icon = (CrossAsyncDelegate)iar.AsyncState; | ||
1550 | ScenePresence agent = icon.EndInvoke(iar); | ||
1551 | |||
1552 | if(agent == null || agent.IsDeleted) | ||
1553 | return; | ||
1554 | |||
1555 | if(!agent.IsChildAgent) | ||
1443 | { | 1556 | { |
1444 | // The destination region just doesn't exist | 1557 | // crossing failed |
1445 | failureReason = "Cannot cross into non-existent region"; | 1558 | agent.CrossToNewRegionFail(); |
1446 | } | 1559 | } |
1447 | |||
1448 | if (neighbourRegion == null) | ||
1449 | m_log.DebugFormat("{0} GetDestination: region not found. Old region name={1} at <{2},{3}> of size <{4},{5}>. Old pos={6}", | ||
1450 | LogHeader, scene.RegionInfo.RegionName, | ||
1451 | scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY, | ||
1452 | scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY, | ||
1453 | pos); | ||
1454 | else | 1560 | else |
1455 | m_log.DebugFormat("{0} GetDestination: new region={1} at <{2},{3}> of size <{4},{5}>, newpos=<{6},{7}>", | 1561 | m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname); |
1456 | LogHeader, neighbourRegion.RegionName, | ||
1457 | neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY, | ||
1458 | newpos.X, newpos.Y); | ||
1459 | 1562 | ||
1460 | return neighbourRegion; | 1563 | agent.IsInTransit = false; |
1461 | } | 1564 | } |
1462 | 1565 | ||
1463 | public bool Cross(ScenePresence agent, bool isFlying) | 1566 | public ScenePresence CrossAsync(ScenePresence agent, bool isFlying) |
1464 | { | 1567 | { |
1465 | Vector3 newpos; | 1568 | Vector3 newpos; |
1466 | EntityTransferContext ctx = new EntityTransferContext(); | 1569 | EntityTransferContext ctx = new EntityTransferContext(); |
1467 | string failureReason; | 1570 | string failureReason; |
1468 | 1571 | ||
1469 | GridRegion neighbourRegion = GetDestination(agent.Scene, agent.UUID, agent.AbsolutePosition, | 1572 | // We need this because of decimal number parsing of the protocols. |
1573 | Culture.SetCurrentCulture(); | ||
1574 | |||
1575 | Vector3 pos = agent.AbsolutePosition + agent.Velocity * 0.2f; | ||
1576 | |||
1577 | GridRegion neighbourRegion = GetDestination(agent.Scene, agent.UUID, pos, | ||
1470 | ctx, out newpos, out failureReason); | 1578 | ctx, out newpos, out failureReason); |
1471 | if (neighbourRegion == null) | 1579 | if (neighbourRegion == null) |
1472 | { | 1580 | { |
1473 | agent.ControllingClient.SendAlertMessage(failureReason); | 1581 | if (!agent.IsDeleted && failureReason != String.Empty && agent.ControllingClient != null) |
1474 | return false; | 1582 | agent.ControllingClient.SendAlertMessage(failureReason); |
1583 | return agent; | ||
1475 | } | 1584 | } |
1476 | 1585 | ||
1477 | agent.IsInTransit = true; | 1586 | // agent.IsInTransit = true; |
1478 | |||
1479 | CrossAgentToNewRegionDelegate d = CrossAgentToNewRegionAsync; | ||
1480 | d.BeginInvoke(agent, newpos, neighbourRegion, isFlying, ctx, CrossAgentToNewRegionCompleted, d); | ||
1481 | |||
1482 | Scene.EventManager.TriggerCrossAgentToNewRegion(agent, isFlying, neighbourRegion); | ||
1483 | 1587 | ||
1484 | return true; | 1588 | CrossAgentToNewRegionAsync(agent, newpos, neighbourRegion, isFlying, ctx); |
1589 | agent.IsInTransit = false; | ||
1590 | return agent; | ||
1485 | } | 1591 | } |
1486 | 1592 | ||
1487 | 1593 | public delegate void InformClientToInitiateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene); | |
1488 | public delegate void InformClientToInitiateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY, | ||
1489 | Vector3 position, | ||
1490 | Scene initiatingScene); | ||
1491 | 1594 | ||
1492 | private void InformClientToInitiateTeleportToLocation(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene) | 1595 | private void InformClientToInitiateTeleportToLocation(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene) |
1493 | { | 1596 | { |
@@ -1506,14 +1609,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1506 | Thread.Sleep(10000); | 1609 | Thread.Sleep(10000); |
1507 | 1610 | ||
1508 | m_log.DebugFormat( | 1611 | m_log.DebugFormat( |
1509 | "[ENTITY TRANSFER MODULE]: Auto-reteleporting {0} to correct megaregion location {1},{2},{3} from {4}", | 1612 | "[ENTITY TRANSFER MODULE]: Auto-reteleporting {0} to correct megaregion location {1},{2},{3} from {4}", |
1510 | agent.Name, regionX, regionY, position, initiatingScene.Name); | 1613 | agent.Name, regionX, regionY, position, initiatingScene.Name); |
1511 | 1614 | ||
1512 | agent.Scene.RequestTeleportLocation( | 1615 | agent.Scene.RequestTeleportLocation( |
1513 | agent.ControllingClient, | 1616 | agent.ControllingClient, |
1514 | Util.RegionLocToHandle(regionX, regionY), | 1617 | Util.RegionGridLocToHandle(regionX, regionY), |
1515 | position, | 1618 | position, |
1516 | agent.Lookat, | 1619 | agent.Lookat, |
1517 | (uint)Constants.TeleportFlags.ViaLocation); | 1620 | (uint)Constants.TeleportFlags.ViaLocation); |
1518 | 1621 | ||
1519 | /* | 1622 | /* |
@@ -1557,15 +1660,71 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1557 | icon.EndInvoke(iar); | 1660 | icon.EndInvoke(iar); |
1558 | } | 1661 | } |
1559 | 1662 | ||
1560 | public bool CrossAgentToNewRegionPrep(ScenePresence agent, GridRegion neighbourRegion) | 1663 | public bool CrossAgentCreateFarChild(ScenePresence agent, GridRegion neighbourRegion, Vector3 pos, EntityTransferContext ctx) |
1561 | { | 1664 | { |
1562 | if (neighbourRegion == null) | 1665 | ulong regionhandler = neighbourRegion.RegionHandle; |
1666 | |||
1667 | if(agent.knowsNeighbourRegion(regionhandler)) | ||
1668 | return true; | ||
1669 | |||
1670 | string reason; | ||
1671 | ulong currentRegionHandler = agent.Scene.RegionInfo.RegionHandle; | ||
1672 | GridRegion source = new GridRegion(agent.Scene.RegionInfo); | ||
1673 | |||
1674 | AgentCircuitData currentAgentCircuit = | ||
1675 | agent.Scene.AuthenticateHandler.GetAgentCircuitData(agent.ControllingClient.CircuitCode); | ||
1676 | AgentCircuitData agentCircuit = agent.ControllingClient.RequestClientInfo(); | ||
1677 | agentCircuit.startpos = pos; | ||
1678 | agentCircuit.child = true; | ||
1679 | |||
1680 | agentCircuit.Appearance = new AvatarAppearance(); | ||
1681 | agentCircuit.Appearance.AvatarHeight = agent.Appearance.AvatarHeight; | ||
1682 | |||
1683 | if (currentAgentCircuit != null) | ||
1684 | { | ||
1685 | agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs; | ||
1686 | agentCircuit.IPAddress = currentAgentCircuit.IPAddress; | ||
1687 | agentCircuit.Viewer = currentAgentCircuit.Viewer; | ||
1688 | agentCircuit.Channel = currentAgentCircuit.Channel; | ||
1689 | agentCircuit.Mac = currentAgentCircuit.Mac; | ||
1690 | agentCircuit.Id0 = currentAgentCircuit.Id0; | ||
1691 | } | ||
1692 | |||
1693 | agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); | ||
1694 | agent.AddNeighbourRegion(neighbourRegion, agentCircuit.CapsPath); | ||
1695 | |||
1696 | IPEndPoint endPoint = neighbourRegion.ExternalEndPoint; | ||
1697 | if(endPoint == null) | ||
1698 | { | ||
1699 | m_log.DebugFormat("CrossAgentCreateFarChild failed to resolve neighbour address {0}", neighbourRegion.ExternalHostName); | ||
1563 | return false; | 1700 | return false; |
1564 | 1701 | } | |
1565 | m_entityTransferStateMachine.SetInTransit(agent.UUID); | 1702 | if (!Scene.SimulationService.CreateAgent(source, neighbourRegion, agentCircuit, (int)TeleportFlags.Default, ctx, out reason)) |
1703 | { | ||
1704 | agent.RemoveNeighbourRegion(regionhandler); | ||
1705 | return false; | ||
1706 | } | ||
1707 | |||
1708 | string capsPath = neighbourRegion.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); | ||
1709 | int newSizeX = neighbourRegion.RegionSizeX; | ||
1710 | int newSizeY = neighbourRegion.RegionSizeY; | ||
1566 | 1711 | ||
1567 | agent.RemoveFromPhysicalScene(); | 1712 | if (m_eqModule != null) |
1713 | { | ||
1714 | m_log.DebugFormat("{0} {1} is sending {2} EnableSimulator for neighbour region {3}(loc=<{4},{5}>,siz=<{6},{7}>) " + | ||
1715 | "and EstablishAgentCommunication with seed cap {8}", LogHeader, | ||
1716 | source.RegionName, agent.Name, | ||
1717 | neighbourRegion.RegionName, neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, newSizeX, newSizeY , capsPath); | ||
1568 | 1718 | ||
1719 | m_eqModule.EnableSimulator(regionhandler, | ||
1720 | endPoint, agent.UUID, newSizeX, newSizeY); | ||
1721 | m_eqModule.EstablishAgentCommunication(agent.UUID, endPoint, capsPath, | ||
1722 | regionhandler, newSizeX, newSizeY); | ||
1723 | } | ||
1724 | else | ||
1725 | { | ||
1726 | agent.ControllingClient.InformClientOfNeighbour(regionhandler, endPoint); | ||
1727 | } | ||
1569 | return true; | 1728 | return true; |
1570 | } | 1729 | } |
1571 | 1730 | ||
@@ -1582,37 +1741,56 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1582 | m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: new region={1} at <{2},{3}>. newpos={4}", | 1741 | m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: new region={1} at <{2},{3}>. newpos={4}", |
1583 | LogHeader, neighbourRegion.RegionName, neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, pos); | 1742 | LogHeader, neighbourRegion.RegionName, neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, pos); |
1584 | 1743 | ||
1585 | if (!CrossAgentToNewRegionPrep(agent, neighbourRegion)) | 1744 | if (neighbourRegion == null) |
1586 | { | 1745 | { |
1587 | m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: prep failed. Resetting transfer state", LogHeader); | 1746 | m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: invalid destiny", LogHeader); |
1588 | m_entityTransferStateMachine.ResetFromTransit(agent.UUID); | 1747 | return agent; |
1748 | } | ||
1749 | |||
1750 | IPEndPoint endpoint = neighbourRegion.ExternalEndPoint; | ||
1751 | if(endpoint == null) | ||
1752 | { | ||
1753 | m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: failed to resolve neighbour address {0} ",neighbourRegion.ExternalHostName); | ||
1754 | return agent; | ||
1589 | } | 1755 | } |
1590 | 1756 | ||
1591 | if (!CrossAgentIntoNewRegionMain(agent, pos, neighbourRegion, isFlying, ctx)) | 1757 | m_entityTransferStateMachine.SetInTransit(agent.UUID); |
1758 | agent.RemoveFromPhysicalScene(); | ||
1759 | |||
1760 | if (!CrossAgentIntoNewRegionMain(agent, pos, neighbourRegion, endpoint, isFlying, ctx)) | ||
1592 | { | 1761 | { |
1593 | m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: cross main failed. Resetting transfer state", LogHeader); | 1762 | m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: cross main failed. Resetting transfer state", LogHeader); |
1594 | m_entityTransferStateMachine.ResetFromTransit(agent.UUID); | 1763 | m_entityTransferStateMachine.ResetFromTransit(agent.UUID); |
1595 | } | 1764 | } |
1596 | |||
1597 | CrossAgentToNewRegionPost(agent, pos, neighbourRegion, isFlying, ctx); | ||
1598 | } | 1765 | } |
1599 | catch (Exception e) | 1766 | catch (Exception e) |
1600 | { | 1767 | { |
1601 | m_log.Error(string.Format("{0}: CrossAgentToNewRegionAsync: failed with exception ", LogHeader), e); | 1768 | m_log.Error(string.Format("{0}: CrossAgentToNewRegionAsync: failed with exception ", LogHeader), e); |
1602 | } | 1769 | } |
1603 | |||
1604 | return agent; | 1770 | return agent; |
1605 | } | 1771 | } |
1606 | 1772 | ||
1607 | public bool CrossAgentIntoNewRegionMain(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, bool isFlying, EntityTransferContext ctx) | 1773 | public bool CrossAgentIntoNewRegionMain(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, |
1774 | IPEndPoint endpoint, bool isFlying, EntityTransferContext ctx) | ||
1608 | { | 1775 | { |
1776 | int ts = Util.EnvironmentTickCount(); | ||
1777 | bool sucess = true; | ||
1778 | string reason = String.Empty; | ||
1779 | List<ulong> childRegionsToClose = null; | ||
1609 | try | 1780 | try |
1610 | { | 1781 | { |
1611 | AgentData cAgent = new AgentData(); | 1782 | AgentData cAgent = new AgentData(); |
1612 | agent.CopyTo(cAgent); | 1783 | agent.CopyTo(cAgent,true); |
1613 | if (ctx.OutboundVersion < 0.5f) | 1784 | |
1614 | cAgent.Appearance.PackLegacyWearables = true; | ||
1615 | cAgent.Position = pos; | 1785 | cAgent.Position = pos; |
1786 | cAgent.ChildrenCapSeeds = agent.KnownRegions; | ||
1787 | |||
1788 | childRegionsToClose = agent.GetChildAgentsToClose(neighbourRegion.RegionHandle, neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY); | ||
1789 | if(cAgent.ChildrenCapSeeds != null) | ||
1790 | { | ||
1791 | foreach(ulong regh in childRegionsToClose) | ||
1792 | cAgent.ChildrenCapSeeds.Remove(regh); | ||
1793 | } | ||
1616 | 1794 | ||
1617 | if (isFlying) | 1795 | if (isFlying) |
1618 | cAgent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY; | 1796 | cAgent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY; |
@@ -1623,21 +1801,31 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1623 | // Beyond this point, extra cleanup is needed beyond removing transit state | 1801 | // Beyond this point, extra cleanup is needed beyond removing transit state |
1624 | m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.Transferring); | 1802 | m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.Transferring); |
1625 | 1803 | ||
1626 | if (!agent.Scene.SimulationService.UpdateAgent(neighbourRegion, cAgent)) | 1804 | if (sucess && !agent.Scene.SimulationService.UpdateAgent(neighbourRegion, cAgent, ctx)) |
1805 | { | ||
1806 | sucess = false; | ||
1807 | reason = "agent update failed"; | ||
1808 | } | ||
1809 | |||
1810 | if(!sucess) | ||
1627 | { | 1811 | { |
1628 | // region doesn't take it | 1812 | // region doesn't take it |
1629 | m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); | 1813 | m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); |
1630 | 1814 | ||
1631 | m_log.WarnFormat( | 1815 | m_log.WarnFormat( |
1632 | "[ENTITY TRANSFER MODULE]: Region {0} would not accept update for agent {1} on cross attempt. Returning to original region.", | 1816 | "[ENTITY TRANSFER MODULE]: agent {0} crossing to {1} failed: {2}", |
1633 | neighbourRegion.RegionName, agent.Name); | 1817 | agent.Name, neighbourRegion.RegionName, reason); |
1634 | 1818 | ||
1635 | ReInstantiateScripts(agent); | 1819 | ReInstantiateScripts(agent); |
1636 | agent.AddToPhysicalScene(isFlying); | 1820 | if(agent.ParentID == 0 && agent.ParentUUID == UUID.Zero) |
1821 | { | ||
1822 | agent.AddToPhysicalScene(isFlying); | ||
1823 | } | ||
1637 | 1824 | ||
1638 | return false; | 1825 | return false; |
1639 | } | 1826 | } |
1640 | 1827 | ||
1828 | m_log.DebugFormat("[CrossAgentIntoNewRegionMain] ok, time {0}ms",Util.EnvironmentTickCountSubtract(ts)); | ||
1641 | } | 1829 | } |
1642 | catch (Exception e) | 1830 | catch (Exception e) |
1643 | { | 1831 | { |
@@ -1649,44 +1837,38 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1649 | return false; | 1837 | return false; |
1650 | } | 1838 | } |
1651 | 1839 | ||
1652 | return true; | ||
1653 | } | ||
1654 | |||
1655 | public void CrossAgentToNewRegionPost(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, | ||
1656 | bool isFlying, EntityTransferContext ctx) | ||
1657 | { | ||
1658 | agent.ControllingClient.RequestClientInfo(); | ||
1659 | |||
1660 | string agentcaps; | 1840 | string agentcaps; |
1661 | if (!agent.KnownRegions.TryGetValue(neighbourRegion.RegionHandle, out agentcaps)) | 1841 | if (!agent.KnownRegions.TryGetValue(neighbourRegion.RegionHandle, out agentcaps)) |
1662 | { | 1842 | { |
1663 | m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: No ENTITY TRANSFER MODULE information for region handle {0}, exiting CrossToNewRegion.", | 1843 | m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: No ENTITY TRANSFER MODULE information for region handle {0}, exiting CrossToNewRegion.", |
1664 | neighbourRegion.RegionHandle); | 1844 | neighbourRegion.RegionHandle); |
1665 | return; | 1845 | return false; |
1666 | } | 1846 | } |
1667 | 1847 | ||
1668 | // No turning back | 1848 | // No turning back |
1849 | |||
1669 | agent.IsChildAgent = true; | 1850 | agent.IsChildAgent = true; |
1670 | 1851 | ||
1671 | string capsPath = neighbourRegion.ServerURI + CapsUtil.GetCapsSeedPath(agentcaps); | 1852 | string capsPath = neighbourRegion.ServerURI + CapsUtil.GetCapsSeedPath(agentcaps); |
1672 | 1853 | ||
1673 | m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID); | 1854 | m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID); |
1674 | 1855 | ||
1675 | Vector3 vel2 = new Vector3(agent.Velocity.X, agent.Velocity.Y, 0); | 1856 | Vector3 vel2 = Vector3.Zero; |
1857 | if((agent.crossingFlags & 2) != 0) | ||
1858 | vel2 = new Vector3(agent.Velocity.X, agent.Velocity.Y, 0); | ||
1676 | 1859 | ||
1677 | if (m_eqModule != null) | 1860 | if (m_eqModule != null) |
1678 | { | 1861 | { |
1679 | m_eqModule.CrossRegion( | 1862 | m_eqModule.CrossRegion( |
1680 | neighbourRegion.RegionHandle, pos + agent.Velocity, vel2 /* agent.Velocity */, | 1863 | neighbourRegion.RegionHandle, pos, vel2 /* agent.Velocity */, |
1681 | neighbourRegion.ExternalEndPoint, | 1864 | endpoint, capsPath, agent.UUID, agent.ControllingClient.SessionId, |
1682 | capsPath, agent.UUID, agent.ControllingClient.SessionId, | ||
1683 | neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY); | 1865 | neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY); |
1684 | } | 1866 | } |
1685 | else | 1867 | else |
1686 | { | 1868 | { |
1687 | m_log.ErrorFormat("{0} Using old CrossRegion packet. Varregion will not work!!", LogHeader); | 1869 | m_log.ErrorFormat("{0} Using old CrossRegion packet. Varregion will not work!!", LogHeader); |
1688 | agent.ControllingClient.CrossRegion(neighbourRegion.RegionHandle, pos + agent.Velocity, agent.Velocity, neighbourRegion.ExternalEndPoint, | 1870 | agent.ControllingClient.CrossRegion(neighbourRegion.RegionHandle, pos, agent.Velocity, |
1689 | capsPath); | 1871 | endpoint,capsPath); |
1690 | } | 1872 | } |
1691 | 1873 | ||
1692 | // SUCCESS! | 1874 | // SUCCESS! |
@@ -1695,51 +1877,23 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1695 | // Unlike a teleport, here we do not wait for the destination region to confirm the receipt. | 1877 | // Unlike a teleport, here we do not wait for the destination region to confirm the receipt. |
1696 | m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); | 1878 | m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); |
1697 | 1879 | ||
1698 | agent.MakeChildAgent(); | 1880 | if(childRegionsToClose != null) |
1881 | agent.CloseChildAgents(childRegionsToClose); | ||
1699 | 1882 | ||
1700 | // FIXME: Possibly this should occur lower down after other commands to close other agents, | 1883 | if((agent.crossingFlags & 8) == 0) |
1701 | // but not sure yet what the side effects would be. | 1884 | agent.ClearControls(); // don't let attachments delete (called in HasMovedAway) disturb taken controls on viewers |
1702 | m_entityTransferStateMachine.ResetFromTransit(agent.UUID); | ||
1703 | |||
1704 | // now we have a child agent in this region. Request all interesting data about other (root) agents | ||
1705 | agent.SendOtherAgentsAvatarDataToClient(); | ||
1706 | agent.SendOtherAgentsAppearanceToClient(); | ||
1707 | |||
1708 | // TODO: Check since what version this wasn't needed anymore. May be as old as 0.6 | ||
1709 | /* | ||
1710 | // Backwards compatibility. Best effort | ||
1711 | if (version == 0f) | ||
1712 | { | ||
1713 | m_log.DebugFormat("[ENTITY TRANSFER MODULE]: neighbor with old version, passing attachments one by one..."); | ||
1714 | Thread.Sleep(3000); // wait a little now that we're not waiting for the callback | ||
1715 | CrossAttachmentsIntoNewRegion(neighbourRegion, agent, true); | ||
1716 | } | ||
1717 | */ | ||
1718 | // Next, let's close the child agent connections that are too far away. | ||
1719 | uint neighbourx; | ||
1720 | uint neighboury; | ||
1721 | Util.RegionHandleToRegionLoc(neighbourRegion.RegionHandle, out neighbourx, out neighboury); | ||
1722 | 1885 | ||
1723 | agent.CloseChildAgents(neighbourx, neighboury); | 1886 | agent.HasMovedAway((agent.crossingFlags & 8) == 0); |
1724 | 1887 | ||
1725 | AgentHasMovedAway(agent, false); | 1888 | agent.MakeChildAgent(neighbourRegion.RegionHandle); |
1726 | 1889 | ||
1727 | // the user may change their profile information in other region, | 1890 | // FIXME: Possibly this should occur lower down after other commands to close other agents, |
1728 | // so the userinfo in UserProfileCache is not reliable any more, delete it | 1891 | // but not sure yet what the side effects would be. |
1729 | // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! | 1892 | m_entityTransferStateMachine.ResetFromTransit(agent.UUID); |
1730 | // if (agent.Scene.NeedSceneCacheClear(agent.UUID)) | ||
1731 | // { | ||
1732 | // m_log.DebugFormat( | ||
1733 | // "[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID); | ||
1734 | // } | ||
1735 | |||
1736 | //m_log.Debug("AFTER CROSS"); | ||
1737 | //Scene.DumpChildrenSeeds(UUID); | ||
1738 | //DumpKnownRegions(); | ||
1739 | 1893 | ||
1740 | return; | 1894 | return true; |
1741 | } | 1895 | } |
1742 | 1896 | ||
1743 | private void CrossAgentToNewRegionCompleted(IAsyncResult iar) | 1897 | private void CrossAgentToNewRegionCompleted(IAsyncResult iar) |
1744 | { | 1898 | { |
1745 | CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState; | 1899 | CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState; |
@@ -1754,7 +1908,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1754 | // In any case | 1908 | // In any case |
1755 | agent.IsInTransit = false; | 1909 | agent.IsInTransit = false; |
1756 | 1910 | ||
1757 | m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname); | 1911 | // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname); |
1758 | } | 1912 | } |
1759 | 1913 | ||
1760 | #endregion | 1914 | #endregion |
@@ -1762,7 +1916,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1762 | #region Enable Child Agent | 1916 | #region Enable Child Agent |
1763 | 1917 | ||
1764 | /// <summary> | 1918 | /// <summary> |
1765 | /// This informs a single neighbouring region about agent "avatar". | 1919 | /// This informs a single neighbouring region about agent "avatar", and avatar about it |
1766 | /// Calls an asynchronous method to do so.. so it doesn't lag the sim. | 1920 | /// Calls an asynchronous method to do so.. so it doesn't lag the sim. |
1767 | /// </summary> | 1921 | /// </summary> |
1768 | /// <param name="sp"></param> | 1922 | /// <param name="sp"></param> |
@@ -1771,42 +1925,46 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1771 | { | 1925 | { |
1772 | m_log.DebugFormat("[ENTITY TRANSFER]: Enabling child agent in new neighbour {0}", region.RegionName); | 1926 | m_log.DebugFormat("[ENTITY TRANSFER]: Enabling child agent in new neighbour {0}", region.RegionName); |
1773 | 1927 | ||
1928 | ulong currentRegionHandler = sp.Scene.RegionInfo.RegionHandle; | ||
1929 | ulong regionhandler = region.RegionHandle; | ||
1930 | |||
1931 | Dictionary<ulong, string> seeds = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID)); | ||
1932 | |||
1933 | if (seeds.ContainsKey(regionhandler)) | ||
1934 | seeds.Remove(regionhandler); | ||
1935 | /* | ||
1936 | List<ulong> oldregions = new List<ulong>(seeds.Keys); | ||
1937 | |||
1938 | if (oldregions.Contains(currentRegionHandler)) | ||
1939 | oldregions.Remove(currentRegionHandler); | ||
1940 | */ | ||
1941 | if (!seeds.ContainsKey(currentRegionHandler)) | ||
1942 | seeds.Add(currentRegionHandler, sp.ControllingClient.RequestClientInfo().CapsPath); | ||
1943 | |||
1774 | AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); | 1944 | AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); |
1775 | AgentCircuitData agent = sp.ControllingClient.RequestClientInfo(); | 1945 | AgentCircuitData agent = sp.ControllingClient.RequestClientInfo(); |
1776 | agent.BaseFolder = UUID.Zero; | 1946 | agent.BaseFolder = UUID.Zero; |
1777 | agent.InventoryFolder = UUID.Zero; | 1947 | agent.InventoryFolder = UUID.Zero; |
1778 | agent.startpos = new Vector3(128, 128, 70); | 1948 | agent.startpos = sp.AbsolutePosition + CalculateOffset(sp, region); |
1779 | agent.child = true; | 1949 | agent.child = true; |
1780 | agent.Appearance = new AvatarAppearance(); | 1950 | agent.Appearance = new AvatarAppearance(); |
1781 | agent.Appearance.PackLegacyWearables = true; | 1951 | agent.Appearance.AvatarHeight = sp.Appearance.AvatarHeight; |
1782 | agent.CapsPath = CapsUtil.GetRandomCapsObjectPath(); | ||
1783 | |||
1784 | agent.ChildrenCapSeeds = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID)); | ||
1785 | //m_log.DebugFormat("[XXX] Seeds 1 {0}", agent.ChildrenCapSeeds.Count); | ||
1786 | 1952 | ||
1787 | if (!agent.ChildrenCapSeeds.ContainsKey(sp.Scene.RegionInfo.RegionHandle)) | 1953 | agent.CapsPath = CapsUtil.GetRandomCapsObjectPath(); |
1788 | agent.ChildrenCapSeeds.Add(sp.Scene.RegionInfo.RegionHandle, sp.ControllingClient.RequestClientInfo().CapsPath); | ||
1789 | //m_log.DebugFormat("[XXX] Seeds 2 {0}", agent.ChildrenCapSeeds.Count); | ||
1790 | 1954 | ||
1791 | sp.AddNeighbourRegion(region.RegionHandle, agent.CapsPath); | 1955 | seeds.Add(regionhandler, agent.CapsPath); |
1792 | //foreach (ulong h in agent.ChildrenCapSeeds.Keys) | ||
1793 | // m_log.DebugFormat("[XXX] --> {0}", h); | ||
1794 | //m_log.DebugFormat("[XXX] Adding {0}", region.RegionHandle); | ||
1795 | if (agent.ChildrenCapSeeds.ContainsKey(region.RegionHandle)) | ||
1796 | { | ||
1797 | m_log.WarnFormat( | ||
1798 | "[ENTITY TRANSFER]: Overwriting caps seed {0} with {1} for region {2} (handle {3}) for {4} in {5}", | ||
1799 | agent.ChildrenCapSeeds[region.RegionHandle], agent.CapsPath, | ||
1800 | region.RegionName, region.RegionHandle, sp.Name, Scene.Name); | ||
1801 | } | ||
1802 | 1956 | ||
1803 | agent.ChildrenCapSeeds[region.RegionHandle] = agent.CapsPath; | 1957 | // agent.ChildrenCapSeeds = new Dictionary<ulong, string>(seeds); |
1958 | agent.ChildrenCapSeeds = null; | ||
1804 | 1959 | ||
1805 | if (sp.Scene.CapsModule != null) | 1960 | if (sp.Scene.CapsModule != null) |
1806 | { | 1961 | { |
1807 | sp.Scene.CapsModule.SetChildrenSeed(sp.UUID, agent.ChildrenCapSeeds); | 1962 | sp.Scene.CapsModule.SetChildrenSeed(sp.UUID, seeds); |
1808 | } | 1963 | } |
1809 | 1964 | ||
1965 | sp.KnownRegions = seeds; | ||
1966 | sp.AddNeighbourRegionSizeInfo(region); | ||
1967 | |||
1810 | if (currentAgentCircuit != null) | 1968 | if (currentAgentCircuit != null) |
1811 | { | 1969 | { |
1812 | agent.ServiceURLs = currentAgentCircuit.ServiceURLs; | 1970 | agent.ServiceURLs = currentAgentCircuit.ServiceURLs; |
@@ -1816,7 +1974,24 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1816 | agent.Mac = currentAgentCircuit.Mac; | 1974 | agent.Mac = currentAgentCircuit.Mac; |
1817 | agent.Id0 = currentAgentCircuit.Id0; | 1975 | agent.Id0 = currentAgentCircuit.Id0; |
1818 | } | 1976 | } |
1819 | 1977 | /* | |
1978 | AgentPosition agentpos = null; | ||
1979 | |||
1980 | if (oldregions.Count > 0) | ||
1981 | { | ||
1982 | agentpos = new AgentPosition(); | ||
1983 | agentpos.AgentID = new UUID(sp.UUID.Guid); | ||
1984 | agentpos.SessionID = sp.ControllingClient.SessionId; | ||
1985 | agentpos.Size = sp.Appearance.AvatarSize; | ||
1986 | agentpos.Center = sp.CameraPosition; | ||
1987 | agentpos.Far = sp.DrawDistance; | ||
1988 | agentpos.Position = sp.AbsolutePosition; | ||
1989 | agentpos.Velocity = sp.Velocity; | ||
1990 | agentpos.RegionHandle = currentRegionHandler; | ||
1991 | agentpos.Throttles = sp.ControllingClient.GetThrottlesPacked(1); | ||
1992 | agentpos.ChildrenCapSeeds = seeds; | ||
1993 | } | ||
1994 | */ | ||
1820 | IPEndPoint external = region.ExternalEndPoint; | 1995 | IPEndPoint external = region.ExternalEndPoint; |
1821 | if (external != null) | 1996 | if (external != null) |
1822 | { | 1997 | { |
@@ -1825,7 +2000,22 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1825 | InformClientOfNeighbourCompleted, | 2000 | InformClientOfNeighbourCompleted, |
1826 | d); | 2001 | d); |
1827 | } | 2002 | } |
2003 | /* | ||
2004 | if(oldregions.Count >0) | ||
2005 | { | ||
2006 | uint neighbourx; | ||
2007 | uint neighboury; | ||
2008 | UUID scope = sp.Scene.RegionInfo.ScopeID; | ||
2009 | foreach (ulong handler in oldregions) | ||
2010 | { | ||
2011 | Utils.LongToUInts(handler, out neighbourx, out neighboury); | ||
2012 | GridRegion neighbour = sp.Scene.GridService.GetRegionByPosition(scope, (int)neighbourx, (int)neighboury); | ||
2013 | sp.Scene.SimulationService.UpdateAgent(neighbour, agentpos); | ||
2014 | } | ||
2015 | } | ||
2016 | */ | ||
1828 | } | 2017 | } |
2018 | |||
1829 | #endregion | 2019 | #endregion |
1830 | 2020 | ||
1831 | #region Enable Child Agents | 2021 | #region Enable Child Agents |
@@ -1835,167 +2025,175 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1835 | 2025 | ||
1836 | /// <summary> | 2026 | /// <summary> |
1837 | /// This informs all neighbouring regions about agent "avatar". | 2027 | /// This informs all neighbouring regions about agent "avatar". |
2028 | /// and as important informs the avatar about then | ||
1838 | /// </summary> | 2029 | /// </summary> |
1839 | /// <param name="sp"></param> | 2030 | /// <param name="sp"></param> |
1840 | public void EnableChildAgents(ScenePresence sp) | 2031 | public void EnableChildAgents(ScenePresence sp) |
1841 | { | 2032 | { |
2033 | // assumes that out of view range regions are disconnected by the previus region | ||
2034 | |||
1842 | List<GridRegion> neighbours = new List<GridRegion>(); | 2035 | List<GridRegion> neighbours = new List<GridRegion>(); |
1843 | RegionInfo m_regionInfo = sp.Scene.RegionInfo; | 2036 | Scene spScene = sp.Scene; |
2037 | RegionInfo m_regionInfo = spScene.RegionInfo; | ||
1844 | 2038 | ||
1845 | if (m_regionInfo != null) | 2039 | if (m_regionInfo != null) |
1846 | { | 2040 | { |
1847 | neighbours = GetNeighbours(sp, m_regionInfo.RegionLocX, m_regionInfo.RegionLocY); | 2041 | neighbours = GetNeighbors(sp, m_regionInfo.RegionLocX, m_regionInfo.RegionLocY); |
1848 | } | 2042 | } |
1849 | else | 2043 | else |
1850 | { | 2044 | { |
1851 | m_log.Debug("[ENTITY TRANSFER MODULE]: m_regionInfo was null in EnableChildAgents, is this a NPC?"); | 2045 | m_log.Debug("[ENTITY TRANSFER MODULE]: m_regionInfo was null in EnableChildAgents, is this a NPC?"); |
1852 | } | 2046 | } |
1853 | 2047 | ||
1854 | /// We need to find the difference between the new regions where there are no child agents | 2048 | ulong currentRegionHandler = m_regionInfo.RegionHandle; |
1855 | /// and the regions where there are already child agents. We only send notification to the former. | ||
1856 | List<ulong> neighbourHandles = NeighbourHandles(neighbours); // on this region | ||
1857 | neighbourHandles.Add(sp.Scene.RegionInfo.RegionHandle); // add this region too | ||
1858 | List<ulong> previousRegionNeighbourHandles; | ||
1859 | 2049 | ||
1860 | if (sp.Scene.CapsModule != null) | 2050 | LinkedList<ulong> previousRegionNeighbourHandles; |
2051 | Dictionary<ulong, string> seeds; | ||
2052 | ICapabilitiesModule capsModule = spScene.CapsModule; | ||
2053 | |||
2054 | if (capsModule != null) | ||
1861 | { | 2055 | { |
1862 | previousRegionNeighbourHandles = | 2056 | seeds = new Dictionary<ulong, string>(capsModule.GetChildrenSeeds(sp.UUID)); |
1863 | new List<ulong>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID).Keys); | 2057 | previousRegionNeighbourHandles = new LinkedList<ulong>(seeds.Keys); |
1864 | } | 2058 | } |
1865 | else | 2059 | else |
1866 | { | 2060 | { |
1867 | previousRegionNeighbourHandles = new List<ulong>(); | 2061 | seeds = new Dictionary<ulong, string>(); |
2062 | previousRegionNeighbourHandles = new LinkedList<ulong>(); | ||
1868 | } | 2063 | } |
1869 | 2064 | ||
1870 | List<ulong> newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles); | 2065 | IClientAPI spClient = sp.ControllingClient; |
1871 | List<ulong> oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles); | ||
1872 | |||
1873 | // Dump("Current Neighbors", neighbourHandles); | ||
1874 | // Dump("Previous Neighbours", previousRegionNeighbourHandles); | ||
1875 | // Dump("New Neighbours", newRegions); | ||
1876 | // Dump("Old Neighbours", oldRegions); | ||
1877 | 2066 | ||
1878 | /// Update the scene presence's known regions here on this region | 2067 | // This will fail if the user aborts login |
1879 | sp.DropOldNeighbours(oldRegions); | 2068 | try |
1880 | 2069 | { | |
1881 | /// Collect as many seeds as possible | 2070 | if (!seeds.ContainsKey(currentRegionHandler)) |
1882 | Dictionary<ulong, string> seeds; | 2071 | seeds.Add(currentRegionHandler, spClient.RequestClientInfo().CapsPath); |
1883 | if (sp.Scene.CapsModule != null) | 2072 | } |
1884 | seeds = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID)); | 2073 | catch |
1885 | else | 2074 | { |
1886 | seeds = new Dictionary<ulong, string>(); | 2075 | return; |
2076 | } | ||
1887 | 2077 | ||
1888 | //m_log.Debug(" !!! No. of seeds: " + seeds.Count); | 2078 | AgentCircuitData currentAgentCircuit = |
1889 | if (!seeds.ContainsKey(sp.Scene.RegionInfo.RegionHandle)) | 2079 | spScene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); |
1890 | seeds.Add(sp.Scene.RegionInfo.RegionHandle, sp.ControllingClient.RequestClientInfo().CapsPath); | ||
1891 | 2080 | ||
1892 | /// Create the necessary child agents | ||
1893 | List<AgentCircuitData> cagents = new List<AgentCircuitData>(); | 2081 | List<AgentCircuitData> cagents = new List<AgentCircuitData>(); |
2082 | List<ulong> newneighbours = new List<ulong>(); | ||
2083 | |||
1894 | foreach (GridRegion neighbour in neighbours) | 2084 | foreach (GridRegion neighbour in neighbours) |
1895 | { | 2085 | { |
1896 | if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle) | 2086 | ulong handler = neighbour.RegionHandle; |
2087 | |||
2088 | if (previousRegionNeighbourHandles.Contains(handler)) | ||
1897 | { | 2089 | { |
1898 | AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); | 2090 | // agent already knows this region |
1899 | AgentCircuitData agent = sp.ControllingClient.RequestClientInfo(); | 2091 | previousRegionNeighbourHandles.Remove(handler); |
1900 | agent.BaseFolder = UUID.Zero; | 2092 | continue; |
1901 | agent.InventoryFolder = UUID.Zero; | 2093 | } |
1902 | agent.startpos = sp.AbsolutePosition + CalculateOffset(sp, neighbour); | ||
1903 | agent.child = true; | ||
1904 | agent.Appearance = new AvatarAppearance(); | ||
1905 | agent.Appearance.PackLegacyWearables = true; | ||
1906 | if (currentAgentCircuit != null) | ||
1907 | { | ||
1908 | agent.ServiceURLs = currentAgentCircuit.ServiceURLs; | ||
1909 | agent.IPAddress = currentAgentCircuit.IPAddress; | ||
1910 | agent.Viewer = currentAgentCircuit.Viewer; | ||
1911 | agent.Channel = currentAgentCircuit.Channel; | ||
1912 | agent.Mac = currentAgentCircuit.Mac; | ||
1913 | agent.Id0 = currentAgentCircuit.Id0; | ||
1914 | } | ||
1915 | 2094 | ||
1916 | if (newRegions.Contains(neighbour.RegionHandle)) | 2095 | if (handler == currentRegionHandler) |
1917 | { | 2096 | continue; |
1918 | agent.CapsPath = CapsUtil.GetRandomCapsObjectPath(); | ||
1919 | sp.AddNeighbourRegion(neighbour.RegionHandle, agent.CapsPath); | ||
1920 | seeds.Add(neighbour.RegionHandle, agent.CapsPath); | ||
1921 | } | ||
1922 | else | ||
1923 | { | ||
1924 | agent.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, neighbour.RegionHandle); | ||
1925 | } | ||
1926 | 2097 | ||
1927 | cagents.Add(agent); | 2098 | // a new region to add |
2099 | AgentCircuitData agent = spClient.RequestClientInfo(); | ||
2100 | agent.BaseFolder = UUID.Zero; | ||
2101 | agent.InventoryFolder = UUID.Zero; | ||
2102 | agent.startpos = sp.AbsolutePosition + CalculateOffset(sp, neighbour); | ||
2103 | agent.child = true; | ||
2104 | agent.Appearance = new AvatarAppearance(); | ||
2105 | agent.Appearance.AvatarHeight = sp.Appearance.AvatarHeight; | ||
2106 | |||
2107 | if (currentAgentCircuit != null) | ||
2108 | { | ||
2109 | agent.ServiceURLs = currentAgentCircuit.ServiceURLs; | ||
2110 | agent.IPAddress = currentAgentCircuit.IPAddress; | ||
2111 | agent.Viewer = currentAgentCircuit.Viewer; | ||
2112 | agent.Channel = currentAgentCircuit.Channel; | ||
2113 | agent.Mac = currentAgentCircuit.Mac; | ||
2114 | agent.Id0 = currentAgentCircuit.Id0; | ||
1928 | } | 2115 | } |
1929 | } | ||
1930 | 2116 | ||
1931 | /// Update all child agent with everyone's seeds | 2117 | newneighbours.Add(handler); |
1932 | foreach (AgentCircuitData a in cagents) | 2118 | agent.CapsPath = CapsUtil.GetRandomCapsObjectPath(); |
1933 | { | 2119 | seeds.Add(handler, agent.CapsPath); |
1934 | a.ChildrenCapSeeds = new Dictionary<ulong, string>(seeds); | ||
1935 | } | ||
1936 | 2120 | ||
1937 | if (sp.Scene.CapsModule != null) | 2121 | agent.ChildrenCapSeeds = null; |
1938 | { | 2122 | cagents.Add(agent); |
1939 | sp.Scene.CapsModule.SetChildrenSeed(sp.UUID, seeds); | ||
1940 | } | 2123 | } |
1941 | sp.KnownRegions = seeds; | ||
1942 | //avatar.Scene.DumpChildrenSeeds(avatar.UUID); | ||
1943 | //avatar.DumpKnownRegions(); | ||
1944 | 2124 | ||
1945 | bool newAgent = false; | 2125 | if (previousRegionNeighbourHandles.Contains(currentRegionHandler)) |
1946 | int count = 0; | 2126 | previousRegionNeighbourHandles.Remove(currentRegionHandler); |
1947 | foreach (GridRegion neighbour in neighbours) | ||
1948 | { | ||
1949 | //m_log.WarnFormat("--> Going to send child agent to {0}", neighbour.RegionName); | ||
1950 | // Don't do it if there's already an agent in that region | ||
1951 | if (newRegions.Contains(neighbour.RegionHandle)) | ||
1952 | newAgent = true; | ||
1953 | else | ||
1954 | newAgent = false; | ||
1955 | // continue; | ||
1956 | 2127 | ||
1957 | if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle) | 2128 | // previousRegionNeighbourHandles now contains regions to forget |
1958 | { | 2129 | foreach (ulong handler in previousRegionNeighbourHandles) |
1959 | try | 2130 | seeds.Remove(handler); |
1960 | { | ||
1961 | // Let's put this back at sync, so that it doesn't clog | ||
1962 | // the network, especially for regions in the same physical server. | ||
1963 | // We're really not in a hurry here. | ||
1964 | InformClientOfNeighbourAsync(sp, cagents[count], neighbour, neighbour.ExternalEndPoint, newAgent); | ||
1965 | //InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync; | ||
1966 | //d.BeginInvoke(sp, cagents[count], neighbour, neighbour.ExternalEndPoint, newAgent, | ||
1967 | // InformClientOfNeighbourCompleted, | ||
1968 | // d); | ||
1969 | } | ||
1970 | 2131 | ||
1971 | catch (ArgumentOutOfRangeException) | 2132 | /// Update all child agent with everyone's seeds |
1972 | { | 2133 | // foreach (AgentCircuitData a in cagents) |
1973 | m_log.ErrorFormat( | 2134 | // a.ChildrenCapSeeds = new Dictionary<ulong, string>(seeds); |
1974 | "[ENTITY TRANSFER MODULE]: Neighbour Regions response included the current region in the neighbour list. The following region will not display to the client: {0} for region {1} ({2}, {3}).", | ||
1975 | neighbour.ExternalHostName, | ||
1976 | neighbour.RegionHandle, | ||
1977 | neighbour.RegionLocX, | ||
1978 | neighbour.RegionLocY); | ||
1979 | } | ||
1980 | catch (Exception e) | ||
1981 | { | ||
1982 | m_log.ErrorFormat( | ||
1983 | "[ENTITY TRANSFER MODULE]: Could not resolve external hostname {0} for region {1} ({2}, {3}). {4}", | ||
1984 | neighbour.ExternalHostName, | ||
1985 | neighbour.RegionHandle, | ||
1986 | neighbour.RegionLocX, | ||
1987 | neighbour.RegionLocY, | ||
1988 | e); | ||
1989 | 2135 | ||
1990 | // FIXME: Okay, even though we've failed, we're still going to throw the exception on, | 2136 | if (capsModule != null) |
1991 | // since I don't know what will happen if we just let the client continue | 2137 | capsModule.SetChildrenSeed(sp.UUID, seeds); |
1992 | 2138 | ||
1993 | // XXX: Well, decided to swallow the exception instead for now. Let us see how that goes. | 2139 | sp.KnownRegions = seeds; |
1994 | // throw e; | 2140 | sp.SetNeighbourRegionSizeInfo(neighbours); |
2141 | |||
2142 | if(newneighbours.Count > 0 || previousRegionNeighbourHandles.Count > 0) | ||
2143 | { | ||
2144 | AgentPosition agentpos = new AgentPosition(); | ||
2145 | agentpos.AgentID = new UUID(sp.UUID.Guid); | ||
2146 | agentpos.SessionID = spClient.SessionId; | ||
2147 | agentpos.Size = sp.Appearance.AvatarSize; | ||
2148 | agentpos.Center = sp.CameraPosition; | ||
2149 | agentpos.Far = sp.DrawDistance; | ||
2150 | agentpos.Position = sp.AbsolutePosition; | ||
2151 | agentpos.Velocity = sp.Velocity; | ||
2152 | agentpos.RegionHandle = currentRegionHandler; | ||
2153 | //agentpos.GodLevel = sp.GodLevel; | ||
2154 | agentpos.GodData = sp.GodController.State(); | ||
2155 | agentpos.Throttles = spClient.GetThrottlesPacked(1); | ||
2156 | // agentpos.ChildrenCapSeeds = seeds; | ||
2157 | |||
2158 | Util.FireAndForget(delegate | ||
2159 | { | ||
2160 | Thread.Sleep(200); // the original delay that was at InformClientOfNeighbourAsync start | ||
2161 | int count = 0; | ||
2162 | IPEndPoint ipe; | ||
1995 | 2163 | ||
2164 | foreach (GridRegion neighbour in neighbours) | ||
2165 | { | ||
2166 | ulong handler = neighbour.RegionHandle; | ||
2167 | try | ||
2168 | { | ||
2169 | if (newneighbours.Contains(handler)) | ||
2170 | { | ||
2171 | ipe = neighbour.ExternalEndPoint; | ||
2172 | if (ipe != null) | ||
2173 | InformClientOfNeighbourAsync(sp, cagents[count], neighbour, ipe, true); | ||
2174 | else | ||
2175 | { | ||
2176 | m_log.DebugFormat("[ENTITY TRANSFER MODULE]: lost DNS resolution for neighbour {0}", neighbour.ExternalHostName); | ||
2177 | } | ||
2178 | count++; | ||
2179 | } | ||
2180 | else if (!previousRegionNeighbourHandles.Contains(handler)) | ||
2181 | { | ||
2182 | spScene.SimulationService.UpdateAgent(neighbour, agentpos); | ||
2183 | } | ||
2184 | } | ||
2185 | catch (Exception e) | ||
2186 | { | ||
2187 | m_log.ErrorFormat( | ||
2188 | "[ENTITY TRANSFER MODULE]: Error creating child agent at {0} ({1} ({2}, {3}). {4}", | ||
2189 | neighbour.ExternalHostName, | ||
2190 | neighbour.RegionHandle, | ||
2191 | neighbour.RegionLocX, | ||
2192 | neighbour.RegionLocY, | ||
2193 | e); | ||
2194 | } | ||
1996 | } | 2195 | } |
1997 | } | 2196 | }); |
1998 | count++; | ||
1999 | } | 2197 | } |
2000 | } | 2198 | } |
2001 | 2199 | ||
@@ -2004,26 +2202,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2004 | // The first region is the home region of the passed scene presence. | 2202 | // The first region is the home region of the passed scene presence. |
2005 | Vector3 CalculateOffset(ScenePresence sp, GridRegion neighbour) | 2203 | Vector3 CalculateOffset(ScenePresence sp, GridRegion neighbour) |
2006 | { | 2204 | { |
2007 | /* | 2205 | return new Vector3(sp.Scene.RegionInfo.WorldLocX - neighbour.RegionLocX, |
2008 | int rRegionX = (int)sp.Scene.RegionInfo.LegacyRegionLocX; | ||
2009 | int rRegionY = (int)sp.Scene.RegionInfo.LegacyRegionLocY; | ||
2010 | int tRegionX = neighbour.RegionLocX / (int)Constants.RegionSize; | ||
2011 | int tRegionY = neighbour.RegionLocY / (int)Constants.RegionSize; | ||
2012 | int shiftx = (rRegionX - tRegionX) * (int)Constants.RegionSize; | ||
2013 | int shifty = (rRegionY - tRegionY) * (int)Constants.RegionSize; | ||
2014 | return new Vector3(shiftx, shifty, 0f); | ||
2015 | */ | ||
2016 | return new Vector3( sp.Scene.RegionInfo.WorldLocX - neighbour.RegionLocX, | ||
2017 | sp.Scene.RegionInfo.WorldLocY - neighbour.RegionLocY, | 2206 | sp.Scene.RegionInfo.WorldLocY - neighbour.RegionLocY, |
2018 | 0f); | 2207 | 0f); |
2019 | } | 2208 | } |
2020 | 2209 | #endregion | |
2021 | public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py) | ||
2022 | { | ||
2023 | // Since we don't know how big the regions could be, we have to search a very large area | ||
2024 | // to find possible regions. | ||
2025 | return GetRegionContainingWorldLocation(pGridService, pScopeID, px, py, Constants.MaximumRegionSize); | ||
2026 | } | ||
2027 | 2210 | ||
2028 | #region NotFoundLocationCache class | 2211 | #region NotFoundLocationCache class |
2029 | // A collection of not found locations to make future lookups 'not found' lookups quick. | 2212 | // A collection of not found locations to make future lookups 'not found' lookups quick. |
@@ -2032,162 +2215,131 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2032 | // contains that point. A conservitive estimate. | 2215 | // contains that point. A conservitive estimate. |
2033 | private class NotFoundLocationCache | 2216 | private class NotFoundLocationCache |
2034 | { | 2217 | { |
2035 | private struct NotFoundLocation | 2218 | private Dictionary<ulong, DateTime> m_notFoundLocations = new Dictionary<ulong, DateTime>(); |
2036 | { | ||
2037 | public double minX, maxX, minY, maxY; | ||
2038 | public DateTime expireTime; | ||
2039 | } | ||
2040 | private List<NotFoundLocation> m_notFoundLocations = new List<NotFoundLocation>(); | ||
2041 | public NotFoundLocationCache() | 2219 | public NotFoundLocationCache() |
2042 | { | 2220 | { |
2043 | } | 2221 | } |
2044 | // Add an area to the list of 'not found' places. The area is the snapped region | 2222 | // just use normal regions handlers and sizes |
2045 | // area around the added point. | ||
2046 | public void Add(double pX, double pY) | 2223 | public void Add(double pX, double pY) |
2047 | { | 2224 | { |
2225 | ulong psh = (ulong)pX & 0xffffff00ul; | ||
2226 | psh <<= 32; | ||
2227 | psh |= (ulong)pY & 0xffffff00ul; | ||
2228 | |||
2048 | lock (m_notFoundLocations) | 2229 | lock (m_notFoundLocations) |
2049 | { | 2230 | m_notFoundLocations[psh] = DateTime.UtcNow + TimeSpan.FromSeconds(30); |
2050 | if (!LockedContains(pX, pY)) | ||
2051 | { | ||
2052 | NotFoundLocation nfl = new NotFoundLocation(); | ||
2053 | // A not found location is not found for at least a whole region sized area | ||
2054 | nfl.minX = pX - (pX % (double)Constants.RegionSize); | ||
2055 | nfl.minY = pY - (pY % (double)Constants.RegionSize); | ||
2056 | nfl.maxX = nfl.minX + (double)Constants.RegionSize; | ||
2057 | nfl.maxY = nfl.minY + (double)Constants.RegionSize; | ||
2058 | nfl.expireTime = DateTime.Now + TimeSpan.FromSeconds(30); | ||
2059 | m_notFoundLocations.Add(nfl); | ||
2060 | } | ||
2061 | } | ||
2062 | |||
2063 | } | 2231 | } |
2064 | // Test to see of this point is in any of the 'not found' areas. | 2232 | // Test to see of this point is in any of the 'not found' areas. |
2065 | // Return 'true' if the point is found inside the 'not found' areas. | 2233 | // Return 'true' if the point is found inside the 'not found' areas. |
2066 | public bool Contains(double pX, double pY) | 2234 | public bool Contains(double pX, double pY) |
2067 | { | 2235 | { |
2068 | bool ret = false; | 2236 | ulong psh = (ulong)pX & 0xffffff00ul; |
2237 | psh <<= 32; | ||
2238 | psh |= (ulong)pY & 0xffffff00ul; | ||
2239 | |||
2069 | lock (m_notFoundLocations) | 2240 | lock (m_notFoundLocations) |
2070 | ret = LockedContains(pX, pY); | ||
2071 | return ret; | ||
2072 | } | ||
2073 | private bool LockedContains(double pX, double pY) | ||
2074 | { | ||
2075 | bool ret = false; | ||
2076 | this.DoExpiration(); | ||
2077 | foreach (NotFoundLocation nfl in m_notFoundLocations) | ||
2078 | { | 2241 | { |
2079 | if (pX >= nfl.minX && pX < nfl.maxX && pY >= nfl.minY && pY < nfl.maxY) | 2242 | if(m_notFoundLocations.ContainsKey(psh)) |
2080 | { | 2243 | { |
2081 | ret = true; | 2244 | if(m_notFoundLocations[psh] > DateTime.UtcNow) |
2082 | break; | 2245 | return true; |
2246 | m_notFoundLocations.Remove(psh); | ||
2083 | } | 2247 | } |
2248 | return false; | ||
2084 | } | 2249 | } |
2085 | return ret; | ||
2086 | } | 2250 | } |
2251 | |||
2087 | private void DoExpiration() | 2252 | private void DoExpiration() |
2088 | { | 2253 | { |
2089 | List<NotFoundLocation> m_toRemove = null; | 2254 | List<ulong> m_toRemove = new List<ulong>();; |
2090 | DateTime now = DateTime.Now; | 2255 | DateTime now = DateTime.UtcNow; |
2091 | foreach (NotFoundLocation nfl in m_notFoundLocations) | 2256 | lock (m_notFoundLocations) |
2092 | { | 2257 | { |
2093 | if (nfl.expireTime < now) | 2258 | foreach (KeyValuePair<ulong, DateTime> kvp in m_notFoundLocations) |
2094 | { | 2259 | { |
2095 | if (m_toRemove == null) | 2260 | if (kvp.Value < now) |
2096 | m_toRemove = new List<NotFoundLocation>(); | 2261 | m_toRemove.Add(kvp.Key); |
2097 | m_toRemove.Add(nfl); | 2262 | } |
2263 | |||
2264 | if (m_toRemove.Count > 0) | ||
2265 | { | ||
2266 | foreach (ulong u in m_toRemove) | ||
2267 | m_notFoundLocations.Remove(u); | ||
2268 | m_toRemove.Clear(); | ||
2098 | } | 2269 | } |
2099 | } | ||
2100 | if (m_toRemove != null) | ||
2101 | { | ||
2102 | foreach (NotFoundLocation nfl in m_toRemove) | ||
2103 | m_notFoundLocations.Remove(nfl); | ||
2104 | m_toRemove.Clear(); | ||
2105 | } | 2270 | } |
2106 | } | 2271 | } |
2107 | } | 2272 | } |
2273 | |||
2108 | #endregion // NotFoundLocationCache class | 2274 | #endregion // NotFoundLocationCache class |
2275 | #region getregions | ||
2109 | private NotFoundLocationCache m_notFoundLocationCache = new NotFoundLocationCache(); | 2276 | private NotFoundLocationCache m_notFoundLocationCache = new NotFoundLocationCache(); |
2110 | 2277 | ||
2111 | // Given a world position (fractional meter coordinate), get the GridRegion info for | 2278 | protected GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py) |
2279 | { | ||
2280 | // Since we don't know how big the regions could be, we have to search a very large area | ||
2281 | // to find possible regions. | ||
2282 | return GetRegionContainingWorldLocation(pGridService, pScopeID, px, py, Constants.MaximumRegionSize); | ||
2283 | } | ||
2284 | |||
2285 | // Given a world position, get the GridRegion info for | ||
2112 | // the region containing that point. | 2286 | // the region containing that point. |
2113 | // Someday this should be a method on GridService. | 2287 | // for compatibility with old grids it does a scan to find large regions |
2114 | // 'pSizeHint' is the size of the source region but since the destination point can be anywhere | 2288 | // 0.9 grids to that |
2115 | // the size of the target region is unknown thus the search area might have to be very large. | 2289 | |
2116 | // Return 'null' if no such region exists. | 2290 | protected GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, |
2117 | public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, | ||
2118 | double px, double py, uint pSizeHint) | 2291 | double px, double py, uint pSizeHint) |
2119 | { | 2292 | { |
2120 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: query, loc=<{1},{2}>", LogHeader, px, py); | 2293 | // m_log.DebugFormat("{0} GetRegionContainingWorldLocation: call, XY=<{1},{2}>", LogHeader, px, py); |
2121 | GridRegion ret = null; | 2294 | GridRegion ret = null; |
2122 | const double fudge = 2.0; | ||
2123 | 2295 | ||
2124 | // One problem with this routine is negative results. That is, this can be called lots of times | ||
2125 | // for regions that don't exist. m_notFoundLocationCache remembers 'not found' results so they | ||
2126 | // will be quick 'not found's next time. | ||
2127 | // NotFoundLocationCache is an expiring cache so it will eventually forget about 'not found' and | ||
2128 | // thus re-ask the GridService about the location. | ||
2129 | if (m_notFoundLocationCache.Contains(px, py)) | 2296 | if (m_notFoundLocationCache.Contains(px, py)) |
2130 | { | 2297 | { |
2131 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found via cache. loc=<{1},{2}>", LogHeader, px, py); | 2298 | // m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found via cache. loc=<{1},{2}>", LogHeader, px, py); |
2132 | return null; | 2299 | return null; |
2133 | } | 2300 | } |
2134 | 2301 | ||
2135 | // As an optimization, since most regions will be legacy sized regions (256x256), first try to get | 2302 | // As an optimization, since most regions will be legacy sized regions (256x256), first try to get |
2136 | // the region at the appropriate legacy region location. | 2303 | // the region at the appropriate legacy region location. |
2137 | uint possibleX = (uint)Math.Floor(px); | 2304 | // this is all that is needed on 0.9 grids |
2138 | possibleX -= possibleX % Constants.RegionSize; | 2305 | uint possibleX = (uint)px & 0xffffff00u; |
2139 | uint possibleY = (uint)Math.Floor(py); | 2306 | uint possibleY = (uint)py & 0xffffff00u; |
2140 | possibleY -= possibleY % Constants.RegionSize; | ||
2141 | ret = pGridService.GetRegionByPosition(pScopeID, (int)possibleX, (int)possibleY); | 2307 | ret = pGridService.GetRegionByPosition(pScopeID, (int)possibleX, (int)possibleY); |
2142 | if (ret != null) | 2308 | if (ret != null) |
2143 | { | 2309 | { |
2144 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Found region using legacy size. rloc=<{1},{2}>. Rname={3}", | 2310 | // m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Found region using legacy size. rloc=<{1},{2}>. Rname={3}", |
2145 | LogHeader, possibleX, possibleY, ret.RegionName); | 2311 | // LogHeader, possibleX, possibleY, ret.RegionName); |
2312 | return ret; | ||
2146 | } | 2313 | } |
2147 | 2314 | ||
2148 | if (ret == null) | 2315 | // for 0.8 regions just make a BIG area request. old code whould do it plus 4 more smaller on region open edges |
2316 | // this is what 0.9 grids now do internally | ||
2317 | List<GridRegion> possibleRegions = pGridService.GetRegionRange(pScopeID, | ||
2318 | (int)(px - Constants.MaximumRegionSize), (int)(px + 1), // +1 bc left mb not part of range | ||
2319 | (int)(py - Constants.MaximumRegionSize), (int)(py + 1)); | ||
2320 | // m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegions cnt={1}, range={2}", | ||
2321 | // LogHeader, possibleRegions.Count, range); | ||
2322 | if (possibleRegions != null && possibleRegions.Count > 0) | ||
2149 | { | 2323 | { |
2150 | // If the simple lookup failed, search the larger area for a region that contains this point | 2324 | // If we found some regions, check to see if the point is within |
2151 | double range = (double)pSizeHint + fudge; | 2325 | foreach (GridRegion gr in possibleRegions) |
2152 | while (ret == null && range <= (Constants.MaximumRegionSize + Constants.RegionSize)) | ||
2153 | { | 2326 | { |
2154 | // Get from the grid service a list of regions that might contain this point. | 2327 | // m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegion nm={1}, regionLoc=<{2},{3}>, regionSize=<{4},{5}>", |
2155 | // The region origin will be in the zero direction so only subtract the range. | 2328 | // LogHeader, gr.RegionName, gr.RegionLocX, gr.RegionLocY, gr.RegionSizeX, gr.RegionSizeY); |
2156 | List<GridRegion> possibleRegions = pGridService.GetRegionRange(pScopeID, | 2329 | if (px >= (double)gr.RegionLocX && px < (double)(gr.RegionLocX + gr.RegionSizeX) |
2157 | (int)(px - range), (int)(px), | ||
2158 | (int)(py - range), (int)(py)); | ||
2159 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegions cnt={1}, range={2}", | ||
2160 | LogHeader, possibleRegions.Count, range); | ||
2161 | if (possibleRegions != null && possibleRegions.Count > 0) | ||
2162 | { | ||
2163 | // If we found some regions, check to see if the point is within | ||
2164 | foreach (GridRegion gr in possibleRegions) | ||
2165 | { | ||
2166 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegion nm={1}, regionLoc=<{2},{3}>, regionSize=<{4},{5}>", | ||
2167 | LogHeader, gr.RegionName, gr.RegionLocX, gr.RegionLocY, gr.RegionSizeX, gr.RegionSizeY); | ||
2168 | if (px >= (double)gr.RegionLocX && px < (double)(gr.RegionLocX + gr.RegionSizeX) | ||
2169 | && py >= (double)gr.RegionLocY && py < (double)(gr.RegionLocY + gr.RegionSizeY)) | 2330 | && py >= (double)gr.RegionLocY && py < (double)(gr.RegionLocY + gr.RegionSizeY)) |
2170 | { | 2331 | { |
2171 | // Found a region that contains the point | 2332 | // Found a region that contains the point |
2172 | ret = gr; | 2333 | return gr; |
2173 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: found. RegionName={1}", LogHeader, ret.RegionName); | 2334 | // m_log.DebugFormat("{0} GetRegionContainingWorldLocation: found. RegionName={1}", LogHeader, ret.RegionName); |
2174 | break; | ||
2175 | } | ||
2176 | } | ||
2177 | } | 2335 | } |
2178 | // Larger search area for next time around if not found | ||
2179 | range *= 2; | ||
2180 | } | 2336 | } |
2181 | } | 2337 | } |
2182 | 2338 | ||
2183 | if (ret == null) | 2339 | // remember this location was not found so we can quickly not find it next time |
2184 | { | 2340 | m_notFoundLocationCache.Add(px, py); |
2185 | // remember this location was not found so we can quickly not find it next time | 2341 | // m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found. Remembering loc=<{1},{2}>", LogHeader, px, py); |
2186 | m_notFoundLocationCache.Add(px, py); | 2342 | return null; |
2187 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found. Remembering loc=<{1},{2}>", LogHeader, px, py); | ||
2188 | } | ||
2189 | |||
2190 | return ret; | ||
2191 | } | 2343 | } |
2192 | 2344 | ||
2193 | private void InformClientOfNeighbourCompleted(IAsyncResult iar) | 2345 | private void InformClientOfNeighbourCompleted(IAsyncResult iar) |
@@ -2207,81 +2359,65 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2207 | /// <param name="a"></param> | 2359 | /// <param name="a"></param> |
2208 | /// <param name="regionHandle"></param> | 2360 | /// <param name="regionHandle"></param> |
2209 | /// <param name="endPoint"></param> | 2361 | /// <param name="endPoint"></param> |
2210 | private void InformClientOfNeighbourAsync(ScenePresence sp, AgentCircuitData a, GridRegion reg, | 2362 | private void InformClientOfNeighbourAsync(ScenePresence sp, AgentCircuitData agentCircData, GridRegion reg, |
2211 | IPEndPoint endPoint, bool newAgent) | 2363 | IPEndPoint endPoint, bool newAgent) |
2212 | { | 2364 | { |
2213 | // Let's wait just a little to give time to originating regions to catch up with closing child agents | ||
2214 | // after a cross here | ||
2215 | Thread.Sleep(500); | ||
2216 | 2365 | ||
2217 | Scene scene = sp.Scene; | 2366 | if (newAgent) |
2218 | 2367 | { | |
2219 | m_log.DebugFormat( | 2368 | // we may already had lost this sp |
2220 | "[ENTITY TRANSFER MODULE]: Informing {0} {1} about neighbour {2} {3} at ({4},{5})", | 2369 | if(sp == null || sp.IsDeleted || sp.ClientView == null) // something bad already happened |
2221 | sp.Name, sp.UUID, reg.RegionName, endPoint, reg.RegionCoordX, reg.RegionCoordY); | 2370 | return; |
2222 | 2371 | ||
2223 | string capsPath = reg.ServerURI + CapsUtil.GetCapsSeedPath(a.CapsPath); | 2372 | Scene scene = sp.Scene; |
2224 | 2373 | ||
2225 | string reason = String.Empty; | 2374 | m_log.DebugFormat( |
2375 | "[ENTITY TRANSFER MODULE]: Informing {0} {1} about neighbour {2} {3} at ({4},{5})", | ||
2376 | sp.Name, sp.UUID, reg.RegionName, endPoint, reg.RegionCoordX, reg.RegionCoordY); | ||
2226 | 2377 | ||
2227 | bool regionAccepted = scene.SimulationService.CreateAgent(null, reg, a, (uint)TeleportFlags.Default, out reason); | 2378 | string capsPath = reg.ServerURI + CapsUtil.GetCapsSeedPath(agentCircData.CapsPath); |
2228 | 2379 | ||
2229 | if (regionAccepted && newAgent) | 2380 | string reason = String.Empty; |
2230 | { | 2381 | |
2231 | if (m_eqModule != null) | 2382 | EntityTransferContext ctx = new EntityTransferContext(); |
2383 | bool regionAccepted = scene.SimulationService.CreateAgent(reg, reg, agentCircData, (uint)TeleportFlags.Default, ctx, out reason); | ||
2384 | |||
2385 | if (regionAccepted) | ||
2232 | { | 2386 | { |
2233 | #region IP Translation for NAT | 2387 | // give time for createAgent to finish, since it is async and does grid services access |
2234 | IClientIPEndpoint ipepClient; | 2388 | Thread.Sleep(500); |
2235 | if (sp.ClientView.TryGet(out ipepClient)) | 2389 | |
2390 | if (m_eqModule != null) | ||
2236 | { | 2391 | { |
2237 | endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); | 2392 | if(sp == null || sp.IsDeleted || sp.ClientView == null) // something bad already happened |
2238 | } | 2393 | return; |
2239 | #endregion | ||
2240 | 2394 | ||
2241 | m_log.DebugFormat("{0} {1} is sending {2} EnableSimulator for neighbour region {3}(loc=<{4},{5}>,siz=<{6},{7}>) " + | 2395 | m_log.DebugFormat("{0} {1} is sending {2} EnableSimulator for neighbour region {3}(loc=<{4},{5}>,siz=<{6},{7}>) " + |
2242 | "and EstablishAgentCommunication with seed cap {8}", LogHeader, | 2396 | "and EstablishAgentCommunication with seed cap {8}", LogHeader, |
2243 | scene.RegionInfo.RegionName, sp.Name, | 2397 | scene.RegionInfo.RegionName, sp.Name, |
2244 | reg.RegionName, reg.RegionLocX, reg.RegionLocY, reg.RegionSizeX, reg.RegionSizeY , capsPath); | 2398 | reg.RegionName, reg.RegionLocX, reg.RegionLocY, reg.RegionSizeX, reg.RegionSizeY, capsPath); |
2399 | |||
2400 | m_eqModule.EnableSimulator(reg.RegionHandle, endPoint, sp.UUID, reg.RegionSizeX, reg.RegionSizeY); | ||
2401 | m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath, reg.RegionHandle, reg.RegionSizeX, reg.RegionSizeY); | ||
2402 | } | ||
2403 | else | ||
2404 | { | ||
2405 | sp.ControllingClient.InformClientOfNeighbour(reg.RegionHandle, endPoint); | ||
2406 | // TODO: make Event Queue disablable! | ||
2407 | } | ||
2245 | 2408 | ||
2246 | m_eqModule.EnableSimulator(reg.RegionHandle, endPoint, sp.UUID, reg.RegionSizeX, reg.RegionSizeY); | 2409 | m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Completed inform {0} {1} about neighbour {2}", sp.Name, sp.UUID, endPoint); |
2247 | m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath, reg.RegionHandle, reg.RegionSizeX, reg.RegionSizeY); | ||
2248 | } | 2410 | } |
2411 | |||
2249 | else | 2412 | else |
2250 | { | 2413 | { |
2251 | sp.ControllingClient.InformClientOfNeighbour(reg.RegionHandle, endPoint); | 2414 | sp.RemoveNeighbourRegion(reg.RegionHandle); |
2252 | // TODO: make Event Queue disablable! | 2415 | m_log.WarnFormat( |
2416 | "[ENTITY TRANSFER MODULE]: Region {0} did not accept {1} {2}: {3}", | ||
2417 | reg.RegionName, sp.Name, sp.UUID, reason); | ||
2253 | } | 2418 | } |
2254 | |||
2255 | m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Completed inform {0} {1} about neighbour {2}", sp.Name, sp.UUID, endPoint); | ||
2256 | } | 2419 | } |
2257 | 2420 | ||
2258 | if (!regionAccepted) | ||
2259 | m_log.WarnFormat( | ||
2260 | "[ENTITY TRANSFER MODULE]: Region {0} did not accept {1} {2}: {3}", | ||
2261 | reg.RegionName, sp.Name, sp.UUID, reason); | ||
2262 | } | ||
2263 | |||
2264 | /// <summary> | ||
2265 | /// Gets the range considered in view of this megaregion (assuming this is a megaregion). | ||
2266 | /// </summary> | ||
2267 | /// <remarks>Expressed in 256m units</remarks> | ||
2268 | /// <param name='swCorner'></param> | ||
2269 | /// <param name='neCorner'></param> | ||
2270 | private void GetMegaregionViewRange(out Vector2 swCorner, out Vector2 neCorner) | ||
2271 | { | ||
2272 | Vector2 extent = Vector2.Zero; | ||
2273 | |||
2274 | if (m_regionCombinerModule != null) | ||
2275 | { | ||
2276 | Vector2 megaRegionSize = m_regionCombinerModule.GetSizeOfMegaregion(Scene.RegionInfo.RegionID); | ||
2277 | extent.X = (float)Util.WorldToRegionLoc((uint)megaRegionSize.X); | ||
2278 | extent.Y = (float)Util.WorldToRegionLoc((uint)megaRegionSize.Y); | ||
2279 | } | ||
2280 | |||
2281 | swCorner.X = Scene.RegionInfo.RegionLocX - 1; | ||
2282 | swCorner.Y = Scene.RegionInfo.RegionLocY - 1; | ||
2283 | neCorner.X = Scene.RegionInfo.RegionLocX + extent.X; | ||
2284 | neCorner.Y = Scene.RegionInfo.RegionLocY + extent.Y; | ||
2285 | } | 2421 | } |
2286 | 2422 | ||
2287 | /// <summary> | 2423 | /// <summary> |
@@ -2290,98 +2426,42 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2290 | /// <param name="avatar"></param> | 2426 | /// <param name="avatar"></param> |
2291 | /// <param name="pRegionLocX"></param> | 2427 | /// <param name="pRegionLocX"></param> |
2292 | /// <param name="pRegionLocY"></param> | 2428 | /// <param name="pRegionLocY"></param> |
2293 | /// <returns></returns> | 2429 | /// <returns></returns> |
2294 | protected List<GridRegion> GetNeighbours(ScenePresence avatar, uint pRegionLocX, uint pRegionLocY) | 2430 | protected List<GridRegion> GetNeighbors(ScenePresence avatar, uint pRegionLocX, uint pRegionLocY) |
2295 | { | 2431 | { |
2296 | Scene pScene = avatar.Scene; | 2432 | Scene pScene = avatar.Scene; |
2297 | RegionInfo m_regionInfo = pScene.RegionInfo; | 2433 | RegionInfo m_regionInfo = pScene.RegionInfo; |
2298 | List<GridRegion> neighbours; | 2434 | List<GridRegion> neighbours; |
2299 | 2435 | ||
2300 | // Leaving this as a "megaregions" computation vs "non-megaregions" computation; it isn't | 2436 | uint dd = (uint)avatar.RegionViewDistance; |
2301 | // clear what should be done with a "far view" given that megaregions already extended the | ||
2302 | // view to include everything in the megaregion | ||
2303 | if (m_regionCombinerModule == null || !m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID)) | ||
2304 | { | ||
2305 | // The area to check is as big as the current region. | ||
2306 | // We presume all adjacent regions are the same size as this region. | ||
2307 | uint dd = Math.Max((uint)avatar.Scene.DefaultDrawDistance, | ||
2308 | Math.Max(Scene.RegionInfo.RegionSizeX, Scene.RegionInfo.RegionSizeY)); | ||
2309 | 2437 | ||
2310 | uint startX = Util.RegionToWorldLoc(pRegionLocX) - dd + Constants.RegionSize/2; | 2438 | // until avatar movement updates client connections, we need to seend at least this current region imediate neighbors |
2311 | uint startY = Util.RegionToWorldLoc(pRegionLocY) - dd + Constants.RegionSize/2; | 2439 | uint ddX = Math.Max(dd, Constants.RegionSize); |
2440 | uint ddY = Math.Max(dd, Constants.RegionSize); | ||
2312 | 2441 | ||
2313 | uint endX = Util.RegionToWorldLoc(pRegionLocX) + dd + Constants.RegionSize/2; | 2442 | ddX--; |
2314 | uint endY = Util.RegionToWorldLoc(pRegionLocY) + dd + Constants.RegionSize/2; | 2443 | ddY--; |
2315 | 2444 | ||
2316 | neighbours | 2445 | // reference to region edges. Should be avatar position |
2317 | = avatar.Scene.GridService.GetRegionRange( | 2446 | uint startX = Util.RegionToWorldLoc(pRegionLocX); |
2318 | m_regionInfo.ScopeID, (int)startX, (int)endX, (int)startY, (int)endY); | 2447 | uint endX = startX + m_regionInfo.RegionSizeX; |
2319 | } | 2448 | uint startY = Util.RegionToWorldLoc(pRegionLocY); |
2320 | else | 2449 | uint endY = startY + m_regionInfo.RegionSizeY; |
2321 | { | ||
2322 | Vector2 swCorner, neCorner; | ||
2323 | GetMegaregionViewRange(out swCorner, out neCorner); | ||
2324 | 2450 | ||
2325 | neighbours | 2451 | startX -= ddX; |
2326 | = pScene.GridService.GetRegionRange( | 2452 | startY -= ddY; |
2327 | m_regionInfo.ScopeID, | 2453 | endX += ddX; |
2328 | (int)Util.RegionToWorldLoc((uint)swCorner.X), (int)Util.RegionToWorldLoc((uint)neCorner.X), | 2454 | endY += ddY; |
2329 | (int)Util.RegionToWorldLoc((uint)swCorner.Y), (int)Util.RegionToWorldLoc((uint)neCorner.Y)); | ||
2330 | } | ||
2331 | 2455 | ||
2332 | // neighbours.ForEach( | 2456 | neighbours |
2333 | // n => | 2457 | = avatar.Scene.GridService.GetRegionRange( |
2334 | // m_log.DebugFormat( | 2458 | m_regionInfo.ScopeID, (int)startX, (int)endX, (int)startY, (int)endY); |
2335 | // "[ENTITY TRANSFER MODULE]: Region flags for {0} as seen by {1} are {2}", | ||
2336 | // n.RegionName, Scene.Name, n.RegionFlags != null ? n.RegionFlags.ToString() : "not present")); | ||
2337 | 2459 | ||
2338 | // The r.RegionFlags == null check only needs to be made for simulators before 2015-01-14 (pre 0.8.1). | 2460 | // The r.RegionFlags == null check only needs to be made for simulators before 2015-01-14 (pre 0.8.1). |
2339 | neighbours.RemoveAll( | 2461 | neighbours.RemoveAll( r => r.RegionID == m_regionInfo.RegionID ); |
2340 | r => | ||
2341 | r.RegionID == m_regionInfo.RegionID | ||
2342 | || (r.RegionFlags != null && (r.RegionFlags & OpenSim.Framework.RegionFlags.RegionOnline) == 0)); | ||
2343 | 2462 | ||
2344 | return neighbours; | 2463 | return neighbours; |
2345 | } | 2464 | } |
2346 | |||
2347 | private List<ulong> NewNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours) | ||
2348 | { | ||
2349 | return currentNeighbours.FindAll(delegate(ulong handle) { return !previousNeighbours.Contains(handle); }); | ||
2350 | } | ||
2351 | |||
2352 | // private List<ulong> CommonNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours) | ||
2353 | // { | ||
2354 | // return currentNeighbours.FindAll(delegate(ulong handle) { return previousNeighbours.Contains(handle); }); | ||
2355 | // } | ||
2356 | |||
2357 | private List<ulong> OldNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours) | ||
2358 | { | ||
2359 | return previousNeighbours.FindAll(delegate(ulong handle) { return !currentNeighbours.Contains(handle); }); | ||
2360 | } | ||
2361 | |||
2362 | private List<ulong> NeighbourHandles(List<GridRegion> neighbours) | ||
2363 | { | ||
2364 | List<ulong> handles = new List<ulong>(); | ||
2365 | foreach (GridRegion reg in neighbours) | ||
2366 | { | ||
2367 | handles.Add(reg.RegionHandle); | ||
2368 | } | ||
2369 | return handles; | ||
2370 | } | ||
2371 | |||
2372 | // private void Dump(string msg, List<ulong> handles) | ||
2373 | // { | ||
2374 | // m_log.InfoFormat("-------------- HANDLE DUMP ({0}) ---------", msg); | ||
2375 | // foreach (ulong handle in handles) | ||
2376 | // { | ||
2377 | // uint x, y; | ||
2378 | // Utils.LongToUInts(handle, out x, out y); | ||
2379 | // x = x / Constants.RegionSize; | ||
2380 | // y = y / Constants.RegionSize; | ||
2381 | // m_log.InfoFormat("({0}, {1})", x, y); | ||
2382 | // } | ||
2383 | // } | ||
2384 | |||
2385 | #endregion | 2465 | #endregion |
2386 | 2466 | ||
2387 | #region Agent Arrived | 2467 | #region Agent Arrived |
@@ -2395,83 +2475,47 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2395 | 2475 | ||
2396 | #region Object Transfers | 2476 | #region Object Transfers |
2397 | 2477 | ||
2398 | /// <summary> | 2478 | public GridRegion GetObjectDestination(SceneObjectGroup grp, Vector3 targetPosition,out Vector3 newpos) |
2399 | /// Move the given scene object into a new region depending on which region its absolute position has moved | ||
2400 | /// into. | ||
2401 | /// | ||
2402 | /// Using the objects new world location, ask the grid service for a the new region and adjust the prim | ||
2403 | /// position to be relative to the new region. | ||
2404 | /// </summary> | ||
2405 | /// <param name="grp">the scene object that we're crossing</param> | ||
2406 | /// <param name="attemptedPosition">the attempted out of region position of the scene object. This position is | ||
2407 | /// relative to the region the object currently is in.</param> | ||
2408 | /// <param name="silent">if 'true', the deletion of the client from the region is not broadcast to the clients</param> | ||
2409 | public void Cross(SceneObjectGroup grp, Vector3 attemptedPosition, bool silent) | ||
2410 | { | 2479 | { |
2411 | if (grp == null) | 2480 | newpos = targetPosition; |
2412 | return; | ||
2413 | if (grp.IsDeleted) | ||
2414 | return; | ||
2415 | 2481 | ||
2416 | Scene scene = grp.Scene; | 2482 | Scene scene = grp.Scene; |
2417 | if (scene == null) | 2483 | if (scene == null) |
2418 | return; | 2484 | return null; |
2419 | |||
2420 | if (grp.RootPart.DIE_AT_EDGE) | ||
2421 | { | ||
2422 | // We remove the object here | ||
2423 | try | ||
2424 | { | ||
2425 | scene.DeleteSceneObject(grp, false); | ||
2426 | } | ||
2427 | catch (Exception) | ||
2428 | { | ||
2429 | m_log.Warn("[DATABASE]: exception when trying to remove the prim that crossed the border."); | ||
2430 | } | ||
2431 | return; | ||
2432 | } | ||
2433 | |||
2434 | // Remember the old group position in case the region lookup fails so position can be restored. | ||
2435 | Vector3 oldGroupPosition = grp.RootPart.GroupPosition; | ||
2436 | 2485 | ||
2437 | // Compute the absolute position of the object. | 2486 | int x = (int)targetPosition.X + (int)scene.RegionInfo.WorldLocX; |
2438 | double objectWorldLocX = (double)scene.RegionInfo.WorldLocX + attemptedPosition.X; | 2487 | if (targetPosition.X >= 0) |
2439 | double objectWorldLocY = (double)scene.RegionInfo.WorldLocY + attemptedPosition.Y; | 2488 | x++; |
2489 | else | ||
2490 | x--; | ||
2440 | 2491 | ||
2441 | // Ask the grid service for the region that contains the passed address | 2492 | int y = (int)targetPosition.Y + (int)scene.RegionInfo.WorldLocY; |
2442 | GridRegion destination = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID, | 2493 | if (targetPosition.Y >= 0) |
2443 | objectWorldLocX, objectWorldLocY); | 2494 | y++; |
2495 | else | ||
2496 | y--; | ||
2444 | 2497 | ||
2445 | Vector3 pos = Vector3.Zero; | 2498 | GridRegion neighbourRegion = scene.GridService.GetRegionByPosition(scene.RegionInfo.ScopeID,x,y); |
2446 | if (destination != null) | 2499 | if (neighbourRegion == null) |
2447 | { | 2500 | { |
2448 | // Adjust the object's relative position from the old region (attemptedPosition) | 2501 | return null; |
2449 | // to be relative to the new region (pos). | ||
2450 | pos = new Vector3( (float)(objectWorldLocX - (double)destination.RegionLocX), | ||
2451 | (float)(objectWorldLocY - (double)destination.RegionLocY), | ||
2452 | attemptedPosition.Z); | ||
2453 | } | 2502 | } |
2454 | 2503 | ||
2455 | if (destination == null || !CrossPrimGroupIntoNewRegion(destination, pos, grp, silent)) | 2504 | float newRegionSizeX = neighbourRegion.RegionSizeX; |
2456 | { | 2505 | float newRegionSizeY = neighbourRegion.RegionSizeY; |
2457 | m_log.InfoFormat("[ENTITY TRANSFER MODULE] cross region transfer failed for object {0}", grp.UUID); | 2506 | if (newRegionSizeX == 0) |
2458 | 2507 | newRegionSizeX = Constants.RegionSize; | |
2459 | // We are going to move the object back to the old position so long as the old position | 2508 | if (newRegionSizeY == 0) |
2460 | // is in the region | 2509 | newRegionSizeY = Constants.RegionSize; |
2461 | oldGroupPosition.X = Util.Clamp<float>(oldGroupPosition.X, 1.0f, (float)(scene.RegionInfo.RegionSizeX - 1)); | ||
2462 | oldGroupPosition.Y = Util.Clamp<float>(oldGroupPosition.Y, 1.0f, (float)(scene.RegionInfo.RegionSizeY - 1)); | ||
2463 | oldGroupPosition.Z = Util.Clamp<float>(oldGroupPosition.Z, 1.0f, Constants.RegionHeight); | ||
2464 | 2510 | ||
2465 | grp.AbsolutePosition = oldGroupPosition; | 2511 | newpos.X = targetPosition.X - (neighbourRegion.RegionLocX - (int)scene.RegionInfo.WorldLocX); |
2466 | grp.Velocity = Vector3.Zero; | 2512 | newpos.Y = targetPosition.Y - (neighbourRegion.RegionLocY - (int)scene.RegionInfo.WorldLocY); |
2467 | if (grp.RootPart.PhysActor != null) | ||
2468 | grp.RootPart.PhysActor.CrossingFailure(); | ||
2469 | 2513 | ||
2470 | if (grp.RootPart.KeyframeMotion != null) | 2514 | const float enterDistance = 0.2f; |
2471 | grp.RootPart.KeyframeMotion.CrossingFailure(); | 2515 | newpos.X = Util.Clamp(newpos.X, enterDistance, newRegionSizeX - enterDistance); |
2516 | newpos.Y = Util.Clamp(newpos.Y, enterDistance, newRegionSizeY - enterDistance); | ||
2472 | 2517 | ||
2473 | grp.ScheduleGroupForFullUpdate(); | 2518 | return neighbourRegion; |
2474 | } | ||
2475 | } | 2519 | } |
2476 | 2520 | ||
2477 | /// <summary> | 2521 | /// <summary> |
@@ -2483,10 +2527,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2483 | /// true if the crossing itself was successful, false on failure | 2527 | /// true if the crossing itself was successful, false on failure |
2484 | /// FIMXE: we still return true if the crossing object was not successfully deleted from the originating region | 2528 | /// FIMXE: we still return true if the crossing object was not successfully deleted from the originating region |
2485 | /// </returns> | 2529 | /// </returns> |
2486 | protected bool CrossPrimGroupIntoNewRegion(GridRegion destination, Vector3 newPosition, SceneObjectGroup grp, bool silent) | 2530 | public bool CrossPrimGroupIntoNewRegion(GridRegion destination, Vector3 newPosition, SceneObjectGroup grp, bool silent, bool removeScripts) |
2487 | { | 2531 | { |
2488 | //m_log.Debug(" >>> CrossPrimGroupIntoNewRegion <<<"); | 2532 | //m_log.Debug(" >>> CrossPrimGroupIntoNewRegion <<<"); |
2489 | 2533 | ||
2534 | Culture.SetCurrentCulture(); | ||
2535 | |||
2490 | bool successYN = false; | 2536 | bool successYN = false; |
2491 | grp.RootPart.ClearUpdateSchedule(); | 2537 | grp.RootPart.ClearUpdateSchedule(); |
2492 | //int primcrossingXMLmethod = 0; | 2538 | //int primcrossingXMLmethod = 0; |
@@ -2515,7 +2561,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2515 | // We remove the object here | 2561 | // We remove the object here |
2516 | try | 2562 | try |
2517 | { | 2563 | { |
2518 | grp.Scene.DeleteSceneObject(grp, silent); | 2564 | grp.Scene.DeleteSceneObject(grp, silent, removeScripts); |
2519 | } | 2565 | } |
2520 | catch (Exception e) | 2566 | catch (Exception e) |
2521 | { | 2567 | { |
@@ -2524,30 +2570,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2524 | grp, e); | 2570 | grp, e); |
2525 | } | 2571 | } |
2526 | } | 2572 | } |
2527 | /* | ||
2528 | * done on caller ( not in attachments crossing for now) | ||
2529 | else | ||
2530 | { | ||
2531 | |||
2532 | if (!grp.IsDeleted) | ||
2533 | { | ||
2534 | PhysicsActor pa = grp.RootPart.PhysActor; | ||
2535 | if (pa != null) | ||
2536 | { | ||
2537 | pa.CrossingFailure(); | ||
2538 | if (grp.RootPart.KeyframeMotion != null) | ||
2539 | { | ||
2540 | // moved to KeyframeMotion.CrossingFailure | ||
2541 | // grp.RootPart.Velocity = Vector3.Zero; | ||
2542 | grp.RootPart.KeyframeMotion.CrossingFailure(); | ||
2543 | // grp.SendGroupRootTerseUpdate(); | ||
2544 | } | ||
2545 | } | ||
2546 | } | ||
2547 | |||
2548 | m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: Prim crossing failed for {0}", grp); | ||
2549 | } | ||
2550 | */ | ||
2551 | } | 2573 | } |
2552 | else | 2574 | else |
2553 | { | 2575 | { |
@@ -2589,7 +2611,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2589 | "[ENTITY TRANSFER MODULE]: Sending attachment {0} to region {1}", | 2611 | "[ENTITY TRANSFER MODULE]: Sending attachment {0} to region {1}", |
2590 | clone.UUID, destination.RegionName); | 2612 | clone.UUID, destination.RegionName); |
2591 | 2613 | ||
2592 | CrossPrimGroupIntoNewRegion(destination, Vector3.Zero, clone, silent); | 2614 | CrossPrimGroupIntoNewRegion(destination, Vector3.Zero, clone, silent,true); |
2593 | } | 2615 | } |
2594 | } | 2616 | } |
2595 | 2617 | ||
@@ -2639,7 +2661,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2639 | if (Scene.RegionInfo.EstateSettings.IsBanned(so.OwnerID)) | 2661 | if (Scene.RegionInfo.EstateSettings.IsBanned(so.OwnerID)) |
2640 | { | 2662 | { |
2641 | m_log.DebugFormat( | 2663 | m_log.DebugFormat( |
2642 | "[ENTITY TRANSFER MODULE]: Denied prim crossing of {0} {1} into {2} for banned avatar {3}", | 2664 | "[ENTITY TRANSFER MODULE]: Denied prim crossing of {0} {1} into {2} for banned avatar {3}", |
2643 | so.Name, so.UUID, Scene.Name, so.OwnerID); | 2665 | so.Name, so.UUID, Scene.Name, so.OwnerID); |
2644 | 2666 | ||
2645 | return false; | 2667 | return false; |
@@ -2651,7 +2673,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2651 | if (!Scene.AddSceneObject(so)) | 2673 | if (!Scene.AddSceneObject(so)) |
2652 | { | 2674 | { |
2653 | m_log.DebugFormat( | 2675 | m_log.DebugFormat( |
2654 | "[ENTITY TRANSFER MODULE]: Problem adding scene object {0} {1} into {2} ", | 2676 | "[ENTITY TRANSFER MODULE]: Problem adding scene object {0} {1} into {2} ", |
2655 | so.Name, so.UUID, Scene.Name); | 2677 | so.Name, so.UUID, Scene.Name); |
2656 | 2678 | ||
2657 | return false; | 2679 | return false; |
@@ -2661,7 +2683,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2661 | { | 2683 | { |
2662 | // FIXME: It would be better to never add the scene object at all rather than add it and then delete | 2684 | // FIXME: It would be better to never add the scene object at all rather than add it and then delete |
2663 | // it | 2685 | // it |
2664 | if (!Scene.Permissions.CanObjectEntry(so.UUID, true, so.AbsolutePosition)) | 2686 | if (!Scene.Permissions.CanObjectEntry(so, true, so.AbsolutePosition)) |
2665 | { | 2687 | { |
2666 | // Deny non attachments based on parcel settings | 2688 | // Deny non attachments based on parcel settings |
2667 | // | 2689 | // |
@@ -2679,8 +2701,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2679 | 2701 | ||
2680 | so.ResumeScripts(); | 2702 | so.ResumeScripts(); |
2681 | 2703 | ||
2682 | if (so.RootPart.KeyframeMotion != null) | 2704 | // AddSceneObject already does this and doing it again messes |
2683 | so.RootPart.KeyframeMotion.UpdateSceneObject(so); | 2705 | //if (so.RootPart.KeyframeMotion != null) |
2706 | // so.RootPart.KeyframeMotion.UpdateSceneObject(so); | ||
2684 | } | 2707 | } |
2685 | 2708 | ||
2686 | return true; | 2709 | return true; |