diff options
Diffstat (limited to '')
13 files changed, 436 insertions, 172 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs index 221f02b..5fcf376 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs | |||
@@ -79,7 +79,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
79 | 79 | ||
80 | J2KDecoderModule j2kdm = new J2KDecoderModule(); | 80 | J2KDecoderModule j2kdm = new J2KDecoderModule(); |
81 | 81 | ||
82 | scene = new SceneHelpers().SetupScene(); | 82 | SceneHelpers sceneHelpers = new SceneHelpers(); |
83 | scene = sceneHelpers.SetupScene(); | ||
83 | SceneHelpers.SetupSceneModules(scene, j2kdm); | 84 | SceneHelpers.SetupSceneModules(scene, j2kdm); |
84 | 85 | ||
85 | tc = new TestClient(SceneHelpers.GenerateAgentData(userId), scene); | 86 | tc = new TestClient(SceneHelpers.GenerateAgentData(userId), scene); |
diff --git a/OpenSim/Region/ClientStack/RegionApplicationBase.cs b/OpenSim/Region/ClientStack/RegionApplicationBase.cs index 6e3a58e..6e78d6d 100644 --- a/OpenSim/Region/ClientStack/RegionApplicationBase.cs +++ b/OpenSim/Region/ClientStack/RegionApplicationBase.cs | |||
@@ -111,7 +111,7 @@ namespace OpenSim.Region.ClientStack | |||
111 | server.Start(); | 111 | server.Start(); |
112 | } | 112 | } |
113 | } | 113 | } |
114 | 114 | ||
115 | base.StartupSpecific(); | 115 | base.StartupSpecific(); |
116 | } | 116 | } |
117 | 117 | ||
diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs index bc5c1ff..92cf9d1 100644 --- a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs | |||
@@ -240,13 +240,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure | |||
240 | { | 240 | { |
241 | ScenePresence sp = scene.GetScenePresence(client.AgentId); | 241 | ScenePresence sp = scene.GetScenePresence(client.AgentId); |
242 | IEntityTransferModule transferMod = scene.RequestModuleInterface<IEntityTransferModule>(); | 242 | IEntityTransferModule transferMod = scene.RequestModuleInterface<IEntityTransferModule>(); |
243 | IEventQueue eq = sp.Scene.RequestModuleInterface<IEventQueue>(); | 243 | |
244 | if (transferMod != null && sp != null && eq != null) | 244 | if (transferMod != null && sp != null) |
245 | transferMod.DoTeleport(sp, gatekeeper, finalDestination, im.Position + new Vector3(0.5f, 0.5f, 0f), Vector3.UnitX, teleportflags, eq); | 245 | transferMod.DoTeleport( |
246 | sp, gatekeeper, finalDestination, im.Position + new Vector3(0.5f, 0.5f, 0f), | ||
247 | Vector3.UnitX, teleportflags); | ||
246 | } | 248 | } |
247 | } | 249 | } |
248 | } | 250 | } |
249 | } | 251 | } |
250 | } | 252 | } |
251 | } | 253 | } |
252 | } | 254 | } \ No newline at end of file |
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 07ea35e..a31e0aa 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | |||
@@ -51,15 +51,20 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
51 | { | 51 | { |
52 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 52 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
53 | 53 | ||
54 | public const int DefaultMaxTransferDistance = 4095; | ||
55 | public const bool EnableWaitForCallbackFromTeleportDestDefault = true; | ||
56 | |||
57 | |||
54 | /// <summary> | 58 | /// <summary> |
55 | /// The maximum distance, in standard region units (256m) that an agent is allowed to transfer. | 59 | /// The maximum distance, in standard region units (256m) that an agent is allowed to transfer. |
56 | /// </summary> | 60 | /// </summary> |
57 | private int m_MaxTransferDistance = 4095; | 61 | public int MaxTransferDistance { get; set; } |
58 | public int MaxTransferDistance | 62 | |
59 | { | 63 | /// <summary> |
60 | get { return m_MaxTransferDistance; } | 64 | /// If true then on a teleport, the source region waits for a callback from the destination region. If |
61 | set { m_MaxTransferDistance = value; } | 65 | /// a callback fails to arrive within a set time then the user is pulled back into the source region. |
62 | } | 66 | /// </summary> |
67 | public bool EnableWaitForCallbackFromTeleportDest { get; set; } | ||
63 | 68 | ||
64 | protected bool m_Enabled = false; | 69 | protected bool m_Enabled = false; |
65 | protected Scene m_aScene; | 70 | protected Scene m_aScene; |
@@ -103,7 +108,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
103 | IConfig transferConfig = source.Configs["EntityTransfer"]; | 108 | IConfig transferConfig = source.Configs["EntityTransfer"]; |
104 | if (transferConfig != null) | 109 | if (transferConfig != null) |
105 | { | 110 | { |
106 | MaxTransferDistance = transferConfig.GetInt("max_distance", 4095); | 111 | EnableWaitForCallbackFromTeleportDest |
112 | = transferConfig.GetBoolean("wait_for_callback", EnableWaitForCallbackFromTeleportDestDefault); | ||
113 | |||
114 | MaxTransferDistance = transferConfig.GetInt("max_distance", DefaultMaxTransferDistance); | ||
115 | } | ||
116 | else | ||
117 | { | ||
118 | MaxTransferDistance = DefaultMaxTransferDistance; | ||
107 | } | 119 | } |
108 | 120 | ||
109 | m_agentsInTransit = new List<UUID>(); | 121 | m_agentsInTransit = new List<UUID>(); |
@@ -170,8 +182,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
170 | if (!sp.Scene.Permissions.CanTeleport(sp.UUID)) | 182 | if (!sp.Scene.Permissions.CanTeleport(sp.UUID)) |
171 | return; | 183 | return; |
172 | 184 | ||
173 | IEventQueue eq = sp.Scene.RequestModuleInterface<IEventQueue>(); | ||
174 | |||
175 | // Reset animations; the viewer does that in teleports. | 185 | // Reset animations; the viewer does that in teleports. |
176 | sp.Animator.ResetAnimations(); | 186 | sp.Animator.ResetAnimations(); |
177 | 187 | ||
@@ -183,146 +193,194 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
183 | { | 193 | { |
184 | destinationRegionName = sp.Scene.RegionInfo.RegionName; | 194 | destinationRegionName = sp.Scene.RegionInfo.RegionName; |
185 | 195 | ||
186 | m_log.DebugFormat( | 196 | TeleportAgentWithinRegion(sp, position, lookAt, teleportFlags); |
187 | "[ENTITY TRANSFER MODULE]: Teleport for {0} to {1} within {2}", | 197 | } |
188 | sp.Name, position, destinationRegionName); | 198 | else // Another region possibly in another simulator |
199 | { | ||
200 | GridRegion finalDestination; | ||
201 | TeleportAgentToDifferentRegion( | ||
202 | sp, regionHandle, position, lookAt, teleportFlags, out finalDestination); | ||
189 | 203 | ||
190 | // Teleport within the same region | 204 | if (finalDestination != null) |
191 | if (IsOutsideRegion(sp.Scene, position) || position.Z < 0) | 205 | destinationRegionName = finalDestination.RegionName; |
192 | { | 206 | } |
193 | Vector3 emergencyPos = new Vector3(128, 128, 128); | 207 | } |
208 | catch (Exception e) | ||
209 | { | ||
210 | m_log.ErrorFormat( | ||
211 | "[ENTITY TRANSFER MODULE]: Exception on teleport of {0} from {1}@{2} to {3}@{4}: {5}{6}", | ||
212 | sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, destinationRegionName, | ||
213 | e.Message, e.StackTrace); | ||
194 | 214 | ||
195 | m_log.WarnFormat( | 215 | sp.ControllingClient.SendTeleportFailed("Internal error"); |
196 | "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}", | 216 | } |
197 | position, sp.Name, sp.UUID, emergencyPos); | 217 | } |
198 | 218 | ||
199 | position = emergencyPos; | 219 | /// <summary> |
200 | } | 220 | /// Teleports the agent within its current region. |
221 | /// </summary> | ||
222 | /// <param name="sp"></param> | ||
223 | /// <param name="position"></param> | ||
224 | /// <param name="lookAt"></param> | ||
225 | /// <param name="teleportFlags"></param | ||
226 | private void TeleportAgentWithinRegion(ScenePresence sp, Vector3 position, Vector3 lookAt, uint teleportFlags) | ||
227 | { | ||
228 | m_log.DebugFormat( | ||
229 | "[ENTITY TRANSFER MODULE]: Teleport for {0} to {1} within {2}", | ||
230 | sp.Name, position, sp.Scene.RegionInfo.RegionName); | ||
201 | 231 | ||
202 | // TODO: Get proper AVG Height | 232 | // Teleport within the same region |
203 | float localAVHeight = 1.56f; | 233 | if (IsOutsideRegion(sp.Scene, position) || position.Z < 0) |
204 | float posZLimit = 22; | 234 | { |
235 | Vector3 emergencyPos = new Vector3(128, 128, 128); | ||
205 | 236 | ||
206 | // TODO: Check other Scene HeightField | 237 | m_log.WarnFormat( |
207 | if (position.X > 0 && position.X <= (int)Constants.RegionSize && position.Y > 0 && position.Y <= (int)Constants.RegionSize) | 238 | "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}", |
208 | { | 239 | position, sp.Name, sp.UUID, emergencyPos); |
209 | posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y]; | ||
210 | } | ||
211 | 240 | ||
212 | float newPosZ = posZLimit + localAVHeight; | 241 | position = emergencyPos; |
213 | if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) | 242 | } |
214 | { | ||
215 | position.Z = newPosZ; | ||
216 | } | ||
217 | 243 | ||
218 | sp.ControllingClient.SendTeleportStart(teleportFlags); | 244 | // TODO: Get proper AVG Height |
245 | float localAVHeight = 1.56f; | ||
246 | float posZLimit = 22; | ||
219 | 247 | ||
220 | sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); | 248 | // TODO: Check other Scene HeightField |
221 | sp.TeleportFlags = (Constants.TeleportFlags)teleportFlags; | 249 | if (position.X > 0 && position.X <= (int)Constants.RegionSize && position.Y > 0 && position.Y <= (int)Constants.RegionSize) |
222 | sp.Velocity = Vector3.Zero; | 250 | { |
223 | sp.Teleport(position); | 251 | posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y]; |
252 | } | ||
224 | 253 | ||
225 | foreach (SceneObjectGroup grp in sp.GetAttachments()) | 254 | float newPosZ = posZLimit + localAVHeight; |
226 | { | 255 | if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) |
227 | sp.Scene.EventManager.TriggerOnScriptChangedEvent(grp.LocalId, (uint)Changed.TELEPORT); | 256 | { |
228 | } | 257 | position.Z = newPosZ; |
258 | } | ||
259 | |||
260 | sp.ControllingClient.SendTeleportStart(teleportFlags); | ||
261 | |||
262 | sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); | ||
263 | sp.TeleportFlags = (Constants.TeleportFlags)teleportFlags; | ||
264 | sp.Velocity = Vector3.Zero; | ||
265 | sp.Teleport(position); | ||
266 | |||
267 | foreach (SceneObjectGroup grp in sp.GetAttachments()) | ||
268 | { | ||
269 | sp.Scene.EventManager.TriggerOnScriptChangedEvent(grp.LocalId, (uint)Changed.TELEPORT); | ||
270 | } | ||
271 | } | ||
272 | |||
273 | /// <summary> | ||
274 | /// Teleports the agent to a different region. | ||
275 | /// </summary> | ||
276 | /// <param name='sp'></param> | ||
277 | /// <param name='regionHandle'>/param> | ||
278 | /// <param name='position'></param> | ||
279 | /// <param name='lookAt'></param> | ||
280 | /// <param name='teleportFlags'></param> | ||
281 | /// <param name='finalDestination'></param> | ||
282 | private void TeleportAgentToDifferentRegion( | ||
283 | ScenePresence sp, ulong regionHandle, Vector3 position, | ||
284 | Vector3 lookAt, uint teleportFlags, out GridRegion finalDestination) | ||
285 | { | ||
286 | uint x = 0, y = 0; | ||
287 | Utils.LongToUInts(regionHandle, out x, out y); | ||
288 | GridRegion reg = m_aScene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y); | ||
289 | |||
290 | if (reg != null) | ||
291 | { | ||
292 | finalDestination = GetFinalDestination(reg); | ||
293 | |||
294 | if (finalDestination == null) | ||
295 | { | ||
296 | m_log.WarnFormat( | ||
297 | "[ENTITY TRANSFER MODULE]: Final destination is having problems. Unable to teleport {0} {1}", | ||
298 | sp.Name, sp.UUID); | ||
299 | |||
300 | sp.ControllingClient.SendTeleportFailed("Problem at destination"); | ||
301 | return; | ||
229 | } | 302 | } |
230 | else // Another region possibly in another simulator | 303 | |
304 | // Check that these are not the same coordinates | ||
305 | if (finalDestination.RegionLocX == sp.Scene.RegionInfo.RegionLocX && | ||
306 | finalDestination.RegionLocY == sp.Scene.RegionInfo.RegionLocY) | ||
231 | { | 307 | { |
232 | uint x = 0, y = 0; | 308 | // Can't do. Viewer crashes |
233 | Utils.LongToUInts(regionHandle, out x, out y); | 309 | sp.ControllingClient.SendTeleportFailed("Space warp! You would crash. Move to a different region and try again."); |
234 | GridRegion reg = m_aScene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y); | 310 | return; |
311 | } | ||
235 | 312 | ||
236 | if (reg != null) | 313 | // |
237 | { | 314 | // This is it |
238 | GridRegion finalDestination = GetFinalDestination(reg); | 315 | // |
239 | if (finalDestination == null) | 316 | DoTeleport(sp, reg, finalDestination, position, lookAt, teleportFlags); |
240 | { | 317 | // |
241 | m_log.WarnFormat( | 318 | // |
242 | "[ENTITY TRANSFER MODULE]: Final destination is having problems. Unable to teleport {0} {1}", | 319 | // |
243 | sp.Name, sp.UUID); | 320 | } |
321 | else | ||
322 | { | ||
323 | finalDestination = null; | ||
244 | 324 | ||
245 | sp.ControllingClient.SendTeleportFailed("Problem at destination"); | 325 | // TP to a place that doesn't exist (anymore) |
246 | return; | 326 | // Inform the viewer about that |
247 | } | 327 | sp.ControllingClient.SendTeleportFailed("The region you tried to teleport to doesn't exist anymore"); |
248 | 328 | ||
249 | destinationRegionName = finalDestination.RegionName; | 329 | // and set the map-tile to '(Offline)' |
330 | uint regX, regY; | ||
331 | Utils.LongToUInts(regionHandle, out regX, out regY); | ||
332 | |||
333 | MapBlockData block = new MapBlockData(); | ||
334 | block.X = (ushort)(regX / Constants.RegionSize); | ||
335 | block.Y = (ushort)(regY / Constants.RegionSize); | ||
336 | block.Access = 254; // == not there | ||
250 | 337 | ||
251 | uint curX = 0, curY = 0; | 338 | List<MapBlockData> blocks = new List<MapBlockData>(); |
252 | Utils.LongToUInts(sp.Scene.RegionInfo.RegionHandle, out curX, out curY); | 339 | blocks.Add(block); |
253 | int curCellX = (int)(curX / Constants.RegionSize); | 340 | sp.ControllingClient.SendMapBlock(blocks, 0); |
254 | int curCellY = (int)(curY / Constants.RegionSize); | 341 | } |
255 | int destCellX = (int)(finalDestination.RegionLocX / Constants.RegionSize); | 342 | } |
256 | int destCellY = (int)(finalDestination.RegionLocY / Constants.RegionSize); | ||
257 | 343 | ||
344 | /// <summary> | ||
345 | /// Determines whether this instance is within the max transfer distance. | ||
346 | /// </summary> | ||
347 | /// <param name="sourceRegion"></param> | ||
348 | /// <param name="destRegion"></param> | ||
349 | /// <returns> | ||
350 | /// <c>true</c> if this instance is within max transfer distance; otherwise, <c>false</c>. | ||
351 | /// </returns> | ||
352 | private bool IsWithinMaxTeleportDistance(RegionInfo sourceRegion, GridRegion destRegion) | ||
353 | { | ||
258 | // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Source co-ords are x={0} y={1}", curRegionX, curRegionY); | 354 | // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Source co-ords are x={0} y={1}", curRegionX, curRegionY); |
259 | // | 355 | // |
260 | // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final dest is x={0} y={1} {2}@{3}", | 356 | // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final dest is x={0} y={1} {2}@{3}", |
261 | // destRegionX, destRegionY, finalDestination.RegionID, finalDestination.ServerURI); | 357 | // destRegionX, destRegionY, finalDestination.RegionID, finalDestination.ServerURI); |
262 | 358 | ||
263 | // Check that these are not the same coordinates | 359 | // Insanely, RegionLoc on RegionInfo is the 256m map co-ord whilst GridRegion.RegionLoc is the raw meters position. |
264 | if (finalDestination.RegionLocX == sp.Scene.RegionInfo.RegionLocX && | 360 | return Math.Abs(sourceRegion.RegionLocX - destRegion.RegionCoordX) <= MaxTransferDistance |
265 | finalDestination.RegionLocY == sp.Scene.RegionInfo.RegionLocY) | 361 | && Math.Abs(sourceRegion.RegionLocY - destRegion.RegionCoordY) <= MaxTransferDistance; |
266 | { | 362 | } |
267 | // Can't do. Viewer crashes | ||
268 | sp.ControllingClient.SendTeleportFailed("Space warp! You would crash. Move to a different region and try again."); | ||
269 | return; | ||
270 | } | ||
271 | 363 | ||
272 | if (Math.Abs(curCellX - destCellX) > MaxTransferDistance || Math.Abs(curCellY - destCellY) > MaxTransferDistance) | 364 | public void DoTeleport( |
273 | { | 365 | ScenePresence sp, GridRegion reg, GridRegion finalDestination, |
274 | sp.ControllingClient.SendTeleportFailed( | 366 | Vector3 position, Vector3 lookAt, uint teleportFlags) |
275 | string.Format( | 367 | { |
276 | "Can't teleport to {0} ({1},{2}) from {3} ({4},{5}), destination is more than {6} regions way", | 368 | RegionInfo sourceRegion = sp.Scene.RegionInfo; |
277 | finalDestination.RegionName, destCellX, destCellY, | ||
278 | sp.Scene.RegionInfo.RegionName, curCellX, curCellY, | ||
279 | MaxTransferDistance)); | ||
280 | |||
281 | return; | ||
282 | } | ||
283 | 369 | ||
284 | // | 370 | if (!IsWithinMaxTeleportDistance(sourceRegion, finalDestination)) |
285 | // This is it | ||
286 | // | ||
287 | DoTeleport(sp, reg, finalDestination, position, lookAt, teleportFlags, eq); | ||
288 | // | ||
289 | // | ||
290 | // | ||
291 | } | ||
292 | else | ||
293 | { | ||
294 | // TP to a place that doesn't exist (anymore) | ||
295 | // Inform the viewer about that | ||
296 | sp.ControllingClient.SendTeleportFailed("The region you tried to teleport to doesn't exist anymore"); | ||
297 | |||
298 | // and set the map-tile to '(Offline)' | ||
299 | uint regX, regY; | ||
300 | Utils.LongToUInts(regionHandle, out regX, out regY); | ||
301 | |||
302 | MapBlockData block = new MapBlockData(); | ||
303 | block.X = (ushort)(regX / Constants.RegionSize); | ||
304 | block.Y = (ushort)(regY / Constants.RegionSize); | ||
305 | block.Access = 254; // == not there | ||
306 | |||
307 | List<MapBlockData> blocks = new List<MapBlockData>(); | ||
308 | blocks.Add(block); | ||
309 | sp.ControllingClient.SendMapBlock(blocks, 0); | ||
310 | } | ||
311 | } | ||
312 | } | ||
313 | catch (Exception e) | ||
314 | { | 371 | { |
315 | m_log.ErrorFormat( | 372 | sp.ControllingClient.SendTeleportFailed( |
316 | "[ENTITY TRANSFER MODULE]: Exception on teleport of {0} from {1}@{2} to {3}@{4}: {5}{6}", | 373 | string.Format( |
317 | sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, destinationRegionName, | 374 | "Can't teleport to {0} ({1},{2}) from {3} ({4},{5}), destination is more than {6} regions way", |
318 | e.Message, e.StackTrace); | 375 | finalDestination.RegionName, finalDestination.RegionCoordX, finalDestination.RegionCoordY, |
376 | sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY, | ||
377 | MaxTransferDistance)); | ||
319 | 378 | ||
320 | sp.ControllingClient.SendTeleportFailed("Internal error"); | 379 | return; |
321 | } | 380 | } |
322 | } | ||
323 | 381 | ||
324 | public void DoTeleport(ScenePresence sp, GridRegion reg, GridRegion finalDestination, Vector3 position, Vector3 lookAt, uint teleportFlags, IEventQueue eq) | 382 | IEventQueue eq = sp.Scene.RequestModuleInterface<IEventQueue>(); |
325 | { | 383 | |
326 | if (reg == null || finalDestination == null) | 384 | if (reg == null || finalDestination == null) |
327 | { | 385 | { |
328 | sp.ControllingClient.SendTeleportFailed("Unable to locate destination"); | 386 | sp.ControllingClient.SendTeleportFailed("Unable to locate destination"); |
@@ -485,7 +543,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
485 | sp.ControllingClient.SendTeleportProgress(teleportFlags | (uint)TeleportFlags.DisableCancel, "sending_dest"); | 543 | sp.ControllingClient.SendTeleportProgress(teleportFlags | (uint)TeleportFlags.DisableCancel, "sending_dest"); |
486 | 544 | ||
487 | m_log.DebugFormat( | 545 | m_log.DebugFormat( |
488 | "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, sp.UUID); | 546 | "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", |
547 | capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); | ||
489 | 548 | ||
490 | if (eq != null) | 549 | if (eq != null) |
491 | { | 550 | { |
@@ -504,7 +563,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
504 | // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which | 563 | // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which |
505 | // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation | 564 | // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation |
506 | // that the client contacted the destination before we close things here. | 565 | // that the client contacted the destination before we close things here. |
507 | if (!WaitForCallback(sp.UUID)) | 566 | if (EnableWaitForCallbackFromTeleportDest && !WaitForCallback(sp.UUID)) |
508 | { | 567 | { |
509 | m_log.WarnFormat( | 568 | m_log.WarnFormat( |
510 | "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} failed due to no callback from destination region. Returning avatar to source region.", | 569 | "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} failed due to no callback from destination region. Returning avatar to source region.", |
@@ -537,7 +596,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
537 | 596 | ||
538 | if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) | 597 | if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) |
539 | { | 598 | { |
540 | Thread.Sleep(5000); | 599 | // Thread.Sleep(5000); |
541 | sp.Close(); | 600 | sp.Close(); |
542 | sp.Scene.IncomingCloseAgent(sp.UUID); | 601 | sp.Scene.IncomingCloseAgent(sp.UUID); |
543 | } | 602 | } |
@@ -630,7 +689,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
630 | 689 | ||
631 | protected virtual bool IsOutsideRegion(Scene s, Vector3 pos) | 690 | protected virtual bool IsOutsideRegion(Scene s, Vector3 pos) |
632 | { | 691 | { |
633 | |||
634 | if (s.TestBorderCross(pos, Cardinals.N)) | 692 | if (s.TestBorderCross(pos, Cardinals.N)) |
635 | return true; | 693 | return true; |
636 | if (s.TestBorderCross(pos, Cardinals.S)) | 694 | if (s.TestBorderCross(pos, Cardinals.S)) |
@@ -752,7 +810,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
752 | 810 | ||
753 | neighbourx--; | 811 | neighbourx--; |
754 | newpos.X = Constants.RegionSize - enterDistance; | 812 | newpos.X = Constants.RegionSize - enterDistance; |
755 | |||
756 | } | 813 | } |
757 | else if (scene.TestBorderCross(pos + eastCross, Cardinals.E)) | 814 | else if (scene.TestBorderCross(pos + eastCross, Cardinals.E)) |
758 | { | 815 | { |
@@ -1202,7 +1259,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1202 | { | 1259 | { |
1203 | if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle) | 1260 | if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle) |
1204 | { | 1261 | { |
1205 | |||
1206 | AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); | 1262 | AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); |
1207 | AgentCircuitData agent = sp.ControllingClient.RequestClientInfo(); | 1263 | AgentCircuitData agent = sp.ControllingClient.RequestClientInfo(); |
1208 | agent.BaseFolder = UUID.Zero; | 1264 | agent.BaseFolder = UUID.Zero; |
@@ -1227,7 +1283,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1227 | seeds.Add(neighbour.RegionHandle, agent.CapsPath); | 1283 | seeds.Add(neighbour.RegionHandle, agent.CapsPath); |
1228 | } | 1284 | } |
1229 | else | 1285 | else |
1286 | { | ||
1230 | agent.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, neighbour.RegionHandle); | 1287 | agent.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, neighbour.RegionHandle); |
1288 | } | ||
1231 | 1289 | ||
1232 | cagents.Add(agent); | 1290 | cagents.Add(agent); |
1233 | } | 1291 | } |
@@ -1851,7 +1909,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1851 | int count = 200; | 1909 | int count = 200; |
1852 | while (m_agentsInTransit.Contains(id) && count-- > 0) | 1910 | while (m_agentsInTransit.Contains(id) && count-- > 0) |
1853 | { | 1911 | { |
1854 | //m_log.Debug(" >>> Waiting... " + count); | 1912 | // m_log.Debug(" >>> Waiting... " + count); |
1855 | Thread.Sleep(100); | 1913 | Thread.Sleep(100); |
1856 | } | 1914 | } |
1857 | 1915 | ||
@@ -1859,6 +1917,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1859 | return true; | 1917 | return true; |
1860 | else | 1918 | else |
1861 | return false; | 1919 | return false; |
1920 | |||
1921 | return true; | ||
1862 | } | 1922 | } |
1863 | 1923 | ||
1864 | protected void SetInTransit(UUID id) | 1924 | protected void SetInTransit(UUID id) |
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs index a9ffd8f..6e27299 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs | |||
@@ -246,13 +246,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
246 | return false; | 246 | return false; |
247 | } | 247 | } |
248 | 248 | ||
249 | IEventQueue eq = sp.Scene.RequestModuleInterface<IEventQueue>(); | ||
250 | GridRegion homeGatekeeper = MakeRegion(aCircuit); | 249 | GridRegion homeGatekeeper = MakeRegion(aCircuit); |
251 | 250 | ||
252 | m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: teleporting user {0} {1} home to {2} via {3}:{4}", | 251 | m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: teleporting user {0} {1} home to {2} via {3}:{4}", |
253 | aCircuit.firstname, aCircuit.lastname, finalDestination.RegionName, homeGatekeeper.ServerURI, homeGatekeeper.RegionName); | 252 | aCircuit.firstname, aCircuit.lastname, finalDestination.RegionName, homeGatekeeper.ServerURI, homeGatekeeper.RegionName); |
254 | 253 | ||
255 | DoTeleport(sp, homeGatekeeper, finalDestination, position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome), eq); | 254 | DoTeleport(sp, homeGatekeeper, finalDestination, position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome)); |
256 | return true; | 255 | return true; |
257 | } | 256 | } |
258 | 257 | ||
@@ -293,17 +292,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
293 | { | 292 | { |
294 | ScenePresence sp = scene.GetScenePresence(remoteClient.AgentId); | 293 | ScenePresence sp = scene.GetScenePresence(remoteClient.AgentId); |
295 | IEntityTransferModule transferMod = scene.RequestModuleInterface<IEntityTransferModule>(); | 294 | IEntityTransferModule transferMod = scene.RequestModuleInterface<IEntityTransferModule>(); |
296 | IEventQueue eq = sp.Scene.RequestModuleInterface<IEventQueue>(); | 295 | |
297 | if (transferMod != null && sp != null && eq != null) | 296 | if (transferMod != null && sp != null) |
298 | transferMod.DoTeleport(sp, gatekeeper, finalDestination, lm.Position, | 297 | transferMod.DoTeleport( |
299 | Vector3.UnitX, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark), eq); | 298 | sp, gatekeeper, finalDestination, lm.Position, Vector3.UnitX, |
299 | (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark)); | ||
300 | } | 300 | } |
301 | 301 | ||
302 | } | 302 | } |
303 | 303 | ||
304 | // can't find the region: Tell viewer and abort | 304 | // can't find the region: Tell viewer and abort |
305 | remoteClient.SendTeleportFailed("The teleport destination could not be found."); | 305 | remoteClient.SendTeleportFailed("The teleport destination could not be found."); |
306 | |||
307 | } | 306 | } |
308 | 307 | ||
309 | #endregion | 308 | #endregion |
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs index d6afaa9..21d8bd7 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs | |||
@@ -64,8 +64,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests | |||
64 | IConfigSource config = new IniConfigSource(); | 64 | IConfigSource config = new IniConfigSource(); |
65 | config.AddConfig("Modules"); | 65 | config.AddConfig("Modules"); |
66 | config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); | 66 | config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); |
67 | 67 | ||
68 | m_scene = new SceneHelpers().SetupScene(); | 68 | SceneHelpers sceneHelpers = new SceneHelpers(); |
69 | m_scene = sceneHelpers.SetupScene(); | ||
69 | SceneHelpers.SetupSceneModules(m_scene, config, m_iam); | 70 | SceneHelpers.SetupSceneModules(m_scene, config, m_iam); |
70 | 71 | ||
71 | // Create user | 72 | // Create user |
@@ -76,7 +77,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests | |||
76 | 77 | ||
77 | AgentCircuitData acd = new AgentCircuitData(); | 78 | AgentCircuitData acd = new AgentCircuitData(); |
78 | acd.AgentID = m_userId; | 79 | acd.AgentID = m_userId; |
79 | m_tc = new TestClient(acd, m_scene); | 80 | m_tc = new TestClient(acd, m_scene); |
80 | } | 81 | } |
81 | 82 | ||
82 | [Test] | 83 | [Test] |
diff --git a/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs b/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs index 76f1641..9cd27f9 100644 --- a/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs | |||
@@ -39,13 +39,23 @@ namespace OpenSim.Region.Framework.Interfaces | |||
39 | 39 | ||
40 | public interface IEntityTransferModule | 40 | public interface IEntityTransferModule |
41 | { | 41 | { |
42 | void Teleport(ScenePresence agent, ulong regionHandle, Vector3 position, | 42 | /// <summary> |
43 | Vector3 lookAt, uint teleportFlags); | 43 | /// Teleport an agent within the same or to a different region. |
44 | /// </summary> | ||
45 | /// <param name='agent'></param> | ||
46 | /// <param name='regionHandle'> | ||
47 | /// The handle of the destination region. If it's the same as the region currently | ||
48 | /// occupied by the agent then the teleport will be within that region. | ||
49 | /// </param> | ||
50 | /// <param name='position'></param> | ||
51 | /// <param name='lookAt'></param> | ||
52 | /// <param name='teleportFlags'></param> | ||
53 | void Teleport(ScenePresence agent, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags); | ||
44 | 54 | ||
45 | bool TeleportHome(UUID id, IClientAPI client); | 55 | bool TeleportHome(UUID id, IClientAPI client); |
46 | 56 | ||
47 | void DoTeleport(ScenePresence sp, GridRegion reg, GridRegion finalDestination, | 57 | void DoTeleport(ScenePresence sp, GridRegion reg, GridRegion finalDestination, |
48 | Vector3 position, Vector3 lookAt, uint teleportFlags, IEventQueue eq); | 58 | Vector3 position, Vector3 lookAt, uint teleportFlags); |
49 | 59 | ||
50 | bool Cross(ScenePresence agent, bool isFlying); | 60 | bool Cross(ScenePresence agent, bool isFlying); |
51 | 61 | ||
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 3452f90..35c920b 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs | |||
@@ -3049,8 +3049,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
3049 | x = x / Constants.RegionSize; | 3049 | x = x / Constants.RegionSize; |
3050 | y = y / Constants.RegionSize; | 3050 | y = y / Constants.RegionSize; |
3051 | 3051 | ||
3052 | //m_log.Debug("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX))); | 3052 | // m_log.Debug("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX))); |
3053 | //m_log.Debug("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY))); | 3053 | // m_log.Debug("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY))); |
3054 | if (Util.IsOutsideView(DrawDistance, x, newRegionX, y, newRegionY)) | 3054 | if (Util.IsOutsideView(DrawDistance, x, newRegionX, y, newRegionY)) |
3055 | { | 3055 | { |
3056 | byebyeRegions.Add(handle); | 3056 | byebyeRegions.Add(handle); |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs index 2e46377..1aa48d7 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs | |||
@@ -128,7 +128,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
128 | IConfig config = configSource.AddConfig("Modules"); | 128 | IConfig config = configSource.AddConfig("Modules"); |
129 | config.Set("SimulationServices", "LocalSimulationConnectorModule"); | 129 | config.Set("SimulationServices", "LocalSimulationConnectorModule"); |
130 | 130 | ||
131 | TestScene scene = new SceneHelpers().SetupScene(); | 131 | SceneHelpers sceneHelpers = new SceneHelpers(); |
132 | TestScene scene = sceneHelpers.SetupScene(); | ||
132 | SceneHelpers.SetupSceneModules(scene, configSource, lsc); | 133 | SceneHelpers.SetupSceneModules(scene, configSource, lsc); |
133 | 134 | ||
134 | UUID agentId = TestHelpers.ParseTail(0x01); | 135 | UUID agentId = TestHelpers.ParseTail(0x01); |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs index c750cc5..ea4fb66 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs | |||
@@ -33,8 +33,9 @@ using OpenMetaverse; | |||
33 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
34 | using OpenSim.Framework.Communications; | 34 | using OpenSim.Framework.Communications; |
35 | using OpenSim.Framework.Servers; | 35 | using OpenSim.Framework.Servers; |
36 | using OpenSim.Region.CoreModules.Framework.EntityTransfer; | ||
37 | using OpenSim.Region.Framework.Interfaces; | 36 | using OpenSim.Region.Framework.Interfaces; |
37 | using OpenSim.Region.CoreModules.Framework; | ||
38 | using OpenSim.Region.CoreModules.Framework.EntityTransfer; | ||
38 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; | 39 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; |
39 | using OpenSim.Tests.Common; | 40 | using OpenSim.Tests.Common; |
40 | using OpenSim.Tests.Common.Mock; | 41 | using OpenSim.Tests.Common.Mock; |
@@ -49,6 +50,22 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
49 | [TestFixture] | 50 | [TestFixture] |
50 | public class ScenePresenceTeleportTests | 51 | public class ScenePresenceTeleportTests |
51 | { | 52 | { |
53 | [TestFixtureSetUp] | ||
54 | public void FixtureInit() | ||
55 | { | ||
56 | // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. | ||
57 | Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; | ||
58 | } | ||
59 | |||
60 | [TestFixtureTearDown] | ||
61 | public void TearDown() | ||
62 | { | ||
63 | // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple | ||
64 | // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression | ||
65 | // tests really shouldn't). | ||
66 | Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; | ||
67 | } | ||
68 | |||
52 | [Test] | 69 | [Test] |
53 | public void TestSameRegionTeleport() | 70 | public void TestSameRegionTeleport() |
54 | { | 71 | { |
@@ -96,10 +113,14 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
96 | LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); | 113 | LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); |
97 | 114 | ||
98 | IConfigSource config = new IniConfigSource(); | 115 | IConfigSource config = new IniConfigSource(); |
99 | config.AddConfig("Modules"); | 116 | IConfig modulesConfig = config.AddConfig("Modules"); |
100 | // Not strictly necessary since FriendsModule assumes it is the default (!) | 117 | modulesConfig.Set("EntityTransferModule", etm.Name); |
101 | config.Configs["Modules"].Set("EntityTransferModule", etm.Name); | 118 | modulesConfig.Set("SimulationServices", lscm.Name); |
102 | config.Configs["Modules"].Set("SimulationServices", lscm.Name); | 119 | IConfig entityTransferConfig = config.AddConfig("EntityTransfer"); |
120 | |||
121 | // In order to run a single threaded regression test we do not want the entity transfer module waiting | ||
122 | // for a callback from the destination scene before removing its avatar data. | ||
123 | entityTransferConfig.Set("wait_for_callback", false); | ||
103 | 124 | ||
104 | SceneHelpers sh = new SceneHelpers(); | 125 | SceneHelpers sh = new SceneHelpers(); |
105 | TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); | 126 | TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); |
@@ -110,12 +131,12 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
110 | Vector3 teleportPosition = new Vector3(10, 11, 12); | 131 | Vector3 teleportPosition = new Vector3(10, 11, 12); |
111 | Vector3 teleportLookAt = new Vector3(20, 21, 22); | 132 | Vector3 teleportLookAt = new Vector3(20, 21, 22); |
112 | 133 | ||
113 | ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId); | 134 | ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); |
114 | sp.AbsolutePosition = new Vector3(30, 31, 32); | 135 | sp.AbsolutePosition = new Vector3(30, 31, 32); |
115 | 136 | ||
116 | // XXX: A very nasty hack to tell the client about the destination scene without having to crank the whole | 137 | // XXX: A very nasty hack to tell the client about the destination scene without having to crank the whole |
117 | // UDP stack (?) | 138 | // UDP stack (?) |
118 | ((TestClient)sp.ControllingClient).TeleportTargetScene = sceneB; | 139 | // ((TestClient)sp.ControllingClient).TeleportTargetScene = sceneB; |
119 | 140 | ||
120 | sceneA.RequestTeleportLocation( | 141 | sceneA.RequestTeleportLocation( |
121 | sp.ControllingClient, | 142 | sp.ControllingClient, |
@@ -124,6 +145,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
124 | teleportLookAt, | 145 | teleportLookAt, |
125 | (uint)TeleportFlags.ViaLocation); | 146 | (uint)TeleportFlags.ViaLocation); |
126 | 147 | ||
148 | ((TestClient)sp.ControllingClient).CompleteTeleportClientSide(); | ||
149 | |||
127 | Assert.That(sceneA.GetScenePresence(userId), Is.Null); | 150 | Assert.That(sceneA.GetScenePresence(userId), Is.Null); |
128 | 151 | ||
129 | ScenePresence sceneBSp = sceneB.GetScenePresence(userId); | 152 | ScenePresence sceneBSp = sceneB.GetScenePresence(userId); |
@@ -137,5 +160,80 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
137 | // position instead). | 160 | // position instead). |
138 | // Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); | 161 | // Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); |
139 | } | 162 | } |
163 | |||
164 | [Test] | ||
165 | public void TestSameSimulatorNeighbouringRegionsTeleport() | ||
166 | { | ||
167 | TestHelpers.InMethod(); | ||
168 | // TestHelpers.EnableLogging(); | ||
169 | |||
170 | UUID userId = TestHelpers.ParseTail(0x1); | ||
171 | |||
172 | EntityTransferModule etm = new EntityTransferModule(); | ||
173 | LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); | ||
174 | |||
175 | IConfigSource config = new IniConfigSource(); | ||
176 | IConfig modulesConfig = config.AddConfig("Modules"); | ||
177 | modulesConfig.Set("EntityTransferModule", etm.Name); | ||
178 | modulesConfig.Set("SimulationServices", lscm.Name); | ||
179 | IConfig entityTransferConfig = config.AddConfig("EntityTransfer"); | ||
180 | |||
181 | // In order to run a single threaded regression test we do not want the entity transfer module waiting | ||
182 | // for a callback from the destination scene before removing its avatar data. | ||
183 | entityTransferConfig.Set("wait_for_callback", false); | ||
184 | |||
185 | SceneHelpers sh = new SceneHelpers(); | ||
186 | TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); | ||
187 | TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1001, 1000); | ||
188 | |||
189 | SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, etm, lscm); | ||
190 | SceneHelpers.SetupSceneModules(sceneA, new CapabilitiesModule()); | ||
191 | SceneHelpers.SetupSceneModules(sceneB, new CapabilitiesModule()); | ||
192 | |||
193 | Vector3 teleportPosition = new Vector3(10, 11, 12); | ||
194 | Vector3 teleportLookAt = new Vector3(20, 21, 22); | ||
195 | |||
196 | ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); | ||
197 | originalSp.AbsolutePosition = new Vector3(30, 31, 32); | ||
198 | |||
199 | ScenePresence beforeSceneASp = sceneA.GetScenePresence(userId); | ||
200 | Assert.That(beforeSceneASp, Is.Not.Null); | ||
201 | Assert.That(beforeSceneASp.IsChildAgent, Is.False); | ||
202 | |||
203 | ScenePresence beforeSceneBSp = sceneB.GetScenePresence(userId); | ||
204 | Assert.That(beforeSceneBSp, Is.Not.Null); | ||
205 | Assert.That(beforeSceneBSp.IsChildAgent, Is.True); | ||
206 | |||
207 | // XXX: A very nasty hack to tell the client about the destination scene without having to crank the whole | ||
208 | // UDP stack (?) | ||
209 | // ((TestClient)beforeSceneASp.ControllingClient).TeleportTargetScene = sceneB; | ||
210 | |||
211 | sceneA.RequestTeleportLocation( | ||
212 | beforeSceneASp.ControllingClient, | ||
213 | sceneB.RegionInfo.RegionHandle, | ||
214 | teleportPosition, | ||
215 | teleportLookAt, | ||
216 | (uint)TeleportFlags.ViaLocation); | ||
217 | |||
218 | ((TestClient)beforeSceneASp.ControllingClient).CompleteTeleportClientSide(); | ||
219 | |||
220 | ScenePresence afterSceneASp = sceneA.GetScenePresence(userId); | ||
221 | Assert.That(afterSceneASp, Is.Not.Null); | ||
222 | Assert.That(afterSceneASp.IsChildAgent, Is.True); | ||
223 | |||
224 | ScenePresence afterSceneBSp = sceneB.GetScenePresence(userId); | ||
225 | Assert.That(afterSceneBSp, Is.Not.Null); | ||
226 | Assert.That(afterSceneBSp.IsChildAgent, Is.False); | ||
227 | Assert.That(afterSceneBSp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneB.RegionInfo.RegionName)); | ||
228 | Assert.That(afterSceneBSp.AbsolutePosition, Is.EqualTo(teleportPosition)); | ||
229 | |||
230 | // TODO: Add assertions to check correct circuit details in both scenes. | ||
231 | |||
232 | // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera | ||
233 | // position instead). | ||
234 | // Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); | ||
235 | |||
236 | // TestHelpers.DisableLogging(); | ||
237 | } | ||
140 | } | 238 | } |
141 | } \ No newline at end of file | 239 | } \ No newline at end of file |
diff --git a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs index 8e54707..dc24418 100644 --- a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs | |||
@@ -58,6 +58,11 @@ namespace OpenSim.Tests.Common | |||
58 | /// </summary> | 58 | /// </summary> |
59 | public class SceneHelpers | 59 | public class SceneHelpers |
60 | { | 60 | { |
61 | /// <summary> | ||
62 | /// We need a scene manager so that test clients can retrieve a scene when performing teleport tests. | ||
63 | /// </summary> | ||
64 | public SceneManager SceneManager { get; private set; } | ||
65 | |||
61 | private AgentCircuitManager m_acm = new AgentCircuitManager(); | 66 | private AgentCircuitManager m_acm = new AgentCircuitManager(); |
62 | private ISimulationDataService m_simDataService | 67 | private ISimulationDataService m_simDataService |
63 | = OpenSim.Server.Base.ServerUtils.LoadPlugin<ISimulationDataService>("OpenSim.Tests.Common.dll", null); | 68 | = OpenSim.Server.Base.ServerUtils.LoadPlugin<ISimulationDataService>("OpenSim.Tests.Common.dll", null); |
@@ -76,6 +81,8 @@ namespace OpenSim.Tests.Common | |||
76 | 81 | ||
77 | public SceneHelpers(CoreAssetCache cache) | 82 | public SceneHelpers(CoreAssetCache cache) |
78 | { | 83 | { |
84 | SceneManager = new SceneManager(); | ||
85 | |||
79 | m_assetService = StartAssetService(cache); | 86 | m_assetService = StartAssetService(cache); |
80 | m_authenticationService = StartAuthenticationService(); | 87 | m_authenticationService = StartAuthenticationService(); |
81 | m_inventoryService = StartInventoryService(); | 88 | m_inventoryService = StartInventoryService(); |
@@ -186,6 +193,8 @@ namespace OpenSim.Tests.Common | |||
186 | testScene.LoginsDisabled = false; | 193 | testScene.LoginsDisabled = false; |
187 | testScene.RegisterRegionWithGrid(); | 194 | testScene.RegisterRegionWithGrid(); |
188 | 195 | ||
196 | SceneManager.Add(testScene); | ||
197 | |||
189 | return testScene; | 198 | return testScene; |
190 | } | 199 | } |
191 | 200 | ||
@@ -350,6 +359,7 @@ namespace OpenSim.Tests.Common | |||
350 | List<IRegionModuleBase> newModules = new List<IRegionModuleBase>(); | 359 | List<IRegionModuleBase> newModules = new List<IRegionModuleBase>(); |
351 | foreach (object module in modules) | 360 | foreach (object module in modules) |
352 | { | 361 | { |
362 | // Console.WriteLine("MODULE RAW {0}", module); | ||
353 | if (module is IRegionModule) | 363 | if (module is IRegionModule) |
354 | { | 364 | { |
355 | IRegionModule m = (IRegionModule)module; | 365 | IRegionModule m = (IRegionModule)module; |
@@ -367,6 +377,7 @@ namespace OpenSim.Tests.Common | |||
367 | // for the new system, everything has to be initialised first, | 377 | // for the new system, everything has to be initialised first, |
368 | // shared modules have to be post-initialised, then all get an AddRegion with the scene | 378 | // shared modules have to be post-initialised, then all get an AddRegion with the scene |
369 | IRegionModuleBase m = (IRegionModuleBase)module; | 379 | IRegionModuleBase m = (IRegionModuleBase)module; |
380 | // Console.WriteLine("MODULE {0}", m.Name); | ||
370 | m.Initialise(config); | 381 | m.Initialise(config); |
371 | newModules.Add(m); | 382 | newModules.Add(m); |
372 | } | 383 | } |
@@ -426,6 +437,10 @@ namespace OpenSim.Tests.Common | |||
426 | /// <summary> | 437 | /// <summary> |
427 | /// Add a root agent where the details of the agent connection (apart from the id) are unimportant for the test | 438 | /// Add a root agent where the details of the agent connection (apart from the id) are unimportant for the test |
428 | /// </summary> | 439 | /// </summary> |
440 | /// <remarks> | ||
441 | /// This can be used for tests where there is only one region or where there are multiple non-neighbour regions | ||
442 | /// and teleport doesn't take place. | ||
443 | /// </remarks> | ||
429 | /// <param name="scene"></param> | 444 | /// <param name="scene"></param> |
430 | /// <param name="agentId"></param> | 445 | /// <param name="agentId"></param> |
431 | /// <returns></returns> | 446 | /// <returns></returns> |
@@ -435,6 +450,18 @@ namespace OpenSim.Tests.Common | |||
435 | } | 450 | } |
436 | 451 | ||
437 | /// <summary> | 452 | /// <summary> |
453 | /// Add a root agent where the details of the agent connection (apart from the id) are unimportant for the test | ||
454 | /// </summary> | ||
455 | /// <param name="scene"></param> | ||
456 | /// <param name="agentId"></param> | ||
457 | /// <param name="sceneManager"></param> | ||
458 | /// <returns></returns> | ||
459 | public static ScenePresence AddScenePresence(Scene scene, UUID agentId, SceneManager sceneManager) | ||
460 | { | ||
461 | return AddScenePresence(scene, GenerateAgentData(agentId), sceneManager); | ||
462 | } | ||
463 | |||
464 | /// <summary> | ||
438 | /// Add a root agent. | 465 | /// Add a root agent. |
439 | /// </summary> | 466 | /// </summary> |
440 | /// <remarks> | 467 | /// <remarks> |
@@ -454,6 +481,30 @@ namespace OpenSim.Tests.Common | |||
454 | /// <returns></returns> | 481 | /// <returns></returns> |
455 | public static ScenePresence AddScenePresence(Scene scene, AgentCircuitData agentData) | 482 | public static ScenePresence AddScenePresence(Scene scene, AgentCircuitData agentData) |
456 | { | 483 | { |
484 | return AddScenePresence(scene, agentData, null); | ||
485 | } | ||
486 | |||
487 | /// <summary> | ||
488 | /// Add a root agent. | ||
489 | /// </summary> | ||
490 | /// <remarks> | ||
491 | /// This function | ||
492 | /// | ||
493 | /// 1) Tells the scene that an agent is coming. Normally, the login service (local if standalone, from the | ||
494 | /// userserver if grid) would give initial login data back to the client and separately tell the scene that the | ||
495 | /// agent was coming. | ||
496 | /// | ||
497 | /// 2) Connects the agent with the scene | ||
498 | /// | ||
499 | /// This function performs actions equivalent with notifying the scene that an agent is | ||
500 | /// coming and then actually connecting the agent to the scene. The one step missed out is the very first | ||
501 | /// </remarks> | ||
502 | /// <param name="scene"></param> | ||
503 | /// <param name="agentData"></param> | ||
504 | /// <param name="sceneManager"></param> | ||
505 | /// <returns></returns> | ||
506 | public static ScenePresence AddScenePresence(Scene scene, AgentCircuitData agentData, SceneManager sceneManager) | ||
507 | { | ||
457 | // We emulate the proper login sequence here by doing things in four stages | 508 | // We emulate the proper login sequence here by doing things in four stages |
458 | 509 | ||
459 | // Stage 0: login | 510 | // Stage 0: login |
@@ -463,7 +514,7 @@ namespace OpenSim.Tests.Common | |||
463 | lpsc.m_PresenceService.LoginAgent(agentData.AgentID.ToString(), agentData.SessionID, agentData.SecureSessionID); | 514 | lpsc.m_PresenceService.LoginAgent(agentData.AgentID.ToString(), agentData.SessionID, agentData.SecureSessionID); |
464 | 515 | ||
465 | // Stages 1 & 2 | 516 | // Stages 1 & 2 |
466 | ScenePresence sp = IntroduceClientToScene(scene, agentData, TeleportFlags.ViaLogin); | 517 | ScenePresence sp = IntroduceClientToScene(scene, sceneManager, agentData, TeleportFlags.ViaLogin); |
467 | 518 | ||
468 | // Stage 3: Complete the entrance into the region. This converts the child agent into a root agent. | 519 | // Stage 3: Complete the entrance into the region. This converts the child agent into a root agent. |
469 | sp.CompleteMovement(sp.ControllingClient, true); | 520 | sp.CompleteMovement(sp.ControllingClient, true); |
@@ -471,7 +522,20 @@ namespace OpenSim.Tests.Common | |||
471 | return sp; | 522 | return sp; |
472 | } | 523 | } |
473 | 524 | ||
474 | private static ScenePresence IntroduceClientToScene(Scene scene, AgentCircuitData agentData, TeleportFlags tf) | 525 | /// <summary> |
526 | /// Introduce an agent into the scene by adding a new client. | ||
527 | /// </summary> | ||
528 | /// <returns>The scene presence added</returns> | ||
529 | /// <param name='sceneManager'> | ||
530 | /// Scene manager. Can be null if there is only one region in the test or multiple regions that are not | ||
531 | /// neighbours and where no teleporting takes place. | ||
532 | /// </param> | ||
533 | /// <param name='scene'></param> | ||
534 | /// <param name='sceneManager></param> | ||
535 | /// <param name='agentData'></param> | ||
536 | /// <param name='tf'></param> | ||
537 | private static ScenePresence IntroduceClientToScene( | ||
538 | Scene scene, SceneManager sceneManager, AgentCircuitData agentData, TeleportFlags tf) | ||
475 | { | 539 | { |
476 | string reason; | 540 | string reason; |
477 | 541 | ||
@@ -480,7 +544,7 @@ namespace OpenSim.Tests.Common | |||
480 | Console.WriteLine("NewUserConnection failed: " + reason); | 544 | Console.WriteLine("NewUserConnection failed: " + reason); |
481 | 545 | ||
482 | // Stage 2: add the new client as a child agent to the scene | 546 | // Stage 2: add the new client as a child agent to the scene |
483 | TestClient client = new TestClient(agentData, scene); | 547 | TestClient client = new TestClient(agentData, scene, sceneManager); |
484 | scene.AddNewClient(client, PresenceType.User); | 548 | scene.AddNewClient(client, PresenceType.User); |
485 | 549 | ||
486 | return scene.GetScenePresence(agentData.AgentID); | 550 | return scene.GetScenePresence(agentData.AgentID); |
@@ -492,7 +556,7 @@ namespace OpenSim.Tests.Common | |||
492 | acd.child = true; | 556 | acd.child = true; |
493 | 557 | ||
494 | // XXX: ViaLogin may not be correct for child agents | 558 | // XXX: ViaLogin may not be correct for child agents |
495 | return IntroduceClientToScene(scene, acd, TeleportFlags.ViaLogin); | 559 | return IntroduceClientToScene(scene, null, acd, TeleportFlags.ViaLogin); |
496 | } | 560 | } |
497 | 561 | ||
498 | /// <summary> | 562 | /// <summary> |
diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index 6a7cb0a..8cedebb 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs | |||
@@ -46,12 +46,10 @@ namespace OpenSim.Tests.Common.Mock | |||
46 | 46 | ||
47 | EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing"); | 47 | EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing"); |
48 | 48 | ||
49 | // TODO: This is a really nasty (and temporary) means of telling the test client which scene to invoke setup | ||
50 | // methods on when a teleport is requested | ||
51 | public Scene TeleportTargetScene; | ||
52 | private TestClient TeleportSceneClient; | 49 | private TestClient TeleportSceneClient; |
53 | 50 | ||
54 | private Scene m_scene; | 51 | private Scene m_scene; |
52 | private SceneManager m_sceneManager; | ||
55 | 53 | ||
56 | // Properties so that we can get at received data for test purposes | 54 | // Properties so that we can get at received data for test purposes |
57 | public List<UUID> ReceivedOfflineNotifications { get; private set; } | 55 | public List<UUID> ReceivedOfflineNotifications { get; private set; } |
@@ -434,15 +432,29 @@ namespace OpenSim.Tests.Common.Mock | |||
434 | /// <summary> | 432 | /// <summary> |
435 | /// Constructor | 433 | /// Constructor |
436 | /// </summary> | 434 | /// </summary> |
435 | /// <remarks> | ||
436 | /// Can be used for a test where there is only one region or where there are multiple regions that are not | ||
437 | /// neighbours and where no teleporting takes place. In other situations, the constructor that takes in a | ||
438 | /// scene manager should be used. | ||
439 | /// </remarks> | ||
437 | /// <param name="agentData"></param> | 440 | /// <param name="agentData"></param> |
438 | /// <param name="scene"></param> | 441 | /// <param name="scene"></param> |
439 | public TestClient(AgentCircuitData agentData, Scene scene) | 442 | public TestClient(AgentCircuitData agentData, Scene scene) : this(agentData, scene, null) {} |
443 | |||
444 | /// <summary> | ||
445 | /// Constructor | ||
446 | /// </summary> | ||
447 | /// <param name="agentData"></param> | ||
448 | /// <param name="scene"></param> | ||
449 | /// <param name="sceneManager"></param> | ||
450 | public TestClient(AgentCircuitData agentData, Scene scene, SceneManager sceneManager) | ||
440 | { | 451 | { |
441 | m_agentId = agentData.AgentID; | 452 | m_agentId = agentData.AgentID; |
442 | m_firstName = agentData.firstname; | 453 | m_firstName = agentData.firstname; |
443 | m_lastName = agentData.lastname; | 454 | m_lastName = agentData.lastname; |
444 | m_circuitCode = agentData.circuitcode; | 455 | m_circuitCode = agentData.circuitcode; |
445 | m_scene = scene; | 456 | m_scene = scene; |
457 | m_sceneManager = sceneManager; | ||
446 | SessionId = agentData.SessionID; | 458 | SessionId = agentData.SessionID; |
447 | SecureSessionId = agentData.SecureSessionID; | 459 | SecureSessionId = agentData.SecureSessionID; |
448 | CapsSeedUrl = agentData.CapsPath; | 460 | CapsSeedUrl = agentData.CapsPath; |
@@ -592,8 +604,16 @@ namespace OpenSim.Tests.Common.Mock | |||
592 | AgentCircuitData newAgent = RequestClientInfo(); | 604 | AgentCircuitData newAgent = RequestClientInfo(); |
593 | 605 | ||
594 | // Stage 2: add the new client as a child agent to the scene | 606 | // Stage 2: add the new client as a child agent to the scene |
595 | TeleportSceneClient = new TestClient(newAgent, TeleportTargetScene); | 607 | uint x, y; |
596 | TeleportTargetScene.AddNewClient(TeleportSceneClient, PresenceType.User); | 608 | Utils.LongToUInts(neighbourHandle, out x, out y); |
609 | x /= Constants.RegionSize; | ||
610 | y /= Constants.RegionSize; | ||
611 | |||
612 | Scene neighbourScene; | ||
613 | m_sceneManager.TryGetScene(x, y, out neighbourScene); | ||
614 | |||
615 | TeleportSceneClient = new TestClient(newAgent, neighbourScene, m_sceneManager); | ||
616 | neighbourScene.AddNewClient(TeleportSceneClient, PresenceType.User); | ||
597 | } | 617 | } |
598 | 618 | ||
599 | public virtual void SendRegionTeleport(ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, | 619 | public virtual void SendRegionTeleport(ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, |
@@ -603,6 +623,13 @@ namespace OpenSim.Tests.Common.Mock | |||
603 | 623 | ||
604 | CapsSeedUrl = capsURL; | 624 | CapsSeedUrl = capsURL; |
605 | 625 | ||
626 | // We don't do this here so that the source region can complete processing first in a single-threaded | ||
627 | // regression test scenario. The test itself will have to call CompleteTeleportClientSide() after a teleport | ||
628 | // CompleteTeleportClientSide(); | ||
629 | } | ||
630 | |||
631 | public void CompleteTeleportClientSide() | ||
632 | { | ||
606 | TeleportSceneClient.CompleteMovement(); | 633 | TeleportSceneClient.CompleteMovement(); |
607 | //TeleportTargetScene.AgentCrossing(newAgent.AgentID, new Vector3(90, 90, 90), false); | 634 | //TeleportTargetScene.AgentCrossing(newAgent.AgentID, new Vector3(90, 90, 90), false); |
608 | } | 635 | } |
diff --git a/OpenSim/Tests/Common/TestHelpers.cs b/OpenSim/Tests/Common/TestHelpers.cs index 5030d4b..6744fca 100644 --- a/OpenSim/Tests/Common/TestHelpers.cs +++ b/OpenSim/Tests/Common/TestHelpers.cs | |||
@@ -46,7 +46,8 @@ namespace OpenSim.Tests.Common | |||
46 | <!-- A1 uses PatternLayout --> | 46 | <!-- A1 uses PatternLayout --> |
47 | <layout type=""log4net.Layout.PatternLayout""> | 47 | <layout type=""log4net.Layout.PatternLayout""> |
48 | <!-- Print the date in ISO 8601 format --> | 48 | <!-- Print the date in ISO 8601 format --> |
49 | <conversionPattern value=""%date [%thread] %-5level %logger %ndc - %message%newline"" /> | 49 | <!-- <conversionPattern value=""%date [%thread] %-5level %logger %ndc - %message%newline"" /> --> |
50 | <conversionPattern value=""%date %message%newline"" /> | ||
50 | </layout> | 51 | </layout> |
51 | </appender> | 52 | </appender> |
52 | 53 | ||
@@ -62,9 +63,9 @@ namespace OpenSim.Tests.Common | |||
62 | Encoding.UTF8.GetBytes( | 63 | Encoding.UTF8.GetBytes( |
63 | // "<?xml version=\"1.0\" encoding=\"utf-8\" ?><configuration><log4net><root><level value=\"OFF\"/><appender-ref ref=\"A1\"/></root></log4net></configuration>"))); | 64 | // "<?xml version=\"1.0\" encoding=\"utf-8\" ?><configuration><log4net><root><level value=\"OFF\"/><appender-ref ref=\"A1\"/></root></log4net></configuration>"))); |
64 | //"<?xml version=\"1.0\" encoding=\"utf-8\" ?><configuration><log4net><root><level value=\"OFF\"/></root></log4net></configuration>"))); | 65 | //"<?xml version=\"1.0\" encoding=\"utf-8\" ?><configuration><log4net><root><level value=\"OFF\"/></root></log4net></configuration>"))); |
65 | //"<configuration><log4net><root><level value=\"OFF\"/></root></log4net></configuration>"))); | 66 | // "<configuration><log4net><root><level value=\"OFF\"/></root></log4net></configuration>")); |
66 | //"<configuration><log4net><root></root></log4net></configuration>"))); | 67 | // "<configuration><log4net><root></root></log4net></configuration>"))); |
67 | //"<configuration><log4net><root/></log4net></configuration>"))); | 68 | // "<configuration><log4net><root/></log4net></configuration>")); |
68 | "<log4net><root/></log4net>")); | 69 | "<log4net><root/></log4net>")); |
69 | 70 | ||
70 | public static bool AssertThisDelegateCausesArgumentException(TestDelegate d) | 71 | public static bool AssertThisDelegateCausesArgumentException(TestDelegate d) |