aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs
diff options
context:
space:
mode:
authorDr Scofield2009-02-06 16:55:34 +0000
committerDr Scofield2009-02-06 16:55:34 +0000
commit9b66108081a8c8cf79faaa6c541554091c40850e (patch)
tree095a232ae5a9de3a9244bcd34da08294f61eeea5 /OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs
parent* removed superfluous constants class (diff)
downloadopensim-SC_OLD-9b66108081a8c8cf79faaa6c541554091c40850e.zip
opensim-SC_OLD-9b66108081a8c8cf79faaa6c541554091c40850e.tar.gz
opensim-SC_OLD-9b66108081a8c8cf79faaa6c541554091c40850e.tar.bz2
opensim-SC_OLD-9b66108081a8c8cf79faaa6c541554091c40850e.tar.xz
This changeset is the step 1 of 2 in refactoring
OpenSim.Region.Environment into a "framework" part and a modules only part. This first changeset refactors OpenSim.Region.Environment.Scenes, OpenSim.Region.Environment.Interfaces, and OpenSim.Region.Interfaces into OpenSim.Region.Framework.{Interfaces,Scenes} leaving only region modules in OpenSim.Region.Environment. The next step will be to move region modules up from OpenSim.Region.Environment.Modules to OpenSim.Region.CoreModules and then sort out which modules are really core modules and which should move out to forge. I've been very careful to NOT BREAK anything. i hope i've succeeded. as this is the work of a whole week i hope i managed to keep track with the applied patches of the last week --- could any of you that did check in stuff have a look at whether it survived? thx!
Diffstat (limited to 'OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs')
-rw-r--r--OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs1102
1 files changed, 0 insertions, 1102 deletions
diff --git a/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs
deleted file mode 100644
index 9935512..0000000
--- a/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs
+++ /dev/null
@@ -1,1102 +0,0 @@
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 OpenSim 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;
33using OpenMetaverse;
34using OpenMetaverse.StructuredData;
35using log4net;
36using OpenSim.Region.Environment.Interfaces;
37using OpenSim.Framework;
38using OpenSim.Framework.Communications;
39using OpenSim.Framework.Communications.Capabilities;
40using OpenSim.Region.Interfaces;
41using OSD = OpenMetaverse.StructuredData.OSD;
42
43namespace OpenSim.Region.Environment.Scenes
44{
45 public delegate void KiPrimitiveDelegate(uint localID);
46
47 public delegate void RemoveKnownRegionsFromAvatarList(UUID avatarID, List<ulong> regionlst);
48
49 public class SceneCommunicationService //one instance per region
50 {
51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52
53 protected CommunicationsManager m_commsProvider;
54 protected IInterregionCommsOut m_interregionCommsOut;
55 protected RegionInfo m_regionInfo;
56
57 protected RegionCommsListener regionCommsHost;
58
59 protected List<UUID> m_agentsInTransit;
60
61 public event AgentCrossing OnAvatarCrossingIntoRegion;
62 public event ExpectUserDelegate OnExpectUser;
63 public event ExpectPrimDelegate OnExpectPrim;
64 public event CloseAgentConnection OnCloseAgentConnection;
65 public event PrimCrossing OnPrimCrossingIntoRegion;
66 public event RegionUp OnRegionUp;
67 public event ChildAgentUpdate OnChildAgentUpdate;
68 //public event RemoveKnownRegionsFromAvatarList OnRemoveKnownRegionFromAvatar;
69 public event LogOffUser OnLogOffUser;
70 public event GetLandData OnGetLandData;
71
72 private AgentCrossing handlerAvatarCrossingIntoRegion = null; // OnAvatarCrossingIntoRegion;
73 private ExpectUserDelegate handlerExpectUser = null; // OnExpectUser;
74 private ExpectPrimDelegate handlerExpectPrim = null; // OnExpectPrim;
75 private CloseAgentConnection handlerCloseAgentConnection = null; // OnCloseAgentConnection;
76 private PrimCrossing handlerPrimCrossingIntoRegion = null; // OnPrimCrossingIntoRegion;
77 private RegionUp handlerRegionUp = null; // OnRegionUp;
78 private ChildAgentUpdate handlerChildAgentUpdate = null; // OnChildAgentUpdate;
79 //private RemoveKnownRegionsFromAvatarList handlerRemoveKnownRegionFromAvatar = null; // OnRemoveKnownRegionFromAvatar;
80 private LogOffUser handlerLogOffUser = null;
81 private GetLandData handlerGetLandData = null; // OnGetLandData
82
83 public KiPrimitiveDelegate KiPrimitive;
84
85 public SceneCommunicationService(CommunicationsManager commsMan)
86 {
87 m_commsProvider = commsMan;
88 m_agentsInTransit = new List<UUID>();
89 }
90
91 /// <summary>
92 /// Register a region with the grid
93 /// </summary>
94 /// <param name="regionInfos"></param>
95 /// <exception cref="System.Exception">Thrown if region registration fails.</exception>
96 public void RegisterRegion(IInterregionCommsOut comms_out, RegionInfo regionInfos)
97 {
98 m_interregionCommsOut = comms_out;
99
100 m_regionInfo = regionInfos;
101 m_commsProvider.GridService.gdebugRegionName = regionInfos.RegionName;
102 m_commsProvider.InterRegion.rdebugRegionName = regionInfos.RegionName;
103 regionCommsHost = m_commsProvider.GridService.RegisterRegion(m_regionInfo);
104
105 if (regionCommsHost != null)
106 {
107 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: registered with gridservice and got" + regionCommsHost.ToString());
108
109 regionCommsHost.debugRegionName = regionInfos.RegionName;
110 regionCommsHost.OnExpectPrim += IncomingPrimCrossing;
111 regionCommsHost.OnExpectUser += NewUserConnection;
112 regionCommsHost.OnAvatarCrossingIntoRegion += AgentCrossing;
113 regionCommsHost.OnCloseAgentConnection += CloseConnection;
114 regionCommsHost.OnRegionUp += newRegionUp;
115 regionCommsHost.OnChildAgentUpdate += ChildAgentUpdate;
116 regionCommsHost.OnLogOffUser += GridLogOffUser;
117 regionCommsHost.OnGetLandData += FetchLandData;
118 }
119 else
120 {
121 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: registered with gridservice and got null");
122 }
123 }
124
125 public RegionInfo RequestClosestRegion(string name)
126 {
127 return m_commsProvider.GridService.RequestClosestRegion(name);
128 }
129
130 public void Close()
131 {
132 if (regionCommsHost != null)
133 {
134 regionCommsHost.OnLogOffUser -= GridLogOffUser;
135 regionCommsHost.OnChildAgentUpdate -= ChildAgentUpdate;
136 regionCommsHost.OnRegionUp -= newRegionUp;
137 regionCommsHost.OnExpectUser -= NewUserConnection;
138 regionCommsHost.OnExpectPrim -= IncomingPrimCrossing;
139 regionCommsHost.OnAvatarCrossingIntoRegion -= AgentCrossing;
140 regionCommsHost.OnCloseAgentConnection -= CloseConnection;
141 regionCommsHost.OnGetLandData -= FetchLandData;
142
143 try
144 {
145 m_commsProvider.GridService.DeregisterRegion(m_regionInfo);
146 }
147 catch (Exception e)
148 {
149 m_log.ErrorFormat(
150 "[GRID]: Deregistration of region {0} from the grid failed - {1}. Continuing",
151 m_regionInfo.RegionName, e);
152 }
153
154 regionCommsHost = null;
155 }
156 }
157
158 #region CommsManager Event handlers
159
160 /// <summary>
161 ///
162 /// </summary>
163 /// <param name="regionHandle"></param>
164 /// <param name="agent"></param>
165 ///
166 protected void NewUserConnection(AgentCircuitData agent)
167 {
168 handlerExpectUser = OnExpectUser;
169 if (handlerExpectUser != null)
170 {
171 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: OnExpectUser Fired for User:" + agent.firstname + " " + agent.lastname);
172 handlerExpectUser(agent);
173 }
174 }
175
176 protected void GridLogOffUser(UUID AgentID, UUID RegionSecret, string message)
177 {
178 handlerLogOffUser = OnLogOffUser;
179 if (handlerLogOffUser != null)
180 {
181 handlerLogOffUser(AgentID, RegionSecret, message);
182 }
183 }
184
185 protected bool newRegionUp(RegionInfo region)
186 {
187 handlerRegionUp = OnRegionUp;
188 if (handlerRegionUp != null)
189 {
190 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: newRegionUp Fired for User:" + region.RegionName);
191 handlerRegionUp(region);
192 }
193 return true;
194 }
195
196 protected bool ChildAgentUpdate(ChildAgentDataUpdate cAgentData)
197 {
198 handlerChildAgentUpdate = OnChildAgentUpdate;
199 if (handlerChildAgentUpdate != null)
200 handlerChildAgentUpdate(cAgentData);
201
202
203 return true;
204 }
205
206 protected void AgentCrossing(UUID agentID, Vector3 position, bool isFlying)
207 {
208 handlerAvatarCrossingIntoRegion = OnAvatarCrossingIntoRegion;
209 if (handlerAvatarCrossingIntoRegion != null)
210 {
211 handlerAvatarCrossingIntoRegion(agentID, position, isFlying);
212 }
213 }
214
215 protected bool IncomingPrimCrossing(UUID primID, String objXMLData, int XMLMethod)
216 {
217 handlerExpectPrim = OnExpectPrim;
218 if (handlerExpectPrim != null)
219 {
220 return handlerExpectPrim(primID, objXMLData, XMLMethod);
221 }
222 else
223 {
224 return false;
225 }
226
227 }
228
229 protected void PrimCrossing(UUID primID, Vector3 position, bool isPhysical)
230 {
231 handlerPrimCrossingIntoRegion = OnPrimCrossingIntoRegion;
232 if (handlerPrimCrossingIntoRegion != null)
233 {
234 handlerPrimCrossingIntoRegion(primID, position, isPhysical);
235 }
236 }
237
238 protected bool CloseConnection(UUID agentID)
239 {
240 m_log.Debug("[INTERREGION]: Incoming Agent Close Request for agent: " + agentID);
241
242 handlerCloseAgentConnection = OnCloseAgentConnection;
243 if (handlerCloseAgentConnection != null)
244 {
245 return handlerCloseAgentConnection(agentID);
246 }
247
248 return false;
249 }
250
251 protected LandData FetchLandData(uint x, uint y)
252 {
253 handlerGetLandData = OnGetLandData;
254 if (handlerGetLandData != null)
255 {
256 return handlerGetLandData(x, y);
257 }
258 return null;
259 }
260
261 #endregion
262
263 #region Inform Client of Neighbours
264
265 private delegate void InformClientOfNeighbourDelegate(
266 ScenePresence avatar, AgentCircuitData a, SimpleRegionInfo reg, IPEndPoint endPoint, bool newAgent);
267
268 private void InformClientOfNeighbourCompleted(IAsyncResult iar)
269 {
270 InformClientOfNeighbourDelegate icon = (InformClientOfNeighbourDelegate) iar.AsyncState;
271 icon.EndInvoke(iar);
272 }
273
274 /// <summary>
275 /// Async component for informing client of which neighbours exist
276 /// </summary>
277 /// <remarks>
278 /// This needs to run asynchronesously, as a network timeout may block the thread for a long while
279 /// </remarks>
280 /// <param name="remoteClient"></param>
281 /// <param name="a"></param>
282 /// <param name="regionHandle"></param>
283 /// <param name="endPoint"></param>
284 private void InformClientOfNeighbourAsync(ScenePresence avatar, AgentCircuitData a, SimpleRegionInfo reg,
285 IPEndPoint endPoint, bool newAgent)
286 {
287 // Let's wait just a little to give time to originating regions to catch up with closing child agents
288 // after a cross here
289 Thread.Sleep(500);
290
291 uint x, y;
292 Utils.LongToUInts(reg.RegionHandle, out x, out y);
293 x = x / Constants.RegionSize;
294 y = y / Constants.RegionSize;
295 m_log.Info("[INTERGRID]: Starting to inform client about neighbour " + x + ", " + y + "(" + endPoint.ToString() + ")");
296
297 string capsPath = "http://" + reg.ExternalHostName + ":" + reg.HttpPort
298 + "/CAPS/" + a.CapsPath + "0000/";
299
300 //bool regionAccepted = m_commsProvider.InterRegion.InformRegionOfChildAgent(reg.RegionHandle, a);
301 bool regionAccepted = m_interregionCommsOut.SendCreateChildAgent(reg.RegionHandle, a);
302
303 if (regionAccepted && newAgent)
304 {
305 IEventQueue eq = avatar.Scene.RequestModuleInterface<IEventQueue>();
306 if (eq != null)
307 {
308 OSD Item = EventQueueHelper.EnableSimulator(reg.RegionHandle, endPoint);
309 eq.Enqueue(Item, avatar.UUID);
310
311 Item = EventQueueHelper.EstablishAgentCommunication(avatar.UUID, endPoint.ToString(), capsPath);
312 eq.Enqueue(Item, avatar.UUID);
313
314 m_log.DebugFormat("[CAPS]: Sending new CAPS seed url {0} to client {1} in region {2}", capsPath, avatar.UUID, avatar.Scene.RegionInfo.RegionName);
315 }
316 else
317 {
318 avatar.ControllingClient.InformClientOfNeighbour(reg.RegionHandle, endPoint);
319 // TODO: make Event Queue disablable!
320 }
321
322 m_log.Info("[INTERGRID]: Completed inform client about neighbour " + endPoint.ToString());
323 }
324 }
325
326 public void RequestNeighbors(RegionInfo region)
327 {
328 // List<SimpleRegionInfo> neighbours =
329 m_commsProvider.GridService.RequestNeighbours(m_regionInfo.RegionLocX, m_regionInfo.RegionLocY);
330 //IPEndPoint blah = new IPEndPoint();
331
332 //blah.Address = region.RemotingAddress;
333 //blah.Port = region.RemotingPort;
334 }
335
336 /// <summary>
337 /// This informs all neighboring regions about agent "avatar".
338 /// Calls an asynchronous method to do so.. so it doesn't lag the sim.
339 /// </summary>
340 public void EnableNeighbourChildAgents(ScenePresence avatar, List<RegionInfo> lstneighbours)
341 {
342 List<SimpleRegionInfo> neighbours = new List<SimpleRegionInfo>();
343
344 //m_commsProvider.GridService.RequestNeighbours(m_regionInfo.RegionLocX, m_regionInfo.RegionLocY);
345 for (int i = 0; i < lstneighbours.Count; i++)
346 {
347 // We don't want to keep sending to regions that consistently fail on comms.
348 if (!(lstneighbours[i].commFailTF))
349 {
350 neighbours.Add(new SimpleRegionInfo(lstneighbours[i]));
351 }
352 }
353 // we're going to be using the above code once neighbour cache is correct. Currently it doesn't appear to be
354 // So we're temporarily going back to the old method of grabbing it from the Grid Server Every time :/
355 neighbours =
356 m_commsProvider.GridService.RequestNeighbours(m_regionInfo.RegionLocX, m_regionInfo.RegionLocY);
357
358 /// We need to find the difference between the new regions where there are no child agents
359 /// and the regions where there are already child agents. We only send notification to the former.
360 List<ulong> neighbourHandles = NeighbourHandles(neighbours); // on this region
361 neighbourHandles.Add(avatar.Scene.RegionInfo.RegionHandle); // add this region too
362 List<ulong> previousRegionNeighbourHandles
363 = new List<ulong>(avatar.Scene.CapsModule.GetChildrenSeeds(avatar.UUID).Keys);
364 List<ulong> newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles);
365 List<ulong> oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles);
366
367 //Dump("Current Neighbors", neighbourHandles);
368 //Dump("Previous Neighbours", previousRegionNeighbourHandles);
369 //Dump("New Neighbours", newRegions);
370 //Dump("Old Neighbours", oldRegions);
371
372 /// Update the scene presence's known regions here on this region
373 avatar.DropOldNeighbours(oldRegions);
374
375 /// Collect as many seeds as possible
376 Dictionary<ulong, string> seeds
377 = new Dictionary<ulong, string>(avatar.Scene.CapsModule.GetChildrenSeeds(avatar.UUID));
378
379 //Console.WriteLine(" !!! No. of seeds: " + seeds.Count);
380 if (!seeds.ContainsKey(avatar.Scene.RegionInfo.RegionHandle))
381 seeds.Add(avatar.Scene.RegionInfo.RegionHandle, avatar.ControllingClient.RequestClientInfo().CapsPath);
382
383 /// Create the necessary child agents
384 List<AgentCircuitData> cagents = new List<AgentCircuitData>();
385 foreach (SimpleRegionInfo neighbour in neighbours)
386 {
387 if (neighbour.RegionHandle != avatar.Scene.RegionInfo.RegionHandle)
388 {
389
390 AgentCircuitData agent = avatar.ControllingClient.RequestClientInfo();
391 agent.BaseFolder = UUID.Zero;
392 agent.InventoryFolder = UUID.Zero;
393 agent.startpos = new Vector3(128, 128, 70);
394 agent.child = true;
395
396 if (newRegions.Contains(neighbour.RegionHandle))
397 {
398 agent.CapsPath = CapsUtil.GetRandomCapsObjectPath();
399 avatar.AddNeighbourRegion(neighbour.RegionHandle, agent.CapsPath);
400 seeds.Add(neighbour.RegionHandle, agent.CapsPath);
401 }
402 else
403 agent.CapsPath = avatar.Scene.CapsModule.GetChildSeed(avatar.UUID, neighbour.RegionHandle);
404
405 cagents.Add(agent);
406 }
407 }
408
409 /// Update all child agent with everyone's seeds
410 foreach (AgentCircuitData a in cagents)
411 {
412 a.ChildrenCapSeeds = new Dictionary<ulong, string>(seeds);
413 }
414 // These two are the same thing!
415 avatar.Scene.CapsModule.SetChildrenSeed(avatar.UUID, seeds);
416 avatar.KnownRegions = seeds;
417 //avatar.Scene.DumpChildrenSeeds(avatar.UUID);
418 //avatar.DumpKnownRegions();
419
420 bool newAgent = false;
421 int count = 0;
422 foreach (SimpleRegionInfo neighbour in neighbours)
423 {
424 // Don't do it if there's already an agent in that region
425 if (newRegions.Contains(neighbour.RegionHandle))
426 newAgent = true;
427 else
428 newAgent = false;
429
430 if (neighbour.RegionHandle != avatar.Scene.RegionInfo.RegionHandle)
431 {
432 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
433 try
434 {
435 d.BeginInvoke(avatar, cagents[count], neighbour, neighbour.ExternalEndPoint, newAgent,
436 InformClientOfNeighbourCompleted,
437 d);
438 }
439 catch (Exception e)
440 {
441 m_log.ErrorFormat(
442 "[REGIONINFO]: Could not resolve external hostname {0} for region {1} ({2}, {3}). {4}",
443 neighbour.ExternalHostName,
444 neighbour.RegionHandle,
445 neighbour.RegionLocX,
446 neighbour.RegionLocY,
447 e);
448
449 // FIXME: Okay, even though we've failed, we're still going to throw the exception on,
450 // since I don't know what will happen if we just let the client continue
451
452 // XXX: Well, decided to swallow the exception instead for now. Let us see how that goes.
453 // throw e;
454
455 }
456 }
457 count++;
458 }
459 }
460
461 /// <summary>
462 /// This informs a single neighboring region about agent "avatar".
463 /// Calls an asynchronous method to do so.. so it doesn't lag the sim.
464 /// </summary>
465 public void InformNeighborChildAgent(ScenePresence avatar, SimpleRegionInfo region, List<RegionInfo> neighbours)
466 {
467 AgentCircuitData agent = avatar.ControllingClient.RequestClientInfo();
468 agent.BaseFolder = UUID.Zero;
469 agent.InventoryFolder = UUID.Zero;
470 agent.startpos = new Vector3(128, 128, 70);
471 agent.child = true;
472
473 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
474 d.BeginInvoke(avatar, agent, region, region.ExternalEndPoint, true,
475 InformClientOfNeighbourCompleted,
476 d);
477 }
478
479 #endregion
480
481 public delegate void InformNeighbourThatRegionUpDelegate(RegionInfo region, ulong regionhandle);
482
483 private void InformNeighborsThatRegionisUpCompleted(IAsyncResult iar)
484 {
485 InformNeighbourThatRegionUpDelegate icon = (InformNeighbourThatRegionUpDelegate) iar.AsyncState;
486 icon.EndInvoke(iar);
487 }
488
489 /// <summary>
490 /// Asynchronous call to information neighbouring regions that this region is up
491 /// </summary>
492 /// <param name="region"></param>
493 /// <param name="regionhandle"></param>
494 private void InformNeighboursThatRegionIsUpAsync(RegionInfo region, ulong regionhandle)
495 {
496 m_log.Info("[INTERGRID]: Starting to inform neighbors that I'm here");
497 //RegionUpData regiondata = new RegionUpData(region.RegionLocX, region.RegionLocY, region.ExternalHostName, region.InternalEndPoint.Port);
498
499 bool regionAccepted =
500 m_commsProvider.InterRegion.RegionUp(new SerializableRegionInfo(region), regionhandle);
501
502 if (regionAccepted)
503 {
504 m_log.Info("[INTERGRID]: Completed informing neighbors that I'm here");
505 handlerRegionUp = OnRegionUp;
506
507 // yes, we're notifying ourselves.
508 if (handlerRegionUp != null)
509 handlerRegionUp(region);
510 }
511 else
512 {
513 m_log.Warn("[INTERGRID]: Failed to inform neighbors that I'm here.");
514 }
515 }
516
517 /// <summary>
518 /// Called by scene when region is initialized (not always when it's listening for agents)
519 /// This is an inter-region message that informs the surrounding neighbors that the sim is up.
520 /// </summary>
521 public void InformNeighborsThatRegionisUp(RegionInfo region)
522 {
523 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: Sending InterRegion Notification that region is up " + region.RegionName);
524
525
526 List<SimpleRegionInfo> neighbours = new List<SimpleRegionInfo>();
527 // This stays uncached because we don't already know about our neighbors at this point.
528 neighbours = m_commsProvider.GridService.RequestNeighbours(m_regionInfo.RegionLocX, m_regionInfo.RegionLocY);
529 if (neighbours != null)
530 {
531 for (int i = 0; i < neighbours.Count; i++)
532 {
533 InformNeighbourThatRegionUpDelegate d = InformNeighboursThatRegionIsUpAsync;
534
535 d.BeginInvoke(region, neighbours[i].RegionHandle,
536 InformNeighborsThatRegionisUpCompleted,
537 d);
538 }
539 }
540
541 //bool val = m_commsProvider.InterRegion.RegionUp(new SerializableRegionInfo(region));
542 }
543
544 public delegate void SendChildAgentDataUpdateDelegate(AgentPosition cAgentData, ulong regionHandle);
545
546 /// <summary>
547 /// This informs all neighboring regions about the settings of it's child agent.
548 /// Calls an asynchronous method to do so.. so it doesn't lag the sim.
549 ///
550 /// This contains information, such as, Draw Distance, Camera location, Current Position, Current throttle settings, etc.
551 ///
552 /// </summary>
553 private void SendChildAgentDataUpdateAsync(AgentPosition cAgentData, ulong regionHandle)
554 {
555 //m_log.Info("[INTERGRID]: Informing neighbors about my agent in " + m_regionInfo.RegionName);
556 try
557 {
558 //m_commsProvider.InterRegion.ChildAgentUpdate(regionHandle, cAgentData);
559 m_interregionCommsOut.SendChildAgentUpdate(regionHandle, cAgentData);
560 }
561 catch
562 {
563 // Ignore; we did our best
564 }
565
566 //if (regionAccepted)
567 //{
568 // //m_log.Info("[INTERGRID]: Completed sending a neighbor an update about my agent");
569 //}
570 //else
571 //{
572 // //m_log.Info("[INTERGRID]: Failed sending a neighbor an update about my agent");
573 //}
574
575 }
576
577 private void SendChildAgentDataUpdateCompleted(IAsyncResult iar)
578 {
579 SendChildAgentDataUpdateDelegate icon = (SendChildAgentDataUpdateDelegate) iar.AsyncState;
580 icon.EndInvoke(iar);
581 }
582
583 public void SendChildAgentDataUpdate(AgentPosition cAgentData, ScenePresence presence)
584 {
585 // This assumes that we know what our neighbors are.
586 try
587 {
588 foreach (ulong regionHandle in presence.KnownChildRegionHandles)
589 {
590 if (regionHandle != m_regionInfo.RegionHandle)
591 {
592 SendChildAgentDataUpdateDelegate d = SendChildAgentDataUpdateAsync;
593 d.BeginInvoke(cAgentData, regionHandle,
594 SendChildAgentDataUpdateCompleted,
595 d);
596 }
597 }
598 }
599 catch (InvalidOperationException)
600 {
601 // We're ignoring a collection was modified error because this data gets old and outdated fast.
602 }
603
604 }
605
606 public delegate void SendCloseChildAgentDelegate(UUID agentID, ulong regionHandle);
607
608 /// <summary>
609 /// This Closes child agents on neighboring regions
610 /// Calls an asynchronous method to do so.. so it doesn't lag the sim.
611 /// </summary>
612 protected void SendCloseChildAgentAsync(UUID agentID, ulong regionHandle)
613 {
614
615 m_log.Debug("[INTERGRID]: Sending close agent to " + regionHandle);
616 // let's do our best, but there's not much we can do if the neighbour doesn't accept.
617
618 //m_commsProvider.InterRegion.TellRegionToCloseChildConnection(regionHandle, agentID);
619 m_interregionCommsOut.SendCloseAgent(regionHandle, agentID);
620 }
621
622 private void SendCloseChildAgentCompleted(IAsyncResult iar)
623 {
624 SendCloseChildAgentDelegate icon = (SendCloseChildAgentDelegate)iar.AsyncState;
625 icon.EndInvoke(iar);
626 }
627
628 public void SendCloseChildAgentConnections(UUID agentID, List<ulong> regionslst)
629 {
630 foreach (ulong handle in regionslst)
631 {
632 SendCloseChildAgentDelegate d = SendCloseChildAgentAsync;
633 d.BeginInvoke(agentID, handle,
634 SendCloseChildAgentCompleted,
635 d);
636 }
637 }
638
639 /// <summary>
640 /// Helper function to request neighbors from grid-comms
641 /// </summary>
642 /// <param name="regionHandle"></param>
643 /// <returns></returns>
644 public virtual RegionInfo RequestNeighbouringRegionInfo(ulong regionHandle)
645 {
646 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: Sending Grid Services Request about neighbor " + regionHandle.ToString());
647 return m_commsProvider.GridService.RequestNeighbourInfo(regionHandle);
648 }
649
650 /// <summary>
651 /// Helper function to request neighbors from grid-comms
652 /// </summary>
653 /// <param name="regionID"></param>
654 /// <returns></returns>
655 public virtual RegionInfo RequestNeighbouringRegionInfo(UUID regionID)
656 {
657 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: Sending Grid Services Request about neighbor " + regionID);
658 return m_commsProvider.GridService.RequestNeighbourInfo(regionID);
659 }
660
661 /// <summary>
662 /// Requests map blocks in area of minX, maxX, minY, MaxY in world cordinates
663 /// </summary>
664 /// <param name="minX"></param>
665 /// <param name="minY"></param>
666 /// <param name="maxX"></param>
667 /// <param name="maxY"></param>
668 public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY)
669 {
670 List<MapBlockData> mapBlocks;
671 mapBlocks = m_commsProvider.GridService.RequestNeighbourMapBlocks(minX - 4, minY - 4, minX + 4, minY + 4);
672 remoteClient.SendMapBlock(mapBlocks, 0);
673 }
674
675 /// <summary>
676 /// Try to teleport an agent to a new region.
677 /// </summary>
678 /// <param name="remoteClient"></param>
679 /// <param name="RegionHandle"></param>
680 /// <param name="position"></param>
681 /// <param name="lookAt"></param>
682 /// <param name="flags"></param>
683 public virtual void RequestTeleportToLocation(ScenePresence avatar, ulong regionHandle, Vector3 position,
684 Vector3 lookAt, uint teleportFlags)
685 {
686 if (!avatar.Scene.Permissions.CanTeleport(avatar.UUID))
687 return;
688
689 bool destRegionUp = true;
690
691 IEventQueue eq = avatar.Scene.RequestModuleInterface<IEventQueue>();
692
693 if (regionHandle == m_regionInfo.RegionHandle)
694 {
695 m_log.DebugFormat(
696 "[SCENE COMMUNICATION SERVICE]: RequestTeleportToLocation {0} within {1}",
697 position, m_regionInfo.RegionName);
698
699 // Teleport within the same region
700 if (position.X < 0 || position.X > Constants.RegionSize || position.Y < 0 || position.Y > Constants.RegionSize || position.Z < 0)
701 {
702 Vector3 emergencyPos = new Vector3(128, 128, 128);
703
704 m_log.WarnFormat(
705 "[SCENE COMMUNICATION SERVICE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}",
706 position, avatar.Name, avatar.UUID, emergencyPos);
707 position = emergencyPos;
708 }
709
710 // TODO: Get proper AVG Height
711 float localAVHeight = 1.56f;
712 float posZLimit = (float)avatar.Scene.GetLandHeight((int)position.X, (int)position.Y);
713 float newPosZ = posZLimit + localAVHeight;
714 if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ)))
715 {
716 position.Z = newPosZ;
717 }
718
719 // Only send this if the event queue is null
720 if (eq == null)
721 avatar.ControllingClient.SendTeleportLocationStart();
722
723 avatar.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags);
724 avatar.Teleport(position);
725 }
726 else
727 {
728 RegionInfo reg = RequestNeighbouringRegionInfo(regionHandle);
729 if (reg != null)
730 {
731 m_log.DebugFormat(
732 "[SCENE COMMUNICATION SERVICE]: RequestTeleportToLocation to {0} in {1}",
733 position, reg.RegionName);
734
735 if (eq == null)
736 avatar.ControllingClient.SendTeleportLocationStart();
737
738 // Let's do DNS resolution only once in this process, please!
739 // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field,
740 // it's actually doing a lot of work.
741 IPEndPoint endPoint = reg.ExternalEndPoint;
742 if (endPoint.Address == null)
743 {
744 // Couldn't resolve the name. Can't TP, because the viewer wants IP addresses.
745 destRegionUp = false;
746 }
747
748 if (destRegionUp)
749 {
750 uint newRegionX = (uint)(reg.RegionHandle >> 40);
751 uint newRegionY = (((uint)(reg.RegionHandle)) >> 8);
752 uint oldRegionX = (uint)(m_regionInfo.RegionHandle >> 40);
753 uint oldRegionY = (((uint)(m_regionInfo.RegionHandle)) >> 8);
754
755 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from
756 // both regions
757 if (avatar.ParentID != (uint)0)
758 avatar.StandUp();
759
760 if (!avatar.ValidateAttachments())
761 {
762 avatar.ControllingClient.SendTeleportFailed("Inconsistent attachment state");
763 return;
764 }
765
766 // the avatar.Close below will clear the child region list. We need this below for (possibly)
767 // closing the child agents, so save it here (we need a copy as it is Clear()-ed).
768 //List<ulong> childRegions = new List<ulong>(avatar.GetKnownRegionList());
769 // Compared to ScenePresence.CrossToNewRegion(), there's no obvious code to handle a teleport
770 // failure at this point (unlike a border crossing failure). So perhaps this can never fail
771 // once we reach here...
772 //avatar.Scene.RemoveCapsHandler(avatar.UUID);
773
774 string capsPath = String.Empty;
775 AgentCircuitData agentCircuit = avatar.ControllingClient.RequestClientInfo();
776 agentCircuit.BaseFolder = UUID.Zero;
777 agentCircuit.InventoryFolder = UUID.Zero;
778 agentCircuit.startpos = position;
779 agentCircuit.child = true;
780
781 if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY))
782 {
783 // brand new agent, let's create a new caps seed
784 agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath();
785 }
786
787 // Let's create an agent there if one doesn't exist yet.
788 //if (!m_commsProvider.InterRegion.InformRegionOfChildAgent(reg.RegionHandle, agentCircuit))
789 if (!m_interregionCommsOut.SendCreateChildAgent(reg.RegionHandle, agentCircuit))
790 {
791 avatar.ControllingClient.SendTeleportFailed("Destination is not accepting teleports.");
792 return;
793 }
794
795 // OK, it got this agent. Let's close some child agents
796 avatar.CloseChildAgents(newRegionX, newRegionY);
797
798 if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY))
799 {
800 capsPath
801 = "http://"
802 + reg.ExternalHostName
803 + ":"
804 + reg.HttpPort
805 + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
806
807 if (eq != null)
808 {
809 OSD Item = EventQueueHelper.EnableSimulator(reg.RegionHandle, endPoint);
810 eq.Enqueue(Item, avatar.UUID);
811
812 // ES makes the client send a UseCircuitCode message to the destination,
813 // which triggers a bunch of things there.
814 // So let's wait
815 Thread.Sleep(2000);
816
817 Item = EventQueueHelper.EstablishAgentCommunication(avatar.UUID, endPoint.ToString(), capsPath);
818 eq.Enqueue(Item, avatar.UUID);
819 }
820 else
821 {
822 avatar.ControllingClient.InformClientOfNeighbour(reg.RegionHandle, endPoint);
823 }
824 }
825 else
826 {
827 agentCircuit.CapsPath = avatar.Scene.CapsModule.GetChildSeed(avatar.UUID, reg.RegionHandle);
828 capsPath = "http://" + reg.ExternalHostName + ":" + reg.HttpPort
829 + "/CAPS/" + agentCircuit.CapsPath + "0000/";
830 }
831
832 // Expect avatar crossing is a heavy-duty function at the destination.
833 // That is where MakeRoot is called, which fetches appearance and inventory.
834 // Plus triggers OnMakeRoot, which spawns a series of asynchronous updates.
835 //m_commsProvider.InterRegion.ExpectAvatarCrossing(reg.RegionHandle, avatar.ControllingClient.AgentId,
836 // position, false);
837
838 //{
839 // avatar.ControllingClient.SendTeleportFailed("Problem with destination.");
840 // // We should close that agent we just created over at destination...
841 // List<ulong> lst = new List<ulong>();
842 // lst.Add(reg.RegionHandle);
843 // SendCloseChildAgentAsync(avatar.UUID, lst);
844 // return;
845 //}
846
847 SetInTransit(avatar.UUID);
848 // Let's send a full update of the agent. This is a synchronous call.
849 AgentData agent = new AgentData();
850 avatar.CopyTo(agent);
851 agent.Position = position;
852 agent.CallbackURI = "http://" + m_regionInfo.ExternalHostName + ":" + m_regionInfo.HttpPort +
853 "/agent/" + avatar.UUID.ToString() + "/" + avatar.Scene.RegionInfo.RegionHandle.ToString() + "/release/";
854
855 m_interregionCommsOut.SendChildAgentUpdate(reg.RegionHandle, agent);
856
857 m_log.DebugFormat(
858 "[CAPS]: Sending new CAPS seed url {0} to client {1}", capsPath, avatar.UUID);
859
860
861 if (eq != null)
862 {
863 OSD Item = EventQueueHelper.TeleportFinishEvent(reg.RegionHandle, 13, endPoint,
864 4, teleportFlags, capsPath, avatar.UUID);
865 eq.Enqueue(Item, avatar.UUID);
866 }
867 else
868 {
869 avatar.ControllingClient.SendRegionTeleport(reg.RegionHandle, 13, endPoint, 4,
870 teleportFlags, capsPath);
871 }
872
873 // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which
874 // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation
875 // that the client contacted the destination before we send the attachments and close things here.
876 if (!WaitForCallback(avatar.UUID))
877 {
878 // Client never contacted destination. Let's restore everything back
879 avatar.ControllingClient.SendTeleportFailed("Problems connecting to destination.");
880
881 ResetFromTransit(avatar.UUID);
882
883 // Yikes! We should just have a ref to scene here.
884 avatar.Scene.InformClientOfNeighbours(avatar);
885
886 // Finally, kill the agent we just created at the destination.
887 m_interregionCommsOut.SendCloseAgent(reg.RegionHandle, avatar.UUID);
888
889 return;
890 }
891
892 // Can't go back from here
893 if (KiPrimitive != null)
894 {
895 KiPrimitive(avatar.LocalId);
896 }
897
898 avatar.MakeChildAgent();
899
900 // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it
901 avatar.CrossAttachmentsIntoNewRegion(reg.RegionHandle, true);
902
903 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
904
905 if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY))
906 {
907 Thread.Sleep(5000);
908 avatar.Close();
909 CloseConnection(avatar.UUID);
910 }
911
912 // if (teleport success) // seems to be always success here
913 // the user may change their profile information in other region,
914 // so the userinfo in UserProfileCache is not reliable any more, delete it
915 if (avatar.Scene.NeedSceneCacheClear(avatar.UUID))
916 {
917 m_commsProvider.UserProfileCacheService.RemoveUser(avatar.UUID);
918 m_log.DebugFormat(
919 "[SCENE COMMUNICATION SERVICE]: User {0} is going to another region, profile cache removed",
920 avatar.UUID);
921 }
922 }
923 else
924 {
925 avatar.ControllingClient.SendTeleportFailed("Remote Region appears to be down");
926 }
927 }
928 else
929 {
930 // TP to a place that doesn't exist (anymore)
931 // Inform the viewer about that
932 avatar.ControllingClient.SendTeleportFailed("The region you tried to teleport to doesn't exist anymore");
933
934 // and set the map-tile to '(Offline)'
935 uint regX, regY;
936 Utils.LongToUInts(regionHandle, out regX, out regY);
937
938 MapBlockData block = new MapBlockData();
939 block.X = (ushort)(regX / Constants.RegionSize);
940 block.Y = (ushort)(regY / Constants.RegionSize);
941 block.Access = 254; // == not there
942
943 List<MapBlockData> blocks = new List<MapBlockData>();
944 blocks.Add(block);
945 avatar.ControllingClient.SendMapBlock(blocks, 0);
946 }
947 }
948 }
949
950 protected bool WaitForCallback(UUID id)
951 {
952 int count = 20;
953 while (m_agentsInTransit.Contains(id) && count-- > 0)
954 {
955 //Console.WriteLine(" >>> Waiting... " + count);
956 Thread.Sleep(1000);
957 }
958
959 if (count > 0)
960 return true;
961 else
962 return false;
963 }
964
965 public bool ReleaseAgent(UUID id)
966 {
967 //Console.WriteLine(" >>> ReleaseAgent called <<< ");
968 return ResetFromTransit(id);
969 }
970
971 protected void SetInTransit(UUID id)
972 {
973 lock (m_agentsInTransit)
974 {
975 if (!m_agentsInTransit.Contains(id))
976 m_agentsInTransit.Add(id);
977 }
978 }
979
980 protected bool ResetFromTransit(UUID id)
981 {
982 lock (m_agentsInTransit)
983 {
984 if (m_agentsInTransit.Contains(id))
985 {
986 m_agentsInTransit.Remove(id);
987 return true;
988 }
989 }
990 return false;
991 }
992
993 private List<ulong> NeighbourHandles(List<SimpleRegionInfo> neighbours)
994 {
995 List<ulong> handles = new List<ulong>();
996 foreach (SimpleRegionInfo reg in neighbours)
997 {
998 handles.Add(reg.RegionHandle);
999 }
1000 return handles;
1001 }
1002
1003 private List<ulong> NewNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours)
1004 {
1005 return currentNeighbours.FindAll(delegate(ulong handle) { return !previousNeighbours.Contains(handle); });
1006 }
1007
1008// private List<ulong> CommonNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours)
1009// {
1010// return currentNeighbours.FindAll(delegate(ulong handle) { return previousNeighbours.Contains(handle); });
1011// }
1012
1013 private List<ulong> OldNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours)
1014 {
1015 return previousNeighbours.FindAll(delegate(ulong handle) { return !currentNeighbours.Contains(handle); });
1016 }
1017 /// <summary>
1018 /// Inform a neighbouring region that an avatar is about to cross into it.
1019 /// </summary>
1020 /// <param name="regionhandle"></param>
1021 /// <param name="agentID"></param>
1022 /// <param name="position"></param>
1023 public bool CrossToNeighbouringRegion(ulong regionhandle, UUID agentID, Vector3 position, bool isFlying)
1024 {
1025 return m_commsProvider.InterRegion.ExpectAvatarCrossing(regionhandle, agentID, position, isFlying);
1026 }
1027
1028 public bool PrimCrossToNeighboringRegion(ulong regionhandle, UUID primID, string objData, int XMLMethod)
1029 {
1030 return m_commsProvider.InterRegion.InformRegionOfPrimCrossing(regionhandle, primID, objData, XMLMethod);
1031 }
1032
1033 public Dictionary<string, string> GetGridSettings()
1034 {
1035 return m_commsProvider.GridService.GetGridSettings();
1036 }
1037
1038 public void LogOffUser(UUID userid, UUID regionid, ulong regionhandle, Vector3 position, Vector3 lookat)
1039 {
1040 m_commsProvider.LogOffUser(userid, regionid, regionhandle, position, lookat);
1041 }
1042
1043 // deprecated as of 2008-08-27
1044 public void LogOffUser(UUID userid, UUID regionid, ulong regionhandle, float posx, float posy, float posz)
1045 {
1046 m_commsProvider.LogOffUser(userid, regionid, regionhandle, posx, posy, posz);
1047 }
1048
1049 public void ClearUserAgent(UUID avatarID)
1050 {
1051 m_commsProvider.UserService.ClearUserAgent(avatarID);
1052 }
1053
1054 public void AddNewUserFriend(UUID friendlistowner, UUID friend, uint perms)
1055 {
1056 m_commsProvider.AddNewUserFriend(friendlistowner, friend, perms);
1057 }
1058
1059 public void UpdateUserFriendPerms(UUID friendlistowner, UUID friend, uint perms)
1060 {
1061 m_commsProvider.UpdateUserFriendPerms(friendlistowner, friend, perms);
1062 }
1063
1064 public void RemoveUserFriend(UUID friendlistowner, UUID friend)
1065 {
1066 m_commsProvider.RemoveUserFriend(friendlistowner, friend);
1067 }
1068
1069 public List<FriendListItem> GetUserFriendList(UUID friendlistowner)
1070 {
1071 return m_commsProvider.GetUserFriendList(friendlistowner);
1072 }
1073
1074 public List<MapBlockData> RequestNeighbourMapBlocks(int minX, int minY, int maxX, int maxY)
1075 {
1076 return m_commsProvider.GridService.RequestNeighbourMapBlocks(minX, minY, maxX, maxY);
1077 }
1078
1079 public List<AvatarPickerAvatar> GenerateAgentPickerRequestResponse(UUID queryID, string query)
1080 {
1081 return m_commsProvider.GenerateAgentPickerRequestResponse(queryID, query);
1082 }
1083
1084 public List<RegionInfo> RequestNamedRegions(string name, int maxNumber)
1085 {
1086 return m_commsProvider.GridService.RequestNamedRegions(name, maxNumber);
1087 }
1088
1089// private void Dump(string msg, List<ulong> handles)
1090// {
1091// Console.WriteLine("-------------- HANDLE DUMP ({0}) ---------", msg);
1092// foreach (ulong handle in handles)
1093// {
1094// uint x, y;
1095// Utils.LongToUInts(handle, out x, out y);
1096// x = x / Constants.RegionSize;
1097// y = y / Constants.RegionSize;
1098// Console.WriteLine("({0}, {1})", x, y);
1099// }
1100// }
1101 }
1102}