aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Framework/EntityTransfer
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/CoreModules/Framework/EntityTransfer')
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs1600
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs273
2 files changed, 1873 insertions, 0 deletions
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
new file mode 100644
index 0000000..53de269
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -0,0 +1,1600 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Net;
31using System.Reflection;
32using System.Threading;
33
34using OpenSim.Framework;
35using OpenSim.Framework.Capabilities;
36using OpenSim.Framework.Client;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Services.Interfaces;
40
41using GridRegion = OpenSim.Services.Interfaces.GridRegion;
42
43using OpenMetaverse;
44using log4net;
45using Nini.Config;
46
47namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
48{
49 public class EntityTransferModule : ISharedRegionModule, IEntityTransferModule
50 {
51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52
53 protected bool m_Enabled = false;
54 protected Scene m_aScene;
55 protected List<UUID> m_agentsInTransit;
56
57 #region ISharedRegionModule
58
59 public Type ReplaceableInterface
60 {
61 get { return null; }
62 }
63
64 public virtual string Name
65 {
66 get { return "BasicEntityTransferModule"; }
67 }
68
69 public virtual void Initialise(IConfigSource source)
70 {
71 IConfig moduleConfig = source.Configs["Modules"];
72 if (moduleConfig != null)
73 {
74 string name = moduleConfig.GetString("EntityTransferModule", "");
75 if (name == Name)
76 {
77 m_agentsInTransit = new List<UUID>();
78 m_Enabled = true;
79 m_log.InfoFormat("[ENTITY TRANSFER MODULE]: {0} enabled.", Name);
80 }
81 }
82 }
83
84 public virtual void PostInitialise()
85 {
86 }
87
88 public virtual void AddRegion(Scene scene)
89 {
90 if (!m_Enabled)
91 return;
92
93 if (m_aScene == null)
94 m_aScene = scene;
95
96 scene.RegisterModuleInterface<IEntityTransferModule>(this);
97 scene.EventManager.OnNewClient += OnNewClient;
98 }
99
100 protected virtual void OnNewClient(IClientAPI client)
101 {
102 client.OnTeleportHomeRequest += TeleportHome;
103 }
104
105 public virtual void Close()
106 {
107 if (!m_Enabled)
108 return;
109 }
110
111
112 public virtual void RemoveRegion(Scene scene)
113 {
114 if (!m_Enabled)
115 return;
116 if (scene == m_aScene)
117 m_aScene = null;
118 }
119
120 public virtual void RegionLoaded(Scene scene)
121 {
122 if (!m_Enabled)
123 return;
124
125 }
126
127
128 #endregion
129
130 #region Agent Teleports
131
132 public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags)
133 {
134 if (!sp.Scene.Permissions.CanTeleport(sp.UUID))
135 return;
136
137 IEventQueue eq = sp.Scene.RequestModuleInterface<IEventQueue>();
138
139 // Reset animations; the viewer does that in teleports.
140 sp.Animator.ResetAnimations();
141
142 try
143 {
144 if (regionHandle == sp.Scene.RegionInfo.RegionHandle)
145 {
146 m_log.DebugFormat(
147 "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation {0} within {1}",
148 position, sp.Scene.RegionInfo.RegionName);
149
150 // Teleport within the same region
151 if (IsOutsideRegion(sp.Scene, position) || position.Z < 0)
152 {
153 Vector3 emergencyPos = new Vector3(128, 128, 128);
154
155 m_log.WarnFormat(
156 "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}",
157 position, sp.Name, sp.UUID, emergencyPos);
158 position = emergencyPos;
159 }
160
161 // TODO: Get proper AVG Height
162 float localAVHeight = 1.56f;
163 float posZLimit = 22;
164
165 // TODO: Check other Scene HeightField
166 if (position.X > 0 && position.X <= (int)Constants.RegionSize && position.Y > 0 && position.Y <= (int)Constants.RegionSize)
167 {
168 posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y];
169 }
170
171 float newPosZ = posZLimit + localAVHeight;
172 if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ)))
173 {
174 position.Z = newPosZ;
175 }
176
177 // Only send this if the event queue is null
178 if (eq == null)
179 sp.ControllingClient.SendTeleportLocationStart();
180
181 sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags);
182 sp.Teleport(position);
183 }
184 else // Another region possibly in another simulator
185 {
186 uint x = 0, y = 0;
187 Utils.LongToUInts(regionHandle, out x, out y);
188 GridRegion reg = m_aScene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y);
189
190 if (reg != null)
191 {
192 GridRegion finalDestination = GetFinalDestination(reg);
193 if (finalDestination == null)
194 {
195 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final destination is having problems. Unable to teleport agent.");
196 sp.ControllingClient.SendTeleportFailed("Problem at destination");
197 return;
198 }
199 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final destination is x={0} y={1} uuid={2}",
200 finalDestination.RegionLocX / Constants.RegionSize, finalDestination.RegionLocY / Constants.RegionSize, finalDestination.RegionID);
201
202 //
203 // This is it
204 //
205 DoTeleport(sp, reg, finalDestination, position, lookAt, teleportFlags, eq);
206 //
207 //
208 //
209 }
210 else
211 {
212 // TP to a place that doesn't exist (anymore)
213 // Inform the viewer about that
214 sp.ControllingClient.SendTeleportFailed("The region you tried to teleport to doesn't exist anymore");
215
216 // and set the map-tile to '(Offline)'
217 uint regX, regY;
218 Utils.LongToUInts(regionHandle, out regX, out regY);
219
220 MapBlockData block = new MapBlockData();
221 block.X = (ushort)(regX / Constants.RegionSize);
222 block.Y = (ushort)(regY / Constants.RegionSize);
223 block.Access = 254; // == not there
224
225 List<MapBlockData> blocks = new List<MapBlockData>();
226 blocks.Add(block);
227 sp.ControllingClient.SendMapBlock(blocks, 0);
228 }
229 }
230 }
231 catch (Exception e)
232 {
233 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Exception on teleport: {0}\n{1}", e.Message, e.StackTrace);
234 sp.ControllingClient.SendTeleportFailed("Internal error");
235 }
236 }
237
238 protected void DoTeleport(ScenePresence sp, GridRegion reg, GridRegion finalDestination, Vector3 position, Vector3 lookAt, uint teleportFlags, IEventQueue eq)
239 {
240 if (reg == null || finalDestination == null)
241 {
242 sp.ControllingClient.SendTeleportFailed("Unable to locate destination");
243 return;
244 }
245
246 m_log.DebugFormat(
247 "[ENTITY TRANSFER MODULE]: Request Teleport to {0}:{1}:{2}/{3}",
248 reg.ExternalHostName, reg.HttpPort, finalDestination.RegionName, position);
249
250 uint newRegionX = (uint)(reg.RegionHandle >> 40);
251 uint newRegionY = (((uint)(reg.RegionHandle)) >> 8);
252 uint oldRegionX = (uint)(sp.Scene.RegionInfo.RegionHandle >> 40);
253 uint oldRegionY = (((uint)(sp.Scene.RegionInfo.RegionHandle)) >> 8);
254
255 ulong destinationHandle = finalDestination.RegionHandle;
256
257 if (eq == null)
258 sp.ControllingClient.SendTeleportLocationStart();
259
260 // Let's do DNS resolution only once in this process, please!
261 // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field,
262 // it's actually doing a lot of work.
263 IPEndPoint endPoint = finalDestination.ExternalEndPoint;
264 if (endPoint.Address != null)
265 {
266 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from
267 // both regions
268 if (sp.ParentID != (uint)0)
269 sp.StandUp();
270
271 if (!sp.ValidateAttachments())
272 {
273 sp.ControllingClient.SendTeleportFailed("Inconsistent attachment state");
274 return;
275 }
276
277 // the avatar.Close below will clear the child region list. We need this below for (possibly)
278 // closing the child agents, so save it here (we need a copy as it is Clear()-ed).
279 //List<ulong> childRegions = new List<ulong>(avatar.GetKnownRegionList());
280 // Compared to ScenePresence.CrossToNewRegion(), there's no obvious code to handle a teleport
281 // failure at this point (unlike a border crossing failure). So perhaps this can never fail
282 // once we reach here...
283 //avatar.Scene.RemoveCapsHandler(avatar.UUID);
284
285 string capsPath = String.Empty;
286
287 AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
288 AgentCircuitData agentCircuit = sp.ControllingClient.RequestClientInfo();
289 agentCircuit.startpos = position;
290 agentCircuit.child = true;
291 agentCircuit.Appearance = sp.Appearance;
292 if (currentAgentCircuit != null)
293 agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs;
294
295 if (NeedsNewAgent(oldRegionX, newRegionX, oldRegionY, newRegionY))
296 {
297 // brand new agent, let's create a new caps seed
298 agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath();
299 }
300
301 string reason = String.Empty;
302
303 // Let's create an agent there if one doesn't exist yet.
304 if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason))
305 {
306 sp.ControllingClient.SendTeleportFailed(String.Format("Destination refused: {0}",
307 reason));
308 return;
309 }
310
311 // OK, it got this agent. Let's close some child agents
312 sp.CloseChildAgents(newRegionX, newRegionY);
313
314 if (NeedsNewAgent(oldRegionX, newRegionX, oldRegionY, newRegionY))
315 {
316 #region IP Translation for NAT
317 IClientIPEndpoint ipepClient;
318 if (sp.ClientView.TryGet(out ipepClient))
319 {
320 capsPath
321 = "http://"
322 + NetworkUtil.GetHostFor(ipepClient.EndPoint, finalDestination.ExternalHostName)
323 + ":"
324 + finalDestination.HttpPort
325 + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
326 }
327 else
328 {
329 capsPath
330 = "http://"
331 + finalDestination.ExternalHostName
332 + ":"
333 + finalDestination.HttpPort
334 + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
335 }
336 #endregion
337
338 if (eq != null)
339 {
340 #region IP Translation for NAT
341 // Uses ipepClient above
342 if (sp.ClientView.TryGet(out ipepClient))
343 {
344 endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address);
345 }
346 #endregion
347
348 eq.EnableSimulator(destinationHandle, endPoint, sp.UUID);
349
350 // ES makes the client send a UseCircuitCode message to the destination,
351 // which triggers a bunch of things there.
352 // So let's wait
353 Thread.Sleep(200);
354
355 eq.EstablishAgentCommunication(sp.UUID, endPoint, capsPath);
356
357 }
358 else
359 {
360 sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint);
361 }
362 }
363 else
364 {
365 agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle);
366 capsPath = "http://" + finalDestination.ExternalHostName + ":" + finalDestination.HttpPort
367 + "/CAPS/" + agentCircuit.CapsPath + "0000/";
368 }
369
370 // Expect avatar crossing is a heavy-duty function at the destination.
371 // That is where MakeRoot is called, which fetches appearance and inventory.
372 // Plus triggers OnMakeRoot, which spawns a series of asynchronous updates.
373 //m_commsProvider.InterRegion.ExpectAvatarCrossing(reg.RegionHandle, avatar.ControllingClient.AgentId,
374 // position, false);
375
376 //{
377 // avatar.ControllingClient.SendTeleportFailed("Problem with destination.");
378 // // We should close that agent we just created over at destination...
379 // List<ulong> lst = new List<ulong>();
380 // lst.Add(reg.RegionHandle);
381 // SendCloseChildAgentAsync(avatar.UUID, lst);
382 // return;
383 //}
384
385 SetInTransit(sp.UUID);
386
387 // Let's send a full update of the agent. This is a synchronous call.
388 AgentData agent = new AgentData();
389 sp.CopyTo(agent);
390 agent.Position = position;
391 SetCallbackURL(agent, sp.Scene.RegionInfo);
392
393 UpdateAgent(reg, finalDestination, agent);
394
395 m_log.DebugFormat(
396 "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, sp.UUID);
397
398
399 if (eq != null)
400 {
401 eq.TeleportFinishEvent(destinationHandle, 13, endPoint,
402 0, teleportFlags, capsPath, sp.UUID);
403 }
404 else
405 {
406 sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4,
407 teleportFlags, capsPath);
408 }
409
410 // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which
411 // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation
412 // that the client contacted the destination before we send the attachments and close things here.
413 if (!WaitForCallback(sp.UUID))
414 {
415 // Client never contacted destination. Let's restore everything back
416 sp.ControllingClient.SendTeleportFailed("Problems connecting to destination.");
417
418 ResetFromTransit(sp.UUID);
419
420 // Yikes! We should just have a ref to scene here.
421 //sp.Scene.InformClientOfNeighbours(sp);
422 EnableChildAgents(sp);
423
424 // Finally, kill the agent we just created at the destination.
425 m_aScene.SimulationService.CloseAgent(finalDestination, sp.UUID);
426
427 return;
428 }
429
430
431 // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it
432 CrossAttachmentsIntoNewRegion(finalDestination, sp, true);
433
434 KillEntity(sp.Scene, sp.LocalId);
435
436 sp.MakeChildAgent();
437 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
438
439 if (NeedsClosing(oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
440 {
441 Thread.Sleep(5000);
442 sp.Close();
443 sp.Scene.IncomingCloseAgent(sp.UUID);
444 }
445 else
446 // now we have a child agent in this region.
447 sp.Reset();
448
449
450 // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
451 if (sp.Scene.NeedSceneCacheClear(sp.UUID))
452 {
453 m_log.DebugFormat(
454 "[ENTITY TRANSFER MODULE]: User {0} is going to another region, profile cache removed",
455 sp.UUID);
456 }
457 }
458 else
459 {
460 sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down");
461 }
462 }
463
464
465 protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason)
466 {
467 return m_aScene.SimulationService.CreateAgent(finalDestination, agentCircuit, teleportFlags, out reason);
468 }
469
470 protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent)
471 {
472 return m_aScene.SimulationService.UpdateAgent(finalDestination, agent);
473 }
474
475 protected virtual void SetCallbackURL(AgentData agent, RegionInfo region)
476 {
477 agent.CallbackURI = "http://" + region.ExternalHostName + ":" + region.HttpPort +
478 "/agent/" + agent.AgentID.ToString() + "/" + region.RegionID.ToString() + "/release/";
479
480 }
481
482 protected void KillEntity(Scene scene, uint localID)
483 {
484 scene.SendKillObject(localID);
485 }
486
487 protected virtual GridRegion GetFinalDestination(GridRegion region)
488 {
489 return region;
490 }
491
492 protected virtual bool NeedsNewAgent(uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY)
493 {
494 return Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY);
495 }
496
497 protected virtual bool NeedsClosing(uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg)
498 {
499 return Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY);
500 }
501
502 protected virtual bool IsOutsideRegion(Scene s, Vector3 pos)
503 {
504
505 if (s.TestBorderCross(pos, Cardinals.N))
506 return true;
507 if (s.TestBorderCross(pos, Cardinals.S))
508 return true;
509 if (s.TestBorderCross(pos, Cardinals.E))
510 return true;
511 if (s.TestBorderCross(pos, Cardinals.W))
512 return true;
513
514 return false;
515 }
516
517
518 #endregion
519
520 #region Teleport Home
521
522 public virtual void TeleportHome(UUID id, IClientAPI client)
523 {
524 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.FirstName, client.LastName);
525
526 OpenSim.Services.Interfaces.PresenceInfo pinfo = m_aScene.PresenceService.GetAgent(client.SessionId);
527
528 if (pinfo != null)
529 {
530 GridRegion regionInfo = m_aScene.GridService.GetRegionByUUID(UUID.Zero, pinfo.HomeRegionID);
531 if (regionInfo == null)
532 {
533 // can't find the Home region: Tell viewer and abort
534 client.SendTeleportFailed("Your home region could not be found.");
535 return;
536 }
537 // a little eekie that this goes back to Scene and with a forced cast, will fix that at some point...
538 ((Scene)(client.Scene)).RequestTeleportLocation(
539 client, regionInfo.RegionHandle, pinfo.HomePosition, pinfo.HomeLookAt,
540 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome));
541 }
542 }
543
544 #endregion
545
546
547 #region Agent Crossings
548
549 public void Cross(ScenePresence agent, bool isFlying)
550 {
551 Scene scene = agent.Scene;
552 Vector3 pos = agent.AbsolutePosition;
553 Vector3 newpos = new Vector3(pos.X, pos.Y, pos.Z);
554 uint neighbourx = scene.RegionInfo.RegionLocX;
555 uint neighboury = scene.RegionInfo.RegionLocY;
556 const float boundaryDistance = 1.7f;
557 Vector3 northCross = new Vector3(0, boundaryDistance, 0);
558 Vector3 southCross = new Vector3(0, -1 * boundaryDistance, 0);
559 Vector3 eastCross = new Vector3(boundaryDistance, 0, 0);
560 Vector3 westCross = new Vector3(-1 * boundaryDistance, 0, 0);
561
562 // distance to edge that will trigger crossing
563
564
565 // distance into new region to place avatar
566 const float enterDistance = 0.5f;
567
568 if (scene.TestBorderCross(pos + westCross, Cardinals.W))
569 {
570 if (scene.TestBorderCross(pos + northCross, Cardinals.N))
571 {
572 Border b = scene.GetCrossedBorder(pos + northCross, Cardinals.N);
573 neighboury += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize);
574 }
575 else if (scene.TestBorderCross(pos + southCross, Cardinals.S))
576 {
577 Border b = scene.GetCrossedBorder(pos + southCross, Cardinals.S);
578 if (b.TriggerRegionX == 0 && b.TriggerRegionY == 0)
579 {
580 neighboury--;
581 newpos.Y = Constants.RegionSize - enterDistance;
582 }
583 else
584 {
585 neighboury = b.TriggerRegionY;
586 neighbourx = b.TriggerRegionX;
587
588 Vector3 newposition = pos;
589 newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize;
590 newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize;
591 agent.ControllingClient.SendAgentAlertMessage(
592 String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false);
593 InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene);
594 return;
595 }
596 }
597
598 Border ba = scene.GetCrossedBorder(pos + westCross, Cardinals.W);
599 if (ba.TriggerRegionX == 0 && ba.TriggerRegionY == 0)
600 {
601 neighbourx--;
602 newpos.X = Constants.RegionSize - enterDistance;
603 }
604 else
605 {
606 neighboury = ba.TriggerRegionY;
607 neighbourx = ba.TriggerRegionX;
608
609
610 Vector3 newposition = pos;
611 newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize;
612 newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize;
613 agent.ControllingClient.SendAgentAlertMessage(
614 String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false);
615 InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene);
616
617
618 return;
619 }
620
621 }
622 else if (scene.TestBorderCross(pos + eastCross, Cardinals.E))
623 {
624 Border b = scene.GetCrossedBorder(pos + eastCross, Cardinals.E);
625 neighbourx += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize);
626 newpos.X = enterDistance;
627
628 if (scene.TestBorderCross(pos + southCross, Cardinals.S))
629 {
630 Border ba = scene.GetCrossedBorder(pos + southCross, Cardinals.S);
631 if (ba.TriggerRegionX == 0 && ba.TriggerRegionY == 0)
632 {
633 neighboury--;
634 newpos.Y = Constants.RegionSize - enterDistance;
635 }
636 else
637 {
638 neighboury = ba.TriggerRegionY;
639 neighbourx = ba.TriggerRegionX;
640 Vector3 newposition = pos;
641 newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize;
642 newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize;
643 agent.ControllingClient.SendAgentAlertMessage(
644 String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false);
645 InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene);
646 return;
647 }
648 }
649 else if (scene.TestBorderCross(pos + northCross, Cardinals.N))
650 {
651 Border c = scene.GetCrossedBorder(pos + northCross, Cardinals.N);
652 neighboury += (uint)(int)(c.BorderLine.Z / (int)Constants.RegionSize);
653 newpos.Y = enterDistance;
654 }
655
656
657 }
658 else if (scene.TestBorderCross(pos + southCross, Cardinals.S))
659 {
660 Border b = scene.GetCrossedBorder(pos + southCross, Cardinals.S);
661 if (b.TriggerRegionX == 0 && b.TriggerRegionY == 0)
662 {
663 neighboury--;
664 newpos.Y = Constants.RegionSize - enterDistance;
665 }
666 else
667 {
668 neighboury = b.TriggerRegionY;
669 neighbourx = b.TriggerRegionX;
670 Vector3 newposition = pos;
671 newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize;
672 newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize;
673 agent.ControllingClient.SendAgentAlertMessage(
674 String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false);
675 InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene);
676 return;
677 }
678 }
679 else if (scene.TestBorderCross(pos + northCross, Cardinals.N))
680 {
681
682 Border b = scene.GetCrossedBorder(pos + northCross, Cardinals.N);
683 neighboury += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize);
684 newpos.Y = enterDistance;
685 }
686
687 /*
688
689 if (pos.X < boundaryDistance) //West
690 {
691 neighbourx--;
692 newpos.X = Constants.RegionSize - enterDistance;
693 }
694 else if (pos.X > Constants.RegionSize - boundaryDistance) // East
695 {
696 neighbourx++;
697 newpos.X = enterDistance;
698 }
699
700 if (pos.Y < boundaryDistance) // South
701 {
702 neighboury--;
703 newpos.Y = Constants.RegionSize - enterDistance;
704 }
705 else if (pos.Y > Constants.RegionSize - boundaryDistance) // North
706 {
707 neighboury++;
708 newpos.Y = enterDistance;
709 }
710 */
711
712 CrossAgentToNewRegionDelegate d = CrossAgentToNewRegionAsync;
713 d.BeginInvoke(agent, newpos, neighbourx, neighboury, isFlying, CrossAgentToNewRegionCompleted, d);
714
715 }
716
717
718 public delegate void InformClientToInitateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY,
719 Vector3 position,
720 Scene initiatingScene);
721
722 private void InformClientToInitateTeleportToLocation(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene)
723 {
724
725 // This assumes that we know what our neighbors are.
726
727 InformClientToInitateTeleportToLocationDelegate d = InformClientToInitiateTeleportToLocationAsync;
728 d.BeginInvoke(agent, regionX, regionY, position, initiatingScene,
729 InformClientToInitiateTeleportToLocationCompleted,
730 d);
731 }
732
733 public void InformClientToInitiateTeleportToLocationAsync(ScenePresence agent, uint regionX, uint regionY, Vector3 position,
734 Scene initiatingScene)
735 {
736 Thread.Sleep(10000);
737 IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>();
738 if (im != null)
739 {
740 UUID gotoLocation = Util.BuildFakeParcelID(
741 Util.UIntsToLong(
742 (regionX *
743 (uint)Constants.RegionSize),
744 (regionY *
745 (uint)Constants.RegionSize)),
746 (uint)(int)position.X,
747 (uint)(int)position.Y,
748 (uint)(int)position.Z);
749 GridInstantMessage m = new GridInstantMessage(initiatingScene, UUID.Zero,
750 "Region", agent.UUID,
751 (byte)InstantMessageDialog.GodLikeRequestTeleport, false,
752 "", gotoLocation, false, new Vector3(127, 0, 0),
753 new Byte[0]);
754 im.SendInstantMessage(m, delegate(bool success)
755 {
756 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Client Initiating Teleport sending IM success = {0}", success);
757 });
758
759 }
760 }
761
762 private void InformClientToInitiateTeleportToLocationCompleted(IAsyncResult iar)
763 {
764 InformClientToInitateTeleportToLocationDelegate icon =
765 (InformClientToInitateTeleportToLocationDelegate)iar.AsyncState;
766 icon.EndInvoke(iar);
767 }
768
769 public delegate ScenePresence CrossAgentToNewRegionDelegate(ScenePresence agent, Vector3 pos, uint neighbourx, uint neighboury, bool isFlying);
770
771 /// <summary>
772 /// This Closes child agents on neighboring regions
773 /// Calls an asynchronous method to do so.. so it doesn't lag the sim.
774 /// </summary>
775 protected ScenePresence CrossAgentToNewRegionAsync(ScenePresence agent, Vector3 pos, uint neighbourx, uint neighboury, bool isFlying)
776 {
777 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Crossing agent {0} {1} to {2}-{3}", agent.Firstname, agent.Lastname, neighbourx, neighboury);
778
779 Scene m_scene = agent.Scene;
780 ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize));
781
782 int x = (int)(neighbourx * Constants.RegionSize), y = (int)(neighboury * Constants.RegionSize);
783 GridRegion neighbourRegion = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y);
784
785 if (neighbourRegion != null && agent.ValidateAttachments())
786 {
787 pos = pos + (agent.Velocity);
788
789 SetInTransit(agent.UUID);
790 AgentData cAgent = new AgentData();
791 agent.CopyTo(cAgent);
792 cAgent.Position = pos;
793 if (isFlying)
794 cAgent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY;
795 cAgent.CallbackURI = "http://" + m_scene.RegionInfo.ExternalHostName + ":" + m_scene.RegionInfo.HttpPort +
796 "/agent/" + agent.UUID.ToString() + "/" + m_scene.RegionInfo.RegionID.ToString() + "/release/";
797
798 m_scene.SimulationService.UpdateAgent(neighbourRegion, cAgent);
799
800 // Next, let's close the child agent connections that are too far away.
801 agent.CloseChildAgents(neighbourx, neighboury);
802
803 //AgentCircuitData circuitdata = m_controllingClient.RequestClientInfo();
804 agent.ControllingClient.RequestClientInfo();
805
806 //m_log.Debug("BEFORE CROSS");
807 //Scene.DumpChildrenSeeds(UUID);
808 //DumpKnownRegions();
809 string agentcaps;
810 if (!agent.KnownRegions.TryGetValue(neighbourRegion.RegionHandle, out agentcaps))
811 {
812 m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: No ENTITY TRANSFER MODULE information for region handle {0}, exiting CrossToNewRegion.",
813 neighbourRegion.RegionHandle);
814 return agent;
815 }
816 // TODO Should construct this behind a method
817 string capsPath =
818 "http://" + neighbourRegion.ExternalHostName + ":" + neighbourRegion.HttpPort
819 + "/CAPS/" + agentcaps /*circuitdata.CapsPath*/ + "0000/";
820
821 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID);
822
823 IEventQueue eq = agent.Scene.RequestModuleInterface<IEventQueue>();
824 if (eq != null)
825 {
826 eq.CrossRegion(neighbourHandle, pos, agent.Velocity, neighbourRegion.ExternalEndPoint,
827 capsPath, agent.UUID, agent.ControllingClient.SessionId);
828 }
829 else
830 {
831 agent.ControllingClient.CrossRegion(neighbourHandle, pos, agent.Velocity, neighbourRegion.ExternalEndPoint,
832 capsPath);
833 }
834
835 if (!WaitForCallback(agent.UUID))
836 {
837 m_log.Debug("[ENTITY TRANSFER MODULE]: Callback never came in crossing agent");
838 ResetFromTransit(agent.UUID);
839
840 // Yikes! We should just have a ref to scene here.
841 //agent.Scene.InformClientOfNeighbours(agent);
842 EnableChildAgents(agent);
843
844 return agent;
845 }
846
847 agent.MakeChildAgent();
848 // now we have a child agent in this region. Request all interesting data about other (root) agents
849 agent.SendInitialFullUpdateToAllClients();
850
851 CrossAttachmentsIntoNewRegion(neighbourRegion, agent, true);
852
853 // m_scene.SendKillObject(m_localId);
854
855 agent.Scene.NotifyMyCoarseLocationChange();
856 // the user may change their profile information in other region,
857 // so the userinfo in UserProfileCache is not reliable any more, delete it
858 // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
859 if (agent.Scene.NeedSceneCacheClear(agent.UUID))
860 {
861 m_log.DebugFormat(
862 "[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID);
863 }
864 }
865
866 //m_log.Debug("AFTER CROSS");
867 //Scene.DumpChildrenSeeds(UUID);
868 //DumpKnownRegions();
869 return agent;
870 }
871
872 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
873 {
874 CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
875 ScenePresence agent = icon.EndInvoke(iar);
876
877 // If the cross was successful, this agent is a child agent
878 if (agent.IsChildAgent)
879 agent.Reset();
880 else // Not successful
881 agent.RestoreInCurrentScene();
882
883 // In any case
884 agent.NotInTransit();
885
886 //m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
887 }
888
889 #endregion
890
891 #region Enable Child Agent
892 /// <summary>
893 /// This informs a single neighboring region about agent "avatar".
894 /// Calls an asynchronous method to do so.. so it doesn't lag the sim.
895 /// </summary>
896 public void EnableChildAgent(ScenePresence sp, GridRegion region)
897 {
898 AgentCircuitData agent = sp.ControllingClient.RequestClientInfo();
899 agent.BaseFolder = UUID.Zero;
900 agent.InventoryFolder = UUID.Zero;
901 agent.startpos = new Vector3(128, 128, 70);
902 agent.child = true;
903 agent.Appearance = sp.Appearance;
904
905 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
906 d.BeginInvoke(sp, agent, region, region.ExternalEndPoint, true,
907 InformClientOfNeighbourCompleted,
908 d);
909 }
910 #endregion
911
912 #region Enable Child Agents
913
914 private delegate void InformClientOfNeighbourDelegate(
915 ScenePresence avatar, AgentCircuitData a, GridRegion reg, IPEndPoint endPoint, bool newAgent);
916
917 /// <summary>
918 /// This informs all neighboring regions about agent "avatar".
919 /// Calls an asynchronous method to do so.. so it doesn't lag the sim.
920 /// </summary>
921 public void EnableChildAgents(ScenePresence sp)
922 {
923 List<GridRegion> neighbours = new List<GridRegion>();
924 RegionInfo m_regionInfo = sp.Scene.RegionInfo;
925
926 if (m_regionInfo != null)
927 {
928 neighbours = RequestNeighbours(sp.Scene, m_regionInfo.RegionLocX, m_regionInfo.RegionLocY);
929 }
930 else
931 {
932 m_log.Debug("[ENTITY TRANSFER MODULE]: m_regionInfo was null in EnableChildAgents, is this a NPC?");
933 }
934
935 /// We need to find the difference between the new regions where there are no child agents
936 /// and the regions where there are already child agents. We only send notification to the former.
937 List<ulong> neighbourHandles = NeighbourHandles(neighbours); // on this region
938 neighbourHandles.Add(sp.Scene.RegionInfo.RegionHandle); // add this region too
939 List<ulong> previousRegionNeighbourHandles;
940
941 if (sp.Scene.CapsModule != null)
942 {
943 previousRegionNeighbourHandles =
944 new List<ulong>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID).Keys);
945 }
946 else
947 {
948 previousRegionNeighbourHandles = new List<ulong>();
949 }
950
951 List<ulong> newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles);
952 List<ulong> oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles);
953
954 //Dump("Current Neighbors", neighbourHandles);
955 //Dump("Previous Neighbours", previousRegionNeighbourHandles);
956 //Dump("New Neighbours", newRegions);
957 //Dump("Old Neighbours", oldRegions);
958
959 /// Update the scene presence's known regions here on this region
960 sp.DropOldNeighbours(oldRegions);
961
962 /// Collect as many seeds as possible
963 Dictionary<ulong, string> seeds;
964 if (sp.Scene.CapsModule != null)
965 seeds
966 = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID));
967 else
968 seeds = new Dictionary<ulong, string>();
969
970 //m_log.Debug(" !!! No. of seeds: " + seeds.Count);
971 if (!seeds.ContainsKey(sp.Scene.RegionInfo.RegionHandle))
972 seeds.Add(sp.Scene.RegionInfo.RegionHandle, sp.ControllingClient.RequestClientInfo().CapsPath);
973
974 /// Create the necessary child agents
975 List<AgentCircuitData> cagents = new List<AgentCircuitData>();
976 foreach (GridRegion neighbour in neighbours)
977 {
978 if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle)
979 {
980
981 AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
982 AgentCircuitData agent = sp.ControllingClient.RequestClientInfo();
983 agent.BaseFolder = UUID.Zero;
984 agent.InventoryFolder = UUID.Zero;
985 agent.startpos = new Vector3(128, 128, 70);
986 agent.child = true;
987 agent.Appearance = sp.Appearance;
988 if (currentAgentCircuit != null)
989 agent.ServiceURLs = currentAgentCircuit.ServiceURLs;
990
991 if (newRegions.Contains(neighbour.RegionHandle))
992 {
993 agent.CapsPath = CapsUtil.GetRandomCapsObjectPath();
994 sp.AddNeighbourRegion(neighbour.RegionHandle, agent.CapsPath);
995 seeds.Add(neighbour.RegionHandle, agent.CapsPath);
996 }
997 else
998 agent.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, neighbour.RegionHandle);
999
1000 cagents.Add(agent);
1001 }
1002 }
1003
1004 /// Update all child agent with everyone's seeds
1005 foreach (AgentCircuitData a in cagents)
1006 {
1007 a.ChildrenCapSeeds = new Dictionary<ulong, string>(seeds);
1008 }
1009
1010 if (sp.Scene.CapsModule != null)
1011 {
1012 sp.Scene.CapsModule.SetChildrenSeed(sp.UUID, seeds);
1013 }
1014 sp.KnownRegions = seeds;
1015 //avatar.Scene.DumpChildrenSeeds(avatar.UUID);
1016 //avatar.DumpKnownRegions();
1017
1018 bool newAgent = false;
1019 int count = 0;
1020 foreach (GridRegion neighbour in neighbours)
1021 {
1022 //m_log.WarnFormat("--> Going to send child agent to {0}", neighbour.RegionName);
1023 // Don't do it if there's already an agent in that region
1024 if (newRegions.Contains(neighbour.RegionHandle))
1025 newAgent = true;
1026 else
1027 newAgent = false;
1028
1029 if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle)
1030 {
1031 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
1032 try
1033 {
1034 d.BeginInvoke(sp, cagents[count], neighbour, neighbour.ExternalEndPoint, newAgent,
1035 InformClientOfNeighbourCompleted,
1036 d);
1037 }
1038
1039 catch (ArgumentOutOfRangeException)
1040 {
1041 m_log.ErrorFormat(
1042 "[ENTITY TRANSFER MODULE]: Neighbour Regions response included the current region in the neighbor list. The following region will not display to the client: {0} for region {1} ({2}, {3}).",
1043 neighbour.ExternalHostName,
1044 neighbour.RegionHandle,
1045 neighbour.RegionLocX,
1046 neighbour.RegionLocY);
1047 }
1048 catch (Exception e)
1049 {
1050 m_log.ErrorFormat(
1051 "[ENTITY TRANSFER MODULE]: Could not resolve external hostname {0} for region {1} ({2}, {3}). {4}",
1052 neighbour.ExternalHostName,
1053 neighbour.RegionHandle,
1054 neighbour.RegionLocX,
1055 neighbour.RegionLocY,
1056 e);
1057
1058 // FIXME: Okay, even though we've failed, we're still going to throw the exception on,
1059 // since I don't know what will happen if we just let the client continue
1060
1061 // XXX: Well, decided to swallow the exception instead for now. Let us see how that goes.
1062 // throw e;
1063
1064 }
1065 }
1066 count++;
1067 }
1068 }
1069
1070 private void InformClientOfNeighbourCompleted(IAsyncResult iar)
1071 {
1072 InformClientOfNeighbourDelegate icon = (InformClientOfNeighbourDelegate)iar.AsyncState;
1073 icon.EndInvoke(iar);
1074 //m_log.WarnFormat(" --> InformClientOfNeighbourCompleted");
1075 }
1076
1077 /// <summary>
1078 /// Async component for informing client of which neighbours exist
1079 /// </summary>
1080 /// <remarks>
1081 /// This needs to run asynchronously, as a network timeout may block the thread for a long while
1082 /// </remarks>
1083 /// <param name="remoteClient"></param>
1084 /// <param name="a"></param>
1085 /// <param name="regionHandle"></param>
1086 /// <param name="endPoint"></param>
1087 private void InformClientOfNeighbourAsync(ScenePresence sp, AgentCircuitData a, GridRegion reg,
1088 IPEndPoint endPoint, bool newAgent)
1089 {
1090 // Let's wait just a little to give time to originating regions to catch up with closing child agents
1091 // after a cross here
1092 Thread.Sleep(500);
1093
1094 Scene m_scene = sp.Scene;
1095
1096 uint x, y;
1097 Utils.LongToUInts(reg.RegionHandle, out x, out y);
1098 x = x / Constants.RegionSize;
1099 y = y / Constants.RegionSize;
1100 m_log.Info("[ENTITY TRANSFER MODULE]: Starting to inform client about neighbour " + x + ", " + y + "(" + endPoint.ToString() + ")");
1101
1102 string capsPath = "http://" + reg.ExternalHostName + ":" + reg.HttpPort
1103 + "/CAPS/" + a.CapsPath + "0000/";
1104
1105 string reason = String.Empty;
1106
1107
1108 bool regionAccepted = m_scene.SimulationService.CreateAgent(reg, a, 0, out reason); // m_interregionCommsOut.SendCreateChildAgent(reg.RegionHandle, a, 0, out reason);
1109
1110 if (regionAccepted && newAgent)
1111 {
1112 IEventQueue eq = sp.Scene.RequestModuleInterface<IEventQueue>();
1113 if (eq != null)
1114 {
1115 #region IP Translation for NAT
1116 IClientIPEndpoint ipepClient;
1117 if (sp.ClientView.TryGet(out ipepClient))
1118 {
1119 endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address);
1120 }
1121 #endregion
1122
1123 eq.EnableSimulator(reg.RegionHandle, endPoint, sp.UUID);
1124 eq.EstablishAgentCommunication(sp.UUID, endPoint, capsPath);
1125 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1} in region {2}",
1126 capsPath, sp.UUID, sp.Scene.RegionInfo.RegionName);
1127 }
1128 else
1129 {
1130 sp.ControllingClient.InformClientOfNeighbour(reg.RegionHandle, endPoint);
1131 // TODO: make Event Queue disablable!
1132 }
1133
1134 m_log.Info("[ENTITY TRANSFER MODULE]: Completed inform client about neighbour " + endPoint.ToString());
1135
1136 }
1137
1138 }
1139
1140 protected List<GridRegion> RequestNeighbours(Scene pScene, uint pRegionLocX, uint pRegionLocY)
1141 {
1142 RegionInfo m_regionInfo = pScene.RegionInfo;
1143
1144 Border[] northBorders = pScene.NorthBorders.ToArray();
1145 Border[] southBorders = pScene.SouthBorders.ToArray();
1146 Border[] eastBorders = pScene.EastBorders.ToArray();
1147 Border[] westBorders = pScene.WestBorders.ToArray();
1148
1149 // Legacy one region. Provided for simplicity while testing the all inclusive method in the else statement.
1150 if (northBorders.Length <= 1 && southBorders.Length <= 1 && eastBorders.Length <= 1 && westBorders.Length <= 1)
1151 {
1152 return pScene.GridService.GetNeighbours(m_regionInfo.ScopeID, m_regionInfo.RegionID);
1153 }
1154 else
1155 {
1156 Vector2 extent = Vector2.Zero;
1157 for (int i = 0; i < eastBorders.Length; i++)
1158 {
1159 extent.X = (eastBorders[i].BorderLine.Z > extent.X) ? eastBorders[i].BorderLine.Z : extent.X;
1160 }
1161 for (int i = 0; i < northBorders.Length; i++)
1162 {
1163 extent.Y = (northBorders[i].BorderLine.Z > extent.Y) ? northBorders[i].BorderLine.Z : extent.Y;
1164 }
1165
1166 // Loss of fraction on purpose
1167 extent.X = ((int)extent.X / (int)Constants.RegionSize) + 1;
1168 extent.Y = ((int)extent.Y / (int)Constants.RegionSize) + 1;
1169
1170 int startX = (int)(pRegionLocX - 1) * (int)Constants.RegionSize;
1171 int startY = (int)(pRegionLocY - 1) * (int)Constants.RegionSize;
1172
1173 int endX = ((int)pRegionLocX + (int)extent.X) * (int)Constants.RegionSize;
1174 int endY = ((int)pRegionLocY + (int)extent.Y) * (int)Constants.RegionSize;
1175
1176 List<GridRegion> neighbours = pScene.GridService.GetRegionRange(m_regionInfo.ScopeID, startX, endX, startY, endY);
1177 neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; });
1178
1179 return neighbours;
1180 }
1181 }
1182
1183 private List<ulong> NewNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours)
1184 {
1185 return currentNeighbours.FindAll(delegate(ulong handle) { return !previousNeighbours.Contains(handle); });
1186 }
1187
1188 // private List<ulong> CommonNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours)
1189 // {
1190 // return currentNeighbours.FindAll(delegate(ulong handle) { return previousNeighbours.Contains(handle); });
1191 // }
1192
1193 private List<ulong> OldNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours)
1194 {
1195 return previousNeighbours.FindAll(delegate(ulong handle) { return !currentNeighbours.Contains(handle); });
1196 }
1197
1198 private List<ulong> NeighbourHandles(List<GridRegion> neighbours)
1199 {
1200 List<ulong> handles = new List<ulong>();
1201 foreach (GridRegion reg in neighbours)
1202 {
1203 handles.Add(reg.RegionHandle);
1204 }
1205 return handles;
1206 }
1207
1208 private void Dump(string msg, List<ulong> handles)
1209 {
1210 m_log.InfoFormat("-------------- HANDLE DUMP ({0}) ---------", msg);
1211 foreach (ulong handle in handles)
1212 {
1213 uint x, y;
1214 Utils.LongToUInts(handle, out x, out y);
1215 x = x / Constants.RegionSize;
1216 y = y / Constants.RegionSize;
1217 m_log.InfoFormat("({0}, {1})", x, y);
1218 }
1219 }
1220
1221 #endregion
1222
1223
1224 #region Agent Arrived
1225 public void AgentArrivedAtDestination(UUID id)
1226 {
1227 //m_log.Debug(" >>> ReleaseAgent called <<< ");
1228 ResetFromTransit(id);
1229 }
1230
1231 #endregion
1232
1233 #region Object Transfers
1234 /// <summary>
1235 /// Move the given scene object into a new region depending on which region its absolute position has moved
1236 /// into.
1237 ///
1238 /// This method locates the new region handle and offsets the prim position for the new region
1239 /// </summary>
1240 /// <param name="attemptedPosition">the attempted out of region position of the scene object</param>
1241 /// <param name="grp">the scene object that we're crossing</param>
1242 public void Cross(SceneObjectGroup grp, Vector3 attemptedPosition, bool silent)
1243 {
1244 if (grp == null)
1245 return;
1246 if (grp.IsDeleted)
1247 return;
1248
1249 Scene scene = grp.Scene;
1250 if (scene == null)
1251 return;
1252
1253 if (grp.RootPart.DIE_AT_EDGE)
1254 {
1255 // We remove the object here
1256 try
1257 {
1258 scene.DeleteSceneObject(grp, false);
1259 }
1260 catch (Exception)
1261 {
1262 m_log.Warn("[DATABASE]: exception when trying to remove the prim that crossed the border.");
1263 }
1264 return;
1265 }
1266
1267 int thisx = (int)scene.RegionInfo.RegionLocX;
1268 int thisy = (int)scene.RegionInfo.RegionLocY;
1269 Vector3 EastCross = new Vector3(0.1f, 0, 0);
1270 Vector3 WestCross = new Vector3(-0.1f, 0, 0);
1271 Vector3 NorthCross = new Vector3(0, 0.1f, 0);
1272 Vector3 SouthCross = new Vector3(0, -0.1f, 0);
1273
1274
1275 // use this if no borders were crossed!
1276 ulong newRegionHandle
1277 = Util.UIntsToLong((uint)((thisx) * Constants.RegionSize),
1278 (uint)((thisy) * Constants.RegionSize));
1279
1280 Vector3 pos = attemptedPosition;
1281
1282 int changeX = 1;
1283 int changeY = 1;
1284
1285 if (scene.TestBorderCross(attemptedPosition + WestCross, Cardinals.W))
1286 {
1287 if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
1288 {
1289
1290 Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W);
1291
1292 if (crossedBorderx.BorderLine.Z > 0)
1293 {
1294 pos.X = ((pos.X + crossedBorderx.BorderLine.Z));
1295 changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize);
1296 }
1297 else
1298 pos.X = ((pos.X + Constants.RegionSize));
1299
1300 Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
1301 //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
1302
1303 if (crossedBordery.BorderLine.Z > 0)
1304 {
1305 pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
1306 changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
1307 }
1308 else
1309 pos.Y = ((pos.Y + Constants.RegionSize));
1310
1311
1312
1313 newRegionHandle
1314 = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize),
1315 (uint)((thisy - changeY) * Constants.RegionSize));
1316 // x - 1
1317 // y - 1
1318 }
1319 else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N))
1320 {
1321 Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W);
1322
1323 if (crossedBorderx.BorderLine.Z > 0)
1324 {
1325 pos.X = ((pos.X + crossedBorderx.BorderLine.Z));
1326 changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize);
1327 }
1328 else
1329 pos.X = ((pos.X + Constants.RegionSize));
1330
1331
1332 Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
1333 //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
1334
1335 if (crossedBordery.BorderLine.Z > 0)
1336 {
1337 pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
1338 changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
1339 }
1340 else
1341 pos.Y = ((pos.Y + Constants.RegionSize));
1342
1343 newRegionHandle
1344 = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize),
1345 (uint)((thisy + changeY) * Constants.RegionSize));
1346 // x - 1
1347 // y + 1
1348 }
1349 else
1350 {
1351 Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W);
1352
1353 if (crossedBorderx.BorderLine.Z > 0)
1354 {
1355 pos.X = ((pos.X + crossedBorderx.BorderLine.Z));
1356 changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize);
1357 }
1358 else
1359 pos.X = ((pos.X + Constants.RegionSize));
1360
1361 newRegionHandle
1362 = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize),
1363 (uint)(thisy * Constants.RegionSize));
1364 // x - 1
1365 }
1366 }
1367 else if (scene.TestBorderCross(attemptedPosition + EastCross, Cardinals.E))
1368 {
1369 if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
1370 {
1371
1372 pos.X = ((pos.X - Constants.RegionSize));
1373 Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
1374 //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
1375
1376 if (crossedBordery.BorderLine.Z > 0)
1377 {
1378 pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
1379 changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
1380 }
1381 else
1382 pos.Y = ((pos.Y + Constants.RegionSize));
1383
1384
1385 newRegionHandle
1386 = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize),
1387 (uint)((thisy - changeY) * Constants.RegionSize));
1388 // x + 1
1389 // y - 1
1390 }
1391 else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N))
1392 {
1393 pos.X = ((pos.X - Constants.RegionSize));
1394 pos.Y = ((pos.Y - Constants.RegionSize));
1395 newRegionHandle
1396 = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize),
1397 (uint)((thisy + changeY) * Constants.RegionSize));
1398 // x + 1
1399 // y + 1
1400 }
1401 else
1402 {
1403 pos.X = ((pos.X - Constants.RegionSize));
1404 newRegionHandle
1405 = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize),
1406 (uint)(thisy * Constants.RegionSize));
1407 // x + 1
1408 }
1409 }
1410 else if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
1411 {
1412 Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
1413 //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
1414
1415 if (crossedBordery.BorderLine.Z > 0)
1416 {
1417 pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
1418 changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
1419 }
1420 else
1421 pos.Y = ((pos.Y + Constants.RegionSize));
1422
1423 newRegionHandle
1424 = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy - changeY) * Constants.RegionSize));
1425 // y - 1
1426 }
1427 else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N))
1428 {
1429
1430 pos.Y = ((pos.Y - Constants.RegionSize));
1431 newRegionHandle
1432 = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy + changeY) * Constants.RegionSize));
1433 // y + 1
1434 }
1435
1436 // Offset the positions for the new region across the border
1437 Vector3 oldGroupPosition = grp.RootPart.GroupPosition;
1438 grp.OffsetForNewRegion(pos);
1439
1440 // If we fail to cross the border, then reset the position of the scene object on that border.
1441 uint x = 0, y = 0;
1442 Utils.LongToUInts(newRegionHandle, out x, out y);
1443 GridRegion destination = scene.GridService.GetRegionByPosition(UUID.Zero, (int)x, (int)y);
1444 if (destination != null && !CrossPrimGroupIntoNewRegion(destination, grp, silent))
1445 {
1446 grp.OffsetForNewRegion(oldGroupPosition);
1447 grp.ScheduleGroupForFullUpdate();
1448 }
1449 }
1450
1451
1452 /// <summary>
1453 /// Move the given scene object into a new region
1454 /// </summary>
1455 /// <param name="newRegionHandle"></param>
1456 /// <param name="grp">Scene Object Group that we're crossing</param>
1457 /// <returns>
1458 /// true if the crossing itself was successful, false on failure
1459 /// FIMXE: we still return true if the crossing object was not successfully deleted from the originating region
1460 /// </returns>
1461 protected bool CrossPrimGroupIntoNewRegion(GridRegion destination, SceneObjectGroup grp, bool silent)
1462 {
1463 //m_log.Debug(" >>> CrossPrimGroupIntoNewRegion <<<");
1464
1465 bool successYN = false;
1466 grp.RootPart.UpdateFlag = 0;
1467 //int primcrossingXMLmethod = 0;
1468
1469 if (destination != null)
1470 {
1471 //string objectState = grp.GetStateSnapshot();
1472
1473 //successYN
1474 // = m_sceneGridService.PrimCrossToNeighboringRegion(
1475 // newRegionHandle, grp.UUID, m_serialiser.SaveGroupToXml2(grp), primcrossingXMLmethod);
1476 //if (successYN && (objectState != "") && m_allowScriptCrossings)
1477 //{
1478 // successYN = m_sceneGridService.PrimCrossToNeighboringRegion(
1479 // newRegionHandle, grp.UUID, objectState, 100);
1480 //}
1481
1482 //// And the new channel...
1483 //if (m_interregionCommsOut != null)
1484 // successYN = m_interregionCommsOut.SendCreateObject(newRegionHandle, grp, true);
1485 if (m_aScene.SimulationService != null)
1486 successYN = m_aScene.SimulationService.CreateObject(destination, grp, true);
1487
1488 if (successYN)
1489 {
1490 // We remove the object here
1491 try
1492 {
1493 grp.Scene.DeleteSceneObject(grp, silent);
1494 }
1495 catch (Exception e)
1496 {
1497 m_log.ErrorFormat(
1498 "[ENTITY TRANSFER MODULE]: Exception deleting the old object left behind on a border crossing for {0}, {1}",
1499 grp, e);
1500 }
1501 }
1502 else
1503 {
1504 if (!grp.IsDeleted)
1505 {
1506 if (grp.RootPart.PhysActor != null)
1507 {
1508 grp.RootPart.PhysActor.CrossingFailure();
1509 }
1510 }
1511
1512 m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: Prim crossing failed for {0}", grp);
1513 }
1514 }
1515 else
1516 {
1517 m_log.Error("[ENTITY TRANSFER MODULE]: destination was unexpectedly null in Scene.CrossPrimGroupIntoNewRegion()");
1518 }
1519
1520 return successYN;
1521 }
1522
1523 protected bool CrossAttachmentsIntoNewRegion(GridRegion destination, ScenePresence sp, bool silent)
1524 {
1525 List<SceneObjectGroup> m_attachments = sp.Attachments;
1526 lock (m_attachments)
1527 {
1528 // Validate
1529 foreach (SceneObjectGroup gobj in m_attachments)
1530 {
1531 if (gobj == null || gobj.IsDeleted)
1532 return false;
1533 }
1534
1535 foreach (SceneObjectGroup gobj in m_attachments)
1536 {
1537 // If the prim group is null then something must have happened to it!
1538 if (gobj != null && gobj.RootPart != null)
1539 {
1540 // Set the parent localID to 0 so it transfers over properly.
1541 gobj.RootPart.SetParentLocalId(0);
1542 gobj.AbsolutePosition = gobj.RootPart.AttachedPos;
1543 gobj.RootPart.IsAttachment = false;
1544 //gobj.RootPart.LastOwnerID = gobj.GetFromAssetID();
1545 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending attachment {0} to region {1}", gobj.UUID, destination.RegionName);
1546 CrossPrimGroupIntoNewRegion(destination, gobj, silent);
1547 }
1548 }
1549 m_attachments.Clear();
1550
1551 return true;
1552 }
1553 }
1554
1555 #endregion
1556
1557 #region Misc
1558
1559 protected bool WaitForCallback(UUID id)
1560 {
1561 int count = 200;
1562 while (m_agentsInTransit.Contains(id) && count-- > 0)
1563 {
1564 //m_log.Debug(" >>> Waiting... " + count);
1565 Thread.Sleep(100);
1566 }
1567
1568 if (count > 0)
1569 return true;
1570 else
1571 return false;
1572 }
1573
1574 protected void SetInTransit(UUID id)
1575 {
1576 lock (m_agentsInTransit)
1577 {
1578 if (!m_agentsInTransit.Contains(id))
1579 m_agentsInTransit.Add(id);
1580 }
1581 }
1582
1583 protected bool ResetFromTransit(UUID id)
1584 {
1585 lock (m_agentsInTransit)
1586 {
1587 if (m_agentsInTransit.Contains(id))
1588 {
1589 m_agentsInTransit.Remove(id);
1590 return true;
1591 }
1592 }
1593 return false;
1594 }
1595
1596
1597 #endregion
1598
1599 }
1600}
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
new file mode 100644
index 0000000..28593fc
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
@@ -0,0 +1,273 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31
32using OpenSim.Framework;
33using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Region.Framework.Scenes;
35using OpenSim.Services.Connectors.Hypergrid;
36using OpenSim.Services.Interfaces;
37using OpenSim.Server.Base;
38
39using GridRegion = OpenSim.Services.Interfaces.GridRegion;
40
41using OpenMetaverse;
42using log4net;
43using Nini.Config;
44
45namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
46{
47 public class HGEntityTransferModule : EntityTransferModule, ISharedRegionModule, IEntityTransferModule, IUserAgentVerificationModule
48 {
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50
51 private bool m_Initialized = false;
52
53 private GatekeeperServiceConnector m_GatekeeperConnector;
54
55 #region ISharedRegionModule
56
57 public override string Name
58 {
59 get { return "HGEntityTransferModule"; }
60 }
61
62 public override void Initialise(IConfigSource source)
63 {
64 IConfig moduleConfig = source.Configs["Modules"];
65 if (moduleConfig != null)
66 {
67 string name = moduleConfig.GetString("EntityTransferModule", "");
68 if (name == Name)
69 {
70 m_agentsInTransit = new List<UUID>();
71
72 m_Enabled = true;
73 m_log.InfoFormat("[HG ENTITY TRANSFER MODULE]: {0} enabled.", Name);
74 }
75 }
76 }
77
78 public override void AddRegion(Scene scene)
79 {
80 base.AddRegion(scene);
81 if (m_Enabled)
82 {
83 scene.RegisterModuleInterface<IUserAgentVerificationModule>(this);
84 }
85 }
86
87 protected override void OnNewClient(IClientAPI client)
88 {
89 client.OnTeleportHomeRequest += TeleportHome;
90 client.OnConnectionClosed += new Action<IClientAPI>(OnConnectionClosed);
91 }
92
93
94 public override void RegionLoaded(Scene scene)
95 {
96 base.RegionLoaded(scene);
97 if (m_Enabled)
98 if (!m_Initialized)
99 {
100 m_GatekeeperConnector = new GatekeeperServiceConnector(scene.AssetService);
101 m_Initialized = true;
102 }
103
104 }
105 public override void RemoveRegion(Scene scene)
106 {
107 base.AddRegion(scene);
108 if (m_Enabled)
109 {
110 scene.UnregisterModuleInterface<IUserAgentVerificationModule>(this);
111 }
112 }
113
114
115 #endregion
116
117 #region HG overrides of IEntiryTransferModule
118
119 protected override GridRegion GetFinalDestination(GridRegion region)
120 {
121 int flags = m_aScene.GridService.GetRegionFlags(m_aScene.RegionInfo.ScopeID, region.RegionID);
122 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionID, flags);
123 if ((flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0)
124 {
125 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region {0} is hyperlink", region.RegionID);
126 return m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID);
127 }
128 return region;
129 }
130
131 protected override bool NeedsClosing(uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg)
132 {
133 if (base.NeedsClosing(oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
134 return true;
135
136 int flags = m_aScene.GridService.GetRegionFlags(m_aScene.RegionInfo.ScopeID, reg.RegionID);
137 if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0)
138 return true;
139
140 return false;
141 }
142
143 protected override bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason)
144 {
145 reason = string.Empty;
146 int flags = m_aScene.GridService.GetRegionFlags(m_aScene.RegionInfo.ScopeID, reg.RegionID);
147 if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0)
148 {
149 // this user is going to another grid
150 if (agentCircuit.ServiceURLs.ContainsKey("HomeURI"))
151 {
152 string userAgentDriver = agentCircuit.ServiceURLs["HomeURI"].ToString();
153 IUserAgentService connector = new UserAgentServiceConnector(userAgentDriver);
154 bool success = connector.LoginAgentToGrid(agentCircuit, reg, finalDestination, out reason);
155 if (success)
156 // Log them out of this grid
157 m_aScene.PresenceService.LogoutAgent(agentCircuit.SessionID, sp.AbsolutePosition, sp.Lookat);
158
159 return success;
160 }
161 else
162 {
163 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent does not have a HomeURI address");
164 return false;
165 }
166 }
167
168 return m_aScene.SimulationService.CreateAgent(reg, agentCircuit, teleportFlags, out reason);
169 }
170
171 public override void TeleportHome(UUID id, IClientAPI client)
172 {
173 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.FirstName, client.LastName);
174
175 // Let's find out if this is a foreign user or a local user
176 UserAccount account = m_aScene.UserAccountService.GetUserAccount(m_aScene.RegionInfo.ScopeID, id);
177 if (account != null)
178 {
179 // local grid user
180 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: User is local");
181 base.TeleportHome(id, client);
182 return;
183 }
184
185 // Foreign user wants to go home
186 //
187 AgentCircuitData aCircuit = ((Scene)(client.Scene)).AuthenticateHandler.GetAgentCircuitData(client.CircuitCode);
188 if (aCircuit == null || (aCircuit != null && !aCircuit.ServiceURLs.ContainsKey("HomeURI")))
189 {
190 client.SendTeleportFailed("Your information has been lost");
191 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Unable to locate agent's gateway information");
192 return;
193 }
194
195 IUserAgentService userAgentService = new UserAgentServiceConnector(aCircuit.ServiceURLs["HomeURI"].ToString());
196 Vector3 position = Vector3.UnitY, lookAt = Vector3.UnitY;
197 GridRegion finalDestination = userAgentService.GetHomeRegion(aCircuit.AgentID, out position, out lookAt);
198 if (finalDestination == null)
199 {
200 client.SendTeleportFailed("Your home region could not be found");
201 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent's home region not found");
202 return;
203 }
204
205 ScenePresence sp = ((Scene)(client.Scene)).GetScenePresence(client.AgentId);
206 if (sp == null)
207 {
208 client.SendTeleportFailed("Internal error");
209 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent not found in the scene where it is supposed to be");
210 return;
211 }
212
213 IEventQueue eq = sp.Scene.RequestModuleInterface<IEventQueue>();
214 GridRegion homeGatekeeper = MakeRegion(aCircuit);
215
216 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: teleporting user {0} {1} home to {2} via {3}:{4}:{5}",
217 aCircuit.firstname, aCircuit.lastname, finalDestination.RegionName, homeGatekeeper.ExternalHostName, homeGatekeeper.HttpPort, homeGatekeeper.RegionName);
218
219 DoTeleport(sp, homeGatekeeper, finalDestination, position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome), eq);
220 }
221 #endregion
222
223 #region IUserAgentVerificationModule
224
225 public bool VerifyClient(AgentCircuitData aCircuit, string token)
226 {
227 if (aCircuit.ServiceURLs.ContainsKey("HomeURI"))
228 {
229 string url = aCircuit.ServiceURLs["HomeURI"].ToString();
230 IUserAgentService security = new UserAgentServiceConnector(url);
231 return security.VerifyClient(aCircuit.SessionID, token);
232 }
233
234 return false;
235 }
236
237 void OnConnectionClosed(IClientAPI obj)
238 {
239 if (obj.IsLoggingOut)
240 {
241 AgentCircuitData aCircuit = ((Scene)(obj.Scene)).AuthenticateHandler.GetAgentCircuitData(obj.CircuitCode);
242
243 if (aCircuit.ServiceURLs.ContainsKey("HomeURI"))
244 {
245 string url = aCircuit.ServiceURLs["HomeURI"].ToString();
246 IUserAgentService security = new UserAgentServiceConnector(url);
247 security.LogoutAgent(obj.AgentId, obj.SessionId);
248 //m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Sent logout call to UserAgentService @ {0}", url);
249 }
250 else
251 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: HomeURI not found for agent {0} logout", obj.AgentId);
252 }
253 }
254
255 #endregion
256
257 private GridRegion MakeRegion(AgentCircuitData aCircuit)
258 {
259 GridRegion region = new GridRegion();
260
261 Uri uri = null;
262 if (!aCircuit.ServiceURLs.ContainsKey("HomeURI") ||
263 (aCircuit.ServiceURLs.ContainsKey("HomeURI") && !Uri.TryCreate(aCircuit.ServiceURLs["HomeURI"].ToString(), UriKind.Absolute, out uri)))
264 return null;
265
266 region.ExternalHostName = uri.Host;
267 region.HttpPort = (uint)uri.Port;
268 region.RegionName = string.Empty;
269 region.InternalEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Parse("0.0.0.0"), (int)0);
270 return region;
271 }
272 }
273}