OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
EntityTransferModule.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using System.Collections.Generic;
30 using System.Net;
31 using System.Reflection;
32 using System.Threading;
33 using OpenSim.Framework;
34 using OpenSim.Framework.Capabilities;
35 using OpenSim.Framework.Client;
36 using OpenSim.Framework.Monitoring;
37 using OpenSim.Region.Framework.Interfaces;
38 using OpenSim.Region.Framework.Scenes;
39 using OpenSim.Region.PhysicsModules.SharedBase;
40 using OpenSim.Services.Interfaces;
41 
43 
44 using OpenMetaverse;
45 using log4net;
46 using Nini.Config;
47 using Mono.Addins;
48 
49 namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
50 {
51  [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "EntityTransferModule")]
53  {
54  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55  private static readonly string LogHeader = "[ENTITY TRANSFER MODULE]";
56 
57  public const int DefaultMaxTransferDistance = 4095;
58  public const bool WaitForAgentArrivedAtDestinationDefault = true;
59 
63  public int MaxTransferDistance { get; set; }
64 
69  public bool WaitForAgentArrivedAtDestination { get; set; }
70 
80  public bool DisableInterRegionTeleportCancellation { get; set; }
81 
85  private Stat m_interRegionTeleportAttempts;
86 
90  private Stat m_interRegionTeleportAborts;
91 
95  private Stat m_interRegionTeleportCancels;
96 
105  private Stat m_interRegionTeleportFailures;
106 
107  protected string m_ThisHomeURI;
108  protected string m_GatekeeperURI;
109 
110  protected bool m_Enabled = false;
111 
112  public Scene Scene { get; private set; }
113 
118  private EntityTransferStateMachine m_entityTransferStateMachine;
119 
120  // For performance, we keed a cached of banned regions so we don't keep going
121  // to the grid service.
122  private class BannedRegionCache
123  {
124  private ExpiringCache<UUID, ExpiringCache<ulong, DateTime>> m_bannedRegions =
125  new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>();
126  ExpiringCache<ulong, DateTime> m_idCache;
127  DateTime m_banUntil;
128  public BannedRegionCache()
129  {
130  }
131  // Return 'true' if there is a valid ban entry for this agent in this region
132  public bool IfBanned(ulong pRegionHandle, UUID pAgentID)
133  {
134  bool ret = false;
135  if (m_bannedRegions.TryGetValue(pAgentID, out m_idCache))
136  {
137  if (m_idCache.TryGetValue(pRegionHandle, out m_banUntil))
138  {
139  if (DateTime.Now < m_banUntil)
140  {
141  ret = true;
142  }
143  }
144  }
145  return ret;
146  }
147  // Add this agent in this region as a banned person
148  public void Add(ulong pRegionHandle, UUID pAgentID)
149  {
150  this.Add(pRegionHandle, pAgentID, 45, 15);
151  }
152 
153  public void Add(ulong pRegionHandle, UUID pAgentID, double newTime, double extendTime)
154  {
155  if (!m_bannedRegions.TryGetValue(pAgentID, out m_idCache))
156  {
157  m_idCache = new ExpiringCache<ulong, DateTime>();
158  m_bannedRegions.Add(pAgentID, m_idCache, TimeSpan.FromSeconds(newTime));
159  }
160  m_idCache.Add(pRegionHandle, DateTime.Now + TimeSpan.FromSeconds(extendTime), TimeSpan.FromSeconds(extendTime));
161  }
162 
163  // Remove the agent from the region's banned list
164  public void Remove(ulong pRegionHandle, UUID pAgentID)
165  {
166  if (m_bannedRegions.TryGetValue(pAgentID, out m_idCache))
167  {
168  m_idCache.Remove(pRegionHandle);
169  }
170  }
171  }
172 
173  private BannedRegionCache m_bannedRegionCache = new BannedRegionCache();
174 
175  private IEventQueue m_eqModule;
176  private IRegionCombinerModule m_regionCombinerModule;
177 
178  #region ISharedRegionModule
179 
180  public Type ReplaceableInterface
181  {
182  get { return null; }
183  }
184 
185  public virtual string Name
186  {
187  get { return "BasicEntityTransferModule"; }
188  }
189 
190  public virtual void Initialise(IConfigSource source)
191  {
192  IConfig moduleConfig = source.Configs["Modules"];
193  if (moduleConfig != null)
194  {
195  string name = moduleConfig.GetString("EntityTransferModule", "");
196  if (name == Name)
197  {
198  InitialiseCommon(source);
199  m_log.DebugFormat("[ENTITY TRANSFER MODULE]: {0} enabled.", Name);
200  }
201  }
202  }
203 
208  protected virtual void InitialiseCommon(IConfigSource source)
209  {
210  IConfig hypergridConfig = source.Configs["Hypergrid"];
211  if (hypergridConfig != null)
212  {
213  m_ThisHomeURI = hypergridConfig.GetString("HomeURI", string.Empty);
214  if (m_ThisHomeURI != string.Empty && !m_ThisHomeURI.EndsWith("/"))
215  m_ThisHomeURI += '/';
216 
217  m_GatekeeperURI = hypergridConfig.GetString("GatekeeperURI", string.Empty);
218  if (m_GatekeeperURI != string.Empty && !m_GatekeeperURI.EndsWith("/"))
219  m_GatekeeperURI += '/';
220  }
221 
222  IConfig transferConfig = source.Configs["EntityTransfer"];
223  if (transferConfig != null)
224  {
225  DisableInterRegionTeleportCancellation
226  = transferConfig.GetBoolean("DisableInterRegionTeleportCancellation", false);
227 
228  WaitForAgentArrivedAtDestination
229  = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault);
230 
231  MaxTransferDistance = transferConfig.GetInt("max_distance", DefaultMaxTransferDistance);
232  }
233  else
234  {
235  MaxTransferDistance = DefaultMaxTransferDistance;
236  }
237 
238  m_entityTransferStateMachine = new EntityTransferStateMachine(this);
239 
240  m_Enabled = true;
241  }
242 
243  public virtual void PostInitialise()
244  {
245  }
246 
247  public virtual void AddRegion(Scene scene)
248  {
249  if (!m_Enabled)
250  return;
251 
252  Scene = scene;
253 
254  m_interRegionTeleportAttempts =
255  new Stat(
256  "InterRegionTeleportAttempts",
257  "Number of inter-region teleports attempted.",
258  "This does not count attempts which failed due to pre-conditions (e.g. target simulator refused access).\n"
259  + "You can get successfully teleports by subtracting aborts, cancels and teleport failures from this figure.",
260  "",
261  "entitytransfer",
262  Scene.Name,
263  StatType.Push,
264  null,
265  StatVerbosity.Debug);
266 
267  m_interRegionTeleportAborts =
268  new Stat(
269  "InterRegionTeleportAborts",
270  "Number of inter-region teleports aborted due to client actions.",
271  "The chief action is simultaneous logout whilst teleporting.",
272  "",
273  "entitytransfer",
274  Scene.Name,
275  StatType.Push,
276  null,
277  StatVerbosity.Debug);
278 
279  m_interRegionTeleportCancels =
280  new Stat(
281  "InterRegionTeleportCancels",
282  "Number of inter-region teleports cancelled by the client.",
283  null,
284  "",
285  "entitytransfer",
286  Scene.Name,
287  StatType.Push,
288  null,
289  StatVerbosity.Debug);
290 
291  m_interRegionTeleportFailures =
292  new Stat(
293  "InterRegionTeleportFailures",
294  "Number of inter-region teleports that failed due to server/client/network issues.",
295  "This number may not be very helpful in open-grid/hg situations as the network connectivity/quality of destinations is uncontrollable.",
296  "",
297  "entitytransfer",
298  Scene.Name,
299  StatType.Push,
300  null,
301  StatVerbosity.Debug);
302 
303  StatsManager.RegisterStat(m_interRegionTeleportAttempts);
304  StatsManager.RegisterStat(m_interRegionTeleportAborts);
305  StatsManager.RegisterStat(m_interRegionTeleportCancels);
306  StatsManager.RegisterStat(m_interRegionTeleportFailures);
307 
308  scene.RegisterModuleInterface<IEntityTransferModule>(this);
309  scene.EventManager.OnNewClient += OnNewClient;
310  }
311 
312  protected virtual void OnNewClient(IClientAPI client)
313  {
314  client.OnTeleportHomeRequest += TriggerTeleportHome;
315  client.OnTeleportLandmarkRequest += RequestTeleportLandmark;
316 
317  if (!DisableInterRegionTeleportCancellation)
318  client.OnTeleportCancel += OnClientCancelTeleport;
319 
320  client.OnConnectionClosed += OnConnectionClosed;
321  }
322 
323  public virtual void Close() {}
324 
325  public virtual void RemoveRegion(Scene scene)
326  {
327  if (m_Enabled)
328  {
329  StatsManager.DeregisterStat(m_interRegionTeleportAttempts);
330  StatsManager.DeregisterStat(m_interRegionTeleportAborts);
331  StatsManager.DeregisterStat(m_interRegionTeleportCancels);
332  StatsManager.DeregisterStat(m_interRegionTeleportFailures);
333  }
334  }
335 
336  public virtual void RegionLoaded(Scene scene)
337  {
338  if (!m_Enabled)
339  return;
340 
341  m_eqModule = Scene.RequestModuleInterface<IEventQueue>();
342  m_regionCombinerModule = Scene.RequestModuleInterface<IRegionCombinerModule>();
343  }
344 
345  #endregion
346 
347  #region Agent Teleports
348 
349  private void OnConnectionClosed(IClientAPI client)
350  {
351  if (client.IsLoggingOut && m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting))
352  {
353  m_log.DebugFormat(
354  "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout",
355  client.Name, Scene.Name);
356  }
357  }
358 
359  private void OnClientCancelTeleport(IClientAPI client)
360  {
361  m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Cancelling);
362 
363  m_log.DebugFormat(
364  "[ENTITY TRANSFER MODULE]: Received teleport cancel request from {0} in {1}", client.Name, Scene.Name);
365  }
366 
367  // Attempt to teleport the ScenePresence to the specified position in the specified region (spec'ed by its handle).
368  public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags)
369  {
370  if (sp.Scene.Permissions.IsGridGod(sp.UUID))
371  {
372  // This user will be a God in the destination scene, too
373  teleportFlags |= (uint)TeleportFlags.Godlike;
374  }
375 
376  if (!sp.Scene.Permissions.CanTeleport(sp.UUID))
377  return;
378 
379  string destinationRegionName = "(not found)";
380 
381  // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection
382  // of whether the destination region completes the teleport.
383  if (!m_entityTransferStateMachine.SetInTransit(sp.UUID))
384  {
385  m_log.DebugFormat(
386  "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2}@{3} - agent is already in transit.",
387  sp.Name, sp.UUID, position, regionHandle);
388 
389  sp.ControllingClient.SendTeleportFailed("Previous teleport process incomplete. Please retry shortly.");
390 
391  return;
392  }
393 
394  try
395  {
396  // Reset animations; the viewer does that in teleports.
397  sp.Animator.ResetAnimations();
398 
399  if (regionHandle == sp.Scene.RegionInfo.RegionHandle)
400  {
401  destinationRegionName = sp.Scene.RegionInfo.RegionName;
402 
403  TeleportAgentWithinRegion(sp, position, lookAt, teleportFlags);
404  }
405  else // Another region possibly in another simulator
406  {
407  GridRegion finalDestination = null;
408  try
409  {
410  TeleportAgentToDifferentRegion(
411  sp, regionHandle, position, lookAt, teleportFlags, out finalDestination);
412  }
413  finally
414  {
415  if (finalDestination != null)
416  destinationRegionName = finalDestination.RegionName;
417  }
418  }
419  }
420  catch (Exception e)
421  {
422  m_log.ErrorFormat(
423  "[ENTITY TRANSFER MODULE]: Exception on teleport of {0} from {1}@{2} to {3}@{4}: {5}{6}",
424  sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, destinationRegionName,
425  e.Message, e.StackTrace);
426 
427  sp.ControllingClient.SendTeleportFailed("Internal error");
428  }
429  finally
430  {
431  m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
432  }
433  }
434 
442  private void TeleportAgentWithinRegion(ScenePresence sp, Vector3 position, Vector3 lookAt, uint teleportFlags)
443  {
444  m_log.DebugFormat(
445  "[ENTITY TRANSFER MODULE]: Teleport for {0} to {1} within {2}",
446  sp.Name, position, sp.Scene.RegionInfo.RegionName);
447 
448  // Teleport within the same region
449  if (!sp.Scene.PositionIsInCurrentRegion(position) || position.Z < 0)
450  {
451  Vector3 emergencyPos = new Vector3(128, 128, 128);
452 
453  m_log.WarnFormat(
454  "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2} in {3}. Substituting {4}",
455  position, sp.Name, sp.UUID, Scene.Name, emergencyPos);
456 
457  position = emergencyPos;
458  }
459 
460  // TODO: Get proper AVG Height
461  float localHalfAVHeight = 0.8f;
462  if (sp.Appearance != null)
463  localHalfAVHeight = sp.Appearance.AvatarHeight / 2;
464 
465  float posZLimit = 22;
466 
467  // TODO: Check other Scene HeightField
468  posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y];
469 
470  posZLimit += localHalfAVHeight + 0.1f;
471 
472  if ((position.Z < posZLimit) && !(Single.IsInfinity(posZLimit) || Single.IsNaN(posZLimit)))
473  {
474  position.Z = posZLimit;
475  }
476 
477  if (sp.Flying)
478  teleportFlags |= (uint)TeleportFlags.IsFlying;
479 
480  m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
481 
482  sp.ControllingClient.SendTeleportStart(teleportFlags);
483 
484  sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags);
485  sp.TeleportFlags = (Constants.TeleportFlags)teleportFlags;
486  sp.Velocity = Vector3.Zero;
487  sp.Teleport(position);
488 
489  m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.ReceivedAtDestination);
490 
491  foreach (SceneObjectGroup grp in sp.GetAttachments())
492  {
493  sp.Scene.EventManager.TriggerOnScriptChangedEvent(grp.LocalId, (uint)Changed.TELEPORT);
494  }
495 
496  m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
497  }
498 
508  private void TeleportAgentToDifferentRegion(
509  ScenePresence sp, ulong regionHandle, Vector3 position,
510  Vector3 lookAt, uint teleportFlags, out GridRegion finalDestination)
511  {
512  // Get destination region taking into account that the address could be an offset
513  // region inside a varregion.
514  GridRegion reg = GetTeleportDestinationRegion(sp.Scene.GridService, sp.Scene.RegionInfo.ScopeID, regionHandle, ref position);
515 
516  if (reg != null)
517  {
518  string homeURI = Scene.GetAgentHomeURI(sp.ControllingClient.AgentId);
519 
520  string message;
521  finalDestination = GetFinalDestination(reg, sp.ControllingClient.AgentId, homeURI, out message);
522 
523  if (finalDestination == null)
524  {
525  m_log.WarnFormat( "{0} Final destination is having problems. Unable to teleport {1} {2}: {3}",
526  LogHeader, sp.Name, sp.UUID, message);
527 
528  sp.ControllingClient.SendTeleportFailed(message);
529  return;
530  }
531 
532  // Check that these are not the same coordinates
533  if (finalDestination.RegionLocX == sp.Scene.RegionInfo.RegionLocX &&
534  finalDestination.RegionLocY == sp.Scene.RegionInfo.RegionLocY)
535  {
536  // Can't do. Viewer crashes
537  sp.ControllingClient.SendTeleportFailed("Space warp! You would crash. Move to a different region and try again.");
538  return;
539  }
540 
541  // Validate assorted conditions
542  string reason = string.Empty;
543  if (!ValidateGenericConditions(sp, reg, finalDestination, teleportFlags, out reason))
544  {
545  sp.ControllingClient.SendTeleportFailed(reason);
546  return;
547  }
548 
549  if (message != null)
550  sp.ControllingClient.SendAgentAlertMessage(message, true);
551 
552  //
553  // This is it
554  //
555  DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags);
556  //
557  //
558  //
559  }
560  else
561  {
562  finalDestination = null;
563 
564  // TP to a place that doesn't exist (anymore)
565  // Inform the viewer about that
566  sp.ControllingClient.SendTeleportFailed("The region you tried to teleport to doesn't exist anymore");
567 
568  // and set the map-tile to '(Offline)'
569  uint regX, regY;
570  Util.RegionHandleToRegionLoc(regionHandle, out regX, out regY);
571 
572  MapBlockData block = new MapBlockData();
573  block.X = (ushort)(regX);
574  block.Y = (ushort)(regY);
575  block.Access = (byte)SimAccess.Down; // == not there
576 
577  List<MapBlockData> blocks = new List<MapBlockData>();
578  blocks.Add(block);
579  sp.ControllingClient.SendMapBlock(blocks, 0);
580  }
581  }
582 
583  // The teleport address could be an address in a subregion of a larger varregion.
584  // Find the real base region and adjust the teleport location to account for the
585  // larger region.
586  private GridRegion GetTeleportDestinationRegion(IGridService gridService, UUID scope, ulong regionHandle, ref Vector3 position)
587  {
588  uint x = 0, y = 0;
589  Util.RegionHandleToWorldLoc(regionHandle, out x, out y);
590 
591  // Compute the world location we're teleporting to
592  double worldX = (double)x + position.X;
593  double worldY = (double)y + position.Y;
594 
595  // Find the region that contains the position
596  GridRegion reg = GetRegionContainingWorldLocation(gridService, scope, worldX, worldY);
597 
598  if (reg != null)
599  {
600  // modify the position for the offset into the actual region returned
601  position.X += x - reg.RegionLocX;
602  position.Y += y - reg.RegionLocY;
603  }
604 
605  return reg;
606  }
607 
608  // Nothing to validate here
609  protected virtual bool ValidateGenericConditions(ScenePresence sp, GridRegion reg, GridRegion finalDestination, uint teleportFlags, out string reason)
610  {
611  reason = String.Empty;
612  return true;
613  }
614 
623  private bool IsWithinMaxTeleportDistance(RegionInfo sourceRegion, GridRegion destRegion)
624  {
625  if(MaxTransferDistance == 0)
626  return true;
627 
628 // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Source co-ords are x={0} y={1}", curRegionX, curRegionY);
629 //
630 // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final dest is x={0} y={1} {2}@{3}",
631 // destRegionX, destRegionY, finalDestination.RegionID, finalDestination.ServerURI);
632 
633  // Insanely, RegionLoc on RegionInfo is the 256m map co-ord whilst GridRegion.RegionLoc is the raw meters position.
634  return Math.Abs(sourceRegion.RegionLocX - destRegion.RegionCoordX) <= MaxTransferDistance
635  && Math.Abs(sourceRegion.RegionLocY - destRegion.RegionCoordY) <= MaxTransferDistance;
636  }
637 
641  public void DoTeleport(
642  ScenePresence sp, GridRegion reg, GridRegion finalDestination,
643  Vector3 position, Vector3 lookAt, uint teleportFlags)
644  {
645  // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection
646  // of whether the destination region completes the teleport.
647  if (!m_entityTransferStateMachine.SetInTransit(sp.UUID))
648  {
649  m_log.DebugFormat(
650  "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2} ({3}) {4}/{5} - agent is already in transit.",
651  sp.Name, sp.UUID, reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position);
652  sp.ControllingClient.SendTeleportFailed("Agent is already in transit.");
653  return;
654  }
655 
656  try
657  {
658  DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags);
659  }
660  catch (Exception e)
661  {
662  m_log.ErrorFormat(
663  "[ENTITY TRANSFER MODULE]: Exception on teleport of {0} from {1}@{2} to {3}@{4}: {5}{6}",
664  sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, finalDestination.RegionName,
665  e.Message, e.StackTrace);
666 
667  sp.ControllingClient.SendTeleportFailed("Internal error");
668  }
669  finally
670  {
671  m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
672  }
673  }
674 
679  private void DoTeleportInternal(
680  ScenePresence sp, GridRegion reg, GridRegion finalDestination,
681  Vector3 position, Vector3 lookAt, uint teleportFlags)
682  {
683  if (reg == null || finalDestination == null)
684  {
685  sp.ControllingClient.SendTeleportFailed("Unable to locate destination");
686  return;
687  }
688 
689  string homeURI = Scene.GetAgentHomeURI(sp.ControllingClient.AgentId);
690 
691  m_log.DebugFormat(
692  "[ENTITY TRANSFER MODULE]: Teleporting {0} {1} from {2} to {3} ({4}) {5}/{6}",
693  sp.Name, sp.UUID, sp.Scene.RegionInfo.RegionName,
694  reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position);
695 
696  RegionInfo sourceRegion = sp.Scene.RegionInfo;
697 
698  if (!IsWithinMaxTeleportDistance(sourceRegion, finalDestination))
699  {
700  sp.ControllingClient.SendTeleportFailed(
701  string.Format(
702  "Can't teleport to {0} ({1},{2}) from {3} ({4},{5}), destination is more than {6} regions way",
703  finalDestination.RegionName, finalDestination.RegionCoordX, finalDestination.RegionCoordY,
704  sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY,
705  MaxTransferDistance));
706 
707  return;
708  }
709 
710  ulong destinationHandle = finalDestination.RegionHandle;
711 
712  // Let's do DNS resolution only once in this process, please!
713  // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field,
714  // it's actually doing a lot of work.
715  IPEndPoint endPoint = finalDestination.ExternalEndPoint;
716  if (endPoint == null || endPoint.Address == null)
717  {
718  sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down");
719 
720  return;
721  }
722 
723  if (!sp.ValidateAttachments())
724  m_log.DebugFormat(
725  "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.",
726  sp.Name, sp.Scene.Name, finalDestination.RegionName);
727 
728  string reason;
730 
732  finalDestination, sp.ControllingClient.AgentId, homeURI, true, position, sp.Scene.GetFormatsOffered(), ctx, out reason))
733  {
734  sp.ControllingClient.SendTeleportFailed(reason);
735 
736  m_log.DebugFormat(
737  "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because: {3}",
738  sp.Name, sp.Scene.Name, finalDestination.RegionName, reason);
739 
740  return;
741  }
742 
743  // Before this point, teleport 'failure' is due to checkable pre-conditions such as whether the target
744  // simulator can be found and is explicitly prepared to allow access. Therefore, we will not count these
745  // as server attempts.
746  m_interRegionTeleportAttempts.Value++;
747 
748  m_log.DebugFormat(
749  "[ENTITY TRANSFER MODULE]: {0} transfer protocol version to {1} is {2} / {3}",
750  sp.Scene.Name, finalDestination.RegionName, ctx.OutboundVersion, ctx.InboundVersion);
751 
752  // Fixing a bug where teleporting while sitting results in the avatar ending up removed from
753  // both regions
754  if (sp.ParentID != (uint)0)
755  sp.StandUp();
756  else if (sp.Flying)
757  teleportFlags |= (uint)TeleportFlags.IsFlying;
758 
759  if (DisableInterRegionTeleportCancellation)
760  teleportFlags |= (uint)TeleportFlags.DisableCancel;
761 
762  // At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to
763  // the viewer. However, it might mean that the viewer does not see the black teleport screen (untested).
764  sp.ControllingClient.SendTeleportStart(teleportFlags);
765 
766  // the avatar.Close below will clear the child region list. We need this below for (possibly)
767  // closing the child agents, so save it here (we need a copy as it is Clear()-ed).
768  //List<ulong> childRegions = avatar.KnownRegionHandles;
769  // Compared to ScenePresence.CrossToNewRegion(), there's no obvious code to handle a teleport
770  // failure at this point (unlike a border crossing failure). So perhaps this can never fail
771  // once we reach here...
772  //avatar.Scene.RemoveCapsHandler(avatar.UUID);
773 
774  AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
775  AgentCircuitData agentCircuit = sp.ControllingClient.RequestClientInfo();
776  agentCircuit.startpos = position;
777  agentCircuit.child = true;
778 
779 // agentCircuit.Appearance = sp.Appearance;
780 // agentCircuit.Appearance = new AvatarAppearance(sp.Appearance, true, false);
781  agentCircuit.Appearance = new AvatarAppearance();
782  agentCircuit.Appearance.AvatarHeight = sp.Appearance.AvatarHeight;
783 
784  if (currentAgentCircuit != null)
785  {
786  agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs;
787  agentCircuit.IPAddress = currentAgentCircuit.IPAddress;
788  agentCircuit.Viewer = currentAgentCircuit.Viewer;
789  agentCircuit.Channel = currentAgentCircuit.Channel;
790  agentCircuit.Mac = currentAgentCircuit.Mac;
791  agentCircuit.Id0 = currentAgentCircuit.Id0;
792  }
793 
794  IClientIPEndpoint ipepClient;
795 
796  uint newRegionX, newRegionY, oldRegionX, oldRegionY;
797  Util.RegionHandleToRegionLoc(destinationHandle, out newRegionX, out newRegionY);
798  Util.RegionHandleToRegionLoc(sourceRegion.RegionHandle, out oldRegionX, out oldRegionY);
799  int oldSizeX = (int)sourceRegion.RegionSizeX;
800  int oldSizeY = (int)sourceRegion.RegionSizeY;
801  int newSizeX = finalDestination.RegionSizeX;
802  int newSizeY = finalDestination.RegionSizeY;
803 
804  bool OutSideViewRange = NeedsNewAgent(sp.RegionViewDistance, oldRegionX, newRegionX, oldRegionY, newRegionY,
805  oldSizeX, oldSizeY, newSizeX, newSizeY);
806 
807  if (OutSideViewRange)
808  {
809  m_log.DebugFormat(
810  "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for agent {3} from {4}",
811  finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name);
812 
813  //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent...");
814  #region IP Translation for NAT
815  // Uses ipepClient above
816  if (sp.ClientView.TryGet(out ipepClient))
817  {
818  endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address);
819  }
820  #endregion
821  agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath();
822  }
823  else
824  {
825  agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle);
826  if (agentCircuit.CapsPath == null)
827  agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath();
828  }
829 
830  // We're going to fallback to V1 if the destination gives us anything smaller than 0.2
831  if (ctx.OutboundVersion >= 0.2f)
832  TransferAgent_V2(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, OutSideViewRange , ctx, out reason);
833  else
834  TransferAgent_V1(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, OutSideViewRange, ctx, out reason);
835  }
836 
837  private void TransferAgent_V1(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination,
838  IPEndPoint endPoint, uint teleportFlags, bool OutSideViewRange, EntityTransferContext ctx, out string reason)
839  {
840  ulong destinationHandle = finalDestination.RegionHandle;
841  AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
842 
843  m_log.DebugFormat(
844  "[ENTITY TRANSFER MODULE]: Using TP V1 for {0} going from {1} to {2}",
845  sp.Name, Scene.Name, finalDestination.RegionName);
846 
847  string capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
848 
849  // Let's create an agent there if one doesn't exist yet.
850  // NOTE: logout will always be false for a non-HG teleport.
851  bool logout = false;
852  if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, ctx, out reason, out logout))
853  {
854  m_interRegionTeleportFailures.Value++;
855 
856  m_log.DebugFormat(
857  "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}",
858  sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason);
859 
860  sp.ControllingClient.SendTeleportFailed(reason);
861 
862  return;
863  }
864 
865  if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
866  {
867  m_interRegionTeleportCancels.Value++;
868 
869  m_log.DebugFormat(
870  "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request",
871  sp.Name, finalDestination.RegionName, sp.Scene.Name);
872 
873  return;
874  }
875  else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
876  {
877  m_interRegionTeleportAborts.Value++;
878 
879  m_log.DebugFormat(
880  "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.",
881  sp.Name, finalDestination.RegionName, sp.Scene.Name);
882 
883  return;
884  }
885 
886  // Past this point we have to attempt clean up if the teleport fails, so update transfer state.
887  m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
888 
889  // OK, it got this agent. Let's close some child agents
890 
891  if (OutSideViewRange)
892  {
893  if (m_eqModule != null)
894  {
895  // The EnableSimulator message makes the client establish a connection with the destination
896  // simulator by sending the initial UseCircuitCode UDP packet to the destination containing the
897  // correct circuit code.
898  m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID,
899  finalDestination.RegionSizeX, finalDestination.RegionSizeY);
900  m_log.DebugFormat("{0} Sent EnableSimulator. regName={1}, size=<{2},{3}>", LogHeader,
901  finalDestination.RegionName, finalDestination.RegionSizeX, finalDestination.RegionSizeY);
902 
903  // XXX: Is this wait necessary? We will always end up waiting on UpdateAgent for the destination
904  // simulator to confirm that it has established communication with the viewer.
905  Thread.Sleep(200);
906 
907  // At least on LL 3.3.4 for teleports between different regions on the same simulator this appears
908  // unnecessary - teleport will succeed and SEED caps will be requested without it (though possibly
909  // only on TeleportFinish). This is untested for region teleport between different simulators
910  // though this probably also works.
911  m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath, finalDestination.RegionHandle,
912  finalDestination.RegionSizeX, finalDestination.RegionSizeY);
913  }
914  else
915  {
916  // XXX: This is a little misleading since we're information the client of its avatar destination,
917  // which may or may not be a neighbour region of the source region. This path is probably little
918  // used anyway (with EQ being the one used). But it is currently being used for test code.
919  sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint);
920  }
921  }
922 
923  // Let's send a full update of the agent. This is a synchronous call.
924  AgentData agent = new AgentData();
925  sp.CopyTo(agent);
926 
927  if ((teleportFlags & (uint)TeleportFlags.IsFlying) != 0)
928  agent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY;
929 
930  agent.Position = agentCircuit.startpos;
931  SetCallbackURL(agent, sp.Scene.RegionInfo);
932 
933 
934  // We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to
935  // establish th econnection to the destination which makes it return true.
936  if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
937  {
938  m_interRegionTeleportAborts.Value++;
939 
940  m_log.DebugFormat(
941  "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} before UpdateAgent",
942  sp.Name, finalDestination.RegionName, sp.Scene.Name);
943 
944  return;
945  }
946 
947  // A common teleport failure occurs when we can send CreateAgent to the
948  // destination region but the viewer cannot establish the connection (e.g. due to network issues between
949  // the viewer and the destination). In this case, UpdateAgent timesout after 10 seconds, although then
950  // there's a further 10 second wait whilst we attempt to tell the destination to delete the agent in Fail().
951  if (!UpdateAgent(reg, finalDestination, agent, sp, ctx))
952  {
953  if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
954  {
955  m_interRegionTeleportAborts.Value++;
956 
957  m_log.DebugFormat(
958  "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.",
959  sp.Name, finalDestination.RegionName, sp.Scene.Name);
960 
961  return;
962  }
963 
964  m_log.WarnFormat(
965  "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Keeping avatar in {2}",
966  sp.Name, finalDestination.RegionName, sp.Scene.Name);
967 
968  Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established.");
969  return;
970  }
971 
972  if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
973  {
974  m_interRegionTeleportCancels.Value++;
975 
976  m_log.DebugFormat(
977  "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request",
978  sp.Name, finalDestination.RegionName, sp.Scene.Name);
979 
980  CleanupFailedInterRegionTeleport(sp, currentAgentCircuit.SessionID.ToString(), finalDestination);
981 
982  return;
983  }
984 
985  m_log.DebugFormat(
986  "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}",
987  capsPath, sp.Scene.RegionInfo.RegionName, sp.Name);
988 
989  // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator,
990  // where that neighbour simulator could otherwise request a child agent create on the source which then
991  // closes our existing agent which is still signalled as root.
992  sp.IsChildAgent = true;
993 
994  // OK, send TPFinish to the client, so that it starts the process of contacting the destination region
995  if (m_eqModule != null)
996  {
997  m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID,
998  finalDestination.RegionSizeX, finalDestination.RegionSizeY);
999  }
1000  else
1001  {
1002  sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4,
1003  teleportFlags, capsPath);
1004  }
1005 
1006  // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which
1007  // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation
1008  // that the client contacted the destination before we close things here.
1009  if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID))
1010  {
1011  if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
1012  {
1013  m_interRegionTeleportAborts.Value++;
1014 
1015  m_log.DebugFormat(
1016  "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after WaitForAgentArrivedAtDestination due to previous client close.",
1017  sp.Name, finalDestination.RegionName, sp.Scene.Name);
1018 
1019  return;
1020  }
1021 
1022  m_log.WarnFormat(
1023  "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.",
1024  sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName);
1025 
1026  Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Destination region did not signal teleport completion.");
1027 
1028  return;
1029  }
1030 
1031 
1032 /*
1033  // TODO: This may be 0.6. Check if still needed
1034  // For backwards compatibility
1035  if (version == 0f)
1036  {
1037  // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it
1038  m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Old simulator, sending attachments one by one...");
1039  CrossAttachmentsIntoNewRegion(finalDestination, sp, true);
1040  }
1041 */
1042 
1043  m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
1044 
1045  sp.CloseChildAgents(logout, destinationHandle, finalDestination.RegionSizeX, finalDestination.RegionSizeY);
1046 
1047  // call HG hook
1048  AgentHasMovedAway(sp, logout);
1049 
1050  sp.HasMovedAway(!(OutSideViewRange || logout));
1051 
1052 // ulong sourceRegionHandle = sp.RegionHandle;
1053 
1054  // Now let's make it officially a child agent
1055  sp.MakeChildAgent(destinationHandle);
1056 
1057  // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
1058 
1059  if (NeedsClosing(reg, OutSideViewRange))
1060  {
1061  if (!sp.Scene.IncomingPreCloseClient(sp))
1062  return;
1063 
1064  // We need to delay here because Imprudence viewers, unlike v1 or v3, have a short (<200ms, <500ms) delay before
1065  // they regard the new region as the current region after receiving the AgentMovementComplete
1066  // response. If close is sent before then, it will cause the viewer to quit instead.
1067  //
1068  // This sleep can be increased if necessary. However, whilst it's active,
1069  // an agent cannot teleport back to this region if it has teleported away.
1070  Thread.Sleep(2000);
1071 // if (m_eqModule != null && !sp.DoNotCloseAfterTeleport)
1072 // m_eqModule.DisableSimulator(sourceRegionHandle,sp.UUID);
1073  Thread.Sleep(500);
1074  sp.Scene.CloseAgent(sp.UUID, false);
1075  }
1076  }
1077 
1078  private void TransferAgent_V2(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination,
1079  IPEndPoint endPoint, uint teleportFlags, bool OutSideViewRange, EntityTransferContext ctx, out string reason)
1080  {
1081  ulong destinationHandle = finalDestination.RegionHandle;
1082  AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
1083 
1084  string capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);;
1085 
1086  // Let's create an agent there if one doesn't exist yet.
1087  // NOTE: logout will always be false for a non-HG teleport.
1088  bool logout = false;
1089  if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, ctx, out reason, out logout))
1090  {
1091  m_interRegionTeleportFailures.Value++;
1092 
1093  m_log.DebugFormat(
1094  "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}",
1095  sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason);
1096 
1097  sp.ControllingClient.SendTeleportFailed(reason);
1098 
1099  return;
1100  }
1101 
1102  if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
1103  {
1104  m_interRegionTeleportCancels.Value++;
1105 
1106  m_log.DebugFormat(
1107  "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request",
1108  sp.Name, finalDestination.RegionName, sp.Scene.Name);
1109 
1110  return;
1111  }
1112  else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
1113  {
1114  m_interRegionTeleportAborts.Value++;
1115 
1116  m_log.DebugFormat(
1117  "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.",
1118  sp.Name, finalDestination.RegionName, sp.Scene.Name);
1119 
1120  return;
1121  }
1122 
1123  // Past this point we have to attempt clean up if the teleport fails, so update transfer state.
1124  m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
1125 
1126  // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator,
1127  // where that neighbour simulator could otherwise request a child agent create on the source which then
1128  // closes our existing agent which is still signalled as root.
1129  //sp.IsChildAgent = true;
1130 
1131  // New protocol: send TP Finish directly, without prior ES or EAC. That's what happens in the Linden grid
1132  if (m_eqModule != null)
1133  m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID,
1134  finalDestination.RegionSizeX, finalDestination.RegionSizeY);
1135  else
1136  sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4,
1137  teleportFlags, capsPath);
1138 
1139  m_log.DebugFormat(
1140  "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}",
1141  capsPath, sp.Scene.RegionInfo.RegionName, sp.Name);
1142 
1143  // Let's send a full update of the agent.
1144  AgentData agent = new AgentData();
1145  sp.CopyTo(agent);
1146  agent.Position = agentCircuit.startpos;
1147 
1148  if ((teleportFlags & (uint)TeleportFlags.IsFlying) != 0)
1149  agent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY;
1150 
1151  agent.SenderWantsToWaitForRoot = true;
1152  //SetCallbackURL(agent, sp.Scene.RegionInfo);
1153 
1154  // Reset the do not close flag. This must be done before the destination opens child connections (here
1155  // triggered by UpdateAgent) to avoid race conditions. However, we also want to reset it as late as possible
1156  // to avoid a situation where an unexpectedly early call to Scene.NewUserConnection() wrongly results
1157  // in no close.
1158  sp.DoNotCloseAfterTeleport = false;
1159 
1160  // Send the Update. If this returns true, we know the client has contacted the destination
1161  // via CompleteMovementIntoRegion, so we can let go.
1162  // If it returns false, something went wrong, and we need to abort.
1163  if (!UpdateAgent(reg, finalDestination, agent, sp, ctx))
1164  {
1165  if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
1166  {
1167  m_interRegionTeleportAborts.Value++;
1168 
1169  m_log.DebugFormat(
1170  "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.",
1171  sp.Name, finalDestination.RegionName, sp.Scene.Name);
1172 
1173  return;
1174  }
1175 
1176  m_log.WarnFormat(
1177  "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Keeping avatar in {2}",
1178  sp.Name, finalDestination.RegionName, sp.Scene.Name);
1179 
1180  Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established.");
1181  return;
1182  }
1183 
1184  m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
1185 
1186  // Need to signal neighbours whether child agents may need closing irrespective of whether this
1187  // one needed closing. We also need to close child agents as quickly as possible to avoid complicated
1188  // race conditions with rapid agent releporting (e.g. from A1 to a non-neighbour B, back
1189  // to a neighbour A2 then off to a non-neighbour C). Closing child agents any later requires complex
1190  // distributed checks to avoid problems in rapid reteleporting scenarios and where child agents are
1191  // abandoned without proper close by viewer but then re-used by an incoming connection.
1192  sp.CloseChildAgents(logout, destinationHandle, finalDestination.RegionSizeX, finalDestination.RegionSizeY);
1193 
1194  sp.HasMovedAway(!(OutSideViewRange || logout));
1195 
1196  //HG hook
1197  AgentHasMovedAway(sp, logout);
1198 
1199 // ulong sourceRegionHandle = sp.RegionHandle;
1200 
1201  // Now let's make it officially a child agent
1202  sp.MakeChildAgent(destinationHandle);
1203 
1204  // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
1205  // go by HG hook
1206  if (NeedsClosing(reg, OutSideViewRange))
1207  {
1208  if (!sp.Scene.IncomingPreCloseClient(sp))
1209  return;
1210 
1211  // RED ALERT!!!!
1212  // PLEASE DO NOT DECREASE THIS WAIT TIME UNDER ANY CIRCUMSTANCES.
1213  // THE VIEWERS SEEM TO NEED SOME TIME AFTER RECEIVING MoveAgentIntoRegion
1214  // BEFORE THEY SETTLE IN THE NEW REGION.
1215  // DECREASING THE WAIT TIME HERE WILL EITHER RESULT IN A VIEWER CRASH OR
1216  // IN THE AVIE BEING PLACED IN INFINITY FOR A COUPLE OF SECONDS.
1217 
1218  Thread.Sleep(15000);
1219 // if (m_eqModule != null && !sp.DoNotCloseAfterTeleport)
1220 // m_eqModule.DisableSimulator(sourceRegionHandle,sp.UUID);
1221 // Thread.Sleep(1000);
1222 
1223  // OK, it got this agent. Let's close everything
1224  // If we shouldn't close the agent due to some other region renewing the connection
1225  // then this will be handled in IncomingCloseAgent under lock conditions
1226  m_log.DebugFormat(
1227  "[ENTITY TRANSFER MODULE]: Closing agent {0} in {1} after teleport", sp.Name, Scene.Name);
1228 
1229  sp.Scene.CloseAgent(sp.UUID, false);
1230  }
1231 /*
1232  else
1233  {
1234  // now we have a child agent in this region.
1235  sp.Reset();
1236  }
1237  */
1238  }
1239 
1249  protected virtual void CleanupFailedInterRegionTeleport(ScenePresence sp, string auth_token, GridRegion finalDestination)
1250  {
1251  m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
1252 
1253  if (sp.IsChildAgent) // We had set it to child before attempted TP (V1)
1254  {
1255  sp.IsChildAgent = false;
1256  ReInstantiateScripts(sp);
1257 
1258  EnableChildAgents(sp);
1259  }
1260  // Finally, kill the agent we just created at the destination.
1261  // XXX: Possibly this should be done asynchronously.
1262  Scene.SimulationService.CloseAgent(finalDestination, sp.UUID, auth_token);
1263  }
1264 
1272  protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout, string auth_code, string reason)
1273  {
1274  CleanupFailedInterRegionTeleport(sp, auth_code, finalDestination);
1275 
1276  m_interRegionTeleportFailures.Value++;
1277 
1278  sp.ControllingClient.SendTeleportFailed(
1279  string.Format(
1280  "Problems connecting to destination {0}, reason: {1}", finalDestination.RegionName, reason));
1281 
1282  sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout);
1283  }
1284 
1285  protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, EntityTransferContext ctx, out string reason, out bool logout)
1286  {
1287  GridRegion source = new GridRegion(Scene.RegionInfo);
1288  source.RawServerURI = m_GatekeeperURI;
1289 
1290  logout = false;
1291  bool success = Scene.SimulationService.CreateAgent(source, finalDestination, agentCircuit, teleportFlags, ctx, out reason);
1292 
1293  if (success)
1294  sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout);
1295 
1296  return success;
1297  }
1298 
1299  protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent, ScenePresence sp, EntityTransferContext ctx)
1300  {
1301  return Scene.SimulationService.UpdateAgent(finalDestination, agent, ctx);
1302  }
1303 
1304  protected virtual void SetCallbackURL(AgentData agent, RegionInfo region)
1305  {
1306  agent.CallbackURI = region.ServerURI + "agent/" + agent.AgentID.ToString() + "/" + region.RegionID.ToString() + "/release/";
1307 
1308  m_log.DebugFormat(
1309  "[ENTITY TRANSFER MODULE]: Set release callback URL to {0} in {1}",
1310  agent.CallbackURI, region.RegionName);
1311  }
1312 
1320  protected virtual void AgentHasMovedAway(ScenePresence sp, bool logout)
1321  {
1322 // if (sp.Scene.AttachmentsModule != null)
1323 // sp.Scene.AttachmentsModule.DeleteAttachmentsFromScene(sp, logout);
1324  }
1325 
1326  protected void KillEntity(Scene scene, uint localID)
1327  {
1328  scene.SendKillObject(new List<uint> { localID });
1329  }
1330 
1331  // HG hook
1332  protected virtual GridRegion GetFinalDestination(GridRegion region, UUID agentID, string agentHomeURI, out string message)
1333  {
1334  message = null;
1335  return region;
1336  }
1337 
1338  // This returns 'true' if the new region already has a child agent for our
1339  // incoming agent. The implication is that, if 'false', we have to create the
1340  // child and then teleport into the region.
1341  protected virtual bool NeedsNewAgent(float viewdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY,
1342  int oldsizeX, int oldsizeY, int newsizeX, int newsizeY)
1343  {
1344  if (m_regionCombinerModule != null && m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID))
1345  {
1346  Vector2 swCorner, neCorner;
1347  GetMegaregionViewRange(out swCorner, out neCorner);
1348 
1349  m_log.DebugFormat(
1350  "[ENTITY TRANSFER MODULE]: Megaregion view of {0} is from {1} to {2} with new agent check for {3},{4}",
1351  Scene.Name, swCorner, neCorner, newRegionX, newRegionY);
1352 
1353  return !(newRegionX >= swCorner.X && newRegionX <= neCorner.X && newRegionY >= swCorner.Y && newRegionY <= neCorner.Y);
1354  }
1355 
1356  return Util.IsOutsideView(viewdist, oldRegionX, newRegionX, oldRegionY, newRegionY,
1357  oldsizeX, oldsizeY, newsizeX, newsizeY);
1358  }
1359 
1360  // HG Hook
1361  protected virtual bool NeedsClosing(GridRegion reg, bool OutViewRange)
1362 
1363  {
1364  return OutViewRange;
1365  }
1366 
1367  #endregion
1368 
1369  #region Landmark Teleport
1370  public virtual void RequestTeleportLandmark(IClientAPI remoteClient, AssetLandmark lm)
1377  {
1378  GridRegion info = Scene.GridService.GetRegionByUUID(UUID.Zero, lm.RegionID);
1379 
1380  if (info == null)
1381  {
1382  // can't find the region: Tell viewer and abort
1383  remoteClient.SendTeleportFailed("The teleport destination could not be found.");
1384  return;
1385  }
1386  ((Scene)(remoteClient.Scene)).RequestTeleportLocation(remoteClient, info.RegionHandle, lm.Position,
1387  Vector3.Zero, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark));
1388  }
1389 
1390  #endregion
1391 
1392  #region Teleport Home
1393 
1394  public virtual void TriggerTeleportHome(UUID id, IClientAPI client)
1395  {
1396  TeleportHome(id, client);
1397  }
1398 
1399  public virtual bool TeleportHome(UUID id, IClientAPI client)
1400  {
1401  m_log.DebugFormat(
1402  "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId);
1403 
1404  //OpenSim.Services.Interfaces.PresenceInfo pinfo = Scene.PresenceService.GetAgent(client.SessionId);
1405  GridUserInfo uinfo = Scene.GridUserService.GetGridUserInfo(client.AgentId.ToString());
1406 
1407  if (uinfo != null)
1408  {
1409  if (uinfo.HomeRegionID == UUID.Zero)
1410  {
1411  // can't find the Home region: Tell viewer and abort
1412  m_log.ErrorFormat("{0} No grid user info found for {1} {2}. Cannot send home.",
1413  LogHeader, client.Name, client.AgentId);
1414  client.SendTeleportFailed("You don't have a home position set.");
1415  return false;
1416  }
1417  GridRegion regionInfo = Scene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID);
1418  if (regionInfo == null)
1419  {
1420  // can't find the Home region: Tell viewer and abort
1421  client.SendTeleportFailed("Your home region could not be found.");
1422  return false;
1423  }
1424 
1425  m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Home region of {0} is {1} ({2}-{3})",
1426  client.Name, regionInfo.RegionName, regionInfo.RegionCoordX, regionInfo.RegionCoordY);
1427 
1428  // a little eekie that this goes back to Scene and with a forced cast, will fix that at some point...
1429  ((Scene)(client.Scene)).RequestTeleportLocation(
1430  client, regionInfo.RegionHandle, uinfo.HomePosition, uinfo.HomeLookAt,
1431  (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome));
1432  return true;
1433  }
1434  else
1435  {
1436  // can't find the Home region: Tell viewer and abort
1437  client.SendTeleportFailed("Your home region could not be found.");
1438  }
1439  return false;
1440  }
1441 
1442  #endregion
1443 
1444 
1445  #region Agent Crossings
1446 
1447  public bool checkAgentAccessToRegion(ScenePresence agent, GridRegion destiny, Vector3 position,
1448  EntityTransferContext ctx, out string reason)
1449  {
1450  reason = String.Empty;
1451 
1452  UUID agentID = agent.UUID;
1453  ulong destinyHandle = destiny.RegionHandle;
1454 
1455  if (m_bannedRegionCache.IfBanned(destinyHandle, agentID))
1456  {
1457  return false;
1458  }
1459 
1460  Scene ascene = agent.Scene;
1461  string homeURI = ascene.GetAgentHomeURI(agentID);
1462 
1463 
1464  if (!ascene.SimulationService.QueryAccess(destiny, agentID, homeURI, false, position,
1465  agent.Scene.GetFormatsOffered(), ctx, out reason))
1466  {
1467  m_bannedRegionCache.Add(destinyHandle, agentID, 30.0, 30.0);
1468  return false;
1469  }
1470  return true;
1471  }
1472 
1473  public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, EntityTransferContext ctx, out Vector3 newpos)
1474  {
1475  string r = String.Empty;
1476  return GetDestination(scene, agentID, pos, ctx, out newpos, out r);
1477  }
1478 
1479  // Given a position relative to the current region and outside of it
1480  // find the new region that the point is actually in.
1481  // returns 'null' if new region not found or if information
1482  // and new position relative to it
1483  // now only works for crossings
1484 
1485  public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos,
1486  EntityTransferContext ctx, out Vector3 newpos, out string failureReason)
1487  {
1488  newpos = pos;
1489  failureReason = string.Empty;
1490 
1491 // m_log.DebugFormat(
1492 // "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name);
1493 
1494  // Compute world location of the agente position
1495  double presenceWorldX = (double)scene.RegionInfo.WorldLocX + pos.X;
1496  double presenceWorldY = (double)scene.RegionInfo.WorldLocY + pos.Y;
1497 
1498  // Call the grid service to lookup the region containing the new position.
1499  GridRegion neighbourRegion = GetRegionContainingWorldLocation(
1500  scene.GridService, scene.RegionInfo.ScopeID,
1501  presenceWorldX, presenceWorldY,
1502  Math.Max(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY));
1503 
1504  if (neighbourRegion == null)
1505  {
1506  return null;
1507  }
1508  if (m_bannedRegionCache.IfBanned(neighbourRegion.RegionHandle, agentID))
1509  {
1510  return null;
1511  }
1512 
1513  m_bannedRegionCache.Remove(neighbourRegion.RegionHandle, agentID);
1514 
1515  // Compute the entity's position relative to the new region
1516  newpos = new Vector3((float)(presenceWorldX - (double)neighbourRegion.RegionLocX),
1517  (float)(presenceWorldY - (double)neighbourRegion.RegionLocY),
1518  pos.Z);
1519 
1520  string homeURI = scene.GetAgentHomeURI(agentID);
1521 
1522  if (!scene.SimulationService.QueryAccess(
1523  neighbourRegion, agentID, homeURI, false, newpos,
1524  scene.GetFormatsOffered(), ctx, out failureReason))
1525  {
1526  // remember the fail
1527  m_bannedRegionCache.Add(neighbourRegion.RegionHandle, agentID);
1528  return null;
1529  }
1530 
1531  return neighbourRegion;
1532  }
1533 
1534  public bool Cross(ScenePresence agent, bool isFlying)
1535  {
1536  agent.IsInTransit = true;
1537  CrossAsyncDelegate d = CrossAsync;
1538  d.BeginInvoke(agent, isFlying, CrossCompleted, d);
1539  return true;
1540  }
1541 
1542  private void CrossCompleted(IAsyncResult iar)
1543  {
1544  CrossAsyncDelegate icon = (CrossAsyncDelegate)iar.AsyncState;
1545  ScenePresence agent = icon.EndInvoke(iar);
1546 
1547  m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
1548 
1549  if(!agent.IsChildAgent)
1550  {
1551  // crossing failed
1552  agent.CrossToNewRegionFail();
1553  }
1554  agent.IsInTransit = false;
1555  }
1556 
1557  public ScenePresence CrossAsync(ScenePresence agent, bool isFlying)
1558  {
1559  uint x;
1560  uint y;
1561  Vector3 newpos;
1563  string failureReason;
1564 
1565  Vector3 pos = agent.AbsolutePosition + agent.Velocity;
1566 
1567  GridRegion neighbourRegion = GetDestination(agent.Scene, agent.UUID, pos,
1568  ctx, out newpos, out failureReason);
1569  if (neighbourRegion == null)
1570  {
1571  if (failureReason != String.Empty)
1572  agent.ControllingClient.SendAlertMessage(failureReason);
1573  return agent;
1574  }
1575 
1576 // agent.IsInTransit = true;
1577 
1578  CrossAgentToNewRegionAsync(agent, newpos, neighbourRegion, isFlying, ctx);
1579  agent.IsInTransit = false;
1580  return agent;
1581  }
1582 
1583  public delegate void InformClientToInitiateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene);
1584 
1585  private void InformClientToInitiateTeleportToLocation(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene)
1586  {
1587 
1588  // This assumes that we know what our neighbours are.
1589 
1590  InformClientToInitiateTeleportToLocationDelegate d = InformClientToInitiateTeleportToLocationAsync;
1591  d.BeginInvoke(agent, regionX, regionY, position, initiatingScene,
1592  InformClientToInitiateTeleportToLocationCompleted,
1593  d);
1594  }
1595 
1596  public void InformClientToInitiateTeleportToLocationAsync(ScenePresence agent, uint regionX, uint regionY, Vector3 position,
1597  Scene initiatingScene)
1598  {
1599  Thread.Sleep(10000);
1600 
1601  m_log.DebugFormat(
1602  "[ENTITY TRANSFER MODULE]: Auto-reteleporting {0} to correct megaregion location {1},{2},{3} from {4}",
1603  agent.Name, regionX, regionY, position, initiatingScene.Name);
1604 
1605  agent.Scene.RequestTeleportLocation(
1606  agent.ControllingClient,
1607  Util.RegionLocToHandle(regionX, regionY),
1608  position,
1609  agent.Lookat,
1610  (uint)Constants.TeleportFlags.ViaLocation);
1611 
1612  /*
1613  IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>();
1614  if (im != null)
1615  {
1616  UUID gotoLocation = Util.BuildFakeParcelID(
1617  Util.RegionLocToHandle(regionX, regionY),
1618  (uint)(int)position.X,
1619  (uint)(int)position.Y,
1620  (uint)(int)position.Z);
1621 
1622  GridInstantMessage m
1623  = new GridInstantMessage(
1624  initiatingScene,
1625  UUID.Zero,
1626  "Region",
1627  agent.UUID,
1628  (byte)InstantMessageDialog.GodLikeRequestTeleport,
1629  false,
1630  "",
1631  gotoLocation,
1632  false,
1633  new Vector3(127, 0, 0),
1634  new Byte[0],
1635  false);
1636 
1637  im.SendInstantMessage(m, delegate(bool success)
1638  {
1639  m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Client Initiating Teleport sending IM success = {0}", success);
1640  });
1641 
1642  }
1643  */
1644  }
1645 
1646  private void InformClientToInitiateTeleportToLocationCompleted(IAsyncResult iar)
1647  {
1648  InformClientToInitiateTeleportToLocationDelegate icon =
1649  (InformClientToInitiateTeleportToLocationDelegate)iar.AsyncState;
1650  icon.EndInvoke(iar);
1651  }
1652 
1653  public bool CrossAgentToNewRegionPrep(ScenePresence agent, GridRegion neighbourRegion)
1654  {
1655  if (neighbourRegion == null)
1656  return false;
1657 
1658  m_entityTransferStateMachine.SetInTransit(agent.UUID);
1659 
1660  agent.RemoveFromPhysicalScene();
1661 
1662  return true;
1663  }
1664 
1670  ScenePresence agent, Vector3 pos, GridRegion neighbourRegion,
1671  bool isFlying, EntityTransferContext ctx)
1672  {
1673  try
1674  {
1675  m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: new region={1} at <{2},{3}>. newpos={4}",
1676  LogHeader, neighbourRegion.RegionName, neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, pos);
1677 
1678  if (!CrossAgentToNewRegionPrep(agent, neighbourRegion))
1679  {
1680  m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: prep failed. Resetting transfer state", LogHeader);
1681  m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1682  }
1683 
1684  if (!CrossAgentIntoNewRegionMain(agent, pos, neighbourRegion, isFlying, ctx))
1685  {
1686  m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: cross main failed. Resetting transfer state", LogHeader);
1687  m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1688  }
1689 
1690  CrossAgentToNewRegionPost(agent, pos, neighbourRegion, isFlying, ctx);
1691  }
1692  catch (Exception e)
1693  {
1694  m_log.Error(string.Format("{0}: CrossAgentToNewRegionAsync: failed with exception ", LogHeader), e);
1695  }
1696 
1697  return agent;
1698  }
1699 
1700  public bool CrossAgentIntoNewRegionMain(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, bool isFlying, EntityTransferContext ctx)
1701  {
1702  int ts = Util.EnvironmentTickCount();
1703  try
1704  {
1705  AgentData cAgent = new AgentData();
1706  agent.CopyTo(cAgent);
1707 
1708 // agent.Appearance.WearableCacheItems = null;
1709 
1710  cAgent.Position = pos;
1711 
1712  cAgent.ChildrenCapSeeds = agent.KnownRegions;
1713 
1714  if (isFlying)
1715  cAgent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY;
1716 
1717  // We don't need the callback anymnore
1718  cAgent.CallbackURI = String.Empty;
1719 
1720  // Beyond this point, extra cleanup is needed beyond removing transit state
1721  m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.Transferring);
1722 
1723  if (!agent.Scene.SimulationService.UpdateAgent(neighbourRegion, cAgent, ctx))
1724  {
1725  // region doesn't take it
1726  m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp);
1727 
1728  m_log.WarnFormat(
1729  "[ENTITY TRANSFER MODULE]: Region {0} would not accept update for agent {1} on cross attempt. Returning to original region.",
1730  neighbourRegion.RegionName, agent.Name);
1731 
1732  ReInstantiateScripts(agent);
1733  if(agent.ParentID == 0 && agent.ParentUUID == UUID.Zero)
1734  agent.AddToPhysicalScene(isFlying);
1735 
1736  return false;
1737  }
1738 
1739  m_log.DebugFormat("[CrossAgentIntoNewRegionMain] ok, time {0}ms",Util.EnvironmentTickCountSubtract(ts));
1740 
1741  }
1742  catch (Exception e)
1743  {
1744  m_log.ErrorFormat(
1745  "[ENTITY TRANSFER MODULE]: Problem crossing user {0} to new region {1} from {2}. Exception {3}{4}",
1746  agent.Name, neighbourRegion.RegionName, agent.Scene.RegionInfo.RegionName, e.Message, e.StackTrace);
1747 
1748  // TODO: Might be worth attempting other restoration here such as reinstantiation of scripts, etc.
1749  return false;
1750  }
1751 
1752  return true;
1753  }
1754 
1755  public void CrossAgentToNewRegionPost(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion,
1756  bool isFlying, EntityTransferContext ctx)
1757  {
1758 
1759  string agentcaps;
1760  if (!agent.KnownRegions.TryGetValue(neighbourRegion.RegionHandle, out agentcaps))
1761  {
1762  m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: No ENTITY TRANSFER MODULE information for region handle {0}, exiting CrossToNewRegion.",
1763  neighbourRegion.RegionHandle);
1764  return;
1765  }
1766 
1767  // No turning back
1768 
1769  agent.IsChildAgent = true;
1770 
1771  string capsPath = neighbourRegion.ServerURI + CapsUtil.GetCapsSeedPath(agentcaps);
1772 
1773  m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID);
1774 
1775  Vector3 vel2 = new Vector3(agent.Velocity.X, agent.Velocity.Y, 0);
1776 
1777  if (m_eqModule != null)
1778  {
1779  m_eqModule.CrossRegion(
1780  neighbourRegion.RegionHandle, pos, vel2 /* agent.Velocity */,
1781  neighbourRegion.ExternalEndPoint,
1782  capsPath, agent.UUID, agent.ControllingClient.SessionId,
1783  neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY);
1784  }
1785  else
1786  {
1787  m_log.ErrorFormat("{0} Using old CrossRegion packet. Varregion will not work!!", LogHeader);
1788  agent.ControllingClient.CrossRegion(neighbourRegion.RegionHandle, pos, agent.Velocity, neighbourRegion.ExternalEndPoint,
1789  capsPath);
1790  }
1791 
1792 /*
1793  // Backwards compatibility. Best effort
1794  if (version == 0f)
1795  {
1796  m_log.DebugFormat("[ENTITY TRANSFER MODULE]: neighbor with old version, passing attachments one by one...");
1797  Thread.Sleep(3000); // wait a little now that we're not waiting for the callback
1798  CrossAttachmentsIntoNewRegion(neighbourRegion, agent, true);
1799  }
1800 */
1801  // SUCCESS!
1802  m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.ReceivedAtDestination);
1803 
1804  // Unlike a teleport, here we do not wait for the destination region to confirm the receipt.
1805  m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp);
1806 
1807  agent.CloseChildAgents(false, neighbourRegion.RegionHandle, neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY);
1808 
1809  // this may need the attachments
1810 
1811  agent.HasMovedAway(true);
1812 
1813  agent.MakeChildAgent(neighbourRegion.RegionHandle);
1814 
1815  // FIXME: Possibly this should occur lower down after other commands to close other agents,
1816  // but not sure yet what the side effects would be.
1817  m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1818 
1819 
1820  // TODO: Check since what version this wasn't needed anymore. May be as old as 0.6
1821 /*
1822  // Backwards compatibility. Best effort
1823  if (version == 0f)
1824  {
1825  m_log.DebugFormat("[ENTITY TRANSFER MODULE]: neighbor with old version, passing attachments one by one...");
1826  Thread.Sleep(3000); // wait a little now that we're not waiting for the callback
1827  CrossAttachmentsIntoNewRegion(neighbourRegion, agent, true);
1828  }
1829 */
1830 
1831  // the user may change their profile information in other region,
1832  // so the userinfo in UserProfileCache is not reliable any more, delete it
1833  // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
1834 // if (agent.Scene.NeedSceneCacheClear(agent.UUID))
1835 // {
1836 // m_log.DebugFormat(
1837 // "[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID);
1838 // }
1839 
1840  //m_log.Debug("AFTER CROSS");
1841  //Scene.DumpChildrenSeeds(UUID);
1842  //DumpKnownRegions();
1843 
1844  return;
1845  }
1846 
1847  private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
1848  {
1850  ScenePresence agent = icon.EndInvoke(iar);
1851 
1853  //if (agent.IsChildAgent)
1854  // agent.Reset();
1855  //else // Not successful
1856  // agent.RestoreInCurrentScene();
1857 
1858  // In any case
1859  agent.IsInTransit = false;
1860 
1861  m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
1862  }
1863 
1864  #endregion
1865 
1866  #region Enable Child Agent
1867 
1875  {
1876  m_log.DebugFormat("[ENTITY TRANSFER]: Enabling child agent in new neighbour {0}", region.RegionName);
1877 
1878  ulong currentRegionHandler = sp.Scene.RegionInfo.RegionHandle;
1879  ulong regionhandler = region.RegionHandle;
1880 
1881  Dictionary<ulong, string> seeds = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID));
1882 
1883  if (seeds.ContainsKey(regionhandler))
1884  seeds.Remove(regionhandler);
1885 /*
1886  List<ulong> oldregions = new List<ulong>(seeds.Keys);
1887 
1888  if (oldregions.Contains(currentRegionHandler))
1889  oldregions.Remove(currentRegionHandler);
1890 */
1891  if (!seeds.ContainsKey(currentRegionHandler))
1892  seeds.Add(currentRegionHandler, sp.ControllingClient.RequestClientInfo().CapsPath);
1893 
1894  AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
1895  AgentCircuitData agent = sp.ControllingClient.RequestClientInfo();
1896  agent.BaseFolder = UUID.Zero;
1897  agent.InventoryFolder = UUID.Zero;
1898  agent.startpos = sp.AbsolutePosition + CalculateOffset(sp, region);
1899  agent.child = true;
1900  agent.Appearance = new AvatarAppearance();
1901  agent.Appearance.AvatarHeight = sp.Appearance.AvatarHeight;
1902 
1903  agent.CapsPath = CapsUtil.GetRandomCapsObjectPath();
1904 
1905  seeds.Add(regionhandler, agent.CapsPath);
1906 
1907 
1908 // agent.ChildrenCapSeeds = new Dictionary<ulong, string>(seeds);
1909  agent.ChildrenCapSeeds = null;
1910 
1911  if (sp.Scene.CapsModule != null)
1912  {
1913  sp.Scene.CapsModule.SetChildrenSeed(sp.UUID, seeds);
1914  }
1915 
1916  sp.KnownRegions = seeds;
1917  sp.AddNeighbourRegionSizeInfo(region);
1918 
1919  if (currentAgentCircuit != null)
1920  {
1921  agent.ServiceURLs = currentAgentCircuit.ServiceURLs;
1922  agent.IPAddress = currentAgentCircuit.IPAddress;
1923  agent.Viewer = currentAgentCircuit.Viewer;
1924  agent.Channel = currentAgentCircuit.Channel;
1925  agent.Mac = currentAgentCircuit.Mac;
1926  agent.Id0 = currentAgentCircuit.Id0;
1927  }
1928 /*
1929  AgentPosition agentpos = null;
1930 
1931  if (oldregions.Count > 0)
1932  {
1933  agentpos = new AgentPosition();
1934  agentpos.AgentID = new UUID(sp.UUID.Guid);
1935  agentpos.SessionID = sp.ControllingClient.SessionId;
1936  agentpos.Size = sp.Appearance.AvatarSize;
1937  agentpos.Center = sp.CameraPosition;
1938  agentpos.Far = sp.DrawDistance;
1939  agentpos.Position = sp.AbsolutePosition;
1940  agentpos.Velocity = sp.Velocity;
1941  agentpos.RegionHandle = currentRegionHandler;
1942  agentpos.Throttles = sp.ControllingClient.GetThrottlesPacked(1);
1943  agentpos.ChildrenCapSeeds = seeds;
1944  }
1945 */
1946  IPEndPoint external = region.ExternalEndPoint;
1947  if (external != null)
1948  {
1949  InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
1950  d.BeginInvoke(sp, agent, region, external, true,
1951  InformClientOfNeighbourCompleted,
1952  d);
1953  }
1954 /*
1955  if(oldregions.Count >0)
1956  {
1957  uint neighbourx;
1958  uint neighboury;
1959  UUID scope = sp.Scene.RegionInfo.ScopeID;
1960  foreach (ulong handler in oldregions)
1961  {
1962  Utils.LongToUInts(handler, out neighbourx, out neighboury);
1963  GridRegion neighbour = sp.Scene.GridService.GetRegionByPosition(scope, (int)neighbourx, (int)neighboury);
1964  sp.Scene.SimulationService.UpdateAgent(neighbour, agentpos);
1965  }
1966  }
1967  */
1968  }
1969 
1970  #endregion
1971 
1972  #region Enable Child Agents
1973 
1974  private delegate void InformClientOfNeighbourDelegate(
1975  ScenePresence avatar, AgentCircuitData a, GridRegion reg, IPEndPoint endPoint, bool newAgent);
1976 
1983  {
1984  // assumes that out of view range regions are disconnected by the previus region
1985 
1986  List<GridRegion> neighbours = new List<GridRegion>();
1987  Scene spScene = sp.Scene;
1988  RegionInfo m_regionInfo = spScene.RegionInfo;
1989 
1990  if (m_regionInfo != null)
1991  {
1992  neighbours = GetNeighbors(sp, m_regionInfo.RegionLocX, m_regionInfo.RegionLocY);
1993  }
1994  else
1995  {
1996  m_log.Debug("[ENTITY TRANSFER MODULE]: m_regionInfo was null in EnableChildAgents, is this a NPC?");
1997  }
1998 
1999  ulong currentRegionHandler = m_regionInfo.RegionHandle;
2000 
2001  LinkedList<ulong> previousRegionNeighbourHandles;
2002  Dictionary<ulong, string> seeds;
2003  ICapabilitiesModule capsModule = spScene.CapsModule;
2004 
2005  if (capsModule != null)
2006  {
2007  seeds = new Dictionary<ulong, string>(capsModule.GetChildrenSeeds(sp.UUID));
2008  previousRegionNeighbourHandles = new LinkedList<ulong>(seeds.Keys);
2009  }
2010  else
2011  {
2012  seeds = new Dictionary<ulong, string>();
2013  previousRegionNeighbourHandles = new LinkedList<ulong>();
2014  }
2015 
2016  IClientAPI spClient = sp.ControllingClient;
2017 
2018  if (!seeds.ContainsKey(currentRegionHandler))
2019  seeds.Add(currentRegionHandler, spClient.RequestClientInfo().CapsPath);
2020 
2021  AgentCircuitData currentAgentCircuit =
2022  spScene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
2023 
2024  List<AgentCircuitData> cagents = new List<AgentCircuitData>();
2025  List<ulong> newneighbours = new List<ulong>();
2026 
2027  foreach (GridRegion neighbour in neighbours)
2028  {
2029  ulong handler = neighbour.RegionHandle;
2030 
2031  if (previousRegionNeighbourHandles.Contains(handler))
2032  {
2033  // agent already knows this region
2034  previousRegionNeighbourHandles.Remove(handler);
2035  continue;
2036  }
2037 
2038  if (handler == currentRegionHandler)
2039  continue;
2040 
2041  // a new region to add
2042  AgentCircuitData agent = spClient.RequestClientInfo();
2043  agent.BaseFolder = UUID.Zero;
2044  agent.InventoryFolder = UUID.Zero;
2045  agent.startpos = sp.AbsolutePosition + CalculateOffset(sp, neighbour);
2046  agent.child = true;
2047  agent.Appearance = new AvatarAppearance();
2048  agent.Appearance.AvatarHeight = sp.Appearance.AvatarHeight;
2049 
2050  if (currentAgentCircuit != null)
2051  {
2052  agent.ServiceURLs = currentAgentCircuit.ServiceURLs;
2053  agent.IPAddress = currentAgentCircuit.IPAddress;
2054  agent.Viewer = currentAgentCircuit.Viewer;
2055  agent.Channel = currentAgentCircuit.Channel;
2056  agent.Mac = currentAgentCircuit.Mac;
2057  agent.Id0 = currentAgentCircuit.Id0;
2058  }
2059 
2060  newneighbours.Add(handler);
2061  agent.CapsPath = CapsUtil.GetRandomCapsObjectPath();
2062  seeds.Add(handler, agent.CapsPath);
2063 
2064  agent.ChildrenCapSeeds = null;
2065  cagents.Add(agent);
2066  }
2067 
2068  if (previousRegionNeighbourHandles.Contains(currentRegionHandler))
2069  previousRegionNeighbourHandles.Remove(currentRegionHandler);
2070 
2071  // previousRegionNeighbourHandles now contains regions to forget
2072  foreach (ulong handler in previousRegionNeighbourHandles)
2073  seeds.Remove(handler);
2074 
2076  // foreach (AgentCircuitData a in cagents)
2077  // a.ChildrenCapSeeds = new Dictionary<ulong, string>(seeds);
2078 
2079  if (capsModule != null)
2080  capsModule.SetChildrenSeed(sp.UUID, seeds);
2081 
2082  sp.KnownRegions = seeds;
2083  sp.SetNeighbourRegionSizeInfo(neighbours);
2084 
2085  AgentPosition agentpos = new AgentPosition();
2086  agentpos.AgentID = new UUID(sp.UUID.Guid);
2087  agentpos.SessionID = spClient.SessionId;
2088  agentpos.Size = sp.Appearance.AvatarSize;
2089  agentpos.Center = sp.CameraPosition;
2090  agentpos.Far = sp.DrawDistance;
2091  agentpos.Position = sp.AbsolutePosition;
2092  agentpos.Velocity = sp.Velocity;
2093  agentpos.RegionHandle = currentRegionHandler;
2094  agentpos.Throttles = spClient.GetThrottlesPacked(1);
2095  // agentpos.ChildrenCapSeeds = seeds;
2096 
2097  Util.FireAndForget(delegate
2098  {
2099  Thread.Sleep(200); // the original delay that was at InformClientOfNeighbourAsync start
2100  int count = 0;
2101 
2102  foreach (GridRegion neighbour in neighbours)
2103  {
2104  ulong handler = neighbour.RegionHandle;
2105  try
2106  {
2107  if (newneighbours.Contains(handler))
2108  {
2109  InformClientOfNeighbourAsync(sp, cagents[count], neighbour,
2110  neighbour.ExternalEndPoint, true);
2111  count++;
2112  }
2113  else if (!previousRegionNeighbourHandles.Contains(handler))
2114  {
2115  spScene.SimulationService.UpdateAgent(neighbour, agentpos);
2116  }
2117  }
2118  catch (ArgumentOutOfRangeException)
2119  {
2120  m_log.ErrorFormat(
2121  "[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}).",
2122  neighbour.ExternalHostName,
2123  neighbour.RegionHandle,
2124  neighbour.RegionLocX,
2125  neighbour.RegionLocY);
2126  }
2127  catch (Exception e)
2128  {
2129  m_log.ErrorFormat(
2130  "[ENTITY TRANSFER MODULE]: Could not resolve external hostname {0} for region {1} ({2}, {3}). {4}",
2131  neighbour.ExternalHostName,
2132  neighbour.RegionHandle,
2133  neighbour.RegionLocX,
2134  neighbour.RegionLocY,
2135  e);
2136 
2137  // FIXME: Okay, even though we've failed, we're still going to throw the exception on,
2138  // since I don't know what will happen if we just let the client continue
2139 
2140  // XXX: Well, decided to swallow the exception instead for now. Let us see how that goes.
2141  // throw e;
2142  }
2143  }
2144  });
2145  }
2146 
2147  // Computes the difference between two region bases.
2148  // Returns a vector of world coordinates (meters) from base of first region to the second.
2149  // The first region is the home region of the passed scene presence.
2150  Vector3 CalculateOffset(ScenePresence sp, GridRegion neighbour)
2151  {
2152  return new Vector3(sp.Scene.RegionInfo.WorldLocX - neighbour.RegionLocX,
2153  sp.Scene.RegionInfo.WorldLocY - neighbour.RegionLocY,
2154  0f);
2155  }
2156 
2157 
2158  #region NotFoundLocationCache class
2159  // A collection of not found locations to make future lookups 'not found' lookups quick.
2160  // A simple expiring cache that keeps not found locations for some number of seconds.
2161  // A 'not found' location is presumed to be anywhere in the minimum sized region that
2162  // contains that point. A conservitive estimate.
2163  private class NotFoundLocationCache
2164  {
2165  private struct NotFoundLocation
2166  {
2167  public double minX, maxX, minY, maxY;
2168  public DateTime expireTime;
2169  }
2170  private List<NotFoundLocation> m_notFoundLocations = new List<NotFoundLocation>();
2171  public NotFoundLocationCache()
2172  {
2173  }
2174  // Add an area to the list of 'not found' places. The area is the snapped region
2175  // area around the added point.
2176  public void Add(double pX, double pY)
2177  {
2178  lock (m_notFoundLocations)
2179  {
2180  if (!LockedContains(pX, pY))
2181  {
2182  NotFoundLocation nfl = new NotFoundLocation();
2183  // A not found location is not found for at least a whole region sized area
2184  nfl.minX = pX - (pX % (double)Constants.RegionSize);
2185  nfl.minY = pY - (pY % (double)Constants.RegionSize);
2186  nfl.maxX = nfl.minX + (double)Constants.RegionSize;
2187  nfl.maxY = nfl.minY + (double)Constants.RegionSize;
2188  nfl.expireTime = DateTime.Now + TimeSpan.FromSeconds(30);
2189  m_notFoundLocations.Add(nfl);
2190  }
2191  }
2192 
2193  }
2194  // Test to see of this point is in any of the 'not found' areas.
2195  // Return 'true' if the point is found inside the 'not found' areas.
2196  public bool Contains(double pX, double pY)
2197  {
2198  bool ret = false;
2199  lock (m_notFoundLocations)
2200  ret = LockedContains(pX, pY);
2201  return ret;
2202  }
2203  private bool LockedContains(double pX, double pY)
2204  {
2205  bool ret = false;
2206  this.DoExpiration();
2207  foreach (NotFoundLocation nfl in m_notFoundLocations)
2208  {
2209  if (pX >= nfl.minX && pX < nfl.maxX && pY >= nfl.minY && pY < nfl.maxY)
2210  {
2211  ret = true;
2212  break;
2213  }
2214  }
2215  return ret;
2216  }
2217  private void DoExpiration()
2218  {
2219  List<NotFoundLocation> m_toRemove = null;
2220  DateTime now = DateTime.Now;
2221  foreach (NotFoundLocation nfl in m_notFoundLocations)
2222  {
2223  if (nfl.expireTime < now)
2224  {
2225  if (m_toRemove == null)
2226  m_toRemove = new List<NotFoundLocation>();
2227  m_toRemove.Add(nfl);
2228  }
2229  }
2230  if (m_toRemove != null)
2231  {
2232  foreach (NotFoundLocation nfl in m_toRemove)
2233  m_notFoundLocations.Remove(nfl);
2234  m_toRemove.Clear();
2235  }
2236  }
2237  }
2238  #endregion // NotFoundLocationCache class
2239  private NotFoundLocationCache m_notFoundLocationCache = new NotFoundLocationCache();
2240 
2241 // needed for current OSG or old grid code
2242 
2243  public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py)
2244  {
2245  // Since we don't know how big the regions could be, we have to search a very large area
2246  // to find possible regions.
2247  return GetRegionContainingWorldLocation(pGridService, pScopeID, px, py, Constants.MaximumRegionSize);
2248  }
2249 
2250  // Given a world position, get the GridRegion info for
2251  // the region containing that point.
2252  // Someday this should be a method on GridService.
2253  // 'pSizeHint' is the size of the source region but since the destination point can be anywhere
2254  // the size of the target region is unknown thus the search area might have to be very large.
2255  // Return 'null' if no such region exists.
2256  public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID,
2257  double px, double py, uint pSizeHint)
2258  {
2259  m_log.DebugFormat("{0} GetRegionContainingWorldLocation: call, XY=<{1},{2}>", LogHeader, px, py);
2260  GridRegion ret = null;
2261  const double fudge = 2.0;
2262 
2263  // One problem with this routine is negative results. That is, this can be called lots of times
2264  // for regions that don't exist. m_notFoundLocationCache remembers 'not found' results so they
2265  // will be quick 'not found's next time.
2266  // NotFoundLocationCache is an expiring cache so it will eventually forget about 'not found' and
2267  // thus re-ask the GridService about the location.
2268  if (m_notFoundLocationCache.Contains(px, py))
2269  {
2270 // m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found via cache. loc=<{1},{2}>", LogHeader, px, py);
2271  return null;
2272  }
2273 
2274  // As an optimization, since most regions will be legacy sized regions (256x256), first try to get
2275  // the region at the appropriate legacy region location.
2276  uint possibleX = (uint)Math.Floor(px);
2277  possibleX -= possibleX % Constants.RegionSize;
2278  uint possibleY = (uint)Math.Floor(py);
2279  possibleY -= possibleY % Constants.RegionSize;
2280  ret = pGridService.GetRegionByPosition(pScopeID, (int)possibleX, (int)possibleY);
2281  if (ret != null)
2282  {
2283  m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Found region using legacy size. rloc=<{1},{2}>. Rname={3}",
2284  LogHeader, possibleX, possibleY, ret.RegionName);
2285  }
2286 
2287  if (ret == null)
2288  {
2289  // If the simple lookup failed, search the larger area for a region that contains this point
2290  double range = (double)pSizeHint + fudge;
2291  while (ret == null && range <= (Constants.MaximumRegionSize + Constants.RegionSize))
2292  {
2293  // Get from the grid service a list of regions that might contain this point.
2294  // The region origin will be in the zero direction so only subtract the range.
2295  List<GridRegion> possibleRegions = pGridService.GetRegionRange(pScopeID,
2296  (int)(px - range), (int)(px),
2297  (int)(py - range), (int)(py));
2298  m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegions cnt={1}, range={2}",
2299  LogHeader, possibleRegions.Count, range);
2300  if (possibleRegions != null && possibleRegions.Count > 0)
2301  {
2302  // If we found some regions, check to see if the point is within
2303  foreach (GridRegion gr in possibleRegions)
2304  {
2305  m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegion nm={1}, regionLoc=<{2},{3}>, regionSize=<{4},{5}>",
2306  LogHeader, gr.RegionName, gr.RegionLocX, gr.RegionLocY, gr.RegionSizeX, gr.RegionSizeY);
2307  if (px >= (double)gr.RegionLocX && px < (double)(gr.RegionLocX + gr.RegionSizeX)
2308  && py >= (double)gr.RegionLocY && py < (double)(gr.RegionLocY + gr.RegionSizeY))
2309  {
2310  // Found a region that contains the point
2311  ret = gr;
2312  m_log.DebugFormat("{0} GetRegionContainingWorldLocation: found. RegionName={1}", LogHeader, ret.RegionName);
2313  break;
2314  }
2315  }
2316  }
2317  // Larger search area for next time around if not found
2318  range *= 2;
2319  }
2320  }
2321 
2322  if (ret == null)
2323  {
2324  // remember this location was not found so we can quickly not find it next time
2325  m_notFoundLocationCache.Add(px, py);
2326  m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found. Remembering loc=<{1},{2}>", LogHeader, px, py);
2327  }
2328 
2329  return ret;
2330  }
2331 
2332  private void InformClientOfNeighbourCompleted(IAsyncResult iar)
2333  {
2334  InformClientOfNeighbourDelegate icon = (InformClientOfNeighbourDelegate)iar.AsyncState;
2335  icon.EndInvoke(iar);
2336  //m_log.WarnFormat(" --> InformClientOfNeighbourCompleted");
2337  }
2338 
2349  private void InformClientOfNeighbourAsync(ScenePresence sp, AgentCircuitData a, GridRegion reg,
2350  IPEndPoint endPoint, bool newAgent)
2351  {
2352 
2353  if (newAgent)
2354  {
2355  Scene scene = sp.Scene;
2356 
2357  m_log.DebugFormat(
2358  "[ENTITY TRANSFER MODULE]: Informing {0} {1} about neighbour {2} {3} at ({4},{5})",
2359  sp.Name, sp.UUID, reg.RegionName, endPoint, reg.RegionCoordX, reg.RegionCoordY);
2360 
2361  string capsPath = reg.ServerURI + CapsUtil.GetCapsSeedPath(a.CapsPath);
2362 
2363  string reason = String.Empty;
2364 
2366  bool regionAccepted = scene.SimulationService.CreateAgent(reg, reg, a, (uint)TeleportFlags.Default, ctx, out reason);
2367 
2368  if (regionAccepted)
2369  {
2370  // give time for createAgent to finish, since it is async and does grid services access
2371  Thread.Sleep(500);
2372 
2373  if (m_eqModule != null)
2374  {
2375  #region IP Translation for NAT
2376  IClientIPEndpoint ipepClient;
2377  if (sp.ClientView.TryGet(out ipepClient))
2378  {
2379  endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address);
2380  }
2381  #endregion
2382 
2383  m_log.DebugFormat("{0} {1} is sending {2} EnableSimulator for neighbour region {3}(loc=<{4},{5}>,siz=<{6},{7}>) " +
2384  "and EstablishAgentCommunication with seed cap {8}", LogHeader,
2385  scene.RegionInfo.RegionName, sp.Name,
2386  reg.RegionName, reg.RegionLocX, reg.RegionLocY, reg.RegionSizeX, reg.RegionSizeY, capsPath);
2387 
2388  m_eqModule.EnableSimulator(reg.RegionHandle, endPoint, sp.UUID, reg.RegionSizeX, reg.RegionSizeY);
2389  m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath, reg.RegionHandle, reg.RegionSizeX, reg.RegionSizeY);
2390  }
2391  else
2392  {
2393  sp.ControllingClient.InformClientOfNeighbour(reg.RegionHandle, endPoint);
2394  // TODO: make Event Queue disablable!
2395  }
2396 
2397  m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Completed inform {0} {1} about neighbour {2}", sp.Name, sp.UUID, endPoint);
2398  }
2399 
2400  else
2401  {
2402  sp.RemoveNeighbourRegion(reg.RegionHandle);
2403  m_log.WarnFormat(
2404  "[ENTITY TRANSFER MODULE]: Region {0} did not accept {1} {2}: {3}",
2405  reg.RegionName, sp.Name, sp.UUID, reason);
2406  }
2407  }
2408 
2409  }
2410 
2417  private void GetMegaregionViewRange(out Vector2 swCorner, out Vector2 neCorner)
2418  {
2419  Vector2 extent = Vector2.Zero;
2420 
2421  if (m_regionCombinerModule != null)
2422  {
2423  Vector2 megaRegionSize = m_regionCombinerModule.GetSizeOfMegaregion(Scene.RegionInfo.RegionID);
2424  extent.X = (float)Util.WorldToRegionLoc((uint)megaRegionSize.X);
2425  extent.Y = (float)Util.WorldToRegionLoc((uint)megaRegionSize.Y);
2426  }
2427 
2428  swCorner.X = Scene.RegionInfo.RegionLocX - 1;
2429  swCorner.Y = Scene.RegionInfo.RegionLocY - 1;
2430  neCorner.X = Scene.RegionInfo.RegionLocX + extent.X;
2431  neCorner.Y = Scene.RegionInfo.RegionLocY + extent.Y;
2432  }
2433 
2441  protected List<GridRegion> GetNeighbors(ScenePresence avatar, uint pRegionLocX, uint pRegionLocY)
2442  {
2443  Scene pScene = avatar.Scene;
2444  RegionInfo m_regionInfo = pScene.RegionInfo;
2445  List<GridRegion> neighbours;
2446 
2447  // Leaving this as a "megaregions" computation vs "non-megaregions" computation; it isn't
2448  // clear what should be done with a "far view" given that megaregions already extended the
2449  // view to include everything in the megaregion
2450  if (m_regionCombinerModule == null || !m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID))
2451  {
2452  uint dd = (uint)avatar.RegionViewDistance;
2453 
2454  // until avatar movement updates client connections, we need to seend at least this current region imediate Neighbors
2455  uint ddX = Math.Max(dd, Constants.RegionSize);
2456  uint ddY = Math.Max(dd, Constants.RegionSize);
2457 
2458  ddX--;
2459  ddY--;
2460 
2461  // reference to region edges. Should be avatar position
2462  uint startX = Util.RegionToWorldLoc(pRegionLocX);
2463  uint endX = startX + m_regionInfo.RegionSizeX;
2464  uint startY = Util.RegionToWorldLoc(pRegionLocY);
2465  uint endY = startY + m_regionInfo.RegionSizeY;
2466 
2467  startX -= ddX;
2468  startY -= ddY;
2469  endX += ddX;
2470  endY += ddY;
2471 
2472  neighbours
2473  = avatar.Scene.GridService.GetRegionRange(
2474  m_regionInfo.ScopeID, (int)startX, (int)endX, (int)startY, (int)endY);
2475  }
2476  else
2477  {
2478  Vector2 swCorner, neCorner;
2479  GetMegaregionViewRange(out swCorner, out neCorner);
2480 
2481  neighbours
2482  = pScene.GridService.GetRegionRange(
2483  m_regionInfo.ScopeID,
2484  (int)Util.RegionToWorldLoc((uint)swCorner.X), (int)Util.RegionToWorldLoc((uint)neCorner.X),
2485  (int)Util.RegionToWorldLoc((uint)swCorner.Y), (int)Util.RegionToWorldLoc((uint)neCorner.Y));
2486  }
2487 
2488  // The r.RegionFlags == null check only needs to be made for simulators before 2015-01-14 (pre 0.8.1).
2489  neighbours.RemoveAll( r => r.RegionID == m_regionInfo.RegionID );
2490 
2491  return neighbours;
2492  }
2493  #endregion
2494 
2495  #region Agent Arrived
2496 
2497  public void AgentArrivedAtDestination(UUID id)
2498  {
2499  m_entityTransferStateMachine.SetAgentArrivedAtDestination(id);
2500  }
2501 
2502  #endregion
2503 
2504  #region Object Transfers
2505 
2506  public GridRegion GetObjectDestination(SceneObjectGroup grp, Vector3 targetPosition,out Vector3 newpos)
2507  {
2508  newpos = targetPosition;
2509 
2510  Scene scene = grp.Scene;
2511  if (scene == null)
2512  return null;
2513 
2514  int x = (int)targetPosition.X + (int)scene.RegionInfo.WorldLocX;
2515  if (targetPosition.X >= 0)
2516  x++;
2517  else
2518  x--;
2519 
2520  int y = (int)targetPosition.Y + (int)scene.RegionInfo.WorldLocY;
2521  if (targetPosition.Y >= 0)
2522  y++;
2523  else
2524  y--;
2525 
2526  GridRegion neighbourRegion = scene.GridService.GetRegionByPosition(scene.RegionInfo.ScopeID,x,y);
2527  if (neighbourRegion == null)
2528  {
2529  return null;
2530  }
2531 
2532  float newRegionSizeX = neighbourRegion.RegionSizeX;
2533  float newRegionSizeY = neighbourRegion.RegionSizeY;
2534  if (newRegionSizeX == 0)
2535  newRegionSizeX = Constants.RegionSize;
2536  if (newRegionSizeY == 0)
2537  newRegionSizeY = Constants.RegionSize;
2538 
2539 
2540  newpos.X = targetPosition.X - (neighbourRegion.RegionLocX - (int)scene.RegionInfo.WorldLocX);
2541  newpos.Y = targetPosition.Y - (neighbourRegion.RegionLocY - (int)scene.RegionInfo.WorldLocY);
2542 
2543 
2544  const float enterDistance = 0.2f;
2545  newpos.X = Util.Clamp(newpos.X, enterDistance, newRegionSizeX - enterDistance);
2546  newpos.Y = Util.Clamp(newpos.Y, enterDistance, newRegionSizeY - enterDistance);
2547 
2548  return neighbourRegion;
2549  }
2550 
2551 /* not in use. -> CrossPrimGroupIntoNewRegion
2563  public void Cross(SceneObjectGroup grp, Vector3 attemptedPosition, bool silent)
2564  {
2565  if (grp == null)
2566  return;
2567  if (grp.IsDeleted)
2568  return;
2569 
2570  Scene scene = grp.Scene;
2571  if (scene == null)
2572  return;
2573 
2574  // Remember the old group position in case the region lookup fails so position can be restored.
2575  Vector3 oldGroupPosition = grp.RootPart.GroupPosition;
2576 
2577  // Compute the absolute position of the object.
2578  double objectWorldLocX = (double)scene.RegionInfo.WorldLocX + attemptedPosition.X;
2579  double objectWorldLocY = (double)scene.RegionInfo.WorldLocY + attemptedPosition.Y;
2580 
2581  // Ask the grid service for the region that contains the passed address
2582  GridRegion destination = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID,
2583  objectWorldLocX, objectWorldLocY);
2584 
2585  Vector3 pos = Vector3.Zero;
2586  if (destination != null)
2587  {
2588  // Adjust the object's relative position from the old region (attemptedPosition)
2589  // to be relative to the new region (pos).
2590  pos = new Vector3( (float)(objectWorldLocX - (double)destination.RegionLocX),
2591  (float)(objectWorldLocY - (double)destination.RegionLocY),
2592  attemptedPosition.Z);
2593  }
2594 
2595  if (destination == null || !CrossPrimGroupIntoNewRegion(destination, pos, grp, silent))
2596  {
2597  m_log.InfoFormat("[ENTITY TRANSFER MODULE] cross region transfer failed for object {0}", grp.UUID);
2598 
2599  // We are going to move the object back to the old position so long as the old position
2600  // is in the region
2601  oldGroupPosition.X = Util.Clamp<float>(oldGroupPosition.X, 1.0f, (float)(scene.RegionInfo.RegionSizeX - 1));
2602  oldGroupPosition.Y = Util.Clamp<float>(oldGroupPosition.Y, 1.0f, (float)(scene.RegionInfo.RegionSizeY - 1));
2603  oldGroupPosition.Z = Util.Clamp<float>(oldGroupPosition.Z, 1.0f, Constants.RegionHeight);
2604 
2605  grp.AbsolutePosition = oldGroupPosition;
2606  grp.Velocity = Vector3.Zero;
2607  if (grp.RootPart.PhysActor != null)
2608  grp.RootPart.PhysActor.CrossingFailure();
2609 
2610  if (grp.RootPart.KeyframeMotion != null)
2611  grp.RootPart.KeyframeMotion.CrossingFailure();
2612 
2613  grp.ScheduleGroupForFullUpdate();
2614  }
2615  }
2616 */
2626  public bool CrossPrimGroupIntoNewRegion(GridRegion destination, Vector3 newPosition, SceneObjectGroup grp, bool silent, bool removeScripts)
2627  {
2628  //m_log.Debug(" >>> CrossPrimGroupIntoNewRegion <<<");
2629 
2630  bool successYN = false;
2631  grp.RootPart.ClearUpdateSchedule();
2632  //int primcrossingXMLmethod = 0;
2633 
2634  if (destination != null)
2635  {
2636  //string objectState = grp.GetStateSnapshot();
2637 
2638  //successYN
2639  // = m_sceneGridService.PrimCrossToNeighboringRegion(
2640  // newRegionHandle, grp.UUID, m_serialiser.SaveGroupToXml2(grp), primcrossingXMLmethod);
2641  //if (successYN && (objectState != "") && m_allowScriptCrossings)
2642  //{
2643  // successYN = m_sceneGridService.PrimCrossToNeighboringRegion(
2644  // newRegionHandle, grp.UUID, objectState, 100);
2645  //}
2646 
2648  //if (m_interregionCommsOut != null)
2649  // successYN = m_interregionCommsOut.SendCreateObject(newRegionHandle, grp, true);
2650  if (Scene.SimulationService != null)
2651  successYN = Scene.SimulationService.CreateObject(destination, newPosition, grp, true);
2652 
2653  if (successYN)
2654  {
2655  // We remove the object here
2656  try
2657  {
2658  grp.Scene.DeleteSceneObject(grp, silent, removeScripts);
2659  }
2660  catch (Exception e)
2661  {
2662  m_log.ErrorFormat(
2663  "[ENTITY TRANSFER MODULE]: Exception deleting the old object left behind on a border crossing for {0}, {1}",
2664  grp, e);
2665  }
2666  }
2667  }
2668  else
2669  {
2670  m_log.Error("[ENTITY TRANSFER MODULE]: destination was unexpectedly null in Scene.CrossPrimGroupIntoNewRegion()");
2671  }
2672 
2673  return successYN;
2674  }
2675 
2686  protected void CrossAttachmentsIntoNewRegion(GridRegion destination, ScenePresence sp, bool silent)
2687  {
2688  List<SceneObjectGroup> attachments = sp.GetAttachments();
2689 
2690 // m_log.DebugFormat(
2691 // "[ENTITY TRANSFER MODULE]: Crossing {0} attachments into {1} for {2}",
2692 // m_attachments.Count, destination.RegionName, sp.Name);
2693 
2694  foreach (SceneObjectGroup gobj in attachments)
2695  {
2696  // If the prim group is null then something must have happened to it!
2697  if (gobj != null && !gobj.IsDeleted)
2698  {
2700  clone.RootPart.GroupPosition = gobj.RootPart.AttachedPos;
2701  clone.IsAttachment = false;
2702 
2703  //gobj.RootPart.LastOwnerID = gobj.GetFromAssetID();
2704  m_log.DebugFormat(
2705  "[ENTITY TRANSFER MODULE]: Sending attachment {0} to region {1}",
2706  clone.UUID, destination.RegionName);
2707 
2708  CrossPrimGroupIntoNewRegion(destination, Vector3.Zero, clone, silent,true);
2709  }
2710  }
2711 
2712  sp.ClearAttachments();
2713  }
2714 
2715  #endregion
2716 
2717  #region Misc
2718 
2719  public bool IsInTransit(UUID id)
2720  {
2721  return m_entityTransferStateMachine.GetAgentTransferState(id) != null;
2722  }
2723 
2725  {
2726  int i = 0;
2727  if (sp.InTransitScriptStates.Count > 0)
2728  {
2729  List<SceneObjectGroup> attachments = sp.GetAttachments();
2730 
2731  foreach (SceneObjectGroup sog in attachments)
2732  {
2733  if (i < sp.InTransitScriptStates.Count)
2734  {
2735  sog.SetState(sp.InTransitScriptStates[i++], sp.Scene);
2736  sog.CreateScriptInstances(0, false, sp.Scene.DefaultScriptEngine, 0);
2737  sog.ResumeScripts();
2738  }
2739  else
2740  m_log.ErrorFormat(
2741  "[ENTITY TRANSFER MODULE]: InTransitScriptStates.Count={0} smaller than Attachments.Count={1}",
2742  sp.InTransitScriptStates.Count, attachments.Count);
2743  }
2744 
2745  sp.InTransitScriptStates.Clear();
2746  }
2747  }
2748  #endregion
2749 
2750  public virtual bool HandleIncomingSceneObject(SceneObjectGroup so, Vector3 newPosition)
2751  {
2752  // If the user is banned, we won't let any of their objects
2753  // enter. Period.
2754  //
2756  {
2757  m_log.DebugFormat(
2758  "[ENTITY TRANSFER MODULE]: Denied prim crossing of {0} {1} into {2} for banned avatar {3}",
2759  so.Name, so.UUID, Scene.Name, so.OwnerID);
2760 
2761  return false;
2762  }
2763 
2764  if (newPosition != Vector3.Zero)
2765  so.RootPart.GroupPosition = newPosition;
2766 
2767  if (!Scene.AddSceneObject(so))
2768  {
2769  m_log.DebugFormat(
2770  "[ENTITY TRANSFER MODULE]: Problem adding scene object {0} {1} into {2} ",
2771  so.Name, so.UUID, Scene.Name);
2772 
2773  return false;
2774  }
2775 
2776  if (!so.IsAttachment)
2777  {
2778  // FIXME: It would be better to never add the scene object at all rather than add it and then delete
2779  // it
2781  {
2782  // Deny non attachments based on parcel settings
2783  //
2784  m_log.Info("[ENTITY TRANSFER MODULE]: Denied prim crossing because of parcel settings");
2785 
2786  Scene.DeleteSceneObject(so, false);
2787 
2788  return false;
2789  }
2790 
2791  // For attachments, we need to wait until the agent is root
2792  // before we restart the scripts, or else some functions won't work.
2793  so.RootPart.ParentGroup.CreateScriptInstances(
2794  0, false, Scene.DefaultScriptEngine, GetStateSource(so));
2795 
2796  so.ResumeScripts();
2797 
2798  if (so.RootPart.KeyframeMotion != null)
2799  so.RootPart.KeyframeMotion.UpdateSceneObject(so);
2800  }
2801 
2802  return true;
2803  }
2804 
2805  private int GetStateSource(SceneObjectGroup sog)
2806  {
2807  ScenePresence sp = Scene.GetScenePresence(sog.OwnerID);
2808 
2809  if (sp != null)
2810  return sp.GetStateSource();
2811 
2812  return 2; // StateSource.PrimCrossing
2813  }
2814  }
2815 }
void CrossAgentToNewRegionPost(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, bool isFlying, EntityTransferContext ctx)
virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout, string auth_code, string reason)
Signal that the inter-region teleport failed and perform cleanup.
EstateSettings EstateSettings
Definition: RegionInfo.cs:275
const uint MaximumRegionSize
Definition: Constants.cs:39
OpenSim.Framework.Constants.TeleportFlags TeleportFlags
bool CrossPrimGroupIntoNewRegion(GridRegion destination, Vector3 newPosition, SceneObjectGroup grp, bool silent, bool removeScripts)
Move the given scene object into a new region
void DoTeleport(ScenePresence sp, GridRegion reg, GridRegion finalDestination, Vector3 position, Vector3 lookAt, uint teleportFlags)
Wraps DoTeleportInternal() and manages the transfer state.
bool checkAgentAccessToRegion(ScenePresence agent, GridRegion destiny, Vector3 position, EntityTransferContext ctx, out string reason)
Scene Scene
The scene to which this entity belongs
Definition: EntityBase.cs:46
bool CrossAgentIntoNewRegionMain(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, bool isFlying, EntityTransferContext ctx)
OpenSim.Framework.RegionInfo RegionInfo
GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, EntityTransferContext ctx, out Vector3 newpos)
GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py)
uint RegionSizeX
X dimension of the region.
Definition: RegionInfo.cs:161
Contains the Avatar's Appearance and methods to manipulate the appearance.
ScenePresence CrossAgentToNewRegionAsync(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, bool isFlying, EntityTransferContext ctx)
This Closes child agents on neighbouring regions Calls an asynchronous method to do so...
bool UpdateAgent(GridRegion destination, AgentData data, EntityTransferContext ctx)
Full child agent update.
uint RegionSizeY
X dimension of the region.
Definition: RegionInfo.cs:169
Holds individual statistic details
Definition: Stat.cs:41
A scene object group is conceptually an object in the scene. The object is constituted of SceneObject...
void StandUp()
Perform the logic necessary to stand the avatar up. This method also executes the stand animation...
bool QueryAccess(GridRegion destination, UUID agentID, string agentHomeURI, bool viaTeleport, Vector3 position, List< UUID > features, EntityTransferContext ctx, out string reason)
Returns whether a propspective user is allowed to visit the region.
delegate ScenePresence CrossAsyncDelegate(ScenePresence agent, bool isFlying)
Records user information specific to a grid but which is not part of a user's account.
virtual bool TeleportHome(UUID id, IClientAPI client)
Teleports the agent for the given client to their home destination.
UUID SessionID
Non secure Session ID
int RegionCoordY
The co-ordinate of this region in region units
List< SceneObjectGroup > GetAttachments()
Get all the presence's attachments.
virtual void InitialiseCommon(IConfigSource source)
Initialize config common for this module and any descendents.
bool IsDeleted
Signals whether this entity was in a scene but has since been removed from it.
Definition: EntityBase.cs:73
virtual void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
virtual bool NeedsNewAgent(float viewdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, int oldsizeX, int oldsizeY, int newsizeX, int newsizeY)
GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py, uint pSizeHint)
int RegionLocX
The location of this region in meters. DANGER DANGER! Note that this name means something different i...
bool CanObjectEntry(UUID objectID, bool enteringRegion, Vector3 newPoint)
OpenSim.Services.Interfaces.GridRegion GridRegion
override Vector3 Velocity
Current velocity of the avatar.
virtual void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
virtual void Initialise(IConfigSource source)
This is called to initialize the region module. For shared modules, this is called exactly once...
virtual void AgentHasMovedAway(ScenePresence sp, bool logout)
Clean up operations once an agent has moved away through cross or teleport.
Circuit data for an agent. Connection information shared between regions that accept UDP connections ...
ICapabilitiesModule CapsModule
Definition: Scene.cs:782
int RegionLocY
The location of this region in meters. DANGER DANGER! Note that this name means something different i...
AgentCircuitData RequestClientInfo()
Return circuit information for this client.
void InformClientToInitiateTeleportToLocationAsync(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene)
List< string > InTransitScriptStates
Copy of the script states while the agent is in transit. This state may need to be placed back in cas...
StatVerbosity
Verbosity of stat.
virtual bool ValidateGenericConditions(ScenePresence sp, GridRegion reg, GridRegion finalDestination, uint teleportFlags, out string reason)
GridRegion GetObjectDestination(SceneObjectGroup grp, Vector3 targetPosition, out Vector3 newpos)
delegate void UpdateAgent(IClientAPI remoteClient, AgentUpdateArgs agentData)
Replacement for ChildAgentDataUpdate. Used over RESTComms and LocalComms.
bool IsLoggingOut
Set if the client is closing due to a logout request
Definition: IClientAPI.cs:773
virtual void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
void CrossAttachmentsIntoNewRegion(GridRegion destination, ScenePresence sp, bool silent)
Cross the attachments for an avatar into the destination region.
Interactive OpenSim region server
Definition: OpenSim.cs:55
void EnableChildAgent(ScenePresence sp, GridRegion region)
This informs a single neighbouring region about agent "avatar", and avatar about it Calls an asynch...
virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, EntityTransferContext ctx, out string reason, out bool logout)
bool IncomingPreCloseClient(ScenePresence sp)
Tell a single client to prepare to close.
Definition: Scene.cs:4807
ISimulationService SimulationService
Definition: Scene.cs:701
delegate ScenePresence CrossAgentToNewRegionDelegate(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, bool isFlying, EntityTransferContext ctx)
virtual void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
virtual GridRegion GetFinalDestination(GridRegion region, UUID agentID, string agentHomeURI, out string message)
virtual void CleanupFailedInterRegionTeleport(ScenePresence sp, string auth_token, GridRegion finalDestination)
Clean up an inter-region teleport that did not complete, either because of simulator failure or cance...
bool PositionIsInCurrentRegion(Vector3 pos)
Definition: Scene.cs:2903
override Vector3 AbsolutePosition
The absolute position of this scene object in the scene
AgentTransferState
The possible states that an agent can be in when its being transferred between regions.
void EnableChildAgents(ScenePresence sp)
This informs all neighbouring regions about agent "avatar". and as important informs the avatar about...
bool ValidateAttachments()
This is currently just being done for information.
bool IsInTransit(UUID id)
Show whether the given agent is being teleported.
virtual string Name
The name of this entity
Definition: EntityBase.cs:65
GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, EntityTransferContext ctx, out Vector3 newpos, out string failureReason)
List< GridRegion > GetNeighbors(ScenePresence avatar, uint pRegionLocX, uint pRegionLocY)
Return the list of online regions that are considered to be neighbours to the given scene...
void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags)
Teleport an agent within the same or to a different region.
virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent, ScenePresence sp, EntityTransferContext ctx)
bool CrossAgentToNewRegionPrep(ScenePresence agent, GridRegion neighbourRegion)
uint RegionLocY
The y co-ordinate of this region in map tiles (e.g. 1000). Coordinate is scaled as world coordinates ...
Definition: RegionInfo.cs:496
uint RegionLocX
The x co-ordinate of this region in map tiles (e.g. 1000). Coordinate is scaled as world coordinates ...
Definition: RegionInfo.cs:485
virtual bool HandleIncomingSceneObject(SceneObjectGroup so, Vector3 newPosition)
bool IsAttachment
Is this scene object acting as an attachment?
Records the state of entities when they are in transfer within or between regions (cross or teleport)...
bool AddSceneObject(SceneObjectGroup sceneObject)
Adds a Scene Object group to the Scene. Verifies that the creator of the object is not banned from th...
Definition: Scene.cs:3007
void SendTeleportStart(uint flags)
uint ParentID
If the avatar is sitting, the local ID of the prim that it's sitting on. If not sitting then zero...