aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs392
1 files changed, 200 insertions, 192 deletions
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index 408d63d..4988e93 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -358,33 +358,21 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
358 ScenePresence sp, GridRegion reg, GridRegion finalDestination, 358 ScenePresence sp, GridRegion reg, GridRegion finalDestination,
359 Vector3 position, Vector3 lookAt, uint teleportFlags) 359 Vector3 position, Vector3 lookAt, uint teleportFlags)
360 { 360 {
361 RegionInfo sourceRegion = sp.Scene.RegionInfo; 361 // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection
362 362 // of whether the destination region completes the teleport.
363 if (!IsWithinMaxTeleportDistance(sourceRegion, finalDestination)) 363 if (!SetInTransit(sp.UUID))
364 { 364 {
365 sp.ControllingClient.SendTeleportFailed( 365 m_log.DebugFormat(
366 string.Format( 366 "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2} ({3}) {4}/{5} - agent is already in transit.",
367 "Can't teleport to {0} ({1},{2}) from {3} ({4},{5}), destination is more than {6} regions way", 367 sp.Name, sp.UUID, reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position);
368 finalDestination.RegionName, finalDestination.RegionCoordX, finalDestination.RegionCoordY,
369 sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY,
370 MaxTransferDistance));
371 368
372 return; 369 return;
373 } 370 }
374 371
375 IEventQueue eq = sp.Scene.RequestModuleInterface<IEventQueue>();
376
377 if (reg == null || finalDestination == null) 372 if (reg == null || finalDestination == null)
378 { 373 {
379 sp.ControllingClient.SendTeleportFailed("Unable to locate destination"); 374 sp.ControllingClient.SendTeleportFailed("Unable to locate destination");
380 return; 375 ResetFromTransit(sp.UUID);
381 }
382
383 if (!SetInTransit(sp.UUID)) // Avie is already on the way. Caller shouldn't do this.
384 {
385 m_log.DebugFormat(
386 "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2} ({3}) {4}/{5} - agent is already in transit.",
387 sp.Name, sp.UUID, reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position);
388 376
389 return; 377 return;
390 } 378 }
@@ -394,6 +382,24 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
394 sp.Name, sp.UUID, sp.Scene.RegionInfo.RegionName, 382 sp.Name, sp.UUID, sp.Scene.RegionInfo.RegionName,
395 reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position); 383 reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position);
396 384
385 RegionInfo sourceRegion = sp.Scene.RegionInfo;
386
387 if (!IsWithinMaxTeleportDistance(sourceRegion, finalDestination))
388 {
389 sp.ControllingClient.SendTeleportFailed(
390 string.Format(
391 "Can't teleport to {0} ({1},{2}) from {3} ({4},{5}), destination is more than {6} regions way",
392 finalDestination.RegionName, finalDestination.RegionCoordX, finalDestination.RegionCoordY,
393 sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY,
394 MaxTransferDistance));
395
396 ResetFromTransit(sp.UUID);
397
398 return;
399 }
400
401 IEventQueue eq = sp.Scene.RequestModuleInterface<IEventQueue>();
402
397 uint newRegionX = (uint)(reg.RegionHandle >> 40); 403 uint newRegionX = (uint)(reg.RegionHandle >> 40);
398 uint newRegionY = (((uint)(reg.RegionHandle)) >> 8); 404 uint newRegionY = (((uint)(reg.RegionHandle)) >> 8);
399 uint oldRegionX = (uint)(sp.Scene.RegionInfo.RegionHandle >> 40); 405 uint oldRegionX = (uint)(sp.Scene.RegionInfo.RegionHandle >> 40);
@@ -405,17 +411,24 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
405 // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field, 411 // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field,
406 // it's actually doing a lot of work. 412 // it's actually doing a lot of work.
407 IPEndPoint endPoint = finalDestination.ExternalEndPoint; 413 IPEndPoint endPoint = finalDestination.ExternalEndPoint;
408 if (endPoint.Address != null) 414
415 if (endPoint.Address == null)
409 { 416 {
410 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from 417 sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down");
411 // both regions 418 ResetFromTransit(sp.UUID);
412 if (sp.ParentID != (uint)0) 419
413 sp.StandUp(); 420 return;
421 }
414 422
415 if (!sp.ValidateAttachments()) 423 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from
416 m_log.DebugFormat( 424 // both regions
417 "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.", 425 if (sp.ParentID != (uint)0)
418 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName); 426 sp.StandUp();
427
428 if (!sp.ValidateAttachments())
429 m_log.DebugFormat(
430 "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.",
431 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName);
419 432
420// if (!sp.ValidateAttachments()) 433// if (!sp.ValidateAttachments())
421// { 434// {
@@ -423,211 +436,206 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
423// return; 436// return;
424// } 437// }
425 438
426 string reason; 439 string reason;
427 string version; 440 string version;
428 if (!m_scene.SimulationService.QueryAccess( 441 if (!m_scene.SimulationService.QueryAccess(
429 finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out version, out reason)) 442 finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out version, out reason))
430 { 443 {
431 sp.ControllingClient.SendTeleportFailed(reason); 444 sp.ControllingClient.SendTeleportFailed(reason);
432 ResetFromTransit(sp.UUID); 445 ResetFromTransit(sp.UUID);
433 446
434 m_log.DebugFormat( 447 m_log.DebugFormat(
435 "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because {3}", 448 "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because {3}",
436 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); 449 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason);
437 450
438 return; 451 return;
439 } 452 }
440 453
441 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version); 454 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version);
442 455
443 sp.ControllingClient.SendTeleportStart(teleportFlags); 456 sp.ControllingClient.SendTeleportStart(teleportFlags);
444 457
445 // the avatar.Close below will clear the child region list. We need this below for (possibly) 458 // the avatar.Close below will clear the child region list. We need this below for (possibly)
446 // closing the child agents, so save it here (we need a copy as it is Clear()-ed). 459 // closing the child agents, so save it here (we need a copy as it is Clear()-ed).
447 //List<ulong> childRegions = avatar.KnownRegionHandles; 460 //List<ulong> childRegions = avatar.KnownRegionHandles;
448 // Compared to ScenePresence.CrossToNewRegion(), there's no obvious code to handle a teleport 461 // Compared to ScenePresence.CrossToNewRegion(), there's no obvious code to handle a teleport
449 // failure at this point (unlike a border crossing failure). So perhaps this can never fail 462 // failure at this point (unlike a border crossing failure). So perhaps this can never fail
450 // once we reach here... 463 // once we reach here...
451 //avatar.Scene.RemoveCapsHandler(avatar.UUID); 464 //avatar.Scene.RemoveCapsHandler(avatar.UUID);
452 465
453 string capsPath = String.Empty; 466 string capsPath = String.Empty;
454 467
455 AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); 468 AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
456 AgentCircuitData agentCircuit = sp.ControllingClient.RequestClientInfo(); 469 AgentCircuitData agentCircuit = sp.ControllingClient.RequestClientInfo();
457 agentCircuit.startpos = position; 470 agentCircuit.startpos = position;
458 agentCircuit.child = true; 471 agentCircuit.child = true;
459 agentCircuit.Appearance = sp.Appearance; 472 agentCircuit.Appearance = sp.Appearance;
460 if (currentAgentCircuit != null) 473 if (currentAgentCircuit != null)
461 { 474 {
462 agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs; 475 agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs;
463 agentCircuit.IPAddress = currentAgentCircuit.IPAddress; 476 agentCircuit.IPAddress = currentAgentCircuit.IPAddress;
464 agentCircuit.Viewer = currentAgentCircuit.Viewer; 477 agentCircuit.Viewer = currentAgentCircuit.Viewer;
465 agentCircuit.Channel = currentAgentCircuit.Channel; 478 agentCircuit.Channel = currentAgentCircuit.Channel;
466 agentCircuit.Mac = currentAgentCircuit.Mac; 479 agentCircuit.Mac = currentAgentCircuit.Mac;
467 agentCircuit.Id0 = currentAgentCircuit.Id0; 480 agentCircuit.Id0 = currentAgentCircuit.Id0;
468 } 481 }
469 482
470 if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) 483 if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY))
471 { 484 {
472 // brand new agent, let's create a new caps seed 485 // brand new agent, let's create a new caps seed
473 agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); 486 agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath();
474 } 487 }
475 488
476 // Let's create an agent there if one doesn't exist yet. 489 // Let's create an agent there if one doesn't exist yet.
477 bool logout = false; 490 bool logout = false;
478 if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) 491 if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout))
479 { 492 {
480 sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason)); 493 sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason));
481 ResetFromTransit(sp.UUID); 494 ResetFromTransit(sp.UUID);
482 495
483 m_log.DebugFormat( 496 m_log.DebugFormat(
484 "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}", 497 "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}",
485 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); 498 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason);
486 499
487 return; 500 return;
488 } 501 }
489 502
490 // OK, it got this agent. Let's close some child agents 503 // OK, it got this agent. Let's close some child agents
491 sp.CloseChildAgents(newRegionX, newRegionY); 504 sp.CloseChildAgents(newRegionX, newRegionY);
492 505
493 IClientIPEndpoint ipepClient; 506 IClientIPEndpoint ipepClient;
494 if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) 507 if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY))
508 {
509 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent...");
510 #region IP Translation for NAT
511 // Uses ipepClient above
512 if (sp.ClientView.TryGet(out ipepClient))
495 { 513 {
496 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); 514 endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address);
497 #region IP Translation for NAT 515 }
498 // Uses ipepClient above 516 #endregion
499 if (sp.ClientView.TryGet(out ipepClient)) 517 capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
500 {
501 endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address);
502 }
503 #endregion
504 capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
505 518
506 if (eq != null) 519 if (eq != null)
507 { 520 {
508 eq.EnableSimulator(destinationHandle, endPoint, sp.UUID); 521 eq.EnableSimulator(destinationHandle, endPoint, sp.UUID);
509 522
510 // ES makes the client send a UseCircuitCode message to the destination, 523 // ES makes the client send a UseCircuitCode message to the destination,
511 // which triggers a bunch of things there. 524 // which triggers a bunch of things there.
512 // So let's wait 525 // So let's wait
513 Thread.Sleep(200); 526 Thread.Sleep(200);
514 527
515 eq.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); 528 eq.EstablishAgentCommunication(sp.UUID, endPoint, capsPath);
516 529
517 }
518 else
519 {
520 sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint);
521 }
522 } 530 }
523 else 531 else
524 { 532 {
525 agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle); 533 sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint);
526 capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
527 } 534 }
535 }
536 else
537 {
538 agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle);
539 capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
540 }
528 541
529 // Let's send a full update of the agent. This is a synchronous call. 542 // Let's send a full update of the agent. This is a synchronous call.
530 AgentData agent = new AgentData(); 543 AgentData agent = new AgentData();
531 sp.CopyTo(agent); 544 sp.CopyTo(agent);
532 agent.Position = position; 545 agent.Position = position;
533 SetCallbackURL(agent, sp.Scene.RegionInfo); 546 SetCallbackURL(agent, sp.Scene.RegionInfo);
534 547
535 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent..."); 548 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent...");
536 549
537 if (!UpdateAgent(reg, finalDestination, agent)) 550 if (!UpdateAgent(reg, finalDestination, agent))
538 { 551 {
539 // Region doesn't take it 552 // Region doesn't take it
540 m_log.WarnFormat( 553 m_log.WarnFormat(
541 "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Returning avatar to source region.", 554 "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Returning avatar to source region.",
542 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); 555 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName);
543 556
544 Fail(sp, finalDestination, logout); 557 Fail(sp, finalDestination, logout);
545 return; 558 return;
546 } 559 }
547 560
548 sp.ControllingClient.SendTeleportProgress(teleportFlags | (uint)TeleportFlags.DisableCancel, "sending_dest"); 561 sp.ControllingClient.SendTeleportProgress(teleportFlags | (uint)TeleportFlags.DisableCancel, "sending_dest");
549 562
550 m_log.DebugFormat( 563 m_log.DebugFormat(
551 "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", 564 "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}",
552 capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); 565 capsPath, sp.Scene.RegionInfo.RegionName, sp.Name);
553 566
554 if (eq != null) 567 if (eq != null)
555 { 568 {
556 eq.TeleportFinishEvent(destinationHandle, 13, endPoint, 569 eq.TeleportFinishEvent(destinationHandle, 13, endPoint,
557 0, teleportFlags, capsPath, sp.UUID); 570 0, teleportFlags, capsPath, sp.UUID);
558 } 571 }
559 else 572 else
560 { 573 {
561 sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4, 574 sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4,
562 teleportFlags, capsPath); 575 teleportFlags, capsPath);
563 } 576 }
564 577
565 // Let's set this to true tentatively. This does not trigger OnChildAgent 578 // Let's set this to true tentatively. This does not trigger OnChildAgent
566 sp.IsChildAgent = true; 579 sp.IsChildAgent = true;
567 580
568 // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which 581 // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which
569 // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation 582 // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation
570 // that the client contacted the destination before we close things here. 583 // that the client contacted the destination before we close things here.
571 if (EnableWaitForCallbackFromTeleportDest && !WaitForCallback(sp.UUID)) 584 if (EnableWaitForCallbackFromTeleportDest && !WaitForCallback(sp.UUID))
572 { 585 {
573 m_log.WarnFormat( 586 m_log.WarnFormat(
574 "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", 587 "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.",
575 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); 588 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName);
576 589
577 Fail(sp, finalDestination, logout); 590 Fail(sp, finalDestination, logout);
578 return; 591 return;
579 } 592 }
580 593
581 // For backwards compatibility 594 // For backwards compatibility
582 if (version == "Unknown" || version == string.Empty) 595 if (version == "Unknown" || version == string.Empty)
583 { 596 {
584 // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it 597 // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it
585 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Old simulator, sending attachments one by one..."); 598 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Old simulator, sending attachments one by one...");
586 CrossAttachmentsIntoNewRegion(finalDestination, sp, true); 599 CrossAttachmentsIntoNewRegion(finalDestination, sp, true);
587 } 600 }
588 601
589 // May need to logout or other cleanup 602 // May need to logout or other cleanup
590 AgentHasMovedAway(sp, logout); 603 AgentHasMovedAway(sp, logout);
591 604
592 // Well, this is it. The agent is over there. 605 // Well, this is it. The agent is over there.
593 KillEntity(sp.Scene, sp.LocalId); 606 KillEntity(sp.Scene, sp.LocalId);
594 607
595 // Now let's make it officially a child agent 608 // Now let's make it officially a child agent
596 sp.MakeChildAgent(); 609 sp.MakeChildAgent();
597 610
598// sp.Scene.CleanDroppedAttachments(); 611// sp.Scene.CleanDroppedAttachments();
599 612
600 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone 613 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
601
602 if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
603 {
604 // We need to delay here because Imprudence viewers, unlike v1 or v3, have a short (<200ms, <500ms) delay before
605 // they regard the new region as the current region after receiving the AgentMovementComplete
606 // response. If close is sent before then, it will cause the viewer to quit instead.
607 // However, if this delay is longer, then a viewer can teleport back to this region and experience
608 // a failure because the old ScenePresence has not yet been cleaned up.
609 Thread.Sleep(2000);
610
611 sp.Close();
612 sp.Scene.IncomingCloseAgent(sp.UUID);
613 }
614 else
615 {
616 // now we have a child agent in this region.
617 sp.Reset();
618 }
619 614
620 // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! 615 if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
621 if (sp.Scene.NeedSceneCacheClear(sp.UUID)) 616 {
622 { 617 // We need to delay here because Imprudence viewers, unlike v1 or v3, have a short (<200ms, <500ms) delay before
623 m_log.DebugFormat( 618 // they regard the new region as the current region after receiving the AgentMovementComplete
624 "[ENTITY TRANSFER MODULE]: User {0} is going to another region, profile cache removed", 619 // response. If close is sent before then, it will cause the viewer to quit instead.
625 sp.UUID); 620 // However, if this delay is longer, then a viewer can teleport back to this region and experience
626 } 621 // a failure because the old ScenePresence has not yet been cleaned up.
622 Thread.Sleep(2000);
623
624 sp.Close();
625 sp.Scene.IncomingCloseAgent(sp.UUID);
627 } 626 }
628 else 627 else
629 { 628 {
630 sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); 629 // now we have a child agent in this region.
630 sp.Reset();
631 }
632
633 // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
634 if (sp.Scene.NeedSceneCacheClear(sp.UUID))
635 {
636 m_log.DebugFormat(
637 "[ENTITY TRANSFER MODULE]: User {0} is going to another region, profile cache removed",
638 sp.UUID);
631 } 639 }
632 } 640 }
633 641