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