aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Framework/EntityTransfer
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs2058
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs148
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs290
3 files changed, 1731 insertions, 765 deletions
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index c43edd2..a2417c4 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -33,9 +33,10 @@ using System.Threading;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Framework.Capabilities; 34using OpenSim.Framework.Capabilities;
35using OpenSim.Framework.Client; 35using OpenSim.Framework.Client;
36using OpenSim.Framework.Monitoring;
36using OpenSim.Region.Framework.Interfaces; 37using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes; 38using OpenSim.Region.Framework.Scenes;
38using OpenSim.Region.Physics.Manager; 39using OpenSim.Region.PhysicsModules.SharedBase;
39using OpenSim.Services.Interfaces; 40using OpenSim.Services.Interfaces;
40 41
41using GridRegion = OpenSim.Services.Interfaces.GridRegion; 42using GridRegion = OpenSim.Services.Interfaces.GridRegion;
@@ -51,15 +52,61 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
51 public class EntityTransferModule : INonSharedRegionModule, IEntityTransferModule 52 public class EntityTransferModule : INonSharedRegionModule, IEntityTransferModule
52 { 53 {
53 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55 private static readonly string LogHeader = "[ENTITY TRANSFER MODULE]";
54 56
57 public const int DefaultMaxTransferDistance = 4095;
55 public const bool WaitForAgentArrivedAtDestinationDefault = true; 58 public const bool WaitForAgentArrivedAtDestinationDefault = true;
56 59
57 /// <summary> 60 /// <summary>
61 /// The maximum distance, in standard region units (256m) that an agent is allowed to transfer.
62 /// </summary>
63 public int MaxTransferDistance { get; set; }
64
65 /// <summary>
58 /// If true then on a teleport, the source region waits for a callback from the destination region. If 66 /// If true then on a teleport, the source region waits for a callback from the destination region. If
59 /// a callback fails to arrive within a set time then the user is pulled back into the source region. 67 /// a callback fails to arrive within a set time then the user is pulled back into the source region.
60 /// </summary> 68 /// </summary>
61 public bool WaitForAgentArrivedAtDestination { get; set; } 69 public bool WaitForAgentArrivedAtDestination { get; set; }
62 70
71 /// <summary>
72 /// If true then we ask the viewer to disable teleport cancellation and ignore teleport requests.
73 /// </summary>
74 /// <remarks>
75 /// This is useful in situations where teleport is very likely to always succeed and we want to avoid a
76 /// situation where avatars can be come 'stuck' due to a failed teleport cancellation. Unfortunately, the
77 /// nature of the teleport protocol makes it extremely difficult (maybe impossible) to make teleport
78 /// cancellation consistently suceed.
79 /// </remarks>
80 public bool DisableInterRegionTeleportCancellation { get; set; }
81
82 /// <summary>
83 /// Number of times inter-region teleport was attempted.
84 /// </summary>
85 private Stat m_interRegionTeleportAttempts;
86
87 /// <summary>
88 /// Number of times inter-region teleport was aborted (due to simultaneous client logout).
89 /// </summary>
90 private Stat m_interRegionTeleportAborts;
91
92 /// <summary>
93 /// Number of times inter-region teleport was successfully cancelled by the client.
94 /// </summary>
95 private Stat m_interRegionTeleportCancels;
96
97 /// <summary>
98 /// Number of times inter-region teleport failed due to server/client/network problems (e.g. viewer failed to
99 /// connect with destination region).
100 /// </summary>
101 /// <remarks>
102 /// This is not necessarily a problem for this simulator - in open-grid/hg conditions, viewer connectivity to
103 /// destination simulator is unknown.
104 /// </remarks>
105 private Stat m_interRegionTeleportFailures;
106
107 protected string m_ThisHomeURI;
108 protected string m_GatekeeperURI;
109
63 protected bool m_Enabled = false; 110 protected bool m_Enabled = false;
64 111
65 public Scene Scene { get; private set; } 112 public Scene Scene { get; private set; }
@@ -70,10 +117,56 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
70 /// </summary> 117 /// </summary>
71 private EntityTransferStateMachine m_entityTransferStateMachine; 118 private EntityTransferStateMachine m_entityTransferStateMachine;
72 119
73 private ExpiringCache<UUID, ExpiringCache<ulong, DateTime>> m_bannedRegions = 120 // For performance, we keed a cached of banned regions so we don't keep going
74 new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>(); 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 if (!m_bannedRegions.TryGetValue(pAgentID, out m_idCache))
151 {
152 m_idCache = new ExpiringCache<ulong, DateTime>();
153 m_bannedRegions.Add(pAgentID, m_idCache, TimeSpan.FromSeconds(45));
154 }
155 m_idCache.Add(pRegionHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15));
156 }
157 // Remove the agent from the region's banned list
158 public void Remove(ulong pRegionHandle, UUID pAgentID)
159 {
160 if (m_bannedRegions.TryGetValue(pAgentID, out m_idCache))
161 {
162 m_idCache.Remove(pRegionHandle);
163 }
164 }
165 }
166 private BannedRegionCache m_bannedRegionCache = new BannedRegionCache();
75 167
76 private IEventQueue m_eqModule; 168 private IEventQueue m_eqModule;
169 private IRegionCombinerModule m_regionCombinerModule;
77 170
78 #region ISharedRegionModule 171 #region ISharedRegionModule
79 172
@@ -107,11 +200,32 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
107 /// <param name="source"></param> 200 /// <param name="source"></param>
108 protected virtual void InitialiseCommon(IConfigSource source) 201 protected virtual void InitialiseCommon(IConfigSource source)
109 { 202 {
203 IConfig hypergridConfig = source.Configs["Hypergrid"];
204 if (hypergridConfig != null)
205 {
206 m_ThisHomeURI = hypergridConfig.GetString("HomeURI", string.Empty);
207 if (m_ThisHomeURI != string.Empty && !m_ThisHomeURI.EndsWith("/"))
208 m_ThisHomeURI += '/';
209
210 m_GatekeeperURI = hypergridConfig.GetString("GatekeeperURI", string.Empty);
211 if (m_GatekeeperURI != string.Empty && !m_GatekeeperURI.EndsWith("/"))
212 m_GatekeeperURI += '/';
213 }
214
110 IConfig transferConfig = source.Configs["EntityTransfer"]; 215 IConfig transferConfig = source.Configs["EntityTransfer"];
111 if (transferConfig != null) 216 if (transferConfig != null)
112 { 217 {
218 DisableInterRegionTeleportCancellation
219 = transferConfig.GetBoolean("DisableInterRegionTeleportCancellation", false);
220
113 WaitForAgentArrivedAtDestination 221 WaitForAgentArrivedAtDestination
114 = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault); 222 = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault);
223
224 MaxTransferDistance = transferConfig.GetInt("max_distance", DefaultMaxTransferDistance);
225 }
226 else
227 {
228 MaxTransferDistance = DefaultMaxTransferDistance;
115 } 229 }
116 230
117 m_entityTransferStateMachine = new EntityTransferStateMachine(this); 231 m_entityTransferStateMachine = new EntityTransferStateMachine(this);
@@ -130,19 +244,87 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
130 244
131 Scene = scene; 245 Scene = scene;
132 246
247 m_interRegionTeleportAttempts =
248 new Stat(
249 "InterRegionTeleportAttempts",
250 "Number of inter-region teleports attempted.",
251 "This does not count attempts which failed due to pre-conditions (e.g. target simulator refused access).\n"
252 + "You can get successfully teleports by subtracting aborts, cancels and teleport failures from this figure.",
253 "",
254 "entitytransfer",
255 Scene.Name,
256 StatType.Push,
257 null,
258 StatVerbosity.Debug);
259
260 m_interRegionTeleportAborts =
261 new Stat(
262 "InterRegionTeleportAborts",
263 "Number of inter-region teleports aborted due to client actions.",
264 "The chief action is simultaneous logout whilst teleporting.",
265 "",
266 "entitytransfer",
267 Scene.Name,
268 StatType.Push,
269 null,
270 StatVerbosity.Debug);
271
272 m_interRegionTeleportCancels =
273 new Stat(
274 "InterRegionTeleportCancels",
275 "Number of inter-region teleports cancelled by the client.",
276 null,
277 "",
278 "entitytransfer",
279 Scene.Name,
280 StatType.Push,
281 null,
282 StatVerbosity.Debug);
283
284 m_interRegionTeleportFailures =
285 new Stat(
286 "InterRegionTeleportFailures",
287 "Number of inter-region teleports that failed due to server/client/network issues.",
288 "This number may not be very helpful in open-grid/hg situations as the network connectivity/quality of destinations is uncontrollable.",
289 "",
290 "entitytransfer",
291 Scene.Name,
292 StatType.Push,
293 null,
294 StatVerbosity.Debug);
295
296 StatsManager.RegisterStat(m_interRegionTeleportAttempts);
297 StatsManager.RegisterStat(m_interRegionTeleportAborts);
298 StatsManager.RegisterStat(m_interRegionTeleportCancels);
299 StatsManager.RegisterStat(m_interRegionTeleportFailures);
300
133 scene.RegisterModuleInterface<IEntityTransferModule>(this); 301 scene.RegisterModuleInterface<IEntityTransferModule>(this);
134 scene.EventManager.OnNewClient += OnNewClient; 302 scene.EventManager.OnNewClient += OnNewClient;
135 } 303 }
136 304
137 protected virtual void OnNewClient(IClientAPI client) 305 protected virtual void OnNewClient(IClientAPI client)
138 { 306 {
139 client.OnTeleportHomeRequest += TeleportHome; 307 client.OnTeleportHomeRequest += TriggerTeleportHome;
140 client.OnTeleportLandmarkRequest += RequestTeleportLandmark; 308 client.OnTeleportLandmarkRequest += RequestTeleportLandmark;
309
310 if (!DisableInterRegionTeleportCancellation)
311 client.OnTeleportCancel += OnClientCancelTeleport;
312
313 client.OnConnectionClosed += OnConnectionClosed;
141 } 314 }
142 315
143 public virtual void Close() {} 316 public virtual void Close() {}
144 317
145 public virtual void RemoveRegion(Scene scene) {} 318 public virtual void RemoveRegion(Scene scene)
319 {
320 if (m_Enabled)
321 {
322 StatsManager.DeregisterStat(m_interRegionTeleportAttempts);
323 StatsManager.DeregisterStat(m_interRegionTeleportAborts);
324 StatsManager.DeregisterStat(m_interRegionTeleportCancels);
325 StatsManager.DeregisterStat(m_interRegionTeleportFailures);
326 }
327 }
146 328
147 public virtual void RegionLoaded(Scene scene) 329 public virtual void RegionLoaded(Scene scene)
148 { 330 {
@@ -150,12 +332,32 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
150 return; 332 return;
151 333
152 m_eqModule = Scene.RequestModuleInterface<IEventQueue>(); 334 m_eqModule = Scene.RequestModuleInterface<IEventQueue>();
335 m_regionCombinerModule = Scene.RequestModuleInterface<IRegionCombinerModule>();
153 } 336 }
154 337
155 #endregion 338 #endregion
156 339
157 #region Agent Teleports 340 #region Agent Teleports
158 341
342 private void OnConnectionClosed(IClientAPI client)
343 {
344 if (client.IsLoggingOut && m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting))
345 {
346 m_log.DebugFormat(
347 "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout",
348 client.Name, Scene.Name);
349 }
350 }
351
352 private void OnClientCancelTeleport(IClientAPI client)
353 {
354 m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Cancelling);
355
356 m_log.DebugFormat(
357 "[ENTITY TRANSFER MODULE]: Received teleport cancel request from {0} in {1}", client.Name, Scene.Name);
358 }
359
360 // Attempt to teleport the ScenePresence to the specified position in the specified region (spec'ed by its handle).
159 public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) 361 public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags)
160 { 362 {
161 if (sp.Scene.Permissions.IsGridGod(sp.UUID)) 363 if (sp.Scene.Permissions.IsGridGod(sp.UUID))
@@ -167,13 +369,26 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
167 if (!sp.Scene.Permissions.CanTeleport(sp.UUID)) 369 if (!sp.Scene.Permissions.CanTeleport(sp.UUID))
168 return; 370 return;
169 371
170 // Reset animations; the viewer does that in teleports.
171 sp.Animator.ResetAnimations();
172
173 string destinationRegionName = "(not found)"; 372 string destinationRegionName = "(not found)";
174 373
374 // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection
375 // of whether the destination region completes the teleport.
376 if (!m_entityTransferStateMachine.SetInTransit(sp.UUID))
377 {
378 m_log.DebugFormat(
379 "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2}@{3} - agent is already in transit.",
380 sp.Name, sp.UUID, position, regionHandle);
381
382 sp.ControllingClient.SendTeleportFailed("Previous teleport process incomplete. Please retry shortly.");
383
384 return;
385 }
386
175 try 387 try
176 { 388 {
389 // Reset animations; the viewer does that in teleports.
390 sp.Animator.ResetAnimations();
391
177 if (regionHandle == sp.Scene.RegionInfo.RegionHandle) 392 if (regionHandle == sp.Scene.RegionInfo.RegionHandle)
178 { 393 {
179 destinationRegionName = sp.Scene.RegionInfo.RegionName; 394 destinationRegionName = sp.Scene.RegionInfo.RegionName;
@@ -182,12 +397,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
182 } 397 }
183 else // Another region possibly in another simulator 398 else // Another region possibly in another simulator
184 { 399 {
185 GridRegion finalDestination; 400 GridRegion finalDestination = null;
186 TeleportAgentToDifferentRegion( 401 try
187 sp, regionHandle, position, lookAt, teleportFlags, out finalDestination); 402 {
188 403 TeleportAgentToDifferentRegion(
189 if (finalDestination != null) 404 sp, regionHandle, position, lookAt, teleportFlags, out finalDestination);
190 destinationRegionName = finalDestination.RegionName; 405 }
406 finally
407 {
408 if (finalDestination != null)
409 destinationRegionName = finalDestination.RegionName;
410 }
191 } 411 }
192 } 412 }
193 catch (Exception e) 413 catch (Exception e)
@@ -197,11 +417,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
197 sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, destinationRegionName, 417 sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, destinationRegionName,
198 e.Message, e.StackTrace); 418 e.Message, e.StackTrace);
199 419
200 // Make sure that we clear the in-transit flag so that future teleport attempts don't always fail.
201 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
202
203 sp.ControllingClient.SendTeleportFailed("Internal error"); 420 sp.ControllingClient.SendTeleportFailed("Internal error");
204 } 421 }
422 finally
423 {
424 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
425 }
205 } 426 }
206 427
207 /// <summary> 428 /// <summary>
@@ -210,30 +431,21 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
210 /// <param name="sp"></param> 431 /// <param name="sp"></param>
211 /// <param name="position"></param> 432 /// <param name="position"></param>
212 /// <param name="lookAt"></param> 433 /// <param name="lookAt"></param>
213 /// <param name="teleportFlags"></param 434 /// <param name="teleportFlags"></param>
214 private void TeleportAgentWithinRegion(ScenePresence sp, Vector3 position, Vector3 lookAt, uint teleportFlags) 435 private void TeleportAgentWithinRegion(ScenePresence sp, Vector3 position, Vector3 lookAt, uint teleportFlags)
215 { 436 {
216 m_log.DebugFormat( 437 m_log.DebugFormat(
217 "[ENTITY TRANSFER MODULE]: Teleport for {0} to {1} within {2}", 438 "[ENTITY TRANSFER MODULE]: Teleport for {0} to {1} within {2}",
218 sp.Name, position, sp.Scene.RegionInfo.RegionName); 439 sp.Name, position, sp.Scene.RegionInfo.RegionName);
219 440
220 if (!m_entityTransferStateMachine.SetInTransit(sp.UUID))
221 {
222 m_log.DebugFormat(
223 "[ENTITY TRANSFER MODULE]: Ignoring within region teleport request of {0} {1} to {2} - agent is already in transit.",
224 sp.Name, sp.UUID, position);
225
226 return;
227 }
228
229 // Teleport within the same region 441 // Teleport within the same region
230 if (IsOutsideRegion(sp.Scene, position) || position.Z < 0) 442 if (!sp.Scene.PositionIsInCurrentRegion(position) || position.Z < 0)
231 { 443 {
232 Vector3 emergencyPos = new Vector3(128, 128, 128); 444 Vector3 emergencyPos = new Vector3(128, 128, 128);
233 445
234 m_log.WarnFormat( 446 m_log.WarnFormat(
235 "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}", 447 "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2} in {3}. Substituting {4}",
236 position, sp.Name, sp.UUID, emergencyPos); 448 position, sp.Name, sp.UUID, Scene.Name, emergencyPos);
237 449
238 position = emergencyPos; 450 position = emergencyPos;
239 } 451 }
@@ -243,10 +455,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
243 float posZLimit = 22; 455 float posZLimit = 22;
244 456
245 // TODO: Check other Scene HeightField 457 // TODO: Check other Scene HeightField
246 if (position.X > 0 && position.X <= (int)Constants.RegionSize && position.Y > 0 && position.Y <= (int)Constants.RegionSize) 458 posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y];
247 {
248 posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y];
249 }
250 459
251 float newPosZ = posZLimit + localAVHeight; 460 float newPosZ = posZLimit + localAVHeight;
252 if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) 461 if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ)))
@@ -254,11 +463,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
254 position.Z = newPosZ; 463 position.Z = newPosZ;
255 } 464 }
256 465
466 if (sp.Flying)
467 teleportFlags |= (uint)TeleportFlags.IsFlying;
468
257 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); 469 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
258 470
259 sp.ControllingClient.SendTeleportStart(teleportFlags); 471 sp.ControllingClient.SendTeleportStart(teleportFlags);
260 472
261 sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); 473 sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags);
474 sp.TeleportFlags = (Constants.TeleportFlags)teleportFlags;
262 sp.Velocity = Vector3.Zero; 475 sp.Velocity = Vector3.Zero;
263 sp.Teleport(position); 476 sp.Teleport(position);
264 477
@@ -270,7 +483,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
270 } 483 }
271 484
272 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); 485 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
273 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
274 } 486 }
275 487
276 /// <summary> 488 /// <summary>
@@ -286,21 +498,23 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
286 ScenePresence sp, ulong regionHandle, Vector3 position, 498 ScenePresence sp, ulong regionHandle, Vector3 position,
287 Vector3 lookAt, uint teleportFlags, out GridRegion finalDestination) 499 Vector3 lookAt, uint teleportFlags, out GridRegion finalDestination)
288 { 500 {
289 uint x = 0, y = 0; 501 // Get destination region taking into account that the address could be an offset
290 Utils.LongToUInts(regionHandle, out x, out y); 502 // region inside a varregion.
291 GridRegion reg = Scene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y); 503 GridRegion reg = GetTeleportDestinationRegion(sp.Scene.GridService, sp.Scene.RegionInfo.ScopeID, regionHandle, ref position);
292 504
293 if (reg != null) 505 if (reg != null)
294 { 506 {
295 finalDestination = GetFinalDestination(reg); 507 string homeURI = Scene.GetAgentHomeURI(sp.ControllingClient.AgentId);
508
509 string message;
510 finalDestination = GetFinalDestination(reg, sp.ControllingClient.AgentId, homeURI, out message);
296 511
297 if (finalDestination == null) 512 if (finalDestination == null)
298 { 513 {
299 m_log.WarnFormat( 514 m_log.WarnFormat( "{0} Final destination is having problems. Unable to teleport {1} {2}: {3}",
300 "[ENTITY TRANSFER MODULE]: Final destination is having problems. Unable to teleport {0} {1}", 515 LogHeader, sp.Name, sp.UUID, message);
301 sp.Name, sp.UUID);
302 516
303 sp.ControllingClient.SendTeleportFailed("Problem at destination"); 517 sp.ControllingClient.SendTeleportFailed(message);
304 return; 518 return;
305 } 519 }
306 520
@@ -321,10 +535,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
321 return; 535 return;
322 } 536 }
323 537
538 if (message != null)
539 sp.ControllingClient.SendAgentAlertMessage(message, true);
540
324 // 541 //
325 // This is it 542 // This is it
326 // 543 //
327 DoTeleport(sp, reg, finalDestination, position, lookAt, teleportFlags); 544 DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags);
328 // 545 //
329 // 546 //
330 // 547 //
@@ -339,12 +556,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
339 556
340 // and set the map-tile to '(Offline)' 557 // and set the map-tile to '(Offline)'
341 uint regX, regY; 558 uint regX, regY;
342 Utils.LongToUInts(regionHandle, out regX, out regY); 559 Util.RegionHandleToRegionLoc(regionHandle, out regX, out regY);
343 560
344 MapBlockData block = new MapBlockData(); 561 MapBlockData block = new MapBlockData();
345 block.X = (ushort)(regX / Constants.RegionSize); 562 block.X = (ushort)regX;
346 block.Y = (ushort)(regY / Constants.RegionSize); 563 block.Y = (ushort)regY;
347 block.Access = 254; // == not there 564 block.Access = (byte)SimAccess.Down;
348 565
349 List<MapBlockData> blocks = new List<MapBlockData>(); 566 List<MapBlockData> blocks = new List<MapBlockData>();
350 blocks.Add(block); 567 blocks.Add(block);
@@ -352,6 +569,31 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
352 } 569 }
353 } 570 }
354 571
572 // The teleport address could be an address in a subregion of a larger varregion.
573 // Find the real base region and adjust the teleport location to account for the
574 // larger region.
575 private GridRegion GetTeleportDestinationRegion(IGridService gridService, UUID scope, ulong regionHandle, ref Vector3 position)
576 {
577 uint x = 0, y = 0;
578 Util.RegionHandleToWorldLoc(regionHandle, out x, out y);
579
580 // Compute the world location we're teleporting to
581 double worldX = (double)x + position.X;
582 double worldY = (double)y + position.Y;
583
584 // Find the region that contains the position
585 GridRegion reg = GetRegionContainingWorldLocation(gridService, scope, worldX, worldY);
586
587 if (reg != null)
588 {
589 // modify the position for the offset into the actual region returned
590 position.X += x - reg.RegionLocX;
591 position.Y += y - reg.RegionLocY;
592 }
593
594 return reg;
595 }
596
355 // Nothing to validate here 597 // Nothing to validate here
356 protected virtual bool ValidateGenericConditions(ScenePresence sp, GridRegion reg, GridRegion finalDestination, uint teleportFlags, out string reason) 598 protected virtual bool ValidateGenericConditions(ScenePresence sp, GridRegion reg, GridRegion finalDestination, uint teleportFlags, out string reason)
357 { 599 {
@@ -359,6 +601,32 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
359 return true; 601 return true;
360 } 602 }
361 603
604 /// <summary>
605 /// Determines whether this instance is within the max transfer distance.
606 /// </summary>
607 /// <param name="sourceRegion"></param>
608 /// <param name="destRegion"></param>
609 /// <returns>
610 /// <c>true</c> if this instance is within max transfer distance; otherwise, <c>false</c>.
611 /// </returns>
612 private bool IsWithinMaxTeleportDistance(RegionInfo sourceRegion, GridRegion destRegion)
613 {
614 if(MaxTransferDistance == 0)
615 return true;
616
617// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Source co-ords are x={0} y={1}", curRegionX, curRegionY);
618//
619// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final dest is x={0} y={1} {2}@{3}",
620// destRegionX, destRegionY, finalDestination.RegionID, finalDestination.ServerURI);
621
622 // Insanely, RegionLoc on RegionInfo is the 256m map co-ord whilst GridRegion.RegionLoc is the raw meters position.
623 return Math.Abs(sourceRegion.RegionLocX - destRegion.RegionCoordX) <= MaxTransferDistance
624 && Math.Abs(sourceRegion.RegionLocY - destRegion.RegionCoordY) <= MaxTransferDistance;
625 }
626
627 /// <summary>
628 /// Wraps DoTeleportInternal() and manages the transfer state.
629 /// </summary>
362 public void DoTeleport( 630 public void DoTeleport(
363 ScenePresence sp, GridRegion reg, GridRegion finalDestination, 631 ScenePresence sp, GridRegion reg, GridRegion finalDestination,
364 Vector3 position, Vector3 lookAt, uint teleportFlags) 632 Vector3 position, Vector3 lookAt, uint teleportFlags)
@@ -370,18 +638,45 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
370 m_log.DebugFormat( 638 m_log.DebugFormat(
371 "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2} ({3}) {4}/{5} - agent is already in transit.", 639 "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2} ({3}) {4}/{5} - agent is already in transit.",
372 sp.Name, sp.UUID, reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position); 640 sp.Name, sp.UUID, reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position);
373 641 sp.ControllingClient.SendTeleportFailed("Agent is already in transit.");
374 return; 642 return;
375 } 643 }
644
645 try
646 {
647 DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags);
648 }
649 catch (Exception e)
650 {
651 m_log.ErrorFormat(
652 "[ENTITY TRANSFER MODULE]: Exception on teleport of {0} from {1}@{2} to {3}@{4}: {5}{6}",
653 sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, finalDestination.RegionName,
654 e.Message, e.StackTrace);
376 655
377 if (reg == null || finalDestination == null) 656 sp.ControllingClient.SendTeleportFailed("Internal error");
657 }
658 finally
378 { 659 {
379 sp.ControllingClient.SendTeleportFailed("Unable to locate destination");
380 m_entityTransferStateMachine.ResetFromTransit(sp.UUID); 660 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
661 }
662 }
381 663
664 /// <summary>
665 /// Teleports the agent to another region.
666 /// This method doesn't manage the transfer state; the caller must do that.
667 /// </summary>
668 private void DoTeleportInternal(
669 ScenePresence sp, GridRegion reg, GridRegion finalDestination,
670 Vector3 position, Vector3 lookAt, uint teleportFlags)
671 {
672 if (reg == null || finalDestination == null)
673 {
674 sp.ControllingClient.SendTeleportFailed("Unable to locate destination");
382 return; 675 return;
383 } 676 }
384 677
678 string homeURI = Scene.GetAgentHomeURI(sp.ControllingClient.AgentId);
679
385 m_log.DebugFormat( 680 m_log.DebugFormat(
386 "[ENTITY TRANSFER MODULE]: Teleporting {0} {1} from {2} to {3} ({4}) {5}/{6}", 681 "[ENTITY TRANSFER MODULE]: Teleporting {0} {1} from {2} to {3} ({4}) {5}/{6}",
387 sp.Name, sp.UUID, sp.Scene.RegionInfo.RegionName, 682 sp.Name, sp.UUID, sp.Scene.RegionInfo.RegionName,
@@ -389,10 +684,21 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
389 684
390 RegionInfo sourceRegion = sp.Scene.RegionInfo; 685 RegionInfo sourceRegion = sp.Scene.RegionInfo;
391 686
392 uint newRegionX = (uint)(reg.RegionHandle >> 40); 687 if (!IsWithinMaxTeleportDistance(sourceRegion, finalDestination))
393 uint newRegionY = (((uint)(reg.RegionHandle)) >> 8); 688 {
394 uint oldRegionX = (uint)(sp.Scene.RegionInfo.RegionHandle >> 40); 689 sp.ControllingClient.SendTeleportFailed(
395 uint oldRegionY = (((uint)(sp.Scene.RegionInfo.RegionHandle)) >> 8); 690 string.Format(
691 "Can't teleport to {0} ({1},{2}) from {3} ({4},{5}), destination is more than {6} regions way",
692 finalDestination.RegionName, finalDestination.RegionCoordX, finalDestination.RegionCoordY,
693 sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY,
694 MaxTransferDistance));
695
696 return;
697 }
698
699 uint newRegionX, newRegionY, oldRegionX, oldRegionY;
700 Util.RegionHandleToRegionLoc(reg.RegionHandle, out newRegionX, out newRegionY);
701 Util.RegionHandleToRegionLoc(sp.Scene.RegionInfo.RegionHandle, out oldRegionX, out oldRegionY);
396 702
397 ulong destinationHandle = finalDestination.RegionHandle; 703 ulong destinationHandle = finalDestination.RegionHandle;
398 704
@@ -400,11 +706,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
400 // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field, 706 // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field,
401 // it's actually doing a lot of work. 707 // it's actually doing a lot of work.
402 IPEndPoint endPoint = finalDestination.ExternalEndPoint; 708 IPEndPoint endPoint = finalDestination.ExternalEndPoint;
403 709 if (endPoint == null || endPoint.Address == null)
404 if (endPoint.Address == null)
405 { 710 {
406 sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); 711 sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down");
407 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
408 712
409 return; 713 return;
410 } 714 }
@@ -412,35 +716,41 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
412 if (!sp.ValidateAttachments()) 716 if (!sp.ValidateAttachments())
413 m_log.DebugFormat( 717 m_log.DebugFormat(
414 "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.", 718 "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.",
415 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName); 719 sp.Name, sp.Scene.Name, finalDestination.RegionName);
416
417// if (!sp.ValidateAttachments())
418// {
419// sp.ControllingClient.SendTeleportFailed("Inconsistent attachment state");
420// return;
421// }
422 720
423 string reason; 721 string reason;
424 string version; 722 EntityTransferContext ctx = new EntityTransferContext();
723
425 if (!Scene.SimulationService.QueryAccess( 724 if (!Scene.SimulationService.QueryAccess(
426 finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out version, out reason)) 725 finalDestination, sp.ControllingClient.AgentId, homeURI, true, position, sp.Scene.GetFormatsOffered(), ctx, out reason))
427 { 726 {
428 sp.ControllingClient.SendTeleportFailed(reason); 727 sp.ControllingClient.SendTeleportFailed(reason);
429 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
430 728
431 m_log.DebugFormat( 729 m_log.DebugFormat(
432 "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because {3}", 730 "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because: {3}",
433 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); 731 sp.Name, sp.Scene.Name, finalDestination.RegionName, reason);
434 732
435 return; 733 return;
436 } 734 }
437 735
438 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version); 736 // Before this point, teleport 'failure' is due to checkable pre-conditions such as whether the target
737 // simulator can be found and is explicitly prepared to allow access. Therefore, we will not count these
738 // as server attempts.
739 m_interRegionTeleportAttempts.Value++;
740
741 m_log.DebugFormat(
742 "[ENTITY TRANSFER MODULE]: {0} transfer protocol version to {1} is {2} / {3}",
743 sp.Scene.Name, finalDestination.RegionName, ctx.OutboundVersion, ctx.InboundVersion);
439 744
440 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from 745 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from
441 // both regions 746 // both regions
442 if (sp.ParentID != (uint)0) 747 if (sp.ParentID != (uint)0)
443 sp.StandUp(); 748 sp.StandUp();
749 else if (sp.Flying)
750 teleportFlags |= (uint)TeleportFlags.IsFlying;
751
752 if (DisableInterRegionTeleportCancellation)
753 teleportFlags |= (uint)TeleportFlags.DisableCancel;
444 754
445 // At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to 755 // At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to
446 // the viewer. However, it might mean that the viewer does not see the black teleport screen (untested). 756 // the viewer. However, it might mean that the viewer does not see the black teleport screen (untested).
@@ -454,13 +764,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
454 // once we reach here... 764 // once we reach here...
455 //avatar.Scene.RemoveCapsHandler(avatar.UUID); 765 //avatar.Scene.RemoveCapsHandler(avatar.UUID);
456 766
457 string capsPath = String.Empty;
458
459 AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); 767 AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
460 AgentCircuitData agentCircuit = sp.ControllingClient.RequestClientInfo(); 768 AgentCircuitData agentCircuit = sp.ControllingClient.RequestClientInfo();
461 agentCircuit.startpos = position; 769 agentCircuit.startpos = position;
462 agentCircuit.child = true; 770 agentCircuit.child = true;
463 agentCircuit.Appearance = sp.Appearance; 771 agentCircuit.Appearance = new AvatarAppearance();
772 agentCircuit.Appearance.PackLegacyWearables = true;
464 if (currentAgentCircuit != null) 773 if (currentAgentCircuit != null)
465 { 774 {
466 agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs; 775 agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs;
@@ -471,23 +780,66 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
471 agentCircuit.Id0 = currentAgentCircuit.Id0; 780 agentCircuit.Id0 = currentAgentCircuit.Id0;
472 } 781 }
473 782
474 if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) 783 // if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY))
784 float dist = (float)Math.Max(sp.Scene.DefaultDrawDistance,
785 (float)Math.Max(sp.Scene.RegionInfo.RegionSizeX, sp.Scene.RegionInfo.RegionSizeY));
786 if (NeedsNewAgent(dist, oldRegionX, newRegionX, oldRegionY, newRegionY))
475 { 787 {
476 // brand new agent, let's create a new caps seed 788 // brand new agent, let's create a new caps seed
477 agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); 789 agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath();
478 } 790 }
479 791
480 // Let's create an agent there if one doesn't exist yet. 792 // We're going to fallback to V1 if the destination gives us anything smaller than 0.2
793 if (ctx.OutboundVersion >= 0.2f)
794 TransferAgent_V2(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, ctx, out reason);
795 else
796 TransferAgent_V1(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, ctx, out reason);
797 }
798
799 private void TransferAgent_V1(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination,
800 IPEndPoint endPoint, uint teleportFlags, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, EntityTransferContext ctx, out string reason)
801 {
802 ulong destinationHandle = finalDestination.RegionHandle;
803 AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
804
805 m_log.DebugFormat(
806 "[ENTITY TRANSFER MODULE]: Using TP V1 for {0} going from {1} to {2}",
807 sp.Name, Scene.Name, finalDestination.RegionName);
808
809 // Let's create an agent there if one doesn't exist yet.
810 // NOTE: logout will always be false for a non-HG teleport.
481 bool logout = false; 811 bool logout = false;
482 if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) 812 if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout))
483 { 813 {
484 sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason)); 814 m_interRegionTeleportFailures.Value++;
485 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
486 815
487 m_log.DebugFormat( 816 m_log.DebugFormat(
488 "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}", 817 "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}",
489 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); 818 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason);
490 819
820 sp.ControllingClient.SendTeleportFailed(reason);
821
822 return;
823 }
824
825 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
826 {
827 m_interRegionTeleportCancels.Value++;
828
829 m_log.DebugFormat(
830 "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request",
831 sp.Name, finalDestination.RegionName, sp.Scene.Name);
832
833 return;
834 }
835 else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
836 {
837 m_interRegionTeleportAborts.Value++;
838
839 m_log.DebugFormat(
840 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.",
841 sp.Name, finalDestination.RegionName, sp.Scene.Name);
842
491 return; 843 return;
492 } 844 }
493 845
@@ -497,9 +849,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
497 // OK, it got this agent. Let's close some child agents 849 // OK, it got this agent. Let's close some child agents
498 sp.CloseChildAgents(newRegionX, newRegionY); 850 sp.CloseChildAgents(newRegionX, newRegionY);
499 851
500 IClientIPEndpoint ipepClient; 852 IClientIPEndpoint ipepClient;
501 if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) 853 string capsPath = String.Empty;
854 float dist = (float)Math.Max(sp.Scene.DefaultDrawDistance,
855 (float)Math.Max(sp.Scene.RegionInfo.RegionSizeX, sp.Scene.RegionInfo.RegionSizeY));
856 if (NeedsNewAgent(dist, oldRegionX, newRegionX, oldRegionY, newRegionY))
502 { 857 {
858 m_log.DebugFormat(
859 "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for incoming agent {3} from {4}",
860 finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name);
861
503 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); 862 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent...");
504 #region IP Translation for NAT 863 #region IP Translation for NAT
505 // Uses ipepClient above 864 // Uses ipepClient above
@@ -512,21 +871,30 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
512 871
513 if (m_eqModule != null) 872 if (m_eqModule != null)
514 { 873 {
515 m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID); 874 // The EnableSimulator message makes the client establish a connection with the destination
516 875 // simulator by sending the initial UseCircuitCode UDP packet to the destination containing the
517 // ES makes the client send a UseCircuitCode message to the destination, 876 // correct circuit code.
518 // which triggers a bunch of things there. 877 m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID,
519 // So let's wait 878 finalDestination.RegionSizeX, finalDestination.RegionSizeY);
879 m_log.DebugFormat("{0} Sent EnableSimulator. regName={1}, size=<{2},{3}>", LogHeader,
880 finalDestination.RegionName, finalDestination.RegionSizeX, finalDestination.RegionSizeY);
881
882 // XXX: Is this wait necessary? We will always end up waiting on UpdateAgent for the destination
883 // simulator to confirm that it has established communication with the viewer.
520 Thread.Sleep(200); 884 Thread.Sleep(200);
521 885
522 // At least on LL 3.3.4 for teleports between different regions on the same simulator this appears 886 // At least on LL 3.3.4 for teleports between different regions on the same simulator this appears
523 // unnecessary - teleport will succeed and SEED caps will be requested without it (though possibly 887 // unnecessary - teleport will succeed and SEED caps will be requested without it (though possibly
524 // only on TeleportFinish). This is untested for region teleport between different simulators 888 // only on TeleportFinish). This is untested for region teleport between different simulators
525 // though this probably also works. 889 // though this probably also works.
526 m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); 890 m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath, finalDestination.RegionHandle,
891 finalDestination.RegionSizeX, finalDestination.RegionSizeY);
527 } 892 }
528 else 893 else
529 { 894 {
895 // XXX: This is a little misleading since we're information the client of its avatar destination,
896 // which may or may not be a neighbour region of the source region. This path is probably little
897 // used anyway (with EQ being the one used). But it is currently being used for test code.
530 sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); 898 sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint);
531 } 899 }
532 } 900 }
@@ -539,31 +907,77 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
539 // Let's send a full update of the agent. This is a synchronous call. 907 // Let's send a full update of the agent. This is a synchronous call.
540 AgentData agent = new AgentData(); 908 AgentData agent = new AgentData();
541 sp.CopyTo(agent); 909 sp.CopyTo(agent);
542 agent.Position = position; 910 if (ctx.OutboundVersion < 0.5f)
911 agent.Appearance.PackLegacyWearables = true;
912 agent.Position = agentCircuit.startpos;
543 SetCallbackURL(agent, sp.Scene.RegionInfo); 913 SetCallbackURL(agent, sp.Scene.RegionInfo);
544 914
545 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent...");
546 915
916 // We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to
917 // establish th econnection to the destination which makes it return true.
918 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
919 {
920 m_interRegionTeleportAborts.Value++;
921
922 m_log.DebugFormat(
923 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} before UpdateAgent",
924 sp.Name, finalDestination.RegionName, sp.Scene.Name);
925
926 return;
927 }
928
929 // A common teleport failure occurs when we can send CreateAgent to the
930 // destination region but the viewer cannot establish the connection (e.g. due to network issues between
931 // the viewer and the destination). In this case, UpdateAgent timesout after 10 seconds, although then
932 // there's a further 10 second wait whilst we attempt to tell the destination to delete the agent in Fail().
547 if (!UpdateAgent(reg, finalDestination, agent, sp)) 933 if (!UpdateAgent(reg, finalDestination, agent, sp))
548 { 934 {
549 // Region doesn't take it 935 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
936 {
937 m_interRegionTeleportAborts.Value++;
938
939 m_log.DebugFormat(
940 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.",
941 sp.Name, finalDestination.RegionName, sp.Scene.Name);
942
943 return;
944 }
945
550 m_log.WarnFormat( 946 m_log.WarnFormat(
551 "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Returning avatar to source region.", 947 "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Keeping avatar in {2}",
552 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); 948 sp.Name, finalDestination.RegionName, sp.Scene.Name);
553 949
554 Fail(sp, finalDestination, logout); 950 Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established.");
555 return; 951 return;
556 } 952 }
557 953
558 sp.ControllingClient.SendTeleportProgress(teleportFlags | (uint)TeleportFlags.DisableCancel, "sending_dest"); 954 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
955 {
956 m_interRegionTeleportCancels.Value++;
957
958 m_log.DebugFormat(
959 "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request",
960 sp.Name, finalDestination.RegionName, sp.Scene.Name);
961
962 CleanupFailedInterRegionTeleport(sp, currentAgentCircuit.SessionID.ToString(), finalDestination);
963
964 return;
965 }
559 966
560 m_log.DebugFormat( 967 m_log.DebugFormat(
561 "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", 968 "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}",
562 capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); 969 capsPath, sp.Scene.RegionInfo.RegionName, sp.Name);
563 970
971 // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator,
972 // where that neighbour simulator could otherwise request a child agent create on the source which then
973 // closes our existing agent which is still signalled as root.
974 sp.IsChildAgent = true;
975
976 // OK, send TPFinish to the client, so that it starts the process of contacting the destination region
564 if (m_eqModule != null) 977 if (m_eqModule != null)
565 { 978 {
566 m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); 979 m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID,
980 finalDestination.RegionSizeX, finalDestination.RegionSizeY);
567 } 981 }
568 else 982 else
569 { 983 {
@@ -571,31 +985,43 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
571 teleportFlags, capsPath); 985 teleportFlags, capsPath);
572 } 986 }
573 987
574 // Let's set this to true tentatively. This does not trigger OnChildAgent
575 sp.IsChildAgent = true;
576
577 // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which 988 // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which
578 // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation 989 // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation
579 // that the client contacted the destination before we close things here. 990 // that the client contacted the destination before we close things here.
580 if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID)) 991 if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID))
581 { 992 {
993 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
994 {
995 m_interRegionTeleportAborts.Value++;
996
997 m_log.DebugFormat(
998 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after WaitForAgentArrivedAtDestination due to previous client close.",
999 sp.Name, finalDestination.RegionName, sp.Scene.Name);
1000
1001 return;
1002 }
1003
582 m_log.WarnFormat( 1004 m_log.WarnFormat(
583 "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", 1005 "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.",
584 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); 1006 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName);
585 1007
586 Fail(sp, finalDestination, logout); 1008 Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Destination region did not signal teleport completion.");
1009
587 return; 1010 return;
588 } 1011 }
589 1012
590 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); 1013 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
591 1014
1015/*
1016 // TODO: This may be 0.6. Check if still needed
592 // For backwards compatibility 1017 // For backwards compatibility
593 if (version == "Unknown" || version == string.Empty) 1018 if (version == 0f)
594 { 1019 {
595 // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it 1020 // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it
596 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Old simulator, sending attachments one by one..."); 1021 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Old simulator, sending attachments one by one...");
597 CrossAttachmentsIntoNewRegion(finalDestination, sp, true); 1022 CrossAttachmentsIntoNewRegion(finalDestination, sp, true);
598 } 1023 }
1024*/
599 1025
600 // May need to logout or other cleanup 1026 // May need to logout or other cleanup
601 AgentHasMovedAway(sp, logout); 1027 AgentHasMovedAway(sp, logout);
@@ -606,12 +1032,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
606 // Now let's make it officially a child agent 1032 // Now let's make it officially a child agent
607 sp.MakeChildAgent(); 1033 sp.MakeChildAgent();
608 1034
609// sp.Scene.CleanDroppedAttachments();
610
611 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone 1035 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
612 1036
613 if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) 1037 if (NeedsClosing(sp.Scene.DefaultDrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
614 { 1038 {
1039 if (!sp.Scene.IncomingPreCloseClient(sp))
1040 return;
1041
615 // We need to delay here because Imprudence viewers, unlike v1 or v3, have a short (<200ms, <500ms) delay before 1042 // We need to delay here because Imprudence viewers, unlike v1 or v3, have a short (<200ms, <500ms) delay before
616 // they regard the new region as the current region after receiving the AgentMovementComplete 1043 // they regard the new region as the current region after receiving the AgentMovementComplete
617 // response. If close is sent before then, it will cause the viewer to quit instead. 1044 // response. If close is sent before then, it will cause the viewer to quit instead.
@@ -620,51 +1047,243 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
620 // an agent cannot teleport back to this region if it has teleported away. 1047 // an agent cannot teleport back to this region if it has teleported away.
621 Thread.Sleep(2000); 1048 Thread.Sleep(2000);
622 1049
623 sp.Scene.IncomingCloseAgent(sp.UUID, false); 1050 sp.Scene.CloseAgent(sp.UUID, false);
624 } 1051 }
625 else 1052 else
626 { 1053 {
627 // now we have a child agent in this region. 1054 // now we have a child agent in this region.
628 sp.Reset(); 1055 sp.Reset();
629 } 1056 }
1057 }
630 1058
631 // Commented pending deletion since this method no longer appears to do anything at all 1059 private void TransferAgent_V2(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination,
632// // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! 1060 IPEndPoint endPoint, uint teleportFlags, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, EntityTransferContext ctx, out string reason)
633// if (sp.Scene.NeedSceneCacheClear(sp.UUID)) 1061 {
634// { 1062 ulong destinationHandle = finalDestination.RegionHandle;
635// m_log.DebugFormat( 1063 AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
636// "[ENTITY TRANSFER MODULE]: User {0} is going to another region, profile cache removed", 1064
637// sp.UUID); 1065 // Let's create an agent there if one doesn't exist yet.
638// } 1066 // NOTE: logout will always be false for a non-HG teleport.
1067 bool logout = false;
1068 if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout))
1069 {
1070 m_interRegionTeleportFailures.Value++;
1071
1072 m_log.DebugFormat(
1073 "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}",
1074 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason);
1075
1076 sp.ControllingClient.SendTeleportFailed(reason);
1077
1078 return;
1079 }
1080
1081 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
1082 {
1083 m_interRegionTeleportCancels.Value++;
1084
1085 m_log.DebugFormat(
1086 "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request",
1087 sp.Name, finalDestination.RegionName, sp.Scene.Name);
1088
1089 return;
1090 }
1091 else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
1092 {
1093 m_interRegionTeleportAborts.Value++;
1094
1095 m_log.DebugFormat(
1096 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.",
1097 sp.Name, finalDestination.RegionName, sp.Scene.Name);
1098
1099 return;
1100 }
1101
1102 // Past this point we have to attempt clean up if the teleport fails, so update transfer state.
1103 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
1104
1105 IClientIPEndpoint ipepClient;
1106 string capsPath = String.Empty;
1107 float dist = (float)Math.Max(sp.Scene.DefaultDrawDistance,
1108 (float)Math.Max(sp.Scene.RegionInfo.RegionSizeX, sp.Scene.RegionInfo.RegionSizeY));
1109 if (NeedsNewAgent(dist, oldRegionX, newRegionX, oldRegionY, newRegionY))
1110 {
1111 m_log.DebugFormat(
1112 "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for agent {3} from {4}",
1113 finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name);
1114
1115 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent...");
1116 #region IP Translation for NAT
1117 // Uses ipepClient above
1118 if (sp.ClientView.TryGet(out ipepClient))
1119 {
1120 endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address);
1121 }
1122 #endregion
1123 capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
1124 }
1125 else
1126 {
1127 agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle);
1128 capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
1129 }
1130
1131 // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator,
1132 // where that neighbour simulator could otherwise request a child agent create on the source which then
1133 // closes our existing agent which is still signalled as root.
1134 //sp.IsChildAgent = true;
1135
1136 // New protocol: send TP Finish directly, without prior ES or EAC. That's what happens in the Linden grid
1137 if (m_eqModule != null)
1138 m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID,
1139 finalDestination.RegionSizeX, finalDestination.RegionSizeY);
1140 else
1141 sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4,
1142 teleportFlags, capsPath);
1143
1144 m_log.DebugFormat(
1145 "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}",
1146 capsPath, sp.Scene.RegionInfo.RegionName, sp.Name);
1147
1148 // Let's send a full update of the agent.
1149 AgentData agent = new AgentData();
1150 sp.CopyTo(agent);
1151 if (ctx.OutboundVersion < 0.5f)
1152 agent.Appearance.PackLegacyWearables = true;
1153 agent.Position = agentCircuit.startpos;
1154 agent.SenderWantsToWaitForRoot = true;
1155 //SetCallbackURL(agent, sp.Scene.RegionInfo);
1156
1157 // Reset the do not close flag. This must be done before the destination opens child connections (here
1158 // triggered by UpdateAgent) to avoid race conditions. However, we also want to reset it as late as possible
1159 // to avoid a situation where an unexpectedly early call to Scene.NewUserConnection() wrongly results
1160 // in no close.
1161 sp.DoNotCloseAfterTeleport = false;
1162
1163 // Send the Update. If this returns true, we know the client has contacted the destination
1164 // via CompleteMovementIntoRegion, so we can let go.
1165 // If it returns false, something went wrong, and we need to abort.
1166 if (!UpdateAgent(reg, finalDestination, agent, sp))
1167 {
1168 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
1169 {
1170 m_interRegionTeleportAborts.Value++;
1171
1172 m_log.DebugFormat(
1173 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.",
1174 sp.Name, finalDestination.RegionName, sp.Scene.Name);
1175
1176 return;
1177 }
1178
1179 m_log.WarnFormat(
1180 "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Keeping avatar in {2}",
1181 sp.Name, finalDestination.RegionName, sp.Scene.Name);
1182
1183 Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established.");
1184 return;
1185 }
1186
1187 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
1188
1189 // Need to signal neighbours whether child agents may need closing irrespective of whether this
1190 // one needed closing. We also need to close child agents as quickly as possible to avoid complicated
1191 // race conditions with rapid agent releporting (e.g. from A1 to a non-neighbour B, back
1192 // to a neighbour A2 then off to a non-neighbour C). Closing child agents any later requires complex
1193 // distributed checks to avoid problems in rapid reteleporting scenarios and where child agents are
1194 // abandoned without proper close by viewer but then re-used by an incoming connection.
1195 sp.CloseChildAgents(newRegionX, newRegionY);
1196
1197 // May need to logout or other cleanup
1198 AgentHasMovedAway(sp, logout);
1199
1200 // Well, this is it. The agent is over there.
1201 KillEntity(sp.Scene, sp.LocalId);
639 1202
640 m_entityTransferStateMachine.ResetFromTransit(sp.UUID); 1203 // Now let's make it officially a child agent
1204 sp.MakeChildAgent();
1205
1206 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
1207 if (NeedsClosing(sp.Scene.DefaultDrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
1208 {
1209 if (!sp.Scene.IncomingPreCloseClient(sp))
1210 return;
1211
1212 // RED ALERT!!!!
1213 // PLEASE DO NOT DECREASE THIS WAIT TIME UNDER ANY CIRCUMSTANCES.
1214 // THE VIEWERS SEEM TO NEED SOME TIME AFTER RECEIVING MoveAgentIntoRegion
1215 // BEFORE THEY SETTLE IN THE NEW REGION.
1216 // DECREASING THE WAIT TIME HERE WILL EITHER RESULT IN A VIEWER CRASH OR
1217 // IN THE AVIE BEING PLACED IN INFINITY FOR A COUPLE OF SECONDS.
1218 Thread.Sleep(15000);
1219
1220 // OK, it got this agent. Let's close everything
1221 // If we shouldn't close the agent due to some other region renewing the connection
1222 // then this will be handled in IncomingCloseAgent under lock conditions
1223 m_log.DebugFormat(
1224 "[ENTITY TRANSFER MODULE]: Closing agent {0} in {1} after teleport", sp.Name, Scene.Name);
1225
1226 sp.Scene.CloseAgent(sp.UUID, false);
1227 }
1228 else
1229 {
1230 // now we have a child agent in this region.
1231 sp.Reset();
1232 }
641 } 1233 }
642 1234
643 protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout) 1235 /// <summary>
1236 /// Clean up an inter-region teleport that did not complete, either because of simulator failure or cancellation.
1237 /// </summary>
1238 /// <remarks>
1239 /// All operations here must be idempotent so that we can call this method at any point in the teleport process
1240 /// up until we send the TeleportFinish event quene event to the viewer.
1241 /// <remarks>
1242 /// <param name='sp'> </param>
1243 /// <param name='finalDestination'></param>
1244 protected virtual void CleanupFailedInterRegionTeleport(ScenePresence sp, string auth_token, GridRegion finalDestination)
644 { 1245 {
645 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); 1246 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
646 1247
647 // Client never contacted destination. Let's restore everything back 1248 if (sp.IsChildAgent) // We had set it to child before attempted TP (V1)
648 sp.ControllingClient.SendTeleportFailed("Problems connecting to destination."); 1249 {
1250 sp.IsChildAgent = false;
1251 ReInstantiateScripts(sp);
649 1252
650 // Fail. Reset it back 1253 EnableChildAgents(sp);
651 sp.IsChildAgent = false; 1254 }
652 ReInstantiateScripts(sp); 1255 // Finally, kill the agent we just created at the destination.
1256 // XXX: Possibly this should be done asynchronously.
1257 Scene.SimulationService.CloseAgent(finalDestination, sp.UUID, auth_token);
1258 }
653 1259
654 EnableChildAgents(sp); 1260 /// <summary>
1261 /// Signal that the inter-region teleport failed and perform cleanup.
1262 /// </summary>
1263 /// <param name='sp'></param>
1264 /// <param name='finalDestination'></param>
1265 /// <param name='logout'></param>
1266 /// <param name='reason'>Human readable reason for teleport failure. Will be sent to client.</param>
1267 protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout, string auth_code, string reason)
1268 {
1269 CleanupFailedInterRegionTeleport(sp, auth_code, finalDestination);
655 1270
656 // Finally, kill the agent we just created at the destination. 1271 m_interRegionTeleportFailures.Value++;
657 Scene.SimulationService.CloseAgent(finalDestination, sp.UUID);
658 1272
659 sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout); 1273 sp.ControllingClient.SendTeleportFailed(
1274 string.Format(
1275 "Problems connecting to destination {0}, reason: {1}", finalDestination.RegionName, reason));
660 1276
661 m_entityTransferStateMachine.ResetFromTransit(sp.UUID); 1277 sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout);
662 } 1278 }
663 1279
664 protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout) 1280 protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout)
665 { 1281 {
1282 GridRegion source = new GridRegion(Scene.RegionInfo);
1283 source.RawServerURI = m_GatekeeperURI;
1284
666 logout = false; 1285 logout = false;
667 bool success = Scene.SimulationService.CreateAgent(finalDestination, agentCircuit, teleportFlags, out reason); 1286 bool success = Scene.SimulationService.CreateAgent(source, finalDestination, agentCircuit, teleportFlags, out reason);
668 1287
669 if (success) 1288 if (success)
670 sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout); 1289 sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout);
@@ -702,14 +1321,32 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
702 scene.SendKillObject(new List<uint> { localID }); 1321 scene.SendKillObject(new List<uint> { localID });
703 } 1322 }
704 1323
705 protected virtual GridRegion GetFinalDestination(GridRegion region) 1324 protected virtual GridRegion GetFinalDestination(GridRegion region, UUID agentID, string agentHomeURI, out string message)
706 { 1325 {
1326 message = null;
707 return region; 1327 return region;
708 } 1328 }
709 1329
1330 // This returns 'true' if the new region already has a child agent for our
1331 // incoming agent. The implication is that, if 'false', we have to create the
1332 // child and then teleport into the region.
710 protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY) 1333 protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY)
711 { 1334 {
712 return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY); 1335 if (m_regionCombinerModule != null && m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID))
1336 {
1337 Vector2 swCorner, neCorner;
1338 GetMegaregionViewRange(out swCorner, out neCorner);
1339
1340 m_log.DebugFormat(
1341 "[ENTITY TRANSFER MODULE]: Megaregion view of {0} is from {1} to {2} with new agent check for {3},{4}",
1342 Scene.Name, swCorner, neCorner, newRegionX, newRegionY);
1343
1344 return !(newRegionX >= swCorner.X && newRegionX <= neCorner.X && newRegionY >= swCorner.Y && newRegionY <= neCorner.Y);
1345 }
1346 else
1347 {
1348 return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY);
1349 }
713 } 1350 }
714 1351
715 protected virtual bool NeedsClosing(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg) 1352 protected virtual bool NeedsClosing(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg)
@@ -717,20 +1354,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
717 return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY); 1354 return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY);
718 } 1355 }
719 1356
720 protected virtual bool IsOutsideRegion(Scene s, Vector3 pos)
721 {
722 if (s.TestBorderCross(pos, Cardinals.N))
723 return true;
724 if (s.TestBorderCross(pos, Cardinals.S))
725 return true;
726 if (s.TestBorderCross(pos, Cardinals.E))
727 return true;
728 if (s.TestBorderCross(pos, Cardinals.W))
729 return true;
730
731 return false;
732 }
733
734 #endregion 1357 #endregion
735 1358
736 #region Landmark Teleport 1359 #region Landmark Teleport
@@ -758,7 +1381,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
758 1381
759 #region Teleport Home 1382 #region Teleport Home
760 1383
761 public virtual void TeleportHome(UUID id, IClientAPI client) 1384 public virtual void TriggerTeleportHome(UUID id, IClientAPI client)
1385 {
1386 TeleportHome(id, client);
1387 }
1388
1389 public virtual bool TeleportHome(UUID id, IClientAPI client)
762 { 1390 {
763 m_log.DebugFormat( 1391 m_log.DebugFormat(
764 "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId); 1392 "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId);
@@ -768,12 +1396,20 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
768 1396
769 if (uinfo != null) 1397 if (uinfo != null)
770 { 1398 {
1399 if (uinfo.HomeRegionID == UUID.Zero)
1400 {
1401 // can't find the Home region: Tell viewer and abort
1402 m_log.ErrorFormat("{0} No grid user info found for {1} {2}. Cannot send home.",
1403 LogHeader, client.Name, client.AgentId);
1404 client.SendTeleportFailed("You don't have a home position set.");
1405 return false;
1406 }
771 GridRegion regionInfo = Scene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID); 1407 GridRegion regionInfo = Scene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID);
772 if (regionInfo == null) 1408 if (regionInfo == null)
773 { 1409 {
774 // can't find the Home region: Tell viewer and abort 1410 // can't find the Home region: Tell viewer and abort
775 client.SendTeleportFailed("Your home region could not be found."); 1411 client.SendTeleportFailed("Your home region could not be found.");
776 return; 1412 return false;
777 } 1413 }
778 1414
779 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Home region of {0} is {1} ({2}-{3})", 1415 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Home region of {0} is {1} ({2}-{3})",
@@ -783,13 +1419,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
783 ((Scene)(client.Scene)).RequestTeleportLocation( 1419 ((Scene)(client.Scene)).RequestTeleportLocation(
784 client, regionInfo.RegionHandle, uinfo.HomePosition, uinfo.HomeLookAt, 1420 client, regionInfo.RegionHandle, uinfo.HomePosition, uinfo.HomeLookAt,
785 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome)); 1421 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome));
1422 return true;
786 } 1423 }
787 else 1424 else
788 { 1425 {
789 m_log.ErrorFormat( 1426 // can't find the Home region: Tell viewer and abort
790 "[ENTITY TRANSFER MODULE]: No grid user information found for {0} {1}. Cannot send home.", 1427 client.SendTeleportFailed("Your home region could not be found.");
791 client.Name, client.AgentId);
792 } 1428 }
1429 return false;
793 } 1430 }
794 1431
795 #endregion 1432 #endregion
@@ -797,230 +1434,112 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
797 1434
798 #region Agent Crossings 1435 #region Agent Crossings
799 1436
800 public bool Cross(ScenePresence agent, bool isFlying) 1437 // Given a position relative to the current region (which has previously been tested to
1438 // see that it is actually outside the current region), find the new region that the
1439 // point is actually in.
1440 // Returns the coordinates and information of the new region or 'null' of it doesn't exist.
1441 public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos,
1442 EntityTransferContext ctx, out Vector3 newpos, out string failureReason)
801 { 1443 {
802 Scene scene = agent.Scene; 1444 newpos = pos;
803 Vector3 pos = agent.AbsolutePosition; 1445 failureReason = string.Empty;
804 Vector3 newpos = new Vector3(pos.X, pos.Y, pos.Z); 1446 string homeURI = scene.GetAgentHomeURI(agentID);
805 uint neighbourx = scene.RegionInfo.RegionLocX;
806 uint neighboury = scene.RegionInfo.RegionLocY;
807 const float boundaryDistance = 1.7f;
808 Vector3 northCross = new Vector3(0, boundaryDistance, 0);
809 Vector3 southCross = new Vector3(0, -1 * boundaryDistance, 0);
810 Vector3 eastCross = new Vector3(boundaryDistance, 0, 0);
811 Vector3 westCross = new Vector3(-1 * boundaryDistance, 0, 0);
812
813 // distance into new region to place avatar
814 const float enterDistance = 0.5f;
815 1447
816 if (scene.TestBorderCross(pos + westCross, Cardinals.W)) 1448// m_log.DebugFormat(
817 { 1449// "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name);
818 if (scene.TestBorderCross(pos + northCross, Cardinals.N))
819 {
820 Border b = scene.GetCrossedBorder(pos + northCross, Cardinals.N);
821 neighboury += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize);
822 }
823 else if (scene.TestBorderCross(pos + southCross, Cardinals.S))
824 {
825 Border b = scene.GetCrossedBorder(pos + southCross, Cardinals.S);
826 if (b.TriggerRegionX == 0 && b.TriggerRegionY == 0)
827 {
828 neighboury--;
829 newpos.Y = Constants.RegionSize - enterDistance;
830 }
831 else
832 {
833 agent.IsInTransit = true;
834
835 neighboury = b.TriggerRegionY;
836 neighbourx = b.TriggerRegionX;
837
838 Vector3 newposition = pos;
839 newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize;
840 newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize;
841 agent.ControllingClient.SendAgentAlertMessage(
842 String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false);
843 InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene);
844 return true;
845 }
846 }
847
848 Border ba = scene.GetCrossedBorder(pos + westCross, Cardinals.W);
849 if (ba.TriggerRegionX == 0 && ba.TriggerRegionY == 0)
850 {
851 neighbourx--;
852 newpos.X = Constants.RegionSize - enterDistance;
853 }
854 else
855 {
856 agent.IsInTransit = true;
857 1450
858 neighboury = ba.TriggerRegionY; 1451 // Compute world location of the object's position
859 neighbourx = ba.TriggerRegionX; 1452 double presenceWorldX = (double)scene.RegionInfo.WorldLocX + pos.X;
1453 double presenceWorldY = (double)scene.RegionInfo.WorldLocY + pos.Y;
860 1454
861 Vector3 newposition = pos; 1455 // Call the grid service to lookup the region containing the new position.
862 newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize; 1456 GridRegion neighbourRegion = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID,
863 newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize; 1457 presenceWorldX, presenceWorldY,
864 agent.ControllingClient.SendAgentAlertMessage( 1458 Math.Max(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY));
865 String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false);
866 InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene);
867 1459
868 return true; 1460 if (neighbourRegion != null)
869 }
870
871 }
872 else if (scene.TestBorderCross(pos + eastCross, Cardinals.E))
873 { 1461 {
874 Border b = scene.GetCrossedBorder(pos + eastCross, Cardinals.E); 1462 // Compute the entity's position relative to the new region
875 neighbourx += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize); 1463 newpos = new Vector3((float)(presenceWorldX - (double)neighbourRegion.RegionLocX),
876 newpos.X = enterDistance; 1464 (float)(presenceWorldY - (double)neighbourRegion.RegionLocY),
1465 pos.Z);
877 1466
878 if (scene.TestBorderCross(pos + southCross, Cardinals.S)) 1467 if (m_bannedRegionCache.IfBanned(neighbourRegion.RegionHandle, agentID))
879 {
880 Border ba = scene.GetCrossedBorder(pos + southCross, Cardinals.S);
881 if (ba.TriggerRegionX == 0 && ba.TriggerRegionY == 0)
882 {
883 neighboury--;
884 newpos.Y = Constants.RegionSize - enterDistance;
885 }
886 else
887 {
888 agent.IsInTransit = true;
889
890 neighboury = ba.TriggerRegionY;
891 neighbourx = ba.TriggerRegionX;
892 Vector3 newposition = pos;
893 newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize;
894 newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize;
895 agent.ControllingClient.SendAgentAlertMessage(
896 String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false);
897 InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene);
898 return true;
899 }
900 }
901 else if (scene.TestBorderCross(pos + northCross, Cardinals.N))
902 { 1468 {
903 Border c = scene.GetCrossedBorder(pos + northCross, Cardinals.N); 1469 failureReason = "Cannot region cross into banned parcel";
904 neighboury += (uint)(int)(c.BorderLine.Z / (int)Constants.RegionSize); 1470 neighbourRegion = null;
905 newpos.Y = enterDistance;
906 }
907 }
908 else if (scene.TestBorderCross(pos + southCross, Cardinals.S))
909 {
910 Border b = scene.GetCrossedBorder(pos + southCross, Cardinals.S);
911 if (b.TriggerRegionX == 0 && b.TriggerRegionY == 0)
912 {
913 neighboury--;
914 newpos.Y = Constants.RegionSize - enterDistance;
915 } 1471 }
916 else 1472 else
917 { 1473 {
918 agent.IsInTransit = true; 1474 // If not banned, make sure this agent is not in the list.
919 1475 m_bannedRegionCache.Remove(neighbourRegion.RegionHandle, agentID);
920 neighboury = b.TriggerRegionY;
921 neighbourx = b.TriggerRegionX;
922 Vector3 newposition = pos;
923 newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize;
924 newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize;
925 agent.ControllingClient.SendAgentAlertMessage(
926 String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false);
927 InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene);
928 return true;
929 } 1476 }
930 }
931 else if (scene.TestBorderCross(pos + northCross, Cardinals.N))
932 {
933 Border b = scene.GetCrossedBorder(pos + northCross, Cardinals.N);
934 neighboury += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize);
935 newpos.Y = enterDistance;
936 }
937
938 /*
939
940 if (pos.X < boundaryDistance) //West
941 {
942 neighbourx--;
943 newpos.X = Constants.RegionSize - enterDistance;
944 }
945 else if (pos.X > Constants.RegionSize - boundaryDistance) // East
946 {
947 neighbourx++;
948 newpos.X = enterDistance;
949 }
950 1477
951 if (pos.Y < boundaryDistance) // South 1478 // Check to see if we have access to the target region.
952 { 1479 if (neighbourRegion != null
953 neighboury--; 1480 && !scene.SimulationService.QueryAccess(neighbourRegion, agentID, homeURI, false, newpos, scene.GetFormatsOffered(), ctx, out failureReason))
954 newpos.Y = Constants.RegionSize - enterDistance;
955 }
956 else if (pos.Y > Constants.RegionSize - boundaryDistance) // North
957 {
958 neighboury++;
959 newpos.Y = enterDistance;
960 }
961 */
962
963 ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize));
964
965 int x = (int)(neighbourx * Constants.RegionSize), y = (int)(neighboury * Constants.RegionSize);
966
967 ExpiringCache<ulong, DateTime> r;
968 DateTime banUntil;
969
970 if (m_bannedRegions.TryGetValue(agent.ControllingClient.AgentId, out r))
971 {
972 if (r.TryGetValue(neighbourHandle, out banUntil))
973 { 1481 {
974 if (DateTime.Now < banUntil) 1482 // remember banned
975 return false; 1483 m_bannedRegionCache.Add(neighbourRegion.RegionHandle, agentID);
976 r.Remove(neighbourHandle); 1484 neighbourRegion = null;
977 } 1485 }
978 } 1486 }
979 else 1487 else
980 { 1488 {
981 r = null; 1489 // The destination region just doesn't exist
1490 failureReason = "Cannot cross into non-existent region";
982 } 1491 }
983 1492
984 GridRegion neighbourRegion = scene.GridService.GetRegionByPosition(scene.RegionInfo.ScopeID, (int)x, (int)y); 1493 if (neighbourRegion == null)
1494 m_log.DebugFormat("{0} GetDestination: region not found. Old region name={1} at <{2},{3}> of size <{4},{5}>. Old pos={6}",
1495 LogHeader, scene.RegionInfo.RegionName,
1496 scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY,
1497 scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY,
1498 pos);
1499 else
1500 m_log.DebugFormat("{0} GetDestination: new region={1} at <{2},{3}> of size <{4},{5}>, newpos=<{6},{7}>",
1501 LogHeader, neighbourRegion.RegionName,
1502 neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY,
1503 newpos.X, newpos.Y);
985 1504
986 string reason; 1505 return neighbourRegion;
987 string version; 1506 }
988 if (!scene.SimulationService.QueryAccess(neighbourRegion, agent.ControllingClient.AgentId, newpos, out version, out reason))
989 {
990 agent.ControllingClient.SendAlertMessage("Cannot region cross into banned parcel");
991 if (r == null)
992 {
993 r = new ExpiringCache<ulong, DateTime>();
994 r.Add(neighbourHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15));
995 1507
996 m_bannedRegions.Add(agent.ControllingClient.AgentId, r, TimeSpan.FromSeconds(45)); 1508 public bool Cross(ScenePresence agent, bool isFlying)
997 } 1509 {
998 else 1510 Vector3 newpos;
999 { 1511 EntityTransferContext ctx = new EntityTransferContext();
1000 r.Add(neighbourHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15)); 1512 string failureReason;
1001 } 1513
1514 GridRegion neighbourRegion = GetDestination(agent.Scene, agent.UUID, agent.AbsolutePosition,
1515 ctx, out newpos, out failureReason);
1516 if (neighbourRegion == null)
1517 {
1518 agent.ControllingClient.SendAlertMessage(failureReason);
1002 return false; 1519 return false;
1003 } 1520 }
1004 1521
1005 agent.IsInTransit = true; 1522 agent.IsInTransit = true;
1006 1523
1007 CrossAgentToNewRegionDelegate d = CrossAgentToNewRegionAsync; 1524 CrossAgentToNewRegionDelegate d = CrossAgentToNewRegionAsync;
1008 d.BeginInvoke(agent, newpos, neighbourx, neighboury, neighbourRegion, isFlying, version, CrossAgentToNewRegionCompleted, d); 1525 d.BeginInvoke(agent, newpos, neighbourRegion, isFlying, ctx, CrossAgentToNewRegionCompleted, d);
1526
1527 Scene.EventManager.TriggerCrossAgentToNewRegion(agent, isFlying, neighbourRegion);
1009 1528
1010 return true; 1529 return true;
1011 } 1530 }
1012 1531
1013 1532
1014 public delegate void InformClientToInitateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY, 1533 public delegate void InformClientToInitiateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY,
1015 Vector3 position, 1534 Vector3 position,
1016 Scene initiatingScene); 1535 Scene initiatingScene);
1017 1536
1018 private void InformClientToInitateTeleportToLocation(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene) 1537 private void InformClientToInitiateTeleportToLocation(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene)
1019 { 1538 {
1020 1539
1021 // This assumes that we know what our neighbours are. 1540 // This assumes that we know what our neighbours are.
1022 1541
1023 InformClientToInitateTeleportToLocationDelegate d = InformClientToInitiateTeleportToLocationAsync; 1542 InformClientToInitiateTeleportToLocationDelegate d = InformClientToInitiateTeleportToLocationAsync;
1024 d.BeginInvoke(agent, regionX, regionY, position, initiatingScene, 1543 d.BeginInvoke(agent, regionX, regionY, position, initiatingScene,
1025 InformClientToInitiateTeleportToLocationCompleted, 1544 InformClientToInitiateTeleportToLocationCompleted,
1026 d); 1545 d);
@@ -1030,16 +1549,24 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1030 Scene initiatingScene) 1549 Scene initiatingScene)
1031 { 1550 {
1032 Thread.Sleep(10000); 1551 Thread.Sleep(10000);
1033 1552
1553 m_log.DebugFormat(
1554 "[ENTITY TRANSFER MODULE]: Auto-reteleporting {0} to correct megaregion location {1},{2},{3} from {4}",
1555 agent.Name, regionX, regionY, position, initiatingScene.Name);
1556
1557 agent.Scene.RequestTeleportLocation(
1558 agent.ControllingClient,
1559 Util.RegionLocToHandle(regionX, regionY),
1560 position,
1561 agent.Lookat,
1562 (uint)Constants.TeleportFlags.ViaLocation);
1563
1564 /*
1034 IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>(); 1565 IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>();
1035 if (im != null) 1566 if (im != null)
1036 { 1567 {
1037 UUID gotoLocation = Util.BuildFakeParcelID( 1568 UUID gotoLocation = Util.BuildFakeParcelID(
1038 Util.UIntsToLong( 1569 Util.RegionLocToHandle(regionX, regionY),
1039 (regionX *
1040 (uint)Constants.RegionSize),
1041 (regionY *
1042 (uint)Constants.RegionSize)),
1043 (uint)(int)position.X, 1570 (uint)(int)position.X,
1044 (uint)(int)position.Y, 1571 (uint)(int)position.Y,
1045 (uint)(int)position.Z); 1572 (uint)(int)position.Z);
@@ -1065,53 +1592,73 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1065 }); 1592 });
1066 1593
1067 } 1594 }
1595 */
1068 } 1596 }
1069 1597
1070 private void InformClientToInitiateTeleportToLocationCompleted(IAsyncResult iar) 1598 private void InformClientToInitiateTeleportToLocationCompleted(IAsyncResult iar)
1071 { 1599 {
1072 InformClientToInitateTeleportToLocationDelegate icon = 1600 InformClientToInitiateTeleportToLocationDelegate icon =
1073 (InformClientToInitateTeleportToLocationDelegate)iar.AsyncState; 1601 (InformClientToInitiateTeleportToLocationDelegate)iar.AsyncState;
1074 icon.EndInvoke(iar); 1602 icon.EndInvoke(iar);
1075 } 1603 }
1076 1604
1077 public delegate ScenePresence CrossAgentToNewRegionDelegate(ScenePresence agent, Vector3 pos, uint neighbourx, uint neighboury, GridRegion neighbourRegion, bool isFlying, string version); 1605 public bool CrossAgentToNewRegionPrep(ScenePresence agent, GridRegion neighbourRegion)
1606 {
1607 if (neighbourRegion == null)
1608 return false;
1609
1610 m_entityTransferStateMachine.SetInTransit(agent.UUID);
1611
1612 agent.RemoveFromPhysicalScene();
1613
1614 return true;
1615 }
1078 1616
1079 /// <summary> 1617 /// <summary>
1080 /// This Closes child agents on neighbouring regions 1618 /// This Closes child agents on neighbouring regions
1081 /// Calls an asynchronous method to do so.. so it doesn't lag the sim. 1619 /// Calls an asynchronous method to do so.. so it doesn't lag the sim.
1082 /// </summary> 1620 /// </summary>
1083 protected ScenePresence CrossAgentToNewRegionAsync( 1621 public ScenePresence CrossAgentToNewRegionAsync(
1084 ScenePresence agent, Vector3 pos, uint neighbourx, uint neighboury, GridRegion neighbourRegion, 1622 ScenePresence agent, Vector3 pos, GridRegion neighbourRegion,
1085 bool isFlying, string version) 1623 bool isFlying, EntityTransferContext ctx)
1086 { 1624 {
1087 if (neighbourRegion == null)
1088 return agent;
1089
1090 try 1625 try
1091 { 1626 {
1092 m_entityTransferStateMachine.SetInTransit(agent.UUID); 1627 m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: new region={1} at <{2},{3}>. newpos={4}",
1628 LogHeader, neighbourRegion.RegionName, neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, pos);
1093 1629
1094 ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize)); 1630 if (!CrossAgentToNewRegionPrep(agent, neighbourRegion))
1095 1631 {
1096 m_log.DebugFormat( 1632 m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: prep failed. Resetting transfer state", LogHeader);
1097 "[ENTITY TRANSFER MODULE]: Crossing agent {0} {1} to {2}-{3} running version {4}", 1633 m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1098 agent.Firstname, agent.Lastname, neighbourx, neighboury, version); 1634 }
1099
1100 Scene m_scene = agent.Scene;
1101 1635
1102 if (!agent.ValidateAttachments()) 1636 if (!CrossAgentIntoNewRegionMain(agent, pos, neighbourRegion, isFlying, ctx))
1103 m_log.DebugFormat( 1637 {
1104 "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for region crossing of {0} from {1} to {2}. Continuing.", 1638 m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: cross main failed. Resetting transfer state", LogHeader);
1105 agent.Name, agent.Scene.RegionInfo.RegionName, neighbourRegion.RegionName); 1639 m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1640 }
1106 1641
1107 pos = pos + agent.Velocity; 1642 CrossAgentToNewRegionPost(agent, pos, neighbourRegion, isFlying, ctx);
1108 Vector3 vel2 = new Vector3(agent.Velocity.X, agent.Velocity.Y, 0); 1643 }
1644 catch (Exception e)
1645 {
1646 m_log.Error(string.Format("{0}: CrossAgentToNewRegionAsync: failed with exception ", LogHeader), e);
1647 }
1109 1648
1110 agent.RemoveFromPhysicalScene(); 1649 return agent;
1650 }
1111 1651
1652 public bool CrossAgentIntoNewRegionMain(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, bool isFlying, EntityTransferContext ctx)
1653 {
1654 try
1655 {
1112 AgentData cAgent = new AgentData(); 1656 AgentData cAgent = new AgentData();
1113 agent.CopyTo(cAgent); 1657 agent.CopyTo(cAgent);
1658 if (ctx.OutboundVersion < 0.5f)
1659 cAgent.Appearance.PackLegacyWearables = true;
1114 cAgent.Position = pos; 1660 cAgent.Position = pos;
1661
1115 if (isFlying) 1662 if (isFlying)
1116 cAgent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY; 1663 cAgent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY;
1117 1664
@@ -1121,102 +1668,121 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1121 // Beyond this point, extra cleanup is needed beyond removing transit state 1668 // Beyond this point, extra cleanup is needed beyond removing transit state
1122 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.Transferring); 1669 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.Transferring);
1123 1670
1124 if (!m_scene.SimulationService.UpdateAgent(neighbourRegion, cAgent)) 1671 if (!agent.Scene.SimulationService.UpdateAgent(neighbourRegion, cAgent))
1125 { 1672 {
1126 // region doesn't take it 1673 // region doesn't take it
1127 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); 1674 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp);
1128 1675
1676 m_log.WarnFormat(
1677 "[ENTITY TRANSFER MODULE]: Region {0} would not accept update for agent {1} on cross attempt. Returning to original region.",
1678 neighbourRegion.RegionName, agent.Name);
1679
1129 ReInstantiateScripts(agent); 1680 ReInstantiateScripts(agent);
1130 agent.AddToPhysicalScene(isFlying); 1681 agent.AddToPhysicalScene(isFlying);
1131 m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1132 1682
1133 return agent; 1683 return false;
1134 } 1684 }
1135 1685
1136 //AgentCircuitData circuitdata = m_controllingClient.RequestClientInfo(); 1686 }
1137 agent.ControllingClient.RequestClientInfo(); 1687 catch (Exception e)
1688 {
1689 m_log.ErrorFormat(
1690 "[ENTITY TRANSFER MODULE]: Problem crossing user {0} to new region {1} from {2}. Exception {3}{4}",
1691 agent.Name, neighbourRegion.RegionName, agent.Scene.RegionInfo.RegionName, e.Message, e.StackTrace);
1692
1693 // TODO: Might be worth attempting other restoration here such as reinstantiation of scripts, etc.
1694 return false;
1695 }
1138 1696
1139 //m_log.Debug("BEFORE CROSS"); 1697 return true;
1140 //Scene.DumpChildrenSeeds(UUID); 1698 }
1141 //DumpKnownRegions();
1142 string agentcaps;
1143 if (!agent.KnownRegions.TryGetValue(neighbourRegion.RegionHandle, out agentcaps))
1144 {
1145 m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: No ENTITY TRANSFER MODULE information for region handle {0}, exiting CrossToNewRegion.",
1146 neighbourRegion.RegionHandle);
1147 return agent;
1148 }
1149 // No turning back
1150 agent.IsChildAgent = true;
1151 1699
1152 string capsPath = neighbourRegion.ServerURI + CapsUtil.GetCapsSeedPath(agentcaps); 1700 public void CrossAgentToNewRegionPost(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion,
1701 bool isFlying, EntityTransferContext ctx)
1702 {
1703 agent.ControllingClient.RequestClientInfo();
1153 1704
1154 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID); 1705 string agentcaps;
1706 if (!agent.KnownRegions.TryGetValue(neighbourRegion.RegionHandle, out agentcaps))
1707 {
1708 m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: No ENTITY TRANSFER MODULE information for region handle {0}, exiting CrossToNewRegion.",
1709 neighbourRegion.RegionHandle);
1710 return;
1711 }
1155 1712
1156 if (m_eqModule != null) 1713 // No turning back
1157 { 1714 agent.IsChildAgent = true;
1158 m_eqModule.CrossRegion( 1715
1159 neighbourHandle, pos, vel2 /* agent.Velocity */, neighbourRegion.ExternalEndPoint, 1716 string capsPath = neighbourRegion.ServerURI + CapsUtil.GetCapsSeedPath(agentcaps);
1160 capsPath, agent.UUID, agent.ControllingClient.SessionId);
1161 }
1162 else
1163 {
1164 agent.ControllingClient.CrossRegion(neighbourHandle, pos, agent.Velocity, neighbourRegion.ExternalEndPoint,
1165 capsPath);
1166 }
1167 1717
1168 // SUCCESS! 1718 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID);
1169 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.ReceivedAtDestination);
1170 1719
1171 // Unlike a teleport, here we do not wait for the destination region to confirm the receipt. 1720 Vector3 vel2 = new Vector3(agent.Velocity.X, agent.Velocity.Y, 0);
1172 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp);
1173 1721
1174 agent.MakeChildAgent(); 1722 if (m_eqModule != null)
1723 {
1724 m_eqModule.CrossRegion(
1725 neighbourRegion.RegionHandle, pos + agent.Velocity, vel2 /* agent.Velocity */,
1726 neighbourRegion.ExternalEndPoint,
1727 capsPath, agent.UUID, agent.ControllingClient.SessionId,
1728 neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY);
1729 }
1730 else
1731 {
1732 m_log.ErrorFormat("{0} Using old CrossRegion packet. Varregion will not work!!", LogHeader);
1733 agent.ControllingClient.CrossRegion(neighbourRegion.RegionHandle, pos + agent.Velocity, agent.Velocity, neighbourRegion.ExternalEndPoint,
1734 capsPath);
1735 }
1175 1736
1176 // FIXME: Possibly this should occur lower down after other commands to close other agents, 1737 // SUCCESS!
1177 // but not sure yet what the side effects would be. 1738 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.ReceivedAtDestination);
1178 m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1179 1739
1180 // now we have a child agent in this region. Request all interesting data about other (root) agents 1740 // Unlike a teleport, here we do not wait for the destination region to confirm the receipt.
1181 agent.SendOtherAgentsAvatarDataToMe(); 1741 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp);
1182 agent.SendOtherAgentsAppearanceToMe();
1183 1742
1184 // Backwards compatibility. Best effort 1743 agent.MakeChildAgent();
1185 if (version == "Unknown" || version == string.Empty)
1186 {
1187 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: neighbor with old version, passing attachments one by one...");
1188 Thread.Sleep(3000); // wait a little now that we're not waiting for the callback
1189 CrossAttachmentsIntoNewRegion(neighbourRegion, agent, true);
1190 }
1191 1744
1192 // Next, let's close the child agent connections that are too far away. 1745 // FIXME: Possibly this should occur lower down after other commands to close other agents,
1193 agent.CloseChildAgents(neighbourx, neighboury); 1746 // but not sure yet what the side effects would be.
1747 m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1194 1748
1195 AgentHasMovedAway(agent, false); 1749 // now we have a child agent in this region. Request all interesting data about other (root) agents
1750 agent.SendOtherAgentsAvatarDataToClient();
1751 agent.SendOtherAgentsAppearanceToClient();
1196 1752
1197// // the user may change their profile information in other region, 1753 // TODO: Check since what version this wasn't needed anymore. May be as old as 0.6
1198// // so the userinfo in UserProfileCache is not reliable any more, delete it 1754/*
1199// // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! 1755 // Backwards compatibility. Best effort
1200// if (agent.Scene.NeedSceneCacheClear(agent.UUID)) 1756 if (version == 0f)
1201// {
1202// m_log.DebugFormat(
1203// "[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID);
1204// }
1205
1206 //m_log.Debug("AFTER CROSS");
1207 //Scene.DumpChildrenSeeds(UUID);
1208 //DumpKnownRegions();
1209 }
1210 catch (Exception e)
1211 { 1757 {
1212 m_log.ErrorFormat( 1758 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: neighbor with old version, passing attachments one by one...");
1213 "[ENTITY TRANSFER MODULE]: Problem crossing user {0} to new region {1} from {2}. Exception {3}{4}", 1759 Thread.Sleep(3000); // wait a little now that we're not waiting for the callback
1214 agent.Name, neighbourRegion.RegionName, agent.Scene.RegionInfo.RegionName, e.Message, e.StackTrace); 1760 CrossAttachmentsIntoNewRegion(neighbourRegion, agent, true);
1215
1216 // TODO: Might be worth attempting other restoration here such as reinstantiation of scripts, etc.
1217 } 1761 }
1762*/
1763 // Next, let's close the child agent connections that are too far away.
1764 uint neighbourx;
1765 uint neighboury;
1766 Util.RegionHandleToRegionLoc(neighbourRegion.RegionHandle, out neighbourx, out neighboury);
1218 1767
1219 return agent; 1768 agent.CloseChildAgents(neighbourx, neighboury);
1769
1770 AgentHasMovedAway(agent, false);
1771
1772 // the user may change their profile information in other region,
1773 // so the userinfo in UserProfileCache is not reliable any more, delete it
1774 // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
1775// if (agent.Scene.NeedSceneCacheClear(agent.UUID))
1776// {
1777// m_log.DebugFormat(
1778// "[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID);
1779// }
1780
1781 //m_log.Debug("AFTER CROSS");
1782 //Scene.DumpChildrenSeeds(UUID);
1783 //DumpKnownRegions();
1784
1785 return;
1220 } 1786 }
1221 1787
1222 private void CrossAgentToNewRegionCompleted(IAsyncResult iar) 1788 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
@@ -1256,7 +1822,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1256 agent.InventoryFolder = UUID.Zero; 1822 agent.InventoryFolder = UUID.Zero;
1257 agent.startpos = new Vector3(128, 128, 70); 1823 agent.startpos = new Vector3(128, 128, 70);
1258 agent.child = true; 1824 agent.child = true;
1259 agent.Appearance = sp.Appearance; 1825 agent.Appearance = new AvatarAppearance();
1826 agent.Appearance.PackLegacyWearables = true;
1260 agent.CapsPath = CapsUtil.GetRandomCapsObjectPath(); 1827 agent.CapsPath = CapsUtil.GetRandomCapsObjectPath();
1261 1828
1262 agent.ChildrenCapSeeds = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID)); 1829 agent.ChildrenCapSeeds = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID));
@@ -1270,7 +1837,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1270 //foreach (ulong h in agent.ChildrenCapSeeds.Keys) 1837 //foreach (ulong h in agent.ChildrenCapSeeds.Keys)
1271 // m_log.DebugFormat("[XXX] --> {0}", h); 1838 // m_log.DebugFormat("[XXX] --> {0}", h);
1272 //m_log.DebugFormat("[XXX] Adding {0}", region.RegionHandle); 1839 //m_log.DebugFormat("[XXX] Adding {0}", region.RegionHandle);
1273 agent.ChildrenCapSeeds.Add(region.RegionHandle, agent.CapsPath); 1840 if (agent.ChildrenCapSeeds.ContainsKey(region.RegionHandle))
1841 {
1842 m_log.WarnFormat(
1843 "[ENTITY TRANSFER]: Overwriting caps seed {0} with {1} for region {2} (handle {3}) for {4} in {5}",
1844 agent.ChildrenCapSeeds[region.RegionHandle], agent.CapsPath,
1845 region.RegionName, region.RegionHandle, sp.Name, Scene.Name);
1846 }
1847
1848 agent.ChildrenCapSeeds[region.RegionHandle] = agent.CapsPath;
1274 1849
1275 if (sp.Scene.CapsModule != null) 1850 if (sp.Scene.CapsModule != null)
1276 { 1851 {
@@ -1287,10 +1862,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1287 agent.Id0 = currentAgentCircuit.Id0; 1862 agent.Id0 = currentAgentCircuit.Id0;
1288 } 1863 }
1289 1864
1290 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync; 1865 IPEndPoint external = region.ExternalEndPoint;
1291 d.BeginInvoke(sp, agent, region, region.ExternalEndPoint, true, 1866 if (external != null)
1867 {
1868 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
1869 d.BeginInvoke(sp, agent, region, external, true,
1292 InformClientOfNeighbourCompleted, 1870 InformClientOfNeighbourCompleted,
1293 d); 1871 d);
1872 }
1294 } 1873 }
1295 #endregion 1874 #endregion
1296 1875
@@ -1310,7 +1889,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1310 1889
1311 if (m_regionInfo != null) 1890 if (m_regionInfo != null)
1312 { 1891 {
1313 neighbours = RequestNeighbours(sp, m_regionInfo.RegionLocX, m_regionInfo.RegionLocY); 1892 neighbours = GetNeighbours(sp, m_regionInfo.RegionLocX, m_regionInfo.RegionLocY);
1314 } 1893 }
1315 else 1894 else
1316 { 1895 {
@@ -1336,10 +1915,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1336 List<ulong> newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles); 1915 List<ulong> newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles);
1337 List<ulong> oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles); 1916 List<ulong> oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles);
1338 1917
1339 //Dump("Current Neighbors", neighbourHandles); 1918// Dump("Current Neighbors", neighbourHandles);
1340 //Dump("Previous Neighbours", previousRegionNeighbourHandles); 1919// Dump("Previous Neighbours", previousRegionNeighbourHandles);
1341 //Dump("New Neighbours", newRegions); 1920// Dump("New Neighbours", newRegions);
1342 //Dump("Old Neighbours", oldRegions); 1921// Dump("Old Neighbours", oldRegions);
1343 1922
1344 /// Update the scene presence's known regions here on this region 1923 /// Update the scene presence's known regions here on this region
1345 sp.DropOldNeighbours(oldRegions); 1924 sp.DropOldNeighbours(oldRegions);
@@ -1347,8 +1926,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1347 /// Collect as many seeds as possible 1926 /// Collect as many seeds as possible
1348 Dictionary<ulong, string> seeds; 1927 Dictionary<ulong, string> seeds;
1349 if (sp.Scene.CapsModule != null) 1928 if (sp.Scene.CapsModule != null)
1350 seeds 1929 seeds = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID));
1351 = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID));
1352 else 1930 else
1353 seeds = new Dictionary<ulong, string>(); 1931 seeds = new Dictionary<ulong, string>();
1354 1932
@@ -1368,7 +1946,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1368 agent.InventoryFolder = UUID.Zero; 1946 agent.InventoryFolder = UUID.Zero;
1369 agent.startpos = sp.AbsolutePosition + CalculateOffset(sp, neighbour); 1947 agent.startpos = sp.AbsolutePosition + CalculateOffset(sp, neighbour);
1370 agent.child = true; 1948 agent.child = true;
1371 agent.Appearance = sp.Appearance; 1949 agent.Appearance = new AvatarAppearance();
1950 agent.Appearance.PackLegacyWearables = true;
1372 if (currentAgentCircuit != null) 1951 if (currentAgentCircuit != null)
1373 { 1952 {
1374 agent.ServiceURLs = currentAgentCircuit.ServiceURLs; 1953 agent.ServiceURLs = currentAgentCircuit.ServiceURLs;
@@ -1418,6 +1997,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1418 newAgent = true; 1997 newAgent = true;
1419 else 1998 else
1420 newAgent = false; 1999 newAgent = false;
2000// continue;
1421 2001
1422 if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle) 2002 if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle)
1423 { 2003 {
@@ -1464,15 +2044,195 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1464 } 2044 }
1465 } 2045 }
1466 2046
2047 // Computes the difference between two region bases.
2048 // Returns a vector of world coordinates (meters) from base of first region to the second.
2049 // The first region is the home region of the passed scene presence.
1467 Vector3 CalculateOffset(ScenePresence sp, GridRegion neighbour) 2050 Vector3 CalculateOffset(ScenePresence sp, GridRegion neighbour)
1468 { 2051 {
1469 int rRegionX = (int)sp.Scene.RegionInfo.RegionLocX; 2052 /*
1470 int rRegionY = (int)sp.Scene.RegionInfo.RegionLocY; 2053 int rRegionX = (int)sp.Scene.RegionInfo.LegacyRegionLocX;
2054 int rRegionY = (int)sp.Scene.RegionInfo.LegacyRegionLocY;
1471 int tRegionX = neighbour.RegionLocX / (int)Constants.RegionSize; 2055 int tRegionX = neighbour.RegionLocX / (int)Constants.RegionSize;
1472 int tRegionY = neighbour.RegionLocY / (int)Constants.RegionSize; 2056 int tRegionY = neighbour.RegionLocY / (int)Constants.RegionSize;
1473 int shiftx = (rRegionX - tRegionX) * (int)Constants.RegionSize; 2057 int shiftx = (rRegionX - tRegionX) * (int)Constants.RegionSize;
1474 int shifty = (rRegionY - tRegionY) * (int)Constants.RegionSize; 2058 int shifty = (rRegionY - tRegionY) * (int)Constants.RegionSize;
1475 return new Vector3(shiftx, shifty, 0f); 2059 return new Vector3(shiftx, shifty, 0f);
2060 */
2061 return new Vector3( sp.Scene.RegionInfo.WorldLocX - neighbour.RegionLocX,
2062 sp.Scene.RegionInfo.WorldLocY - neighbour.RegionLocY,
2063 0f);
2064 }
2065
2066 public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py)
2067 {
2068 // Since we don't know how big the regions could be, we have to search a very large area
2069 // to find possible regions.
2070 return GetRegionContainingWorldLocation(pGridService, pScopeID, px, py, Constants.MaximumRegionSize);
2071 }
2072
2073 #region NotFoundLocationCache class
2074 // A collection of not found locations to make future lookups 'not found' lookups quick.
2075 // A simple expiring cache that keeps not found locations for some number of seconds.
2076 // A 'not found' location is presumed to be anywhere in the minimum sized region that
2077 // contains that point. A conservitive estimate.
2078 private class NotFoundLocationCache
2079 {
2080 private struct NotFoundLocation
2081 {
2082 public double minX, maxX, minY, maxY;
2083 public DateTime expireTime;
2084 }
2085 private List<NotFoundLocation> m_notFoundLocations = new List<NotFoundLocation>();
2086 public NotFoundLocationCache()
2087 {
2088 }
2089 // Add an area to the list of 'not found' places. The area is the snapped region
2090 // area around the added point.
2091 public void Add(double pX, double pY)
2092 {
2093 lock (m_notFoundLocations)
2094 {
2095 if (!LockedContains(pX, pY))
2096 {
2097 NotFoundLocation nfl = new NotFoundLocation();
2098 // A not found location is not found for at least a whole region sized area
2099 nfl.minX = pX - (pX % (double)Constants.RegionSize);
2100 nfl.minY = pY - (pY % (double)Constants.RegionSize);
2101 nfl.maxX = nfl.minX + (double)Constants.RegionSize;
2102 nfl.maxY = nfl.minY + (double)Constants.RegionSize;
2103 nfl.expireTime = DateTime.Now + TimeSpan.FromSeconds(30);
2104 m_notFoundLocations.Add(nfl);
2105 }
2106 }
2107
2108 }
2109 // Test to see of this point is in any of the 'not found' areas.
2110 // Return 'true' if the point is found inside the 'not found' areas.
2111 public bool Contains(double pX, double pY)
2112 {
2113 bool ret = false;
2114 lock (m_notFoundLocations)
2115 ret = LockedContains(pX, pY);
2116 return ret;
2117 }
2118 private bool LockedContains(double pX, double pY)
2119 {
2120 bool ret = false;
2121 this.DoExpiration();
2122 foreach (NotFoundLocation nfl in m_notFoundLocations)
2123 {
2124 if (pX >= nfl.minX && pX < nfl.maxX && pY >= nfl.minY && pY < nfl.maxY)
2125 {
2126 ret = true;
2127 break;
2128 }
2129 }
2130 return ret;
2131 }
2132 private void DoExpiration()
2133 {
2134 List<NotFoundLocation> m_toRemove = null;
2135 DateTime now = DateTime.Now;
2136 foreach (NotFoundLocation nfl in m_notFoundLocations)
2137 {
2138 if (nfl.expireTime < now)
2139 {
2140 if (m_toRemove == null)
2141 m_toRemove = new List<NotFoundLocation>();
2142 m_toRemove.Add(nfl);
2143 }
2144 }
2145 if (m_toRemove != null)
2146 {
2147 foreach (NotFoundLocation nfl in m_toRemove)
2148 m_notFoundLocations.Remove(nfl);
2149 m_toRemove.Clear();
2150 }
2151 }
2152 }
2153 #endregion // NotFoundLocationCache class
2154 private NotFoundLocationCache m_notFoundLocationCache = new NotFoundLocationCache();
2155
2156 // Given a world position (fractional meter coordinate), get the GridRegion info for
2157 // the region containing that point.
2158 // Someday this should be a method on GridService.
2159 // 'pSizeHint' is the size of the source region but since the destination point can be anywhere
2160 // the size of the target region is unknown thus the search area might have to be very large.
2161 // Return 'null' if no such region exists.
2162 public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID,
2163 double px, double py, uint pSizeHint)
2164 {
2165 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: query, loc=<{1},{2}>", LogHeader, px, py);
2166 GridRegion ret = null;
2167 const double fudge = 2.0;
2168
2169 // One problem with this routine is negative results. That is, this can be called lots of times
2170 // for regions that don't exist. m_notFoundLocationCache remembers 'not found' results so they
2171 // will be quick 'not found's next time.
2172 // NotFoundLocationCache is an expiring cache so it will eventually forget about 'not found' and
2173 // thus re-ask the GridService about the location.
2174 if (m_notFoundLocationCache.Contains(px, py))
2175 {
2176 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found via cache. loc=<{1},{2}>", LogHeader, px, py);
2177 return null;
2178 }
2179
2180 // As an optimization, since most regions will be legacy sized regions (256x256), first try to get
2181 // the region at the appropriate legacy region location.
2182 uint possibleX = (uint)Math.Floor(px);
2183 possibleX -= possibleX % Constants.RegionSize;
2184 uint possibleY = (uint)Math.Floor(py);
2185 possibleY -= possibleY % Constants.RegionSize;
2186 ret = pGridService.GetRegionByPosition(pScopeID, (int)possibleX, (int)possibleY);
2187 if (ret != null)
2188 {
2189 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Found region using legacy size. rloc=<{1},{2}>. Rname={3}",
2190 LogHeader, possibleX, possibleY, ret.RegionName);
2191 }
2192
2193 if (ret == null)
2194 {
2195 // If the simple lookup failed, search the larger area for a region that contains this point
2196 double range = (double)pSizeHint + fudge;
2197 while (ret == null && range <= (Constants.MaximumRegionSize + Constants.RegionSize))
2198 {
2199 // Get from the grid service a list of regions that might contain this point.
2200 // The region origin will be in the zero direction so only subtract the range.
2201 List<GridRegion> possibleRegions = pGridService.GetRegionRange(pScopeID,
2202 (int)(px - range), (int)(px),
2203 (int)(py - range), (int)(py));
2204 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegions cnt={1}, range={2}",
2205 LogHeader, possibleRegions.Count, range);
2206 if (possibleRegions != null && possibleRegions.Count > 0)
2207 {
2208 // If we found some regions, check to see if the point is within
2209 foreach (GridRegion gr in possibleRegions)
2210 {
2211 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegion nm={1}, regionLoc=<{2},{3}>, regionSize=<{4},{5}>",
2212 LogHeader, gr.RegionName, gr.RegionLocX, gr.RegionLocY, gr.RegionSizeX, gr.RegionSizeY);
2213 if (px >= (double)gr.RegionLocX && px < (double)(gr.RegionLocX + gr.RegionSizeX)
2214 && py >= (double)gr.RegionLocY && py < (double)(gr.RegionLocY + gr.RegionSizeY))
2215 {
2216 // Found a region that contains the point
2217 ret = gr;
2218 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: found. RegionName={1}", LogHeader, ret.RegionName);
2219 break;
2220 }
2221 }
2222 }
2223 // Larger search area for next time around if not found
2224 range *= 2;
2225 }
2226 }
2227
2228 if (ret == null)
2229 {
2230 // remember this location was not found so we can quickly not find it next time
2231 m_notFoundLocationCache.Add(px, py);
2232 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found. Remembering loc=<{1},{2}>", LogHeader, px, py);
2233 }
2234
2235 return ret;
1476 } 2236 }
1477 2237
1478 private void InformClientOfNeighbourCompleted(IAsyncResult iar) 2238 private void InformClientOfNeighbourCompleted(IAsyncResult iar)
@@ -1500,7 +2260,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1500 Thread.Sleep(500); 2260 Thread.Sleep(500);
1501 2261
1502 Scene scene = sp.Scene; 2262 Scene scene = sp.Scene;
1503 2263
1504 m_log.DebugFormat( 2264 m_log.DebugFormat(
1505 "[ENTITY TRANSFER MODULE]: Informing {0} {1} about neighbour {2} {3} at ({4},{5})", 2265 "[ENTITY TRANSFER MODULE]: Informing {0} {1} about neighbour {2} {3} at ({4},{5})",
1506 sp.Name, sp.UUID, reg.RegionName, endPoint, reg.RegionCoordX, reg.RegionCoordY); 2266 sp.Name, sp.UUID, reg.RegionName, endPoint, reg.RegionCoordX, reg.RegionCoordY);
@@ -1509,7 +2269,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1509 2269
1510 string reason = String.Empty; 2270 string reason = String.Empty;
1511 2271
1512 bool regionAccepted = scene.SimulationService.CreateAgent(reg, a, (uint)TeleportFlags.Default, out reason); 2272 bool regionAccepted = scene.SimulationService.CreateAgent(null, reg, a, (uint)TeleportFlags.Default, out reason);
1513 2273
1514 if (regionAccepted && newAgent) 2274 if (regionAccepted && newAgent)
1515 { 2275 {
@@ -1523,12 +2283,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1523 } 2283 }
1524 #endregion 2284 #endregion
1525 2285
1526 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: {0} is sending {1} EnableSimulator for neighbour region {2} @ {3} " + 2286 m_log.DebugFormat("{0} {1} is sending {2} EnableSimulator for neighbour region {3}(loc=<{4},{5}>,siz=<{6},{7}>) " +
1527 "and EstablishAgentCommunication with seed cap {4}", 2287 "and EstablishAgentCommunication with seed cap {8}", LogHeader,
1528 scene.RegionInfo.RegionName, sp.Name, reg.RegionName, reg.RegionHandle, capsPath); 2288 scene.RegionInfo.RegionName, sp.Name,
2289 reg.RegionName, reg.RegionLocX, reg.RegionLocY, reg.RegionSizeX, reg.RegionSizeY , capsPath);
1529 2290
1530 m_eqModule.EnableSimulator(reg.RegionHandle, endPoint, sp.UUID); 2291 m_eqModule.EnableSimulator(reg.RegionHandle, endPoint, sp.UUID, reg.RegionSizeX, reg.RegionSizeY);
1531 m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); 2292 m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath, reg.RegionHandle, reg.RegionSizeX, reg.RegionSizeY);
1532 } 2293 }
1533 else 2294 else
1534 { 2295 {
@@ -1546,68 +2307,86 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1546 } 2307 }
1547 2308
1548 /// <summary> 2309 /// <summary>
1549 /// Return the list of regions that are considered to be neighbours to the given scene. 2310 /// Gets the range considered in view of this megaregion (assuming this is a megaregion).
2311 /// </summary>
2312 /// <remarks>Expressed in 256m units</remarks>
2313 /// <param name='swCorner'></param>
2314 /// <param name='neCorner'></param>
2315 private void GetMegaregionViewRange(out Vector2 swCorner, out Vector2 neCorner)
2316 {
2317 Vector2 extent = Vector2.Zero;
2318
2319 if (m_regionCombinerModule != null)
2320 {
2321 Vector2 megaRegionSize = m_regionCombinerModule.GetSizeOfMegaregion(Scene.RegionInfo.RegionID);
2322 extent.X = (float)Util.WorldToRegionLoc((uint)megaRegionSize.X);
2323 extent.Y = (float)Util.WorldToRegionLoc((uint)megaRegionSize.Y);
2324 }
2325
2326 swCorner.X = Scene.RegionInfo.RegionLocX - 1;
2327 swCorner.Y = Scene.RegionInfo.RegionLocY - 1;
2328 neCorner.X = Scene.RegionInfo.RegionLocX + extent.X;
2329 neCorner.Y = Scene.RegionInfo.RegionLocY + extent.Y;
2330 }
2331
2332 /// <summary>
2333 /// Return the list of online regions that are considered to be neighbours to the given scene.
1550 /// </summary> 2334 /// </summary>
1551 /// <param name="pScene"></param> 2335 /// <param name="avatar"></param>
1552 /// <param name="pRegionLocX"></param> 2336 /// <param name="pRegionLocX"></param>
1553 /// <param name="pRegionLocY"></param> 2337 /// <param name="pRegionLocY"></param>
1554 /// <returns></returns> 2338 /// <returns></returns>
1555 protected List<GridRegion> RequestNeighbours(ScenePresence avatar, uint pRegionLocX, uint pRegionLocY) 2339 protected List<GridRegion> GetNeighbours(ScenePresence avatar, uint pRegionLocX, uint pRegionLocY)
1556 { 2340 {
1557 Scene pScene = avatar.Scene; 2341 Scene pScene = avatar.Scene;
1558 RegionInfo m_regionInfo = pScene.RegionInfo; 2342 RegionInfo m_regionInfo = pScene.RegionInfo;
1559 2343 List<GridRegion> neighbours;
1560 Border[] northBorders = pScene.NorthBorders.ToArray();
1561 Border[] southBorders = pScene.SouthBorders.ToArray();
1562 Border[] eastBorders = pScene.EastBorders.ToArray();
1563 Border[] westBorders = pScene.WestBorders.ToArray();
1564 2344
1565 // Leaving this as a "megaregions" computation vs "non-megaregions" computation; it isn't 2345 // Leaving this as a "megaregions" computation vs "non-megaregions" computation; it isn't
1566 // clear what should be done with a "far view" given that megaregions already extended the 2346 // clear what should be done with a "far view" given that megaregions already extended the
1567 // view to include everything in the megaregion 2347 // view to include everything in the megaregion
1568 if (northBorders.Length <= 1 && southBorders.Length <= 1 && eastBorders.Length <= 1 && westBorders.Length <= 1) 2348 if (m_regionCombinerModule == null || !m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID))
1569 { 2349 {
1570 int dd = avatar.DrawDistance < Constants.RegionSize ? (int)Constants.RegionSize : (int)avatar.DrawDistance; 2350 // The area to check is as big as the current region.
1571 2351 // We presume all adjacent regions are the same size as this region.
1572 int startX = (int)pRegionLocX * (int)Constants.RegionSize - dd + (int)(Constants.RegionSize/2); 2352 uint dd = Math.Max((uint)avatar.Scene.DefaultDrawDistance,
1573 int startY = (int)pRegionLocY * (int)Constants.RegionSize - dd + (int)(Constants.RegionSize/2); 2353 Math.Max(Scene.RegionInfo.RegionSizeX, Scene.RegionInfo.RegionSizeY));
1574 2354
1575 int endX = (int)pRegionLocX * (int)Constants.RegionSize + dd + (int)(Constants.RegionSize/2); 2355 uint startX = Util.RegionToWorldLoc(pRegionLocX) - dd + Constants.RegionSize/2;
1576 int endY = (int)pRegionLocY * (int)Constants.RegionSize + dd + (int)(Constants.RegionSize/2); 2356 uint startY = Util.RegionToWorldLoc(pRegionLocY) - dd + Constants.RegionSize/2;
1577 2357
1578 List<GridRegion> neighbours = 2358 uint endX = Util.RegionToWorldLoc(pRegionLocX) + dd + Constants.RegionSize/2;
1579 avatar.Scene.GridService.GetRegionRange(m_regionInfo.ScopeID, startX, endX, startY, endY); 2359 uint endY = Util.RegionToWorldLoc(pRegionLocY) + dd + Constants.RegionSize/2;
1580 2360
1581 neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; }); 2361 neighbours
1582 return neighbours; 2362 = avatar.Scene.GridService.GetRegionRange(
2363 m_regionInfo.ScopeID, (int)startX, (int)endX, (int)startY, (int)endY);
1583 } 2364 }
1584 else 2365 else
1585 { 2366 {
1586 Vector2 extent = Vector2.Zero; 2367 Vector2 swCorner, neCorner;
1587 for (int i = 0; i < eastBorders.Length; i++) 2368 GetMegaregionViewRange(out swCorner, out neCorner);
1588 {
1589 extent.X = (eastBorders[i].BorderLine.Z > extent.X) ? eastBorders[i].BorderLine.Z : extent.X;
1590 }
1591 for (int i = 0; i < northBorders.Length; i++)
1592 {
1593 extent.Y = (northBorders[i].BorderLine.Z > extent.Y) ? northBorders[i].BorderLine.Z : extent.Y;
1594 }
1595 2369
1596 // Loss of fraction on purpose 2370 neighbours
1597 extent.X = ((int)extent.X / (int)Constants.RegionSize) + 1; 2371 = pScene.GridService.GetRegionRange(
1598 extent.Y = ((int)extent.Y / (int)Constants.RegionSize) + 1; 2372 m_regionInfo.ScopeID,
1599 2373 (int)Util.RegionToWorldLoc((uint)swCorner.X), (int)Util.RegionToWorldLoc((uint)neCorner.X),
1600 int startX = (int)(pRegionLocX - 1) * (int)Constants.RegionSize; 2374 (int)Util.RegionToWorldLoc((uint)swCorner.Y), (int)Util.RegionToWorldLoc((uint)neCorner.Y));
1601 int startY = (int)(pRegionLocY - 1) * (int)Constants.RegionSize; 2375 }
1602 2376
1603 int endX = ((int)pRegionLocX + (int)extent.X) * (int)Constants.RegionSize; 2377// neighbours.ForEach(
1604 int endY = ((int)pRegionLocY + (int)extent.Y) * (int)Constants.RegionSize; 2378// n =>
2379// m_log.DebugFormat(
2380// "[ENTITY TRANSFER MODULE]: Region flags for {0} as seen by {1} are {2}",
2381// n.RegionName, Scene.Name, n.RegionFlags != null ? n.RegionFlags.ToString() : "not present"));
1605 2382
1606 List<GridRegion> neighbours = pScene.GridService.GetRegionRange(m_regionInfo.ScopeID, startX, endX, startY, endY); 2383 // The r.RegionFlags == null check only needs to be made for simulators before 2015-01-14 (pre 0.8.1).
1607 neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; }); 2384 neighbours.RemoveAll(
2385 r =>
2386 r.RegionID == m_regionInfo.RegionID
2387 || (r.RegionFlags != null && (r.RegionFlags & OpenSim.Framework.RegionFlags.RegionOnline) == 0));
1608 2388
1609 return neighbours; 2389 return neighbours;
1610 }
1611 } 2390 }
1612 2391
1613 private List<ulong> NewNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours) 2392 private List<ulong> NewNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours)
@@ -1665,10 +2444,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1665 /// Move the given scene object into a new region depending on which region its absolute position has moved 2444 /// Move the given scene object into a new region depending on which region its absolute position has moved
1666 /// into. 2445 /// into.
1667 /// 2446 ///
1668 /// This method locates the new region handle and offsets the prim position for the new region 2447 /// Using the objects new world location, ask the grid service for a the new region and adjust the prim
2448 /// position to be relative to the new region.
1669 /// </summary> 2449 /// </summary>
1670 /// <param name="attemptedPosition">the attempted out of region position of the scene object</param>
1671 /// <param name="grp">the scene object that we're crossing</param> 2450 /// <param name="grp">the scene object that we're crossing</param>
2451 /// <param name="attemptedPosition">the attempted out of region position of the scene object. This position is
2452 /// relative to the region the object currently is in.</param>
2453 /// <param name="silent">if 'true', the deletion of the client from the region is not broadcast to the clients</param>
1672 public void Cross(SceneObjectGroup grp, Vector3 attemptedPosition, bool silent) 2454 public void Cross(SceneObjectGroup grp, Vector3 attemptedPosition, bool silent)
1673 { 2455 {
1674 if (grp == null) 2456 if (grp == null)
@@ -1694,204 +2476,49 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1694 return; 2476 return;
1695 } 2477 }
1696 2478
1697 int thisx = (int)scene.RegionInfo.RegionLocX; 2479 // Remember the old group position in case the region lookup fails so position can be restored.
1698 int thisy = (int)scene.RegionInfo.RegionLocY; 2480 Vector3 oldGroupPosition = grp.RootPart.GroupPosition;
1699 Vector3 EastCross = new Vector3(0.1f, 0, 0);
1700 Vector3 WestCross = new Vector3(-0.1f, 0, 0);
1701 Vector3 NorthCross = new Vector3(0, 0.1f, 0);
1702 Vector3 SouthCross = new Vector3(0, -0.1f, 0);
1703
1704
1705 // use this if no borders were crossed!
1706 ulong newRegionHandle
1707 = Util.UIntsToLong((uint)((thisx) * Constants.RegionSize),
1708 (uint)((thisy) * Constants.RegionSize));
1709
1710 Vector3 pos = attemptedPosition;
1711
1712 int changeX = 1;
1713 int changeY = 1;
1714
1715 if (scene.TestBorderCross(attemptedPosition + WestCross, Cardinals.W))
1716 {
1717 if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
1718 {
1719
1720 Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W);
1721
1722 if (crossedBorderx.BorderLine.Z > 0)
1723 {
1724 pos.X = ((pos.X + crossedBorderx.BorderLine.Z));
1725 changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize);
1726 }
1727 else
1728 pos.X = ((pos.X + Constants.RegionSize));
1729
1730 Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
1731 //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
1732
1733 if (crossedBordery.BorderLine.Z > 0)
1734 {
1735 pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
1736 changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
1737 }
1738 else
1739 pos.Y = ((pos.Y + Constants.RegionSize));
1740
1741
1742
1743 newRegionHandle
1744 = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize),
1745 (uint)((thisy - changeY) * Constants.RegionSize));
1746 // x - 1
1747 // y - 1
1748 }
1749 else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N))
1750 {
1751 Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W);
1752
1753 if (crossedBorderx.BorderLine.Z > 0)
1754 {
1755 pos.X = ((pos.X + crossedBorderx.BorderLine.Z));
1756 changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize);
1757 }
1758 else
1759 pos.X = ((pos.X + Constants.RegionSize));
1760
1761
1762 Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
1763 //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
1764
1765 if (crossedBordery.BorderLine.Z > 0)
1766 {
1767 pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
1768 changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
1769 }
1770 else
1771 pos.Y = ((pos.Y + Constants.RegionSize));
1772
1773 newRegionHandle
1774 = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize),
1775 (uint)((thisy + changeY) * Constants.RegionSize));
1776 // x - 1
1777 // y + 1
1778 }
1779 else
1780 {
1781 Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W);
1782
1783 if (crossedBorderx.BorderLine.Z > 0)
1784 {
1785 pos.X = ((pos.X + crossedBorderx.BorderLine.Z));
1786 changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize);
1787 }
1788 else
1789 pos.X = ((pos.X + Constants.RegionSize));
1790
1791 newRegionHandle
1792 = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize),
1793 (uint)(thisy * Constants.RegionSize));
1794 // x - 1
1795 }
1796 }
1797 else if (scene.TestBorderCross(attemptedPosition + EastCross, Cardinals.E))
1798 {
1799 if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
1800 {
1801
1802 pos.X = ((pos.X - Constants.RegionSize));
1803 Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
1804 //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
1805
1806 if (crossedBordery.BorderLine.Z > 0)
1807 {
1808 pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
1809 changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
1810 }
1811 else
1812 pos.Y = ((pos.Y + Constants.RegionSize));
1813
1814 2481
1815 newRegionHandle 2482 // Compute the absolute position of the object.
1816 = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize), 2483 double objectWorldLocX = (double)scene.RegionInfo.WorldLocX + attemptedPosition.X;
1817 (uint)((thisy - changeY) * Constants.RegionSize)); 2484 double objectWorldLocY = (double)scene.RegionInfo.WorldLocY + attemptedPosition.Y;
1818 // x + 1
1819 // y - 1
1820 }
1821 else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N))
1822 {
1823 pos.X = ((pos.X - Constants.RegionSize));
1824 pos.Y = ((pos.Y - Constants.RegionSize));
1825 newRegionHandle
1826 = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize),
1827 (uint)((thisy + changeY) * Constants.RegionSize));
1828 // x + 1
1829 // y + 1
1830 }
1831 else
1832 {
1833 pos.X = ((pos.X - Constants.RegionSize));
1834 newRegionHandle
1835 = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize),
1836 (uint)(thisy * Constants.RegionSize));
1837 // x + 1
1838 }
1839 }
1840 else if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
1841 {
1842 Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
1843 //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
1844 2485
1845 if (crossedBordery.BorderLine.Z > 0) 2486 // Ask the grid service for the region that contains the passed address
1846 { 2487 GridRegion destination = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID,
1847 pos.Y = ((pos.Y + crossedBordery.BorderLine.Z)); 2488 objectWorldLocX, objectWorldLocY);
1848 changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
1849 }
1850 else
1851 pos.Y = ((pos.Y + Constants.RegionSize));
1852 2489
1853 newRegionHandle 2490 Vector3 pos = Vector3.Zero;
1854 = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy - changeY) * Constants.RegionSize)); 2491 if (destination != null)
1855 // y - 1
1856 }
1857 else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N))
1858 { 2492 {
1859 2493 // Adjust the object's relative position from the old region (attemptedPosition)
1860 pos.Y = ((pos.Y - Constants.RegionSize)); 2494 // to be relative to the new region (pos).
1861 newRegionHandle 2495 pos = new Vector3( (float)(objectWorldLocX - (double)destination.RegionLocX),
1862 = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy + changeY) * Constants.RegionSize)); 2496 (float)(objectWorldLocY - (double)destination.RegionLocY),
1863 // y + 1 2497 attemptedPosition.Z);
1864 } 2498 }
1865 2499
1866 // Offset the positions for the new region across the border
1867 Vector3 oldGroupPosition = grp.RootPart.GroupPosition;
1868
1869 // If we fail to cross the border, then reset the position of the scene object on that border.
1870 uint x = 0, y = 0;
1871 Utils.LongToUInts(newRegionHandle, out x, out y);
1872 GridRegion destination = scene.GridService.GetRegionByPosition(scene.RegionInfo.ScopeID, (int)x, (int)y);
1873
1874 if (destination == null || !CrossPrimGroupIntoNewRegion(destination, pos, grp, silent)) 2500 if (destination == null || !CrossPrimGroupIntoNewRegion(destination, pos, grp, silent))
1875 { 2501 {
1876 m_log.InfoFormat("[ENTITY TRANSFER MODULE] cross region transfer failed for object {0}",grp.UUID); 2502 m_log.InfoFormat("[ENTITY TRANSFER MODULE] cross region transfer failed for object {0}", grp.UUID);
1877 2503
1878 // We are going to move the object back to the old position so long as the old position 2504 // We are going to move the object back to the old position so long as the old position
1879 // is in the region 2505 // is in the region
1880 oldGroupPosition.X = Util.Clamp<float>(oldGroupPosition.X,1.0f,(float)Constants.RegionSize-1); 2506 oldGroupPosition.X = Util.Clamp<float>(oldGroupPosition.X, 1.0f, (float)(scene.RegionInfo.RegionSizeX - 1));
1881 oldGroupPosition.Y = Util.Clamp<float>(oldGroupPosition.Y,1.0f,(float)Constants.RegionSize-1); 2507 oldGroupPosition.Y = Util.Clamp<float>(oldGroupPosition.Y, 1.0f, (float)(scene.RegionInfo.RegionSizeY - 1));
1882 oldGroupPosition.Z = Util.Clamp<float>(oldGroupPosition.Z,1.0f,4096.0f); 2508 oldGroupPosition.Z = Util.Clamp<float>(oldGroupPosition.Z, 1.0f, Constants.RegionHeight);
1883 2509
1884 grp.RootPart.GroupPosition = oldGroupPosition; 2510 grp.AbsolutePosition = oldGroupPosition;
2511 grp.Velocity = Vector3.Zero;
2512 if (grp.RootPart.PhysActor != null)
2513 grp.RootPart.PhysActor.CrossingFailure();
1885 2514
1886 // Need to turn off the physics flags, otherwise the object will continue to attempt to 2515 if (grp.RootPart.KeyframeMotion != null)
1887 // move out of the region creating an infinite loop of failed attempts to cross 2516 grp.RootPart.KeyframeMotion.CrossingFailure();
1888 grp.UpdatePrimFlags(grp.RootPart.LocalId,false,grp.IsTemporary,grp.IsPhantom,false);
1889 2517
1890 grp.ScheduleGroupForFullUpdate(); 2518 grp.ScheduleGroupForFullUpdate();
1891 } 2519 }
1892 } 2520 }
1893 2521
1894
1895 /// <summary> 2522 /// <summary>
1896 /// Move the given scene object into a new region 2523 /// Move the given scene object into a new region
1897 /// </summary> 2524 /// </summary>
@@ -1942,17 +2569,30 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1942 grp, e); 2569 grp, e);
1943 } 2570 }
1944 } 2571 }
2572/*
2573 * done on caller ( not in attachments crossing for now)
1945 else 2574 else
1946 { 2575 {
2576
1947 if (!grp.IsDeleted) 2577 if (!grp.IsDeleted)
1948 { 2578 {
1949 PhysicsActor pa = grp.RootPart.PhysActor; 2579 PhysicsActor pa = grp.RootPart.PhysActor;
1950 if (pa != null) 2580 if (pa != null)
2581 {
1951 pa.CrossingFailure(); 2582 pa.CrossingFailure();
2583 if (grp.RootPart.KeyframeMotion != null)
2584 {
2585 // moved to KeyframeMotion.CrossingFailure
2586// grp.RootPart.Velocity = Vector3.Zero;
2587 grp.RootPart.KeyframeMotion.CrossingFailure();
2588// grp.SendGroupRootTerseUpdate();
2589 }
2590 }
1952 } 2591 }
1953 2592
1954 m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: Prim crossing failed for {0}", grp); 2593 m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: Prim crossing failed for {0}", grp);
1955 } 2594 }
2595 */
1956 } 2596 }
1957 else 2597 else
1958 { 2598 {
@@ -2007,7 +2647,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
2007 2647
2008 public bool IsInTransit(UUID id) 2648 public bool IsInTransit(UUID id)
2009 { 2649 {
2010 return m_entityTransferStateMachine.IsInTransit(id); 2650 return m_entityTransferStateMachine.GetAgentTransferState(id) != null;
2011 } 2651 }
2012 2652
2013 protected void ReInstantiateScripts(ScenePresence sp) 2653 protected void ReInstantiateScripts(ScenePresence sp)
@@ -2036,5 +2676,69 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
2036 } 2676 }
2037 #endregion 2677 #endregion
2038 2678
2679 public virtual bool HandleIncomingSceneObject(SceneObjectGroup so, Vector3 newPosition)
2680 {
2681 // If the user is banned, we won't let any of their objects
2682 // enter. Period.
2683 //
2684 if (Scene.RegionInfo.EstateSettings.IsBanned(so.OwnerID))
2685 {
2686 m_log.DebugFormat(
2687 "[ENTITY TRANSFER MODULE]: Denied prim crossing of {0} {1} into {2} for banned avatar {3}",
2688 so.Name, so.UUID, Scene.Name, so.OwnerID);
2689
2690 return false;
2691 }
2692
2693 if (newPosition != Vector3.Zero)
2694 so.RootPart.GroupPosition = newPosition;
2695
2696 if (!Scene.AddSceneObject(so))
2697 {
2698 m_log.DebugFormat(
2699 "[ENTITY TRANSFER MODULE]: Problem adding scene object {0} {1} into {2} ",
2700 so.Name, so.UUID, Scene.Name);
2701
2702 return false;
2703 }
2704
2705 if (!so.IsAttachment)
2706 {
2707 // FIXME: It would be better to never add the scene object at all rather than add it and then delete
2708 // it
2709 if (!Scene.Permissions.CanObjectEntry(so.UUID, true, so.AbsolutePosition))
2710 {
2711 // Deny non attachments based on parcel settings
2712 //
2713 m_log.Info("[ENTITY TRANSFER MODULE]: Denied prim crossing because of parcel settings");
2714
2715 Scene.DeleteSceneObject(so, false);
2716
2717 return false;
2718 }
2719
2720 // For attachments, we need to wait until the agent is root
2721 // before we restart the scripts, or else some functions won't work.
2722 so.RootPart.ParentGroup.CreateScriptInstances(
2723 0, false, Scene.DefaultScriptEngine, GetStateSource(so));
2724
2725 so.ResumeScripts();
2726
2727 if (so.RootPart.KeyframeMotion != null)
2728 so.RootPart.KeyframeMotion.UpdateSceneObject(so);
2729 }
2730
2731 return true;
2732 }
2733
2734 private int GetStateSource(SceneObjectGroup sog)
2735 {
2736 ScenePresence sp = Scene.GetScenePresence(sog.OwnerID);
2737
2738 if (sp != null)
2739 return sp.GetStateSource();
2740
2741 return 2; // StateSource.PrimCrossing
2742 }
2039 } 2743 }
2040} \ No newline at end of file 2744}
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs
index d0cab49..a3109e0 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs
@@ -38,7 +38,7 @@ using OpenSim.Framework.Capabilities;
38using OpenSim.Framework.Client; 38using OpenSim.Framework.Client;
39using OpenSim.Region.Framework.Interfaces; 39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
41using OpenSim.Region.Physics.Manager; 41using OpenSim.Region.PhysicsModules.SharedBase;
42using OpenSim.Services.Interfaces; 42using OpenSim.Services.Interfaces;
43using GridRegion = OpenSim.Services.Interfaces.GridRegion; 43using GridRegion = OpenSim.Services.Interfaces.GridRegion;
44 44
@@ -51,10 +51,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
51 /// This is a state machine. 51 /// This is a state machine.
52 /// 52 ///
53 /// [Entry] => Preparing 53 /// [Entry] => Preparing
54 /// Preparing => { Transferring || CleaningUp || [Exit] } 54 /// Preparing => { Transferring || Cancelling || CleaningUp || Aborting || [Exit] }
55 /// Transferring => { ReceivedAtDestination || CleaningUp } 55 /// Transferring => { ReceivedAtDestination || Cancelling || CleaningUp || Aborting }
56 /// ReceivedAtDestination => CleaningUp 56 /// Cancelling => CleaningUp || Aborting
57 /// ReceivedAtDestination => CleaningUp || Aborting
57 /// CleaningUp => [Exit] 58 /// CleaningUp => [Exit]
59 /// Aborting => [Exit]
58 /// 60 ///
59 /// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp 61 /// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp
60 /// However, any state can transition to CleaningUp if the teleport has failed. 62 /// However, any state can transition to CleaningUp if the teleport has failed.
@@ -64,7 +66,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
64 Preparing, // The agent is being prepared for transfer 66 Preparing, // The agent is being prepared for transfer
65 Transferring, // The agent is in the process of being transferred to a destination 67 Transferring, // The agent is in the process of being transferred to a destination
66 ReceivedAtDestination, // The destination has notified us that the agent has been successfully received 68 ReceivedAtDestination, // The destination has notified us that the agent has been successfully received
67 CleaningUp // The agent is being changed to child/removed after a transfer 69 CleaningUp, // The agent is being changed to child/removed after a transfer
70 Cancelling, // The user has cancelled the teleport but we have yet to act upon this.
71 Aborting // The transfer is aborting. Unlike Cancelling, no compensating actions should be performed
68 } 72 }
69 73
70 /// <summary> 74 /// <summary>
@@ -73,6 +77,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
73 public class EntityTransferStateMachine 77 public class EntityTransferStateMachine
74 { 78 {
75 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 79 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
80 private static readonly string LogHeader = "[ENTITY TRANSFER STATE MACHINE]";
76 81
77 /// <summary> 82 /// <summary>
78 /// If true then on a teleport, the source region waits for a callback from the destination region. If 83 /// If true then on a teleport, the source region waits for a callback from the destination region. If
@@ -96,6 +101,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
96 /// <returns>true if the agent was not already in transit, false if it was</returns> 101 /// <returns>true if the agent was not already in transit, false if it was</returns>
97 internal bool SetInTransit(UUID id) 102 internal bool SetInTransit(UUID id)
98 { 103 {
104 m_log.DebugFormat("{0} SetInTransit. agent={1}, newState=Preparing", LogHeader, id);
99 lock (m_agentsInTransit) 105 lock (m_agentsInTransit)
100 { 106 {
101 if (!m_agentsInTransit.ContainsKey(id)) 107 if (!m_agentsInTransit.ContainsKey(id))
@@ -115,42 +121,117 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
115 /// <param name='newState'></param> 121 /// <param name='newState'></param>
116 /// <returns></returns> 122 /// <returns></returns>
117 /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception> 123 /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception>
118 internal void UpdateInTransit(UUID id, AgentTransferState newState) 124 internal bool UpdateInTransit(UUID id, AgentTransferState newState)
119 { 125 {
126 m_log.DebugFormat("{0} UpdateInTransit. agent={1}, newState={2}", LogHeader, id, newState);
127
128 bool transitionOkay = false;
129
130 // We don't want to throw an exception on cancel since this can come it at any time.
131 bool failIfNotOkay = true;
132
133 // Should be a failure message if failure is not okay.
134 string failureMessage = null;
135
136 AgentTransferState? oldState = null;
137
120 lock (m_agentsInTransit) 138 lock (m_agentsInTransit)
121 { 139 {
122 // Illegal to try and update an agent that's not actually in transit. 140 // Illegal to try and update an agent that's not actually in transit.
123 if (!m_agentsInTransit.ContainsKey(id)) 141 if (!m_agentsInTransit.ContainsKey(id))
124 throw new Exception( 142 {
125 string.Format( 143 if (newState != AgentTransferState.Cancelling && newState != AgentTransferState.Aborting)
126 "Agent with ID {0} is not registered as in transit in {1}", 144 failureMessage = string.Format(
127 id, m_mod.Scene.RegionInfo.RegionName)); 145 "Agent with ID {0} is not registered as in transit in {1}",
128 146 id, m_mod.Scene.RegionInfo.RegionName);
129 AgentTransferState oldState = m_agentsInTransit[id]; 147 else
148 failIfNotOkay = false;
149 }
150 else
151 {
152 oldState = m_agentsInTransit[id];
130 153
131 bool transitionOkay = false; 154 if (newState == AgentTransferState.Aborting)
155 {
156 transitionOkay = true;
157 }
158 else if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp)
159 {
160 transitionOkay = true;
161 }
162 else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing)
163 {
164 transitionOkay = true;
165 }
166 else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring)
167 {
168 transitionOkay = true;
169 }
170 else
171 {
172 if (newState == AgentTransferState.Cancelling
173 && (oldState == AgentTransferState.Preparing || oldState == AgentTransferState.Transferring))
174 {
175 transitionOkay = true;
176 }
177 else
178 {
179 failIfNotOkay = false;
180 }
181 }
132 182
133 if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) 183 if (!transitionOkay)
134 transitionOkay = true; 184 failureMessage
135 else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing) 185 = string.Format(
136 transitionOkay = true; 186 "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}",
137 else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring) 187 id, oldState, newState, m_mod.Scene.RegionInfo.RegionName);
138 transitionOkay = true; 188 }
139 189
140 if (transitionOkay) 190 if (transitionOkay)
191 {
141 m_agentsInTransit[id] = newState; 192 m_agentsInTransit[id] = newState;
142 else 193
143 throw new Exception( 194// m_log.DebugFormat(
144 string.Format( 195// "[ENTITY TRANSFER STATE MACHINE]: Changed agent with id {0} from state {1} to {2} in {3}",
145 "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}", 196// id, oldState, newState, m_mod.Scene.Name);
146 id, oldState, newState, m_mod.Scene.RegionInfo.RegionName)); 197 }
198 else if (failIfNotOkay)
199 {
200 m_log.DebugFormat("{0} UpdateInTransit. Throwing transition failure = {1}", LogHeader, failureMessage);
201 throw new Exception(failureMessage);
202 }
203// else
204// {
205// if (oldState != null)
206// m_log.DebugFormat(
207// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} from state {1} to {2} in {3}",
208// id, oldState, newState, m_mod.Scene.Name);
209// else
210// m_log.DebugFormat(
211// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} to state {1} in {2} since agent not in transit",
212// id, newState, m_mod.Scene.Name);
213// }
147 } 214 }
215
216 return transitionOkay;
148 } 217 }
149 218
150 internal bool IsInTransit(UUID id) 219 /// <summary>
220 /// Gets the current agent transfer state.
221 /// </summary>
222 /// <returns>Null if the agent is not in transit</returns>
223 /// <param name='id'>
224 /// Identifier.
225 /// </param>
226 internal AgentTransferState? GetAgentTransferState(UUID id)
151 { 227 {
152 lock (m_agentsInTransit) 228 lock (m_agentsInTransit)
153 return m_agentsInTransit.ContainsKey(id); 229 {
230 if (!m_agentsInTransit.ContainsKey(id))
231 return null;
232 else
233 return m_agentsInTransit[id];
234 }
154 } 235 }
155 236
156 /// <summary> 237 /// <summary>
@@ -203,14 +284,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
203 284
204 lock (m_agentsInTransit) 285 lock (m_agentsInTransit)
205 { 286 {
206 if (!IsInTransit(id)) 287 AgentTransferState? currentState = GetAgentTransferState(id);
288
289 if (currentState == null)
207 throw new Exception( 290 throw new Exception(
208 string.Format( 291 string.Format(
209 "Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit", 292 "Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit",
210 id, m_mod.Scene.RegionInfo.RegionName)); 293 id, m_mod.Scene.RegionInfo.RegionName));
211 294
212 AgentTransferState currentState = m_agentsInTransit[id];
213
214 if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination) 295 if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination)
215 throw new Exception( 296 throw new Exception(
216 string.Format( 297 string.Format(
@@ -222,8 +303,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
222 303
223 // There should be no race condition here since no other code should be removing the agent transfer or 304 // There should be no race condition here since no other code should be removing the agent transfer or
224 // changing the state to another other than Transferring => ReceivedAtDestination. 305 // changing the state to another other than Transferring => ReceivedAtDestination.
225 while (m_agentsInTransit[id] != AgentTransferState.ReceivedAtDestination && count-- > 0) 306
307 while (count-- > 0)
226 { 308 {
309 lock (m_agentsInTransit)
310 {
311 if (m_agentsInTransit[id] == AgentTransferState.ReceivedAtDestination)
312 break;
313 }
314
227// m_log.Debug(" >>> Waiting... " + count); 315// m_log.Debug(" >>> Waiting... " + count);
228 Thread.Sleep(100); 316 Thread.Sleep(100);
229 } 317 }
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
index b188741..fa23590 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -31,6 +31,7 @@ using System.Reflection;
31 31
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Framework.Client; 33using OpenSim.Framework.Client;
34using OpenSim.Framework.Monitoring;
34using OpenSim.Region.Framework.Interfaces; 35using OpenSim.Region.Framework.Interfaces;
35using OpenSim.Region.Framework.Scenes; 36using OpenSim.Region.Framework.Scenes;
36using OpenSim.Services.Connectors.Hypergrid; 37using OpenSim.Services.Connectors.Hypergrid;
@@ -55,6 +56,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
55 private int m_levelHGTeleport = 0; 56 private int m_levelHGTeleport = 0;
56 57
57 private GatekeeperServiceConnector m_GatekeeperConnector; 58 private GatekeeperServiceConnector m_GatekeeperConnector;
59 private IUserAgentService m_UAS;
58 60
59 protected bool m_RestrictAppearanceAbroad; 61 protected bool m_RestrictAppearanceAbroad;
60 protected string m_AccountName; 62 protected string m_AccountName;
@@ -109,6 +111,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
109 } 111 }
110 } 112 }
111 113
114 /// <summary>
115 /// Used for processing analysis of incoming attachments in a controlled fashion.
116 /// </summary>
117 private JobEngine m_incomingSceneObjectEngine;
118
112 #region ISharedRegionModule 119 #region ISharedRegionModule
113 120
114 public override string Name 121 public override string Name
@@ -152,39 +159,33 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
152 if (m_Enabled) 159 if (m_Enabled)
153 { 160 {
154 scene.RegisterModuleInterface<IUserAgentVerificationModule>(this); 161 scene.RegisterModuleInterface<IUserAgentVerificationModule>(this);
155 scene.EventManager.OnIncomingSceneObject += OnIncomingSceneObject; 162 //scene.EventManager.OnIncomingSceneObject += OnIncomingSceneObject;
156 } 163
157 } 164 m_incomingSceneObjectEngine
158 165 = new JobEngine(
159 void OnIncomingSceneObject(SceneObjectGroup so) 166 string.Format("HG Incoming Scene Object Engine ({0})", scene.Name),
160 { 167 "HG INCOMING SCENE OBJECT ENGINE");
161 if (!so.IsAttachment) 168
162 return; 169 StatsManager.RegisterStat(
163 170 new Stat(
164 if (so.Scene.UserManagementModule.IsLocalGridUser(so.AttachedAvatar)) 171 "HGIncomingAttachmentsWaiting",
165 return; 172 "Number of incoming attachments waiting for processing.",
166 173 "",
167 // foreign user 174 "",
168 AgentCircuitData aCircuit = so.Scene.AuthenticateHandler.GetAgentCircuitData(so.AttachedAvatar); 175 "entitytransfer",
169 if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0) 176 Name,
170 { 177 StatType.Pull,
171 if (aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI")) 178 MeasuresOfInterest.None,
172 { 179 stat => stat.Value = m_incomingSceneObjectEngine.JobsWaiting,
173 string url = aCircuit.ServiceURLs["AssetServerURI"].ToString(); 180 StatVerbosity.Debug));
174 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Incoming attachement {0} for HG user {1} with asset server {2}", so.Name, so.AttachedAvatar, url); 181
175 Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>(); 182 m_incomingSceneObjectEngine.Start();
176 HGUuidGatherer uuidGatherer = new HGUuidGatherer(so.Scene.AssetService, url);
177 uuidGatherer.GatherAssetUuids(so, ids);
178
179 foreach (KeyValuePair<UUID, AssetType> kvp in ids)
180 uuidGatherer.FetchAsset(kvp.Key);
181 }
182 } 183 }
183 } 184 }
184 185
185 protected override void OnNewClient(IClientAPI client) 186 protected override void OnNewClient(IClientAPI client)
186 { 187 {
187 client.OnTeleportHomeRequest += TeleportHome; 188 client.OnTeleportHomeRequest += TriggerTeleportHome;
188 client.OnTeleportLandmarkRequest += RequestTeleportLandmark; 189 client.OnTeleportLandmarkRequest += RequestTeleportLandmark;
189 client.OnConnectionClosed += new Action<IClientAPI>(OnConnectionClosed); 190 client.OnConnectionClosed += new Action<IClientAPI>(OnConnectionClosed);
190 } 191 }
@@ -194,34 +195,44 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
194 base.RegionLoaded(scene); 195 base.RegionLoaded(scene);
195 196
196 if (m_Enabled) 197 if (m_Enabled)
198 {
197 m_GatekeeperConnector = new GatekeeperServiceConnector(scene.AssetService); 199 m_GatekeeperConnector = new GatekeeperServiceConnector(scene.AssetService);
200 m_UAS = scene.RequestModuleInterface<IUserAgentService>();
201 if (m_UAS == null)
202 m_UAS = new UserAgentServiceConnector(m_ThisHomeURI);
203
204 }
198 } 205 }
199 206
200 public override void RemoveRegion(Scene scene) 207 public override void RemoveRegion(Scene scene)
201 { 208 {
202 base.AddRegion(scene); 209 base.RemoveRegion(scene);
203 210
204 if (m_Enabled) 211 if (m_Enabled)
212 {
205 scene.UnregisterModuleInterface<IUserAgentVerificationModule>(this); 213 scene.UnregisterModuleInterface<IUserAgentVerificationModule>(this);
214 m_incomingSceneObjectEngine.Stop();
215 }
206 } 216 }
207 217
208 #endregion 218 #endregion
209 219
210 #region HG overrides of IEntiryTransferModule 220 #region HG overrides of IEntityTransferModule
211 221
212 protected override GridRegion GetFinalDestination(GridRegion region) 222 protected override GridRegion GetFinalDestination(GridRegion region, UUID agentID, string agentHomeURI, out string message)
213 { 223 {
214 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID); 224 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID);
215 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionName, flags); 225 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionName, flags);
226 message = null;
216 227
217 if ((flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0) 228 if ((flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
218 { 229 {
219 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region is hyperlink"); 230 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region is hyperlink");
220 GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID); 231 GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID, agentID, agentHomeURI, out message);
221 if (real_destination != null) 232 if (real_destination != null)
222 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: GetFinalDestination serveruri -> {0}", real_destination.ServerURI); 233 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: GetFinalDestination: ServerURI={0}", real_destination.ServerURI);
223 else 234 else
224 m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: GetHyperlinkRegion to Gatekeeper {0} failed", region.ServerURI); 235 m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: GetHyperlinkRegion of region {0} from Gatekeeper {1} failed: {2}", region.RegionID, region.ServerURI, message);
225 return real_destination; 236 return real_destination;
226 } 237 }
227 238
@@ -272,12 +283,21 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
272 if (agentCircuit.ServiceURLs.ContainsKey("HomeURI")) 283 if (agentCircuit.ServiceURLs.ContainsKey("HomeURI"))
273 { 284 {
274 string userAgentDriver = agentCircuit.ServiceURLs["HomeURI"].ToString(); 285 string userAgentDriver = agentCircuit.ServiceURLs["HomeURI"].ToString();
275 IUserAgentService connector = new UserAgentServiceConnector(userAgentDriver); 286 IUserAgentService connector;
276 bool success = connector.LoginAgentToGrid(agentCircuit, reg, finalDestination, out reason); 287
288 if (userAgentDriver.Equals(m_ThisHomeURI) && m_UAS != null)
289 connector = m_UAS;
290 else
291 connector = new UserAgentServiceConnector(userAgentDriver);
292
293 GridRegion source = new GridRegion(Scene.RegionInfo);
294 source.RawServerURI = m_GatekeeperURI;
295
296 bool success = connector.LoginAgentToGrid(source, agentCircuit, reg, finalDestination, false, out reason);
277 logout = success; // flag for later logout from this grid; this is an HG TP 297 logout = success; // flag for later logout from this grid; this is an HG TP
278 298
279 if (success) 299 if (success)
280 sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout); 300 Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout);
281 301
282 return success; 302 return success;
283 } 303 }
@@ -409,7 +429,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
409 // return base.UpdateAgent(reg, finalDestination, agentData, sp); 429 // return base.UpdateAgent(reg, finalDestination, agentData, sp);
410 //} 430 //}
411 431
412 public override void TeleportHome(UUID id, IClientAPI client) 432 public override void TriggerTeleportHome(UUID id, IClientAPI client)
433 {
434 TeleportHome(id, client);
435 }
436
437 public override bool TeleportHome(UUID id, IClientAPI client)
413 { 438 {
414 m_log.DebugFormat( 439 m_log.DebugFormat(
415 "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId); 440 "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId);
@@ -420,8 +445,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
420 { 445 {
421 // local grid user 446 // local grid user
422 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: User is local"); 447 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: User is local");
423 base.TeleportHome(id, client); 448 return base.TeleportHome(id, client);
424 return;
425 } 449 }
426 450
427 // Foreign user wants to go home 451 // Foreign user wants to go home
@@ -431,17 +455,27 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
431 { 455 {
432 client.SendTeleportFailed("Your information has been lost"); 456 client.SendTeleportFailed("Your information has been lost");
433 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Unable to locate agent's gateway information"); 457 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Unable to locate agent's gateway information");
434 return; 458 return false;
435 } 459 }
436 460
437 IUserAgentService userAgentService = new UserAgentServiceConnector(aCircuit.ServiceURLs["HomeURI"].ToString()); 461 IUserAgentService userAgentService = new UserAgentServiceConnector(aCircuit.ServiceURLs["HomeURI"].ToString());
438 Vector3 position = Vector3.UnitY, lookAt = Vector3.UnitY; 462 Vector3 position = Vector3.UnitY, lookAt = Vector3.UnitY;
439 GridRegion finalDestination = userAgentService.GetHomeRegion(aCircuit.AgentID, out position, out lookAt); 463
464 GridRegion finalDestination = null;
465 try
466 {
467 finalDestination = userAgentService.GetHomeRegion(aCircuit.AgentID, out position, out lookAt);
468 }
469 catch (Exception e)
470 {
471 m_log.Debug("[HG ENTITY TRANSFER MODULE]: GetHomeRegion call failed ", e);
472 }
473
440 if (finalDestination == null) 474 if (finalDestination == null)
441 { 475 {
442 client.SendTeleportFailed("Your home region could not be found"); 476 client.SendTeleportFailed("Your home region could not be found");
443 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent's home region not found"); 477 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent's home region not found");
444 return; 478 return false;
445 } 479 }
446 480
447 ScenePresence sp = ((Scene)(client.Scene)).GetScenePresence(client.AgentId); 481 ScenePresence sp = ((Scene)(client.Scene)).GetScenePresence(client.AgentId);
@@ -449,7 +483,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
449 { 483 {
450 client.SendTeleportFailed("Internal error"); 484 client.SendTeleportFailed("Internal error");
451 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent not found in the scene where it is supposed to be"); 485 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent not found in the scene where it is supposed to be");
452 return; 486 return false;
453 } 487 }
454 488
455 GridRegion homeGatekeeper = MakeRegion(aCircuit); 489 GridRegion homeGatekeeper = MakeRegion(aCircuit);
@@ -460,6 +494,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
460 DoTeleport( 494 DoTeleport(
461 sp, homeGatekeeper, finalDestination, 495 sp, homeGatekeeper, finalDestination,
462 position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome)); 496 position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome));
497 return true;
463 } 498 }
464 499
465 /// <summary> 500 /// <summary>
@@ -484,35 +519,174 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
484 // Local region? 519 // Local region?
485 if (info != null) 520 if (info != null)
486 { 521 {
487 ((Scene)(remoteClient.Scene)).RequestTeleportLocation(remoteClient, info.RegionHandle, lm.Position, 522 Scene.RequestTeleportLocation(
523 remoteClient, info.RegionHandle, lm.Position,
488 Vector3.Zero, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark)); 524 Vector3.Zero, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark));
489
490 return;
491 } 525 }
492 else 526 else
493 { 527 {
494 // Foreign region 528 // Foreign region
495 Scene scene = (Scene)(remoteClient.Scene);
496 GatekeeperServiceConnector gConn = new GatekeeperServiceConnector(); 529 GatekeeperServiceConnector gConn = new GatekeeperServiceConnector();
497 GridRegion gatekeeper = new GridRegion(); 530 GridRegion gatekeeper = new GridRegion();
498 gatekeeper.ServerURI = lm.Gatekeeper; 531 gatekeeper.ServerURI = lm.Gatekeeper;
499 GridRegion finalDestination = gConn.GetHyperlinkRegion(gatekeeper, new UUID(lm.RegionID)); 532 string homeURI = Scene.GetAgentHomeURI(remoteClient.AgentId);
533
534 string message;
535 GridRegion finalDestination = gConn.GetHyperlinkRegion(gatekeeper, new UUID(lm.RegionID), remoteClient.AgentId, homeURI, out message);
500 536
501 if (finalDestination != null) 537 if (finalDestination != null)
502 { 538 {
503 ScenePresence sp = scene.GetScenePresence(remoteClient.AgentId); 539 ScenePresence sp = Scene.GetScenePresence(remoteClient.AgentId);
504 IEntityTransferModule transferMod = scene.RequestModuleInterface<IEntityTransferModule>();
505 540
506 if (transferMod != null && sp != null) 541 if (sp != null)
507 transferMod.DoTeleport( 542 {
543 if (message != null)
544 sp.ControllingClient.SendAgentAlertMessage(message, true);
545
546 // Validate assorted conditions
547 string reason = string.Empty;
548 if (!ValidateGenericConditions(sp, gatekeeper, finalDestination, 0, out reason))
549 {
550 sp.ControllingClient.SendTeleportFailed(reason);
551 return;
552 }
553
554 DoTeleport(
508 sp, gatekeeper, finalDestination, lm.Position, Vector3.UnitX, 555 sp, gatekeeper, finalDestination, lm.Position, Vector3.UnitX,
509 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark)); 556 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark));
557 }
558 }
559 else
560 {
561 remoteClient.SendTeleportFailed(message);
510 } 562 }
511 563
512 } 564 }
565 }
566
567 private void RemoveIncomingSceneObjectJobs(string commonIdToRemove)
568 {
569 List<JobEngine.Job> jobsToReinsert = new List<JobEngine.Job>();
570 int jobsRemoved = 0;
513 571
514 // can't find the region: Tell viewer and abort 572 JobEngine.Job job;
515 remoteClient.SendTeleportFailed("The teleport destination could not be found."); 573 while ((job = m_incomingSceneObjectEngine.RemoveNextJob()) != null)
574 {
575 if (job.CommonId != commonIdToRemove)
576 jobsToReinsert.Add(job);
577 else
578 jobsRemoved++;
579 }
580
581 m_log.DebugFormat(
582 "[HG ENTITY TRANSFER]: Removing {0} jobs with common ID {1} and reinserting {2} other jobs",
583 jobsRemoved, commonIdToRemove, jobsToReinsert.Count);
584
585 if (jobsToReinsert.Count > 0)
586 {
587 foreach (JobEngine.Job jobToReinsert in jobsToReinsert)
588 m_incomingSceneObjectEngine.QueueJob(jobToReinsert);
589 }
590 }
591
592 public override bool HandleIncomingSceneObject(SceneObjectGroup so, Vector3 newPosition)
593 {
594 // FIXME: We must make it so that we can use SOG.IsAttachment here. At the moment it is always null!
595 if (!so.IsAttachmentCheckFull())
596 return base.HandleIncomingSceneObject(so, newPosition);
597
598 // Equally, we can't use so.AttachedAvatar here.
599 if (so.OwnerID == UUID.Zero || Scene.UserManagementModule.IsLocalGridUser(so.OwnerID))
600 return base.HandleIncomingSceneObject(so, newPosition);
601
602 // foreign user
603 AgentCircuitData aCircuit = Scene.AuthenticateHandler.GetAgentCircuitData(so.OwnerID);
604 if (aCircuit != null)
605 {
606 if ((aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) == 0)
607 {
608 // We have already pulled the necessary attachments from the source grid.
609 base.HandleIncomingSceneObject(so, newPosition);
610 }
611 else
612 {
613 if (aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI"))
614 {
615 m_incomingSceneObjectEngine.QueueJob(
616 string.Format("HG UUID Gather for attachment {0} for {1}", so.Name, aCircuit.Name),
617 () =>
618 {
619 string url = aCircuit.ServiceURLs["AssetServerURI"].ToString();
620 // m_log.DebugFormat(
621 // "[HG ENTITY TRANSFER MODULE]: Incoming attachment {0} for HG user {1} with asset service {2}",
622 // so.Name, so.AttachedAvatar, url);
623
624 IDictionary<UUID, sbyte> ids = new Dictionary<UUID, sbyte>();
625 HGUuidGatherer uuidGatherer
626 = new HGUuidGatherer(Scene.AssetService, url, ids);
627 uuidGatherer.AddForInspection(so);
628
629 while (!uuidGatherer.Complete)
630 {
631 int tickStart = Util.EnvironmentTickCount();
632
633 UUID? nextUuid = uuidGatherer.NextUuidToInspect;
634 uuidGatherer.GatherNext();
635
636 // m_log.DebugFormat(
637 // "[HG ENTITY TRANSFER]: Gathered attachment asset uuid {0} for object {1} for HG user {2} took {3} ms with asset service {4}",
638 // nextUuid, so.Name, so.OwnerID, Util.EnvironmentTickCountSubtract(tickStart), url);
639
640 int ticksElapsed = Util.EnvironmentTickCountSubtract(tickStart);
641
642 if (ticksElapsed > 30000)
643 {
644 m_log.WarnFormat(
645 "[HG ENTITY TRANSFER]: Removing incoming scene object jobs for HG user {0} as gather of {1} from {2} took {3} ms to respond (> {4} ms)",
646 so.OwnerID, so.Name, url, ticksElapsed, 30000);
647
648 RemoveIncomingSceneObjectJobs(so.OwnerID.ToString());
649
650 return;
651 }
652 }
653
654 // m_log.DebugFormat(
655 // "[HG ENTITY TRANSFER]: Fetching {0} assets for attachment {1} for HG user {2} with asset service {3}",
656 // ids.Count, so.Name, so.OwnerID, url);
657
658 foreach (KeyValuePair<UUID, sbyte> kvp in ids)
659 {
660 int tickStart = Util.EnvironmentTickCount();
661
662 uuidGatherer.FetchAsset(kvp.Key);
663
664 int ticksElapsed = Util.EnvironmentTickCountSubtract(tickStart);
665
666 if (ticksElapsed > 30000)
667 {
668 m_log.WarnFormat(
669 "[HG ENTITY TRANSFER]: Removing incoming scene object jobs for HG user {0} as fetch of {1} from {2} took {3} ms to respond (> {4} ms)",
670 so.OwnerID, kvp.Key, url, ticksElapsed, 30000);
671
672 RemoveIncomingSceneObjectJobs(so.OwnerID.ToString());
673
674 return;
675 }
676 }
677
678 base.HandleIncomingSceneObject(so, newPosition);
679
680 // m_log.DebugFormat(
681 // "[HG ENTITY TRANSFER MODULE]: Completed incoming attachment {0} for HG user {1} with asset server {2}",
682 // so.Name, so.OwnerID, url);
683 },
684 so.OwnerID.ToString());
685 }
686 }
687 }
688
689 return true;
516 } 690 }
517 691
518 #endregion 692 #endregion
@@ -549,12 +723,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
549 if (uMan != null && uMan.IsLocalGridUser(obj.AgentId)) 723 if (uMan != null && uMan.IsLocalGridUser(obj.AgentId))
550 { 724 {
551 // local grid user 725 // local grid user
726 m_UAS.LogoutAgent(obj.AgentId, obj.SessionId);
552 return; 727 return;
553 } 728 }
554 729
555 AgentCircuitData aCircuit = ((Scene)(obj.Scene)).AuthenticateHandler.GetAgentCircuitData(obj.CircuitCode); 730 AgentCircuitData aCircuit = ((Scene)(obj.Scene)).AuthenticateHandler.GetAgentCircuitData(obj.CircuitCode);
556 731 if (aCircuit != null && aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("HomeURI"))
557 if (aCircuit.ServiceURLs.ContainsKey("HomeURI"))
558 { 732 {
559 string url = aCircuit.ServiceURLs["HomeURI"].ToString(); 733 string url = aCircuit.ServiceURLs["HomeURI"].ToString();
560 IUserAgentService security = new UserAgentServiceConnector(url); 734 IUserAgentService security = new UserAgentServiceConnector(url);