EntityTransferModule.cs 125 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744
  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. using System;
  28. using System.Collections.Generic;
  29. using System.Net;
  30. using System.Reflection;
  31. using System.Threading;
  32. using OpenSim.Framework;
  33. using OpenSim.Framework.Capabilities;
  34. using OpenSim.Framework.Client;
  35. using OpenSim.Framework.Monitoring;
  36. using OpenSim.Region.Framework.Interfaces;
  37. using OpenSim.Region.Framework.Scenes;
  38. using OpenSim.Region.PhysicsModules.SharedBase;
  39. using OpenSim.Services.Interfaces;
  40. using GridRegion = OpenSim.Services.Interfaces.GridRegion;
  41. using OpenMetaverse;
  42. using log4net;
  43. using Nini.Config;
  44. using Mono.Addins;
  45. namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
  46. {
  47. [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "EntityTransferModule")]
  48. public class EntityTransferModule : INonSharedRegionModule, IEntityTransferModule
  49. {
  50. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  51. private static readonly string LogHeader = "[ENTITY TRANSFER MODULE]";
  52. public const int DefaultMaxTransferDistance = 4095;
  53. public const bool WaitForAgentArrivedAtDestinationDefault = true;
  54. /// <summary>
  55. /// The maximum distance, in standard region units (256m) that an agent is allowed to transfer.
  56. /// </summary>
  57. public int MaxTransferDistance { get; set; }
  58. /// <summary>
  59. /// If true then on a teleport, the source region waits for a callback from the destination region. If
  60. /// a callback fails to arrive within a set time then the user is pulled back into the source region.
  61. /// </summary>
  62. public bool WaitForAgentArrivedAtDestination { get; set; }
  63. /// <summary>
  64. /// If true then we ask the viewer to disable teleport cancellation and ignore teleport requests.
  65. /// </summary>
  66. /// <remarks>
  67. /// This is useful in situations where teleport is very likely to always succeed and we want to avoid a
  68. /// situation where avatars can be come 'stuck' due to a failed teleport cancellation. Unfortunately, the
  69. /// nature of the teleport protocol makes it extremely difficult (maybe impossible) to make teleport
  70. /// cancellation consistently suceed.
  71. /// </remarks>
  72. public bool DisableInterRegionTeleportCancellation { get; set; }
  73. /// <summary>
  74. /// Number of times inter-region teleport was attempted.
  75. /// </summary>
  76. private Stat m_interRegionTeleportAttempts;
  77. /// <summary>
  78. /// Number of times inter-region teleport was aborted (due to simultaneous client logout).
  79. /// </summary>
  80. private Stat m_interRegionTeleportAborts;
  81. /// <summary>
  82. /// Number of times inter-region teleport was successfully cancelled by the client.
  83. /// </summary>
  84. private Stat m_interRegionTeleportCancels;
  85. /// <summary>
  86. /// Number of times inter-region teleport failed due to server/client/network problems (e.g. viewer failed to
  87. /// connect with destination region).
  88. /// </summary>
  89. /// <remarks>
  90. /// This is not necessarily a problem for this simulator - in open-grid/hg conditions, viewer connectivity to
  91. /// destination simulator is unknown.
  92. /// </remarks>
  93. private Stat m_interRegionTeleportFailures;
  94. protected string m_ThisHomeURI;
  95. protected string m_GatekeeperURI;
  96. protected bool m_Enabled = false;
  97. public Scene Scene { get; private set; }
  98. /// <summary>
  99. /// Handles recording and manipulation of state for entities that are in transfer within or between regions
  100. /// (cross or teleport).
  101. /// </summary>
  102. private EntityTransferStateMachine m_entityTransferStateMachine;
  103. // For performance, we keed a cached of banned regions so we don't keep going
  104. // to the grid service.
  105. private class BannedRegionCache
  106. {
  107. private ExpiringCache<UUID, ExpiringCache<ulong, DateTime>> m_bannedRegions =
  108. new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>();
  109. ExpiringCache<ulong, DateTime> m_idCache;
  110. DateTime m_banUntil;
  111. public BannedRegionCache()
  112. {
  113. }
  114. // Return 'true' if there is a valid ban entry for this agent in this region
  115. public bool IfBanned(ulong pRegionHandle, UUID pAgentID)
  116. {
  117. bool ret = false;
  118. if (m_bannedRegions.TryGetValue(pAgentID, out m_idCache))
  119. {
  120. if (m_idCache.TryGetValue(pRegionHandle, out m_banUntil))
  121. {
  122. if (DateTime.Now < m_banUntil)
  123. {
  124. ret = true;
  125. }
  126. }
  127. }
  128. return ret;
  129. }
  130. // Add this agent in this region as a banned person
  131. public void Add(ulong pRegionHandle, UUID pAgentID)
  132. {
  133. if (!m_bannedRegions.TryGetValue(pAgentID, out m_idCache))
  134. {
  135. m_idCache = new ExpiringCache<ulong, DateTime>();
  136. m_bannedRegions.Add(pAgentID, m_idCache, TimeSpan.FromSeconds(45));
  137. }
  138. m_idCache.Add(pRegionHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15));
  139. }
  140. // Remove the agent from the region's banned list
  141. public void Remove(ulong pRegionHandle, UUID pAgentID)
  142. {
  143. if (m_bannedRegions.TryGetValue(pAgentID, out m_idCache))
  144. {
  145. m_idCache.Remove(pRegionHandle);
  146. }
  147. }
  148. }
  149. private BannedRegionCache m_bannedRegionCache = new BannedRegionCache();
  150. private IEventQueue m_eqModule;
  151. private IRegionCombinerModule m_regionCombinerModule;
  152. #region ISharedRegionModule
  153. public Type ReplaceableInterface
  154. {
  155. get { return null; }
  156. }
  157. public virtual string Name
  158. {
  159. get { return "BasicEntityTransferModule"; }
  160. }
  161. public virtual void Initialise(IConfigSource source)
  162. {
  163. IConfig moduleConfig = source.Configs["Modules"];
  164. if (moduleConfig != null)
  165. {
  166. string name = moduleConfig.GetString("EntityTransferModule", "");
  167. if (name == Name)
  168. {
  169. InitialiseCommon(source);
  170. m_log.DebugFormat("[ENTITY TRANSFER MODULE]: {0} enabled.", Name);
  171. }
  172. }
  173. }
  174. /// <summary>
  175. /// Initialize config common for this module and any descendents.
  176. /// </summary>
  177. /// <param name="source"></param>
  178. protected virtual void InitialiseCommon(IConfigSource source)
  179. {
  180. IConfig hypergridConfig = source.Configs["Hypergrid"];
  181. if (hypergridConfig != null)
  182. {
  183. m_ThisHomeURI = hypergridConfig.GetString("HomeURI", string.Empty);
  184. if (m_ThisHomeURI != string.Empty && !m_ThisHomeURI.EndsWith("/"))
  185. m_ThisHomeURI += '/';
  186. m_GatekeeperURI = hypergridConfig.GetString("GatekeeperURI", string.Empty);
  187. if (m_GatekeeperURI != string.Empty && !m_GatekeeperURI.EndsWith("/"))
  188. m_GatekeeperURI += '/';
  189. }
  190. IConfig transferConfig = source.Configs["EntityTransfer"];
  191. if (transferConfig != null)
  192. {
  193. DisableInterRegionTeleportCancellation
  194. = transferConfig.GetBoolean("DisableInterRegionTeleportCancellation", false);
  195. WaitForAgentArrivedAtDestination
  196. = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault);
  197. MaxTransferDistance = transferConfig.GetInt("max_distance", DefaultMaxTransferDistance);
  198. }
  199. else
  200. {
  201. MaxTransferDistance = DefaultMaxTransferDistance;
  202. }
  203. m_entityTransferStateMachine = new EntityTransferStateMachine(this);
  204. m_Enabled = true;
  205. }
  206. public virtual void PostInitialise()
  207. {
  208. }
  209. public virtual void AddRegion(Scene scene)
  210. {
  211. if (!m_Enabled)
  212. return;
  213. Scene = scene;
  214. m_interRegionTeleportAttempts =
  215. new Stat(
  216. "InterRegionTeleportAttempts",
  217. "Number of inter-region teleports attempted.",
  218. "This does not count attempts which failed due to pre-conditions (e.g. target simulator refused access).\n"
  219. + "You can get successfully teleports by subtracting aborts, cancels and teleport failures from this figure.",
  220. "",
  221. "entitytransfer",
  222. Scene.Name,
  223. StatType.Push,
  224. null,
  225. StatVerbosity.Debug);
  226. m_interRegionTeleportAborts =
  227. new Stat(
  228. "InterRegionTeleportAborts",
  229. "Number of inter-region teleports aborted due to client actions.",
  230. "The chief action is simultaneous logout whilst teleporting.",
  231. "",
  232. "entitytransfer",
  233. Scene.Name,
  234. StatType.Push,
  235. null,
  236. StatVerbosity.Debug);
  237. m_interRegionTeleportCancels =
  238. new Stat(
  239. "InterRegionTeleportCancels",
  240. "Number of inter-region teleports cancelled by the client.",
  241. null,
  242. "",
  243. "entitytransfer",
  244. Scene.Name,
  245. StatType.Push,
  246. null,
  247. StatVerbosity.Debug);
  248. m_interRegionTeleportFailures =
  249. new Stat(
  250. "InterRegionTeleportFailures",
  251. "Number of inter-region teleports that failed due to server/client/network issues.",
  252. "This number may not be very helpful in open-grid/hg situations as the network connectivity/quality of destinations is uncontrollable.",
  253. "",
  254. "entitytransfer",
  255. Scene.Name,
  256. StatType.Push,
  257. null,
  258. StatVerbosity.Debug);
  259. StatsManager.RegisterStat(m_interRegionTeleportAttempts);
  260. StatsManager.RegisterStat(m_interRegionTeleportAborts);
  261. StatsManager.RegisterStat(m_interRegionTeleportCancels);
  262. StatsManager.RegisterStat(m_interRegionTeleportFailures);
  263. scene.RegisterModuleInterface<IEntityTransferModule>(this);
  264. scene.EventManager.OnNewClient += OnNewClient;
  265. }
  266. protected virtual void OnNewClient(IClientAPI client)
  267. {
  268. client.OnTeleportHomeRequest += TriggerTeleportHome;
  269. client.OnTeleportLandmarkRequest += RequestTeleportLandmark;
  270. if (!DisableInterRegionTeleportCancellation)
  271. client.OnTeleportCancel += OnClientCancelTeleport;
  272. client.OnConnectionClosed += OnConnectionClosed;
  273. }
  274. public virtual void Close() {}
  275. public virtual void RemoveRegion(Scene scene)
  276. {
  277. if (m_Enabled)
  278. {
  279. StatsManager.DeregisterStat(m_interRegionTeleportAttempts);
  280. StatsManager.DeregisterStat(m_interRegionTeleportAborts);
  281. StatsManager.DeregisterStat(m_interRegionTeleportCancels);
  282. StatsManager.DeregisterStat(m_interRegionTeleportFailures);
  283. }
  284. }
  285. public virtual void RegionLoaded(Scene scene)
  286. {
  287. if (!m_Enabled)
  288. return;
  289. m_eqModule = Scene.RequestModuleInterface<IEventQueue>();
  290. m_regionCombinerModule = Scene.RequestModuleInterface<IRegionCombinerModule>();
  291. }
  292. #endregion
  293. #region Agent Teleports
  294. private void OnConnectionClosed(IClientAPI client)
  295. {
  296. if (client.IsLoggingOut && m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting))
  297. {
  298. m_log.DebugFormat(
  299. "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout",
  300. client.Name, Scene.Name);
  301. }
  302. }
  303. private void OnClientCancelTeleport(IClientAPI client)
  304. {
  305. m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Cancelling);
  306. m_log.DebugFormat(
  307. "[ENTITY TRANSFER MODULE]: Received teleport cancel request from {0} in {1}", client.Name, Scene.Name);
  308. }
  309. // Attempt to teleport the ScenePresence to the specified position in the specified region (spec'ed by its handle).
  310. public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags)
  311. {
  312. if (sp.Scene.Permissions.IsGridGod(sp.UUID))
  313. {
  314. // This user will be a God in the destination scene, too
  315. teleportFlags |= (uint)TeleportFlags.Godlike;
  316. }
  317. if (!sp.Scene.Permissions.CanTeleport(sp.UUID))
  318. return;
  319. string destinationRegionName = "(not found)";
  320. // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection
  321. // of whether the destination region completes the teleport.
  322. if (!m_entityTransferStateMachine.SetInTransit(sp.UUID))
  323. {
  324. m_log.DebugFormat(
  325. "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2}@{3} - agent is already in transit.",
  326. sp.Name, sp.UUID, position, regionHandle);
  327. sp.ControllingClient.SendTeleportFailed("Previous teleport process incomplete. Please retry shortly.");
  328. return;
  329. }
  330. try
  331. {
  332. // Reset animations; the viewer does that in teleports.
  333. sp.Animator.ResetAnimations();
  334. if (regionHandle == sp.Scene.RegionInfo.RegionHandle)
  335. {
  336. destinationRegionName = sp.Scene.RegionInfo.RegionName;
  337. TeleportAgentWithinRegion(sp, position, lookAt, teleportFlags);
  338. }
  339. else // Another region possibly in another simulator
  340. {
  341. GridRegion finalDestination = null;
  342. try
  343. {
  344. TeleportAgentToDifferentRegion(
  345. sp, regionHandle, position, lookAt, teleportFlags, out finalDestination);
  346. }
  347. finally
  348. {
  349. if (finalDestination != null)
  350. destinationRegionName = finalDestination.RegionName;
  351. }
  352. }
  353. }
  354. catch (Exception e)
  355. {
  356. m_log.ErrorFormat(
  357. "[ENTITY TRANSFER MODULE]: Exception on teleport of {0} from {1}@{2} to {3}@{4}: {5}{6}",
  358. sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, destinationRegionName,
  359. e.Message, e.StackTrace);
  360. sp.ControllingClient.SendTeleportFailed("Internal error");
  361. }
  362. finally
  363. {
  364. m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
  365. }
  366. }
  367. /// <summary>
  368. /// Teleports the agent within its current region.
  369. /// </summary>
  370. /// <param name="sp"></param>
  371. /// <param name="position"></param>
  372. /// <param name="lookAt"></param>
  373. /// <param name="teleportFlags"></param>
  374. private void TeleportAgentWithinRegion(ScenePresence sp, Vector3 position, Vector3 lookAt, uint teleportFlags)
  375. {
  376. m_log.DebugFormat(
  377. "[ENTITY TRANSFER MODULE]: Teleport for {0} to {1} within {2}",
  378. sp.Name, position, sp.Scene.RegionInfo.RegionName);
  379. // Teleport within the same region
  380. if (!sp.Scene.PositionIsInCurrentRegion(position) || position.Z < 0)
  381. {
  382. Vector3 emergencyPos = new Vector3(128, 128, 128);
  383. m_log.WarnFormat(
  384. "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2} in {3}. Substituting {4}",
  385. position, sp.Name, sp.UUID, Scene.Name, emergencyPos);
  386. position = emergencyPos;
  387. }
  388. // TODO: Get proper AVG Height
  389. float localAVHeight = 1.56f;
  390. float posZLimit = 22;
  391. // TODO: Check other Scene HeightField
  392. posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y];
  393. float newPosZ = posZLimit + localAVHeight;
  394. if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ)))
  395. {
  396. position.Z = newPosZ;
  397. }
  398. if (sp.Flying)
  399. teleportFlags |= (uint)TeleportFlags.IsFlying;
  400. m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
  401. sp.ControllingClient.SendTeleportStart(teleportFlags);
  402. sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags);
  403. sp.TeleportFlags = (Constants.TeleportFlags)teleportFlags;
  404. sp.Velocity = Vector3.Zero;
  405. sp.Teleport(position);
  406. m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.ReceivedAtDestination);
  407. foreach (SceneObjectGroup grp in sp.GetAttachments())
  408. {
  409. sp.Scene.EventManager.TriggerOnScriptChangedEvent(grp.LocalId, (uint)Changed.TELEPORT);
  410. }
  411. m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
  412. }
  413. /// <summary>
  414. /// Teleports the agent to a different region.
  415. /// </summary>
  416. /// <param name='sp'></param>
  417. /// <param name='regionHandle'>/param>
  418. /// <param name='position'></param>
  419. /// <param name='lookAt'></param>
  420. /// <param name='teleportFlags'></param>
  421. /// <param name='finalDestination'></param>
  422. private void TeleportAgentToDifferentRegion(
  423. ScenePresence sp, ulong regionHandle, Vector3 position,
  424. Vector3 lookAt, uint teleportFlags, out GridRegion finalDestination)
  425. {
  426. // Get destination region taking into account that the address could be an offset
  427. // region inside a varregion.
  428. GridRegion reg = GetTeleportDestinationRegion(sp.Scene.GridService, sp.Scene.RegionInfo.ScopeID, regionHandle, ref position);
  429. if (reg != null)
  430. {
  431. string homeURI = Scene.GetAgentHomeURI(sp.ControllingClient.AgentId);
  432. string message;
  433. finalDestination = GetFinalDestination(reg, sp.ControllingClient.AgentId, homeURI, out message);
  434. if (finalDestination == null)
  435. {
  436. m_log.WarnFormat( "{0} Final destination is having problems. Unable to teleport {1} {2}: {3}",
  437. LogHeader, sp.Name, sp.UUID, message);
  438. sp.ControllingClient.SendTeleportFailed(message);
  439. return;
  440. }
  441. // Check that these are not the same coordinates
  442. if (finalDestination.RegionLocX == sp.Scene.RegionInfo.RegionLocX &&
  443. finalDestination.RegionLocY == sp.Scene.RegionInfo.RegionLocY)
  444. {
  445. // Can't do. Viewer crashes
  446. sp.ControllingClient.SendTeleportFailed("Space warp! You would crash. Move to a different region and try again.");
  447. return;
  448. }
  449. // Validate assorted conditions
  450. string reason = string.Empty;
  451. if (!ValidateGenericConditions(sp, reg, finalDestination, teleportFlags, out reason))
  452. {
  453. sp.ControllingClient.SendTeleportFailed(reason);
  454. return;
  455. }
  456. if (message != null)
  457. sp.ControllingClient.SendAgentAlertMessage(message, true);
  458. //
  459. // This is it
  460. //
  461. DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags);
  462. //
  463. //
  464. //
  465. }
  466. else
  467. {
  468. finalDestination = null;
  469. // TP to a place that doesn't exist (anymore)
  470. // Inform the viewer about that
  471. sp.ControllingClient.SendTeleportFailed("The region you tried to teleport to doesn't exist anymore");
  472. // and set the map-tile to '(Offline)'
  473. uint regX, regY;
  474. Util.RegionHandleToRegionLoc(regionHandle, out regX, out regY);
  475. MapBlockData block = new MapBlockData();
  476. block.X = (ushort)regX;
  477. block.Y = (ushort)regY;
  478. block.Access = (byte)SimAccess.Down;
  479. List<MapBlockData> blocks = new List<MapBlockData>();
  480. blocks.Add(block);
  481. sp.ControllingClient.SendMapBlock(blocks, 0);
  482. }
  483. }
  484. // The teleport address could be an address in a subregion of a larger varregion.
  485. // Find the real base region and adjust the teleport location to account for the
  486. // larger region.
  487. private GridRegion GetTeleportDestinationRegion(IGridService gridService, UUID scope, ulong regionHandle, ref Vector3 position)
  488. {
  489. uint x = 0, y = 0;
  490. Util.RegionHandleToWorldLoc(regionHandle, out x, out y);
  491. // Compute the world location we're teleporting to
  492. double worldX = (double)x + position.X;
  493. double worldY = (double)y + position.Y;
  494. // Find the region that contains the position
  495. GridRegion reg = GetRegionContainingWorldLocation(gridService, scope, worldX, worldY);
  496. if (reg != null)
  497. {
  498. // modify the position for the offset into the actual region returned
  499. position.X += x - reg.RegionLocX;
  500. position.Y += y - reg.RegionLocY;
  501. }
  502. return reg;
  503. }
  504. // Nothing to validate here
  505. protected virtual bool ValidateGenericConditions(ScenePresence sp, GridRegion reg, GridRegion finalDestination, uint teleportFlags, out string reason)
  506. {
  507. reason = String.Empty;
  508. return true;
  509. }
  510. /// <summary>
  511. /// Determines whether this instance is within the max transfer distance.
  512. /// </summary>
  513. /// <param name="sourceRegion"></param>
  514. /// <param name="destRegion"></param>
  515. /// <returns>
  516. /// <c>true</c> if this instance is within max transfer distance; otherwise, <c>false</c>.
  517. /// </returns>
  518. private bool IsWithinMaxTeleportDistance(RegionInfo sourceRegion, GridRegion destRegion)
  519. {
  520. if(MaxTransferDistance == 0)
  521. return true;
  522. // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Source co-ords are x={0} y={1}", curRegionX, curRegionY);
  523. //
  524. // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final dest is x={0} y={1} {2}@{3}",
  525. // destRegionX, destRegionY, finalDestination.RegionID, finalDestination.ServerURI);
  526. // Insanely, RegionLoc on RegionInfo is the 256m map co-ord whilst GridRegion.RegionLoc is the raw meters position.
  527. return Math.Abs(sourceRegion.RegionLocX - destRegion.RegionCoordX) <= MaxTransferDistance
  528. && Math.Abs(sourceRegion.RegionLocY - destRegion.RegionCoordY) <= MaxTransferDistance;
  529. }
  530. /// <summary>
  531. /// Wraps DoTeleportInternal() and manages the transfer state.
  532. /// </summary>
  533. public void DoTeleport(
  534. ScenePresence sp, GridRegion reg, GridRegion finalDestination,
  535. Vector3 position, Vector3 lookAt, uint teleportFlags)
  536. {
  537. // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection
  538. // of whether the destination region completes the teleport.
  539. if (!m_entityTransferStateMachine.SetInTransit(sp.UUID))
  540. {
  541. m_log.DebugFormat(
  542. "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2} ({3}) {4}/{5} - agent is already in transit.",
  543. sp.Name, sp.UUID, reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position);
  544. sp.ControllingClient.SendTeleportFailed("Agent is already in transit.");
  545. return;
  546. }
  547. try
  548. {
  549. DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags);
  550. }
  551. catch (Exception e)
  552. {
  553. m_log.ErrorFormat(
  554. "[ENTITY TRANSFER MODULE]: Exception on teleport of {0} from {1}@{2} to {3}@{4}: {5}{6}",
  555. sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, finalDestination.RegionName,
  556. e.Message, e.StackTrace);
  557. sp.ControllingClient.SendTeleportFailed("Internal error");
  558. }
  559. finally
  560. {
  561. m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
  562. }
  563. }
  564. /// <summary>
  565. /// Teleports the agent to another region.
  566. /// This method doesn't manage the transfer state; the caller must do that.
  567. /// </summary>
  568. private void DoTeleportInternal(
  569. ScenePresence sp, GridRegion reg, GridRegion finalDestination,
  570. Vector3 position, Vector3 lookAt, uint teleportFlags)
  571. {
  572. if (reg == null || finalDestination == null)
  573. {
  574. sp.ControllingClient.SendTeleportFailed("Unable to locate destination");
  575. return;
  576. }
  577. string homeURI = Scene.GetAgentHomeURI(sp.ControllingClient.AgentId);
  578. m_log.DebugFormat(
  579. "[ENTITY TRANSFER MODULE]: Teleporting {0} {1} from {2} to {3} ({4}) {5}/{6}",
  580. sp.Name, sp.UUID, sp.Scene.RegionInfo.RegionName,
  581. reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position);
  582. RegionInfo sourceRegion = sp.Scene.RegionInfo;
  583. if (!IsWithinMaxTeleportDistance(sourceRegion, finalDestination))
  584. {
  585. sp.ControllingClient.SendTeleportFailed(
  586. string.Format(
  587. "Can't teleport to {0} ({1},{2}) from {3} ({4},{5}), destination is more than {6} regions way",
  588. finalDestination.RegionName, finalDestination.RegionCoordX, finalDestination.RegionCoordY,
  589. sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY,
  590. MaxTransferDistance));
  591. return;
  592. }
  593. uint newRegionX, newRegionY, oldRegionX, oldRegionY;
  594. Util.RegionHandleToRegionLoc(reg.RegionHandle, out newRegionX, out newRegionY);
  595. Util.RegionHandleToRegionLoc(sp.Scene.RegionInfo.RegionHandle, out oldRegionX, out oldRegionY);
  596. ulong destinationHandle = finalDestination.RegionHandle;
  597. // Let's do DNS resolution only once in this process, please!
  598. // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field,
  599. // it's actually doing a lot of work.
  600. IPEndPoint endPoint = finalDestination.ExternalEndPoint;
  601. if (endPoint == null || endPoint.Address == null)
  602. {
  603. sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down");
  604. return;
  605. }
  606. if (!sp.ValidateAttachments())
  607. m_log.DebugFormat(
  608. "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.",
  609. sp.Name, sp.Scene.Name, finalDestination.RegionName);
  610. string reason;
  611. EntityTransferContext ctx = new EntityTransferContext();
  612. if (!Scene.SimulationService.QueryAccess(
  613. finalDestination, sp.ControllingClient.AgentId, homeURI, true, position, sp.Scene.GetFormatsOffered(), ctx, out reason))
  614. {
  615. sp.ControllingClient.SendTeleportFailed(reason);
  616. m_log.DebugFormat(
  617. "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because: {3}",
  618. sp.Name, sp.Scene.Name, finalDestination.RegionName, reason);
  619. return;
  620. }
  621. // Before this point, teleport 'failure' is due to checkable pre-conditions such as whether the target
  622. // simulator can be found and is explicitly prepared to allow access. Therefore, we will not count these
  623. // as server attempts.
  624. m_interRegionTeleportAttempts.Value++;
  625. m_log.DebugFormat(
  626. "[ENTITY TRANSFER MODULE]: {0} transfer protocol version to {1} is {2} / {3}",
  627. sp.Scene.Name, finalDestination.RegionName, ctx.OutboundVersion, ctx.InboundVersion);
  628. // Fixing a bug where teleporting while sitting results in the avatar ending up removed from
  629. // both regions
  630. if (sp.ParentID != (uint)0)
  631. sp.StandUp();
  632. else if (sp.Flying)
  633. teleportFlags |= (uint)TeleportFlags.IsFlying;
  634. if (DisableInterRegionTeleportCancellation)
  635. teleportFlags |= (uint)TeleportFlags.DisableCancel;
  636. // At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to
  637. // the viewer. However, it might mean that the viewer does not see the black teleport screen (untested).
  638. sp.ControllingClient.SendTeleportStart(teleportFlags);
  639. // the avatar.Close below will clear the child region list. We need this below for (possibly)
  640. // closing the child agents, so save it here (we need a copy as it is Clear()-ed).
  641. //List<ulong> childRegions = avatar.KnownRegionHandles;
  642. // Compared to ScenePresence.CrossToNewRegion(), there's no obvious code to handle a teleport
  643. // failure at this point (unlike a border crossing failure). So perhaps this can never fail
  644. // once we reach here...
  645. //avatar.Scene.RemoveCapsHandler(avatar.UUID);
  646. AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
  647. AgentCircuitData agentCircuit = sp.ControllingClient.RequestClientInfo();
  648. agentCircuit.startpos = position;
  649. agentCircuit.child = true;
  650. agentCircuit.Appearance = new AvatarAppearance();
  651. agentCircuit.Appearance.PackLegacyWearables = true;
  652. if (currentAgentCircuit != null)
  653. {
  654. agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs;
  655. agentCircuit.IPAddress = currentAgentCircuit.IPAddress;
  656. agentCircuit.Viewer = currentAgentCircuit.Viewer;
  657. agentCircuit.Channel = currentAgentCircuit.Channel;
  658. agentCircuit.Mac = currentAgentCircuit.Mac;
  659. agentCircuit.Id0 = currentAgentCircuit.Id0;
  660. }
  661. // if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY))
  662. float dist = (float)Math.Max(sp.Scene.DefaultDrawDistance,
  663. (float)Math.Max(sp.Scene.RegionInfo.RegionSizeX, sp.Scene.RegionInfo.RegionSizeY));
  664. if (NeedsNewAgent(dist, oldRegionX, newRegionX, oldRegionY, newRegionY))
  665. {
  666. // brand new agent, let's create a new caps seed
  667. agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath();
  668. }
  669. // We're going to fallback to V1 if the destination gives us anything smaller than 0.2
  670. if (ctx.OutboundVersion >= 0.2f)
  671. TransferAgent_V2(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, ctx, out reason);
  672. else
  673. TransferAgent_V1(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, ctx, out reason);
  674. }
  675. private void TransferAgent_V1(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination,
  676. IPEndPoint endPoint, uint teleportFlags, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, EntityTransferContext ctx, out string reason)
  677. {
  678. ulong destinationHandle = finalDestination.RegionHandle;
  679. AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
  680. m_log.DebugFormat(
  681. "[ENTITY TRANSFER MODULE]: Using TP V1 for {0} going from {1} to {2}",
  682. sp.Name, Scene.Name, finalDestination.RegionName);
  683. // Let's create an agent there if one doesn't exist yet.
  684. // NOTE: logout will always be false for a non-HG teleport.
  685. bool logout = false;
  686. if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout))
  687. {
  688. m_interRegionTeleportFailures.Value++;
  689. m_log.DebugFormat(
  690. "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}",
  691. sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason);
  692. sp.ControllingClient.SendTeleportFailed(reason);
  693. return;
  694. }
  695. if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
  696. {
  697. m_interRegionTeleportCancels.Value++;
  698. m_log.DebugFormat(
  699. "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request",
  700. sp.Name, finalDestination.RegionName, sp.Scene.Name);
  701. return;
  702. }
  703. else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
  704. {
  705. m_interRegionTeleportAborts.Value++;
  706. m_log.DebugFormat(
  707. "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.",
  708. sp.Name, finalDestination.RegionName, sp.Scene.Name);
  709. return;
  710. }
  711. // Past this point we have to attempt clean up if the teleport fails, so update transfer state.
  712. m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
  713. // OK, it got this agent. Let's close some child agents
  714. sp.CloseChildAgents(newRegionX, newRegionY);
  715. IClientIPEndpoint ipepClient;
  716. string capsPath = String.Empty;
  717. float dist = (float)Math.Max(sp.Scene.DefaultDrawDistance,
  718. (float)Math.Max(sp.Scene.RegionInfo.RegionSizeX, sp.Scene.RegionInfo.RegionSizeY));
  719. if (NeedsNewAgent(dist, oldRegionX, newRegionX, oldRegionY, newRegionY))
  720. {
  721. m_log.DebugFormat(
  722. "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for incoming agent {3} from {4}",
  723. finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name);
  724. //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent...");
  725. #region IP Translation for NAT
  726. // Uses ipepClient above
  727. if (sp.ClientView.TryGet(out ipepClient))
  728. {
  729. endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address);
  730. }
  731. #endregion
  732. capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
  733. if (m_eqModule != null)
  734. {
  735. // The EnableSimulator message makes the client establish a connection with the destination
  736. // simulator by sending the initial UseCircuitCode UDP packet to the destination containing the
  737. // correct circuit code.
  738. m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID,
  739. finalDestination.RegionSizeX, finalDestination.RegionSizeY);
  740. m_log.DebugFormat("{0} Sent EnableSimulator. regName={1}, size=<{2},{3}>", LogHeader,
  741. finalDestination.RegionName, finalDestination.RegionSizeX, finalDestination.RegionSizeY);
  742. // XXX: Is this wait necessary? We will always end up waiting on UpdateAgent for the destination
  743. // simulator to confirm that it has established communication with the viewer.
  744. Thread.Sleep(200);
  745. // At least on LL 3.3.4 for teleports between different regions on the same simulator this appears
  746. // unnecessary - teleport will succeed and SEED caps will be requested without it (though possibly
  747. // only on TeleportFinish). This is untested for region teleport between different simulators
  748. // though this probably also works.
  749. m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath, finalDestination.RegionHandle,
  750. finalDestination.RegionSizeX, finalDestination.RegionSizeY);
  751. }
  752. else
  753. {
  754. // XXX: This is a little misleading since we're information the client of its avatar destination,
  755. // which may or may not be a neighbour region of the source region. This path is probably little
  756. // used anyway (with EQ being the one used). But it is currently being used for test code.
  757. sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint);
  758. }
  759. }
  760. else
  761. {
  762. agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle);
  763. capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
  764. }
  765. // Let's send a full update of the agent. This is a synchronous call.
  766. AgentData agent = new AgentData();
  767. sp.CopyTo(agent);
  768. if (ctx.OutboundVersion < 0.5f)
  769. agent.Appearance.PackLegacyWearables = true;
  770. agent.Position = agentCircuit.startpos;
  771. SetCallbackURL(agent, sp.Scene.RegionInfo);
  772. // We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to
  773. // establish th econnection to the destination which makes it return true.
  774. if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
  775. {
  776. m_interRegionTeleportAborts.Value++;
  777. m_log.DebugFormat(
  778. "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} before UpdateAgent",
  779. sp.Name, finalDestination.RegionName, sp.Scene.Name);
  780. return;
  781. }
  782. // A common teleport failure occurs when we can send CreateAgent to the
  783. // destination region but the viewer cannot establish the connection (e.g. due to network issues between
  784. // the viewer and the destination). In this case, UpdateAgent timesout after 10 seconds, although then
  785. // there's a further 10 second wait whilst we attempt to tell the destination to delete the agent in Fail().
  786. if (!UpdateAgent(reg, finalDestination, agent, sp))
  787. {
  788. if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
  789. {
  790. m_interRegionTeleportAborts.Value++;
  791. m_log.DebugFormat(
  792. "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.",
  793. sp.Name, finalDestination.RegionName, sp.Scene.Name);
  794. return;
  795. }
  796. m_log.WarnFormat(
  797. "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Keeping avatar in {2}",
  798. sp.Name, finalDestination.RegionName, sp.Scene.Name);
  799. Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established.");
  800. return;
  801. }
  802. if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
  803. {
  804. m_interRegionTeleportCancels.Value++;
  805. m_log.DebugFormat(
  806. "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request",
  807. sp.Name, finalDestination.RegionName, sp.Scene.Name);
  808. CleanupFailedInterRegionTeleport(sp, currentAgentCircuit.SessionID.ToString(), finalDestination);
  809. return;
  810. }
  811. m_log.DebugFormat(
  812. "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}",
  813. capsPath, sp.Scene.RegionInfo.RegionName, sp.Name);
  814. // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator,
  815. // where that neighbour simulator could otherwise request a child agent create on the source which then
  816. // closes our existing agent which is still signalled as root.
  817. sp.IsChildAgent = true;
  818. // OK, send TPFinish to the client, so that it starts the process of contacting the destination region
  819. if (m_eqModule != null)
  820. {
  821. m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID,
  822. finalDestination.RegionSizeX, finalDestination.RegionSizeY);
  823. }
  824. else
  825. {
  826. sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4,
  827. teleportFlags, capsPath);
  828. }
  829. // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which
  830. // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation
  831. // that the client contacted the destination before we close things here.
  832. if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID))
  833. {
  834. if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
  835. {
  836. m_interRegionTeleportAborts.Value++;
  837. m_log.DebugFormat(
  838. "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after WaitForAgentArrivedAtDestination due to previous client close.",
  839. sp.Name, finalDestination.RegionName, sp.Scene.Name);
  840. return;
  841. }
  842. m_log.WarnFormat(
  843. "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.",
  844. sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName);
  845. Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Destination region did not signal teleport completion.");
  846. return;
  847. }
  848. m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
  849. /*
  850. // TODO: This may be 0.6. Check if still needed
  851. // For backwards compatibility
  852. if (version == 0f)
  853. {
  854. // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it
  855. m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Old simulator, sending attachments one by one...");
  856. CrossAttachmentsIntoNewRegion(finalDestination, sp, true);
  857. }
  858. */
  859. // May need to logout or other cleanup
  860. AgentHasMovedAway(sp, logout);
  861. // Well, this is it. The agent is over there.
  862. KillEntity(sp.Scene, sp.LocalId);
  863. // Now let's make it officially a child agent
  864. sp.MakeChildAgent();
  865. // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
  866. if (NeedsClosing(sp.Scene.DefaultDrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
  867. {
  868. if (!sp.Scene.IncomingPreCloseClient(sp))
  869. return;
  870. // We need to delay here because Imprudence viewers, unlike v1 or v3, have a short (<200ms, <500ms) delay before
  871. // they regard the new region as the current region after receiving the AgentMovementComplete
  872. // response. If close is sent before then, it will cause the viewer to quit instead.
  873. //
  874. // This sleep can be increased if necessary. However, whilst it's active,
  875. // an agent cannot teleport back to this region if it has teleported away.
  876. Thread.Sleep(2000);
  877. sp.Scene.CloseAgent(sp.UUID, false);
  878. }
  879. else
  880. {
  881. // now we have a child agent in this region.
  882. sp.Reset();
  883. }
  884. }
  885. private void TransferAgent_V2(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination,
  886. IPEndPoint endPoint, uint teleportFlags, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, EntityTransferContext ctx, out string reason)
  887. {
  888. ulong destinationHandle = finalDestination.RegionHandle;
  889. AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
  890. // Let's create an agent there if one doesn't exist yet.
  891. // NOTE: logout will always be false for a non-HG teleport.
  892. bool logout = false;
  893. if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout))
  894. {
  895. m_interRegionTeleportFailures.Value++;
  896. m_log.DebugFormat(
  897. "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}",
  898. sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason);
  899. sp.ControllingClient.SendTeleportFailed(reason);
  900. return;
  901. }
  902. if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
  903. {
  904. m_interRegionTeleportCancels.Value++;
  905. m_log.DebugFormat(
  906. "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request",
  907. sp.Name, finalDestination.RegionName, sp.Scene.Name);
  908. return;
  909. }
  910. else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
  911. {
  912. m_interRegionTeleportAborts.Value++;
  913. m_log.DebugFormat(
  914. "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.",
  915. sp.Name, finalDestination.RegionName, sp.Scene.Name);
  916. return;
  917. }
  918. // Past this point we have to attempt clean up if the teleport fails, so update transfer state.
  919. m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
  920. IClientIPEndpoint ipepClient;
  921. string capsPath = String.Empty;
  922. float dist = (float)Math.Max(sp.Scene.DefaultDrawDistance,
  923. (float)Math.Max(sp.Scene.RegionInfo.RegionSizeX, sp.Scene.RegionInfo.RegionSizeY));
  924. if (NeedsNewAgent(dist, oldRegionX, newRegionX, oldRegionY, newRegionY))
  925. {
  926. m_log.DebugFormat(
  927. "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for agent {3} from {4}",
  928. finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name);
  929. //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent...");
  930. #region IP Translation for NAT
  931. // Uses ipepClient above
  932. if (sp.ClientView.TryGet(out ipepClient))
  933. {
  934. endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address);
  935. }
  936. #endregion
  937. capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
  938. }
  939. else
  940. {
  941. agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle);
  942. capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
  943. }
  944. // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator,
  945. // where that neighbour simulator could otherwise request a child agent create on the source which then
  946. // closes our existing agent which is still signalled as root.
  947. //sp.IsChildAgent = true;
  948. // New protocol: send TP Finish directly, without prior ES or EAC. That's what happens in the Linden grid
  949. if (m_eqModule != null)
  950. m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID,
  951. finalDestination.RegionSizeX, finalDestination.RegionSizeY);
  952. else
  953. sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4,
  954. teleportFlags, capsPath);
  955. m_log.DebugFormat(
  956. "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}",
  957. capsPath, sp.Scene.RegionInfo.RegionName, sp.Name);
  958. // Let's send a full update of the agent.
  959. AgentData agent = new AgentData();
  960. sp.CopyTo(agent);
  961. if (ctx.OutboundVersion < 0.5f)
  962. agent.Appearance.PackLegacyWearables = true;
  963. agent.Position = agentCircuit.startpos;
  964. agent.SenderWantsToWaitForRoot = true;
  965. //SetCallbackURL(agent, sp.Scene.RegionInfo);
  966. // Reset the do not close flag. This must be done before the destination opens child connections (here
  967. // triggered by UpdateAgent) to avoid race conditions. However, we also want to reset it as late as possible
  968. // to avoid a situation where an unexpectedly early call to Scene.NewUserConnection() wrongly results
  969. // in no close.
  970. sp.DoNotCloseAfterTeleport = false;
  971. // Send the Update. If this returns true, we know the client has contacted the destination
  972. // via CompleteMovementIntoRegion, so we can let go.
  973. // If it returns false, something went wrong, and we need to abort.
  974. if (!UpdateAgent(reg, finalDestination, agent, sp))
  975. {
  976. if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
  977. {
  978. m_interRegionTeleportAborts.Value++;
  979. m_log.DebugFormat(
  980. "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.",
  981. sp.Name, finalDestination.RegionName, sp.Scene.Name);
  982. return;
  983. }
  984. m_log.WarnFormat(
  985. "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Keeping avatar in {2}",
  986. sp.Name, finalDestination.RegionName, sp.Scene.Name);
  987. Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established.");
  988. return;
  989. }
  990. m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
  991. // Need to signal neighbours whether child agents may need closing irrespective of whether this
  992. // one needed closing. We also need to close child agents as quickly as possible to avoid complicated
  993. // race conditions with rapid agent releporting (e.g. from A1 to a non-neighbour B, back
  994. // to a neighbour A2 then off to a non-neighbour C). Closing child agents any later requires complex
  995. // distributed checks to avoid problems in rapid reteleporting scenarios and where child agents are
  996. // abandoned without proper close by viewer but then re-used by an incoming connection.
  997. sp.CloseChildAgents(newRegionX, newRegionY);
  998. // May need to logout or other cleanup
  999. AgentHasMovedAway(sp, logout);
  1000. // Well, this is it. The agent is over there.
  1001. KillEntity(sp.Scene, sp.LocalId);
  1002. // Now let's make it officially a child agent
  1003. sp.MakeChildAgent();
  1004. // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
  1005. if (NeedsClosing(sp.Scene.DefaultDrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
  1006. {
  1007. if (!sp.Scene.IncomingPreCloseClient(sp))
  1008. return;
  1009. // RED ALERT!!!!
  1010. // PLEASE DO NOT DECREASE THIS WAIT TIME UNDER ANY CIRCUMSTANCES.
  1011. // THE VIEWERS SEEM TO NEED SOME TIME AFTER RECEIVING MoveAgentIntoRegion
  1012. // BEFORE THEY SETTLE IN THE NEW REGION.
  1013. // DECREASING THE WAIT TIME HERE WILL EITHER RESULT IN A VIEWER CRASH OR
  1014. // IN THE AVIE BEING PLACED IN INFINITY FOR A COUPLE OF SECONDS.
  1015. Thread.Sleep(15000);
  1016. // OK, it got this agent. Let's close everything
  1017. // If we shouldn't close the agent due to some other region renewing the connection
  1018. // then this will be handled in IncomingCloseAgent under lock conditions
  1019. m_log.DebugFormat(
  1020. "[ENTITY TRANSFER MODULE]: Closing agent {0} in {1} after teleport", sp.Name, Scene.Name);
  1021. sp.Scene.CloseAgent(sp.UUID, false);
  1022. }
  1023. else
  1024. {
  1025. // now we have a child agent in this region.
  1026. sp.Reset();
  1027. }
  1028. }
  1029. /// <summary>
  1030. /// Clean up an inter-region teleport that did not complete, either because of simulator failure or cancellation.
  1031. /// </summary>
  1032. /// <remarks>
  1033. /// All operations here must be idempotent so that we can call this method at any point in the teleport process
  1034. /// up until we send the TeleportFinish event quene event to the viewer.
  1035. /// <remarks>
  1036. /// <param name='sp'> </param>
  1037. /// <param name='finalDestination'></param>
  1038. protected virtual void CleanupFailedInterRegionTeleport(ScenePresence sp, string auth_token, GridRegion finalDestination)
  1039. {
  1040. m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
  1041. if (sp.IsChildAgent) // We had set it to child before attempted TP (V1)
  1042. {
  1043. sp.IsChildAgent = false;
  1044. ReInstantiateScripts(sp);
  1045. EnableChildAgents(sp);
  1046. }
  1047. // Finally, kill the agent we just created at the destination.
  1048. // XXX: Possibly this should be done asynchronously.
  1049. Scene.SimulationService.CloseAgent(finalDestination, sp.UUID, auth_token);
  1050. }
  1051. /// <summary>
  1052. /// Signal that the inter-region teleport failed and perform cleanup.
  1053. /// </summary>
  1054. /// <param name='sp'></param>
  1055. /// <param name='finalDestination'></param>
  1056. /// <param name='logout'></param>
  1057. /// <param name='reason'>Human readable reason for teleport failure. Will be sent to client.</param>
  1058. protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout, string auth_code, string reason)
  1059. {
  1060. CleanupFailedInterRegionTeleport(sp, auth_code, finalDestination);
  1061. m_interRegionTeleportFailures.Value++;
  1062. sp.ControllingClient.SendTeleportFailed(
  1063. string.Format(
  1064. "Problems connecting to destination {0}, reason: {1}", finalDestination.RegionName, reason));
  1065. sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout);
  1066. }
  1067. protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout)
  1068. {
  1069. GridRegion source = new GridRegion(Scene.RegionInfo);
  1070. source.RawServerURI = m_GatekeeperURI;
  1071. logout = false;
  1072. bool success = Scene.SimulationService.CreateAgent(source, finalDestination, agentCircuit, teleportFlags, out reason);
  1073. if (success)
  1074. sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout);
  1075. return success;
  1076. }
  1077. protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent, ScenePresence sp)
  1078. {
  1079. return Scene.SimulationService.UpdateAgent(finalDestination, agent);
  1080. }
  1081. protected virtual void SetCallbackURL(AgentData agent, RegionInfo region)
  1082. {
  1083. agent.CallbackURI = region.ServerURI + "agent/" + agent.AgentID.ToString() + "/" + region.RegionID.ToString() + "/release/";
  1084. m_log.DebugFormat(
  1085. "[ENTITY TRANSFER MODULE]: Set release callback URL to {0} in {1}",
  1086. agent.CallbackURI, region.RegionName);
  1087. }
  1088. /// <summary>
  1089. /// Clean up operations once an agent has moved away through cross or teleport.
  1090. /// </summary>
  1091. /// <param name='sp'></param>
  1092. /// <param name='logout'></param>
  1093. protected virtual void AgentHasMovedAway(ScenePresence sp, bool logout)
  1094. {
  1095. if (sp.Scene.AttachmentsModule != null)
  1096. sp.Scene.AttachmentsModule.DeleteAttachmentsFromScene(sp, true);
  1097. }
  1098. protected void KillEntity(Scene scene, uint localID)
  1099. {
  1100. scene.SendKillObject(new List<uint> { localID });
  1101. }
  1102. protected virtual GridRegion GetFinalDestination(GridRegion region, UUID agentID, string agentHomeURI, out string message)
  1103. {
  1104. message = null;
  1105. return region;
  1106. }
  1107. // This returns 'true' if the new region already has a child agent for our
  1108. // incoming agent. The implication is that, if 'false', we have to create the
  1109. // child and then teleport into the region.
  1110. protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY)
  1111. {
  1112. if (m_regionCombinerModule != null && m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID))
  1113. {
  1114. Vector2 swCorner, neCorner;
  1115. GetMegaregionViewRange(out swCorner, out neCorner);
  1116. m_log.DebugFormat(
  1117. "[ENTITY TRANSFER MODULE]: Megaregion view of {0} is from {1} to {2} with new agent check for {3},{4}",
  1118. Scene.Name, swCorner, neCorner, newRegionX, newRegionY);
  1119. return !(newRegionX >= swCorner.X && newRegionX <= neCorner.X && newRegionY >= swCorner.Y && newRegionY <= neCorner.Y);
  1120. }
  1121. else
  1122. {
  1123. return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY);
  1124. }
  1125. }
  1126. protected virtual bool NeedsClosing(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg)
  1127. {
  1128. return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY);
  1129. }
  1130. #endregion
  1131. #region Landmark Teleport
  1132. /// <summary>
  1133. /// Tries to teleport agent to landmark.
  1134. /// </summary>
  1135. /// <param name="remoteClient"></param>
  1136. /// <param name="regionHandle"></param>
  1137. /// <param name="position"></param>
  1138. public virtual void RequestTeleportLandmark(IClientAPI remoteClient, AssetLandmark lm)
  1139. {
  1140. GridRegion info = Scene.GridService.GetRegionByUUID(UUID.Zero, lm.RegionID);
  1141. if (info == null)
  1142. {
  1143. // can't find the region: Tell viewer and abort
  1144. remoteClient.SendTeleportFailed("The teleport destination could not be found.");
  1145. return;
  1146. }
  1147. ((Scene)(remoteClient.Scene)).RequestTeleportLocation(remoteClient, info.RegionHandle, lm.Position,
  1148. Vector3.Zero, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark));
  1149. }
  1150. #endregion
  1151. #region Teleport Home
  1152. public virtual void TriggerTeleportHome(UUID id, IClientAPI client)
  1153. {
  1154. TeleportHome(id, client);
  1155. }
  1156. public virtual bool TeleportHome(UUID id, IClientAPI client)
  1157. {
  1158. m_log.DebugFormat(
  1159. "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId);
  1160. //OpenSim.Services.Interfaces.PresenceInfo pinfo = Scene.PresenceService.GetAgent(client.SessionId);
  1161. GridUserInfo uinfo = Scene.GridUserService.GetGridUserInfo(client.AgentId.ToString());
  1162. if (uinfo != null)
  1163. {
  1164. if (uinfo.HomeRegionID == UUID.Zero)
  1165. {
  1166. // can't find the Home region: Tell viewer and abort
  1167. m_log.ErrorFormat("{0} No grid user info found for {1} {2}. Cannot send home.",
  1168. LogHeader, client.Name, client.AgentId);
  1169. client.SendTeleportFailed("You don't have a home position set.");
  1170. return false;
  1171. }
  1172. GridRegion regionInfo = Scene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID);
  1173. if (regionInfo == null)
  1174. {
  1175. // can't find the Home region: Tell viewer and abort
  1176. client.SendTeleportFailed("Your home region could not be found.");
  1177. return false;
  1178. }
  1179. m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Home region of {0} is {1} ({2}-{3})",
  1180. client.Name, regionInfo.RegionName, regionInfo.RegionCoordX, regionInfo.RegionCoordY);
  1181. // a little eekie that this goes back to Scene and with a forced cast, will fix that at some point...
  1182. ((Scene)(client.Scene)).RequestTeleportLocation(
  1183. client, regionInfo.RegionHandle, uinfo.HomePosition, uinfo.HomeLookAt,
  1184. (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome));
  1185. return true;
  1186. }
  1187. else
  1188. {
  1189. // can't find the Home region: Tell viewer and abort
  1190. client.SendTeleportFailed("Your home region could not be found.");
  1191. }
  1192. return false;
  1193. }
  1194. #endregion
  1195. #region Agent Crossings
  1196. // Given a position relative to the current region (which has previously been tested to
  1197. // see that it is actually outside the current region), find the new region that the
  1198. // point is actually in.
  1199. // Returns the coordinates and information of the new region or 'null' of it doesn't exist.
  1200. public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos,
  1201. EntityTransferContext ctx, out Vector3 newpos, out string failureReason)
  1202. {
  1203. newpos = pos;
  1204. failureReason = string.Empty;
  1205. string homeURI = scene.GetAgentHomeURI(agentID);
  1206. // m_log.DebugFormat(
  1207. // "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name);
  1208. // Compute world location of the object's position
  1209. double presenceWorldX = (double)scene.RegionInfo.WorldLocX + pos.X;
  1210. double presenceWorldY = (double)scene.RegionInfo.WorldLocY + pos.Y;
  1211. // Call the grid service to lookup the region containing the new position.
  1212. GridRegion neighbourRegion = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID,
  1213. presenceWorldX, presenceWorldY,
  1214. Math.Max(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY));
  1215. if (neighbourRegion != null)
  1216. {
  1217. // Compute the entity's position relative to the new region
  1218. newpos = new Vector3((float)(presenceWorldX - (double)neighbourRegion.RegionLocX),
  1219. (float)(presenceWorldY - (double)neighbourRegion.RegionLocY),
  1220. pos.Z);
  1221. if (m_bannedRegionCache.IfBanned(neighbourRegion.RegionHandle, agentID))
  1222. {
  1223. failureReason = "Cannot region cross into banned parcel";
  1224. neighbourRegion = null;
  1225. }
  1226. else
  1227. {
  1228. // If not banned, make sure this agent is not in the list.
  1229. m_bannedRegionCache.Remove(neighbourRegion.RegionHandle, agentID);
  1230. }
  1231. // Check to see if we have access to the target region.
  1232. if (neighbourRegion != null
  1233. && !scene.SimulationService.QueryAccess(neighbourRegion, agentID, homeURI, false, newpos, scene.GetFormatsOffered(), ctx, out failureReason))
  1234. {
  1235. // remember banned
  1236. m_bannedRegionCache.Add(neighbourRegion.RegionHandle, agentID);
  1237. neighbourRegion = null;
  1238. }
  1239. }
  1240. else
  1241. {
  1242. // The destination region just doesn't exist
  1243. failureReason = "Cannot cross into non-existent region";
  1244. }
  1245. if (neighbourRegion == null)
  1246. m_log.DebugFormat("{0} GetDestination: region not found. Old region name={1} at <{2},{3}> of size <{4},{5}>. Old pos={6}",
  1247. LogHeader, scene.RegionInfo.RegionName,
  1248. scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY,
  1249. scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY,
  1250. pos);
  1251. else
  1252. m_log.DebugFormat("{0} GetDestination: new region={1} at <{2},{3}> of size <{4},{5}>, newpos=<{6},{7}>",
  1253. LogHeader, neighbourRegion.RegionName,
  1254. neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY,
  1255. newpos.X, newpos.Y);
  1256. return neighbourRegion;
  1257. }
  1258. public bool Cross(ScenePresence agent, bool isFlying)
  1259. {
  1260. Vector3 newpos;
  1261. EntityTransferContext ctx = new EntityTransferContext();
  1262. string failureReason;
  1263. GridRegion neighbourRegion = GetDestination(agent.Scene, agent.UUID, agent.AbsolutePosition,
  1264. ctx, out newpos, out failureReason);
  1265. if (neighbourRegion == null)
  1266. {
  1267. agent.ControllingClient.SendAlertMessage(failureReason);
  1268. return false;
  1269. }
  1270. agent.IsInTransit = true;
  1271. CrossAgentToNewRegionDelegate d = CrossAgentToNewRegionAsync;
  1272. d.BeginInvoke(agent, newpos, neighbourRegion, isFlying, ctx, CrossAgentToNewRegionCompleted, d);
  1273. Scene.EventManager.TriggerCrossAgentToNewRegion(agent, isFlying, neighbourRegion);
  1274. return true;
  1275. }
  1276. public delegate void InformClientToInitiateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY,
  1277. Vector3 position,
  1278. Scene initiatingScene);
  1279. private void InformClientToInitiateTeleportToLocation(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene)
  1280. {
  1281. // This assumes that we know what our neighbours are.
  1282. InformClientToInitiateTeleportToLocationDelegate d = InformClientToInitiateTeleportToLocationAsync;
  1283. d.BeginInvoke(agent, regionX, regionY, position, initiatingScene,
  1284. InformClientToInitiateTeleportToLocationCompleted,
  1285. d);
  1286. }
  1287. public void InformClientToInitiateTeleportToLocationAsync(ScenePresence agent, uint regionX, uint regionY, Vector3 position,
  1288. Scene initiatingScene)
  1289. {
  1290. Thread.Sleep(10000);
  1291. m_log.DebugFormat(
  1292. "[ENTITY TRANSFER MODULE]: Auto-reteleporting {0} to correct megaregion location {1},{2},{3} from {4}",
  1293. agent.Name, regionX, regionY, position, initiatingScene.Name);
  1294. agent.Scene.RequestTeleportLocation(
  1295. agent.ControllingClient,
  1296. Util.RegionLocToHandle(regionX, regionY),
  1297. position,
  1298. agent.Lookat,
  1299. (uint)Constants.TeleportFlags.ViaLocation);
  1300. /*
  1301. IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>();
  1302. if (im != null)
  1303. {
  1304. UUID gotoLocation = Util.BuildFakeParcelID(
  1305. Util.RegionLocToHandle(regionX, regionY),
  1306. (uint)(int)position.X,
  1307. (uint)(int)position.Y,
  1308. (uint)(int)position.Z);
  1309. GridInstantMessage m
  1310. = new GridInstantMessage(
  1311. initiatingScene,
  1312. UUID.Zero,
  1313. "Region",
  1314. agent.UUID,
  1315. (byte)InstantMessageDialog.GodLikeRequestTeleport,
  1316. false,
  1317. "",
  1318. gotoLocation,
  1319. false,
  1320. new Vector3(127, 0, 0),
  1321. new Byte[0],
  1322. false);
  1323. im.SendInstantMessage(m, delegate(bool success)
  1324. {
  1325. m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Client Initiating Teleport sending IM success = {0}", success);
  1326. });
  1327. }
  1328. */
  1329. }
  1330. private void InformClientToInitiateTeleportToLocationCompleted(IAsyncResult iar)
  1331. {
  1332. InformClientToInitiateTeleportToLocationDelegate icon =
  1333. (InformClientToInitiateTeleportToLocationDelegate)iar.AsyncState;
  1334. icon.EndInvoke(iar);
  1335. }
  1336. public bool CrossAgentToNewRegionPrep(ScenePresence agent, GridRegion neighbourRegion)
  1337. {
  1338. if (neighbourRegion == null)
  1339. return false;
  1340. m_entityTransferStateMachine.SetInTransit(agent.UUID);
  1341. agent.RemoveFromPhysicalScene();
  1342. return true;
  1343. }
  1344. /// <summary>
  1345. /// This Closes child agents on neighbouring regions
  1346. /// Calls an asynchronous method to do so.. so it doesn't lag the sim.
  1347. /// </summary>
  1348. public ScenePresence CrossAgentToNewRegionAsync(
  1349. ScenePresence agent, Vector3 pos, GridRegion neighbourRegion,
  1350. bool isFlying, EntityTransferContext ctx)
  1351. {
  1352. try
  1353. {
  1354. m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: new region={1} at <{2},{3}>. newpos={4}",
  1355. LogHeader, neighbourRegion.RegionName, neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, pos);
  1356. if (!CrossAgentToNewRegionPrep(agent, neighbourRegion))
  1357. {
  1358. m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: prep failed. Resetting transfer state", LogHeader);
  1359. m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
  1360. }
  1361. if (!CrossAgentIntoNewRegionMain(agent, pos, neighbourRegion, isFlying, ctx))
  1362. {
  1363. m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: cross main failed. Resetting transfer state", LogHeader);
  1364. m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
  1365. }
  1366. CrossAgentToNewRegionPost(agent, pos, neighbourRegion, isFlying, ctx);
  1367. }
  1368. catch (Exception e)
  1369. {
  1370. m_log.Error(string.Format("{0}: CrossAgentToNewRegionAsync: failed with exception ", LogHeader), e);
  1371. }
  1372. return agent;
  1373. }
  1374. public bool CrossAgentIntoNewRegionMain(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, bool isFlying, EntityTransferContext ctx)
  1375. {
  1376. try
  1377. {
  1378. AgentData cAgent = new AgentData();
  1379. agent.CopyTo(cAgent);
  1380. if (ctx.OutboundVersion < 0.5f)
  1381. cAgent.Appearance.PackLegacyWearables = true;
  1382. cAgent.Position = pos;
  1383. if (isFlying)
  1384. cAgent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY;
  1385. // We don't need the callback anymnore
  1386. cAgent.CallbackURI = String.Empty;
  1387. // Beyond this point, extra cleanup is needed beyond removing transit state
  1388. m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.Transferring);
  1389. if (!agent.Scene.SimulationService.UpdateAgent(neighbourRegion, cAgent))
  1390. {
  1391. // region doesn't take it
  1392. m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp);
  1393. m_log.WarnFormat(
  1394. "[ENTITY TRANSFER MODULE]: Region {0} would not accept update for agent {1} on cross attempt. Returning to original region.",
  1395. neighbourRegion.RegionName, agent.Name);
  1396. ReInstantiateScripts(agent);
  1397. agent.AddToPhysicalScene(isFlying);
  1398. return false;
  1399. }
  1400. }
  1401. catch (Exception e)
  1402. {
  1403. m_log.ErrorFormat(
  1404. "[ENTITY TRANSFER MODULE]: Problem crossing user {0} to new region {1} from {2}. Exception {3}{4}",
  1405. agent.Name, neighbourRegion.RegionName, agent.Scene.RegionInfo.RegionName, e.Message, e.StackTrace);
  1406. // TODO: Might be worth attempting other restoration here such as reinstantiation of scripts, etc.
  1407. return false;
  1408. }
  1409. return true;
  1410. }
  1411. public void CrossAgentToNewRegionPost(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion,
  1412. bool isFlying, EntityTransferContext ctx)
  1413. {
  1414. agent.ControllingClient.RequestClientInfo();
  1415. string agentcaps;
  1416. if (!agent.KnownRegions.TryGetValue(neighbourRegion.RegionHandle, out agentcaps))
  1417. {
  1418. m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: No ENTITY TRANSFER MODULE information for region handle {0}, exiting CrossToNewRegion.",
  1419. neighbourRegion.RegionHandle);
  1420. return;
  1421. }
  1422. // No turning back
  1423. agent.IsChildAgent = true;
  1424. string capsPath = neighbourRegion.ServerURI + CapsUtil.GetCapsSeedPath(agentcaps);
  1425. m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID);
  1426. Vector3 vel2 = new Vector3(agent.Velocity.X, agent.Velocity.Y, 0);
  1427. if (m_eqModule != null)
  1428. {
  1429. m_eqModule.CrossRegion(
  1430. neighbourRegion.RegionHandle, pos + agent.Velocity, vel2 /* agent.Velocity */,
  1431. neighbourRegion.ExternalEndPoint,
  1432. capsPath, agent.UUID, agent.ControllingClient.SessionId,
  1433. neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY);
  1434. }
  1435. else
  1436. {
  1437. m_log.ErrorFormat("{0} Using old CrossRegion packet. Varregion will not work!!", LogHeader);
  1438. agent.ControllingClient.CrossRegion(neighbourRegion.RegionHandle, pos + agent.Velocity, agent.Velocity, neighbourRegion.ExternalEndPoint,
  1439. capsPath);
  1440. }
  1441. // SUCCESS!
  1442. m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.ReceivedAtDestination);
  1443. // Unlike a teleport, here we do not wait for the destination region to confirm the receipt.
  1444. m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp);
  1445. agent.MakeChildAgent();
  1446. // FIXME: Possibly this should occur lower down after other commands to close other agents,
  1447. // but not sure yet what the side effects would be.
  1448. m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
  1449. // now we have a child agent in this region. Request all interesting data about other (root) agents
  1450. agent.SendOtherAgentsAvatarDataToClient();
  1451. agent.SendOtherAgentsAppearanceToClient();
  1452. // TODO: Check since what version this wasn't needed anymore. May be as old as 0.6
  1453. /*
  1454. // Backwards compatibility. Best effort
  1455. if (version == 0f)
  1456. {
  1457. m_log.DebugFormat("[ENTITY TRANSFER MODULE]: neighbor with old version, passing attachments one by one...");
  1458. Thread.Sleep(3000); // wait a little now that we're not waiting for the callback
  1459. CrossAttachmentsIntoNewRegion(neighbourRegion, agent, true);
  1460. }
  1461. */
  1462. // Next, let's close the child agent connections that are too far away.
  1463. uint neighbourx;
  1464. uint neighboury;
  1465. Util.RegionHandleToRegionLoc(neighbourRegion.RegionHandle, out neighbourx, out neighboury);
  1466. agent.CloseChildAgents(neighbourx, neighboury);
  1467. AgentHasMovedAway(agent, false);
  1468. // the user may change their profile information in other region,
  1469. // so the userinfo in UserProfileCache is not reliable any more, delete it
  1470. // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
  1471. // if (agent.Scene.NeedSceneCacheClear(agent.UUID))
  1472. // {
  1473. // m_log.DebugFormat(
  1474. // "[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID);
  1475. // }
  1476. //m_log.Debug("AFTER CROSS");
  1477. //Scene.DumpChildrenSeeds(UUID);
  1478. //DumpKnownRegions();
  1479. return;
  1480. }
  1481. private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
  1482. {
  1483. CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
  1484. ScenePresence agent = icon.EndInvoke(iar);
  1485. //// If the cross was successful, this agent is a child agent
  1486. //if (agent.IsChildAgent)
  1487. // agent.Reset();
  1488. //else // Not successful
  1489. // agent.RestoreInCurrentScene();
  1490. // In any case
  1491. agent.IsInTransit = false;
  1492. m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
  1493. }
  1494. #endregion
  1495. #region Enable Child Agent
  1496. /// <summary>
  1497. /// This informs a single neighbouring region about agent "avatar".
  1498. /// Calls an asynchronous method to do so.. so it doesn't lag the sim.
  1499. /// </summary>
  1500. /// <param name="sp"></param>
  1501. /// <param name="region"></param>
  1502. public void EnableChildAgent(ScenePresence sp, GridRegion region)
  1503. {
  1504. m_log.DebugFormat("[ENTITY TRANSFER]: Enabling child agent in new neighbour {0}", region.RegionName);
  1505. AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
  1506. AgentCircuitData agent = sp.ControllingClient.RequestClientInfo();
  1507. agent.BaseFolder = UUID.Zero;
  1508. agent.InventoryFolder = UUID.Zero;
  1509. agent.startpos = new Vector3(128, 128, 70);
  1510. agent.child = true;
  1511. agent.Appearance = new AvatarAppearance();
  1512. agent.Appearance.PackLegacyWearables = true;
  1513. agent.CapsPath = CapsUtil.GetRandomCapsObjectPath();
  1514. agent.ChildrenCapSeeds = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID));
  1515. //m_log.DebugFormat("[XXX] Seeds 1 {0}", agent.ChildrenCapSeeds.Count);
  1516. if (!agent.ChildrenCapSeeds.ContainsKey(sp.Scene.RegionInfo.RegionHandle))
  1517. agent.ChildrenCapSeeds.Add(sp.Scene.RegionInfo.RegionHandle, sp.ControllingClient.RequestClientInfo().CapsPath);
  1518. //m_log.DebugFormat("[XXX] Seeds 2 {0}", agent.ChildrenCapSeeds.Count);
  1519. sp.AddNeighbourRegion(region.RegionHandle, agent.CapsPath);
  1520. //foreach (ulong h in agent.ChildrenCapSeeds.Keys)
  1521. // m_log.DebugFormat("[XXX] --> {0}", h);
  1522. //m_log.DebugFormat("[XXX] Adding {0}", region.RegionHandle);
  1523. if (agent.ChildrenCapSeeds.ContainsKey(region.RegionHandle))
  1524. {
  1525. m_log.WarnFormat(
  1526. "[ENTITY TRANSFER]: Overwriting caps seed {0} with {1} for region {2} (handle {3}) for {4} in {5}",
  1527. agent.ChildrenCapSeeds[region.RegionHandle], agent.CapsPath,
  1528. region.RegionName, region.RegionHandle, sp.Name, Scene.Name);
  1529. }
  1530. agent.ChildrenCapSeeds[region.RegionHandle] = agent.CapsPath;
  1531. if (sp.Scene.CapsModule != null)
  1532. {
  1533. sp.Scene.CapsModule.SetChildrenSeed(sp.UUID, agent.ChildrenCapSeeds);
  1534. }
  1535. if (currentAgentCircuit != null)
  1536. {
  1537. agent.ServiceURLs = currentAgentCircuit.ServiceURLs;
  1538. agent.IPAddress = currentAgentCircuit.IPAddress;
  1539. agent.Viewer = currentAgentCircuit.Viewer;
  1540. agent.Channel = currentAgentCircuit.Channel;
  1541. agent.Mac = currentAgentCircuit.Mac;
  1542. agent.Id0 = currentAgentCircuit.Id0;
  1543. }
  1544. IPEndPoint external = region.ExternalEndPoint;
  1545. if (external != null)
  1546. {
  1547. InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
  1548. d.BeginInvoke(sp, agent, region, external, true,
  1549. InformClientOfNeighbourCompleted,
  1550. d);
  1551. }
  1552. }
  1553. #endregion
  1554. #region Enable Child Agents
  1555. private delegate void InformClientOfNeighbourDelegate(
  1556. ScenePresence avatar, AgentCircuitData a, GridRegion reg, IPEndPoint endPoint, bool newAgent);
  1557. /// <summary>
  1558. /// This informs all neighbouring regions about agent "avatar".
  1559. /// </summary>
  1560. /// <param name="sp"></param>
  1561. public void EnableChildAgents(ScenePresence sp)
  1562. {
  1563. List<GridRegion> neighbours = new List<GridRegion>();
  1564. RegionInfo m_regionInfo = sp.Scene.RegionInfo;
  1565. if (m_regionInfo != null)
  1566. {
  1567. neighbours = GetNeighbours(sp, m_regionInfo.RegionLocX, m_regionInfo.RegionLocY);
  1568. }
  1569. else
  1570. {
  1571. m_log.Debug("[ENTITY TRANSFER MODULE]: m_regionInfo was null in EnableChildAgents, is this a NPC?");
  1572. }
  1573. /// We need to find the difference between the new regions where there are no child agents
  1574. /// and the regions where there are already child agents. We only send notification to the former.
  1575. List<ulong> neighbourHandles = NeighbourHandles(neighbours); // on this region
  1576. neighbourHandles.Add(sp.Scene.RegionInfo.RegionHandle); // add this region too
  1577. List<ulong> previousRegionNeighbourHandles;
  1578. if (sp.Scene.CapsModule != null)
  1579. {
  1580. previousRegionNeighbourHandles =
  1581. new List<ulong>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID).Keys);
  1582. }
  1583. else
  1584. {
  1585. previousRegionNeighbourHandles = new List<ulong>();
  1586. }
  1587. List<ulong> newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles);
  1588. List<ulong> oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles);
  1589. // Dump("Current Neighbors", neighbourHandles);
  1590. // Dump("Previous Neighbours", previousRegionNeighbourHandles);
  1591. // Dump("New Neighbours", newRegions);
  1592. // Dump("Old Neighbours", oldRegions);
  1593. /// Update the scene presence's known regions here on this region
  1594. sp.DropOldNeighbours(oldRegions);
  1595. /// Collect as many seeds as possible
  1596. Dictionary<ulong, string> seeds;
  1597. if (sp.Scene.CapsModule != null)
  1598. seeds = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID));
  1599. else
  1600. seeds = new Dictionary<ulong, string>();
  1601. //m_log.Debug(" !!! No. of seeds: " + seeds.Count);
  1602. if (!seeds.ContainsKey(sp.Scene.RegionInfo.RegionHandle))
  1603. seeds.Add(sp.Scene.RegionInfo.RegionHandle, sp.ControllingClient.RequestClientInfo().CapsPath);
  1604. /// Create the necessary child agents
  1605. List<AgentCircuitData> cagents = new List<AgentCircuitData>();
  1606. foreach (GridRegion neighbour in neighbours)
  1607. {
  1608. if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle)
  1609. {
  1610. AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
  1611. AgentCircuitData agent = sp.ControllingClient.RequestClientInfo();
  1612. agent.BaseFolder = UUID.Zero;
  1613. agent.InventoryFolder = UUID.Zero;
  1614. agent.startpos = sp.AbsolutePosition + CalculateOffset(sp, neighbour);
  1615. agent.child = true;
  1616. agent.Appearance = new AvatarAppearance();
  1617. agent.Appearance.PackLegacyWearables = true;
  1618. if (currentAgentCircuit != null)
  1619. {
  1620. agent.ServiceURLs = currentAgentCircuit.ServiceURLs;
  1621. agent.IPAddress = currentAgentCircuit.IPAddress;
  1622. agent.Viewer = currentAgentCircuit.Viewer;
  1623. agent.Channel = currentAgentCircuit.Channel;
  1624. agent.Mac = currentAgentCircuit.Mac;
  1625. agent.Id0 = currentAgentCircuit.Id0;
  1626. }
  1627. if (newRegions.Contains(neighbour.RegionHandle))
  1628. {
  1629. agent.CapsPath = CapsUtil.GetRandomCapsObjectPath();
  1630. sp.AddNeighbourRegion(neighbour.RegionHandle, agent.CapsPath);
  1631. seeds.Add(neighbour.RegionHandle, agent.CapsPath);
  1632. }
  1633. else
  1634. {
  1635. agent.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, neighbour.RegionHandle);
  1636. }
  1637. cagents.Add(agent);
  1638. }
  1639. }
  1640. /// Update all child agent with everyone's seeds
  1641. foreach (AgentCircuitData a in cagents)
  1642. {
  1643. a.ChildrenCapSeeds = new Dictionary<ulong, string>(seeds);
  1644. }
  1645. if (sp.Scene.CapsModule != null)
  1646. {
  1647. sp.Scene.CapsModule.SetChildrenSeed(sp.UUID, seeds);
  1648. }
  1649. sp.KnownRegions = seeds;
  1650. //avatar.Scene.DumpChildrenSeeds(avatar.UUID);
  1651. //avatar.DumpKnownRegions();
  1652. bool newAgent = false;
  1653. int count = 0;
  1654. foreach (GridRegion neighbour in neighbours)
  1655. {
  1656. //m_log.WarnFormat("--> Going to send child agent to {0}", neighbour.RegionName);
  1657. // Don't do it if there's already an agent in that region
  1658. if (newRegions.Contains(neighbour.RegionHandle))
  1659. newAgent = true;
  1660. else
  1661. newAgent = false;
  1662. // continue;
  1663. if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle)
  1664. {
  1665. try
  1666. {
  1667. // Let's put this back at sync, so that it doesn't clog
  1668. // the network, especially for regions in the same physical server.
  1669. // We're really not in a hurry here.
  1670. InformClientOfNeighbourAsync(sp, cagents[count], neighbour, neighbour.ExternalEndPoint, newAgent);
  1671. //InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
  1672. //d.BeginInvoke(sp, cagents[count], neighbour, neighbour.ExternalEndPoint, newAgent,
  1673. // InformClientOfNeighbourCompleted,
  1674. // d);
  1675. }
  1676. catch (ArgumentOutOfRangeException)
  1677. {
  1678. m_log.ErrorFormat(
  1679. "[ENTITY TRANSFER MODULE]: Neighbour Regions response included the current region in the neighbour list. The following region will not display to the client: {0} for region {1} ({2}, {3}).",
  1680. neighbour.ExternalHostName,
  1681. neighbour.RegionHandle,
  1682. neighbour.RegionLocX,
  1683. neighbour.RegionLocY);
  1684. }
  1685. catch (Exception e)
  1686. {
  1687. m_log.ErrorFormat(
  1688. "[ENTITY TRANSFER MODULE]: Could not resolve external hostname {0} for region {1} ({2}, {3}). {4}",
  1689. neighbour.ExternalHostName,
  1690. neighbour.RegionHandle,
  1691. neighbour.RegionLocX,
  1692. neighbour.RegionLocY,
  1693. e);
  1694. // FIXME: Okay, even though we've failed, we're still going to throw the exception on,
  1695. // since I don't know what will happen if we just let the client continue
  1696. // XXX: Well, decided to swallow the exception instead for now. Let us see how that goes.
  1697. // throw e;
  1698. }
  1699. }
  1700. count++;
  1701. }
  1702. }
  1703. // Computes the difference between two region bases.
  1704. // Returns a vector of world coordinates (meters) from base of first region to the second.
  1705. // The first region is the home region of the passed scene presence.
  1706. Vector3 CalculateOffset(ScenePresence sp, GridRegion neighbour)
  1707. {
  1708. /*
  1709. int rRegionX = (int)sp.Scene.RegionInfo.LegacyRegionLocX;
  1710. int rRegionY = (int)sp.Scene.RegionInfo.LegacyRegionLocY;
  1711. int tRegionX = neighbour.RegionLocX / (int)Constants.RegionSize;
  1712. int tRegionY = neighbour.RegionLocY / (int)Constants.RegionSize;
  1713. int shiftx = (rRegionX - tRegionX) * (int)Constants.RegionSize;
  1714. int shifty = (rRegionY - tRegionY) * (int)Constants.RegionSize;
  1715. return new Vector3(shiftx, shifty, 0f);
  1716. */
  1717. return new Vector3( sp.Scene.RegionInfo.WorldLocX - neighbour.RegionLocX,
  1718. sp.Scene.RegionInfo.WorldLocY - neighbour.RegionLocY,
  1719. 0f);
  1720. }
  1721. public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py)
  1722. {
  1723. // Since we don't know how big the regions could be, we have to search a very large area
  1724. // to find possible regions.
  1725. return GetRegionContainingWorldLocation(pGridService, pScopeID, px, py, Constants.MaximumRegionSize);
  1726. }
  1727. #region NotFoundLocationCache class
  1728. // A collection of not found locations to make future lookups 'not found' lookups quick.
  1729. // A simple expiring cache that keeps not found locations for some number of seconds.
  1730. // A 'not found' location is presumed to be anywhere in the minimum sized region that
  1731. // contains that point. A conservitive estimate.
  1732. private class NotFoundLocationCache
  1733. {
  1734. private struct NotFoundLocation
  1735. {
  1736. public double minX, maxX, minY, maxY;
  1737. public DateTime expireTime;
  1738. }
  1739. private List<NotFoundLocation> m_notFoundLocations = new List<NotFoundLocation>();
  1740. public NotFoundLocationCache()
  1741. {
  1742. }
  1743. // Add an area to the list of 'not found' places. The area is the snapped region
  1744. // area around the added point.
  1745. public void Add(double pX, double pY)
  1746. {
  1747. lock (m_notFoundLocations)
  1748. {
  1749. if (!LockedContains(pX, pY))
  1750. {
  1751. NotFoundLocation nfl = new NotFoundLocation();
  1752. // A not found location is not found for at least a whole region sized area
  1753. nfl.minX = pX - (pX % (double)Constants.RegionSize);
  1754. nfl.minY = pY - (pY % (double)Constants.RegionSize);
  1755. nfl.maxX = nfl.minX + (double)Constants.RegionSize;
  1756. nfl.maxY = nfl.minY + (double)Constants.RegionSize;
  1757. nfl.expireTime = DateTime.Now + TimeSpan.FromSeconds(30);
  1758. m_notFoundLocations.Add(nfl);
  1759. }
  1760. }
  1761. }
  1762. // Test to see of this point is in any of the 'not found' areas.
  1763. // Return 'true' if the point is found inside the 'not found' areas.
  1764. public bool Contains(double pX, double pY)
  1765. {
  1766. bool ret = false;
  1767. lock (m_notFoundLocations)
  1768. ret = LockedContains(pX, pY);
  1769. return ret;
  1770. }
  1771. private bool LockedContains(double pX, double pY)
  1772. {
  1773. bool ret = false;
  1774. this.DoExpiration();
  1775. foreach (NotFoundLocation nfl in m_notFoundLocations)
  1776. {
  1777. if (pX >= nfl.minX && pX < nfl.maxX && pY >= nfl.minY && pY < nfl.maxY)
  1778. {
  1779. ret = true;
  1780. break;
  1781. }
  1782. }
  1783. return ret;
  1784. }
  1785. private void DoExpiration()
  1786. {
  1787. List<NotFoundLocation> m_toRemove = null;
  1788. DateTime now = DateTime.Now;
  1789. foreach (NotFoundLocation nfl in m_notFoundLocations)
  1790. {
  1791. if (nfl.expireTime < now)
  1792. {
  1793. if (m_toRemove == null)
  1794. m_toRemove = new List<NotFoundLocation>();
  1795. m_toRemove.Add(nfl);
  1796. }
  1797. }
  1798. if (m_toRemove != null)
  1799. {
  1800. foreach (NotFoundLocation nfl in m_toRemove)
  1801. m_notFoundLocations.Remove(nfl);
  1802. m_toRemove.Clear();
  1803. }
  1804. }
  1805. }
  1806. #endregion // NotFoundLocationCache class
  1807. private NotFoundLocationCache m_notFoundLocationCache = new NotFoundLocationCache();
  1808. // Given a world position (fractional meter coordinate), get the GridRegion info for
  1809. // the region containing that point.
  1810. // Someday this should be a method on GridService.
  1811. // 'pSizeHint' is the size of the source region but since the destination point can be anywhere
  1812. // the size of the target region is unknown thus the search area might have to be very large.
  1813. // Return 'null' if no such region exists.
  1814. public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID,
  1815. double px, double py, uint pSizeHint)
  1816. {
  1817. m_log.DebugFormat("{0} GetRegionContainingWorldLocation: query, loc=<{1},{2}>", LogHeader, px, py);
  1818. GridRegion ret = null;
  1819. const double fudge = 2.0;
  1820. // One problem with this routine is negative results. That is, this can be called lots of times
  1821. // for regions that don't exist. m_notFoundLocationCache remembers 'not found' results so they
  1822. // will be quick 'not found's next time.
  1823. // NotFoundLocationCache is an expiring cache so it will eventually forget about 'not found' and
  1824. // thus re-ask the GridService about the location.
  1825. if (m_notFoundLocationCache.Contains(px, py))
  1826. {
  1827. m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found via cache. loc=<{1},{2}>", LogHeader, px, py);
  1828. return null;
  1829. }
  1830. // As an optimization, since most regions will be legacy sized regions (256x256), first try to get
  1831. // the region at the appropriate legacy region location.
  1832. uint possibleX = (uint)Math.Floor(px);
  1833. possibleX -= possibleX % Constants.RegionSize;
  1834. uint possibleY = (uint)Math.Floor(py);
  1835. possibleY -= possibleY % Constants.RegionSize;
  1836. ret = pGridService.GetRegionByPosition(pScopeID, (int)possibleX, (int)possibleY);
  1837. if (ret != null)
  1838. {
  1839. m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Found region using legacy size. rloc=<{1},{2}>. Rname={3}",
  1840. LogHeader, possibleX, possibleY, ret.RegionName);
  1841. }
  1842. if (ret == null)
  1843. {
  1844. // If the simple lookup failed, search the larger area for a region that contains this point
  1845. double range = (double)pSizeHint + fudge;
  1846. while (ret == null && range <= (Constants.MaximumRegionSize + Constants.RegionSize))
  1847. {
  1848. // Get from the grid service a list of regions that might contain this point.
  1849. // The region origin will be in the zero direction so only subtract the range.
  1850. List<GridRegion> possibleRegions = pGridService.GetRegionRange(pScopeID,
  1851. (int)(px - range), (int)(px),
  1852. (int)(py - range), (int)(py));
  1853. m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegions cnt={1}, range={2}",
  1854. LogHeader, possibleRegions.Count, range);
  1855. if (possibleRegions != null && possibleRegions.Count > 0)
  1856. {
  1857. // If we found some regions, check to see if the point is within
  1858. foreach (GridRegion gr in possibleRegions)
  1859. {
  1860. m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegion nm={1}, regionLoc=<{2},{3}>, regionSize=<{4},{5}>",
  1861. LogHeader, gr.RegionName, gr.RegionLocX, gr.RegionLocY, gr.RegionSizeX, gr.RegionSizeY);
  1862. if (px >= (double)gr.RegionLocX && px < (double)(gr.RegionLocX + gr.RegionSizeX)
  1863. && py >= (double)gr.RegionLocY && py < (double)(gr.RegionLocY + gr.RegionSizeY))
  1864. {
  1865. // Found a region that contains the point
  1866. ret = gr;
  1867. m_log.DebugFormat("{0} GetRegionContainingWorldLocation: found. RegionName={1}", LogHeader, ret.RegionName);
  1868. break;
  1869. }
  1870. }
  1871. }
  1872. // Larger search area for next time around if not found
  1873. range *= 2;
  1874. }
  1875. }
  1876. if (ret == null)
  1877. {
  1878. // remember this location was not found so we can quickly not find it next time
  1879. m_notFoundLocationCache.Add(px, py);
  1880. m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found. Remembering loc=<{1},{2}>", LogHeader, px, py);
  1881. }
  1882. return ret;
  1883. }
  1884. private void InformClientOfNeighbourCompleted(IAsyncResult iar)
  1885. {
  1886. InformClientOfNeighbourDelegate icon = (InformClientOfNeighbourDelegate)iar.AsyncState;
  1887. icon.EndInvoke(iar);
  1888. //m_log.WarnFormat(" --> InformClientOfNeighbourCompleted");
  1889. }
  1890. /// <summary>
  1891. /// Async component for informing client of which neighbours exist
  1892. /// </summary>
  1893. /// <remarks>
  1894. /// This needs to run asynchronously, as a network timeout may block the thread for a long while
  1895. /// </remarks>
  1896. /// <param name="remoteClient"></param>
  1897. /// <param name="a"></param>
  1898. /// <param name="regionHandle"></param>
  1899. /// <param name="endPoint"></param>
  1900. private void InformClientOfNeighbourAsync(ScenePresence sp, AgentCircuitData a, GridRegion reg,
  1901. IPEndPoint endPoint, bool newAgent)
  1902. {
  1903. // Let's wait just a little to give time to originating regions to catch up with closing child agents
  1904. // after a cross here
  1905. Thread.Sleep(500);
  1906. Scene scene = sp.Scene;
  1907. m_log.DebugFormat(
  1908. "[ENTITY TRANSFER MODULE]: Informing {0} {1} about neighbour {2} {3} at ({4},{5})",
  1909. sp.Name, sp.UUID, reg.RegionName, endPoint, reg.RegionCoordX, reg.RegionCoordY);
  1910. string capsPath = reg.ServerURI + CapsUtil.GetCapsSeedPath(a.CapsPath);
  1911. string reason = String.Empty;
  1912. bool regionAccepted = scene.SimulationService.CreateAgent(null, reg, a, (uint)TeleportFlags.Default, out reason);
  1913. if (regionAccepted && newAgent)
  1914. {
  1915. if (m_eqModule != null)
  1916. {
  1917. #region IP Translation for NAT
  1918. IClientIPEndpoint ipepClient;
  1919. if (sp.ClientView.TryGet(out ipepClient))
  1920. {
  1921. endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address);
  1922. }
  1923. #endregion
  1924. m_log.DebugFormat("{0} {1} is sending {2} EnableSimulator for neighbour region {3}(loc=<{4},{5}>,siz=<{6},{7}>) " +
  1925. "and EstablishAgentCommunication with seed cap {8}", LogHeader,
  1926. scene.RegionInfo.RegionName, sp.Name,
  1927. reg.RegionName, reg.RegionLocX, reg.RegionLocY, reg.RegionSizeX, reg.RegionSizeY , capsPath);
  1928. m_eqModule.EnableSimulator(reg.RegionHandle, endPoint, sp.UUID, reg.RegionSizeX, reg.RegionSizeY);
  1929. m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath, reg.RegionHandle, reg.RegionSizeX, reg.RegionSizeY);
  1930. }
  1931. else
  1932. {
  1933. sp.ControllingClient.InformClientOfNeighbour(reg.RegionHandle, endPoint);
  1934. // TODO: make Event Queue disablable!
  1935. }
  1936. m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Completed inform {0} {1} about neighbour {2}", sp.Name, sp.UUID, endPoint);
  1937. }
  1938. if (!regionAccepted)
  1939. m_log.WarnFormat(
  1940. "[ENTITY TRANSFER MODULE]: Region {0} did not accept {1} {2}: {3}",
  1941. reg.RegionName, sp.Name, sp.UUID, reason);
  1942. }
  1943. /// <summary>
  1944. /// Gets the range considered in view of this megaregion (assuming this is a megaregion).
  1945. /// </summary>
  1946. /// <remarks>Expressed in 256m units</remarks>
  1947. /// <param name='swCorner'></param>
  1948. /// <param name='neCorner'></param>
  1949. private void GetMegaregionViewRange(out Vector2 swCorner, out Vector2 neCorner)
  1950. {
  1951. Vector2 extent = Vector2.Zero;
  1952. if (m_regionCombinerModule != null)
  1953. {
  1954. Vector2 megaRegionSize = m_regionCombinerModule.GetSizeOfMegaregion(Scene.RegionInfo.RegionID);
  1955. extent.X = (float)Util.WorldToRegionLoc((uint)megaRegionSize.X);
  1956. extent.Y = (float)Util.WorldToRegionLoc((uint)megaRegionSize.Y);
  1957. }
  1958. swCorner.X = Scene.RegionInfo.RegionLocX - 1;
  1959. swCorner.Y = Scene.RegionInfo.RegionLocY - 1;
  1960. neCorner.X = Scene.RegionInfo.RegionLocX + extent.X;
  1961. neCorner.Y = Scene.RegionInfo.RegionLocY + extent.Y;
  1962. }
  1963. /// <summary>
  1964. /// Return the list of online regions that are considered to be neighbours to the given scene.
  1965. /// </summary>
  1966. /// <param name="avatar"></param>
  1967. /// <param name="pRegionLocX"></param>
  1968. /// <param name="pRegionLocY"></param>
  1969. /// <returns></returns>
  1970. protected List<GridRegion> GetNeighbours(ScenePresence avatar, uint pRegionLocX, uint pRegionLocY)
  1971. {
  1972. Scene pScene = avatar.Scene;
  1973. RegionInfo m_regionInfo = pScene.RegionInfo;
  1974. List<GridRegion> neighbours;
  1975. // Leaving this as a "megaregions" computation vs "non-megaregions" computation; it isn't
  1976. // clear what should be done with a "far view" given that megaregions already extended the
  1977. // view to include everything in the megaregion
  1978. if (m_regionCombinerModule == null || !m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID))
  1979. {
  1980. // The area to check is as big as the current region.
  1981. // We presume all adjacent regions are the same size as this region.
  1982. uint dd = Math.Max((uint)avatar.Scene.DefaultDrawDistance,
  1983. Math.Max(Scene.RegionInfo.RegionSizeX, Scene.RegionInfo.RegionSizeY));
  1984. uint startX = Util.RegionToWorldLoc(pRegionLocX) - dd + Constants.RegionSize/2;
  1985. uint startY = Util.RegionToWorldLoc(pRegionLocY) - dd + Constants.RegionSize/2;
  1986. uint endX = Util.RegionToWorldLoc(pRegionLocX) + dd + Constants.RegionSize/2;
  1987. uint endY = Util.RegionToWorldLoc(pRegionLocY) + dd + Constants.RegionSize/2;
  1988. neighbours
  1989. = avatar.Scene.GridService.GetRegionRange(
  1990. m_regionInfo.ScopeID, (int)startX, (int)endX, (int)startY, (int)endY);
  1991. }
  1992. else
  1993. {
  1994. Vector2 swCorner, neCorner;
  1995. GetMegaregionViewRange(out swCorner, out neCorner);
  1996. neighbours
  1997. = pScene.GridService.GetRegionRange(
  1998. m_regionInfo.ScopeID,
  1999. (int)Util.RegionToWorldLoc((uint)swCorner.X), (int)Util.RegionToWorldLoc((uint)neCorner.X),
  2000. (int)Util.RegionToWorldLoc((uint)swCorner.Y), (int)Util.RegionToWorldLoc((uint)neCorner.Y));
  2001. }
  2002. // neighbours.ForEach(
  2003. // n =>
  2004. // m_log.DebugFormat(
  2005. // "[ENTITY TRANSFER MODULE]: Region flags for {0} as seen by {1} are {2}",
  2006. // n.RegionName, Scene.Name, n.RegionFlags != null ? n.RegionFlags.ToString() : "not present"));
  2007. // The r.RegionFlags == null check only needs to be made for simulators before 2015-01-14 (pre 0.8.1).
  2008. neighbours.RemoveAll(
  2009. r =>
  2010. r.RegionID == m_regionInfo.RegionID
  2011. || (r.RegionFlags != null && (r.RegionFlags & OpenSim.Framework.RegionFlags.RegionOnline) == 0));
  2012. return neighbours;
  2013. }
  2014. private List<ulong> NewNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours)
  2015. {
  2016. return currentNeighbours.FindAll(delegate(ulong handle) { return !previousNeighbours.Contains(handle); });
  2017. }
  2018. // private List<ulong> CommonNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours)
  2019. // {
  2020. // return currentNeighbours.FindAll(delegate(ulong handle) { return previousNeighbours.Contains(handle); });
  2021. // }
  2022. private List<ulong> OldNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours)
  2023. {
  2024. return previousNeighbours.FindAll(delegate(ulong handle) { return !currentNeighbours.Contains(handle); });
  2025. }
  2026. private List<ulong> NeighbourHandles(List<GridRegion> neighbours)
  2027. {
  2028. List<ulong> handles = new List<ulong>();
  2029. foreach (GridRegion reg in neighbours)
  2030. {
  2031. handles.Add(reg.RegionHandle);
  2032. }
  2033. return handles;
  2034. }
  2035. // private void Dump(string msg, List<ulong> handles)
  2036. // {
  2037. // m_log.InfoFormat("-------------- HANDLE DUMP ({0}) ---------", msg);
  2038. // foreach (ulong handle in handles)
  2039. // {
  2040. // uint x, y;
  2041. // Utils.LongToUInts(handle, out x, out y);
  2042. // x = x / Constants.RegionSize;
  2043. // y = y / Constants.RegionSize;
  2044. // m_log.InfoFormat("({0}, {1})", x, y);
  2045. // }
  2046. // }
  2047. #endregion
  2048. #region Agent Arrived
  2049. public void AgentArrivedAtDestination(UUID id)
  2050. {
  2051. m_entityTransferStateMachine.SetAgentArrivedAtDestination(id);
  2052. }
  2053. #endregion
  2054. #region Object Transfers
  2055. /// <summary>
  2056. /// Move the given scene object into a new region depending on which region its absolute position has moved
  2057. /// into.
  2058. ///
  2059. /// Using the objects new world location, ask the grid service for a the new region and adjust the prim
  2060. /// position to be relative to the new region.
  2061. /// </summary>
  2062. /// <param name="grp">the scene object that we're crossing</param>
  2063. /// <param name="attemptedPosition">the attempted out of region position of the scene object. This position is
  2064. /// relative to the region the object currently is in.</param>
  2065. /// <param name="silent">if 'true', the deletion of the client from the region is not broadcast to the clients</param>
  2066. public void Cross(SceneObjectGroup grp, Vector3 attemptedPosition, bool silent)
  2067. {
  2068. if (grp == null)
  2069. return;
  2070. if (grp.IsDeleted)
  2071. return;
  2072. Scene scene = grp.Scene;
  2073. if (scene == null)
  2074. return;
  2075. if (grp.RootPart.DIE_AT_EDGE)
  2076. {
  2077. // We remove the object here
  2078. try
  2079. {
  2080. scene.DeleteSceneObject(grp, false);
  2081. }
  2082. catch (Exception)
  2083. {
  2084. m_log.Warn("[DATABASE]: exception when trying to remove the prim that crossed the border.");
  2085. }
  2086. return;
  2087. }
  2088. // Remember the old group position in case the region lookup fails so position can be restored.
  2089. Vector3 oldGroupPosition = grp.RootPart.GroupPosition;
  2090. // Compute the absolute position of the object.
  2091. double objectWorldLocX = (double)scene.RegionInfo.WorldLocX + attemptedPosition.X;
  2092. double objectWorldLocY = (double)scene.RegionInfo.WorldLocY + attemptedPosition.Y;
  2093. // Ask the grid service for the region that contains the passed address
  2094. GridRegion destination = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID,
  2095. objectWorldLocX, objectWorldLocY);
  2096. Vector3 pos = Vector3.Zero;
  2097. if (destination != null)
  2098. {
  2099. // Adjust the object's relative position from the old region (attemptedPosition)
  2100. // to be relative to the new region (pos).
  2101. pos = new Vector3( (float)(objectWorldLocX - (double)destination.RegionLocX),
  2102. (float)(objectWorldLocY - (double)destination.RegionLocY),
  2103. attemptedPosition.Z);
  2104. }
  2105. if (destination == null || !CrossPrimGroupIntoNewRegion(destination, pos, grp, silent))
  2106. {
  2107. m_log.InfoFormat("[ENTITY TRANSFER MODULE] cross region transfer failed for object {0}", grp.UUID);
  2108. // We are going to move the object back to the old position so long as the old position
  2109. // is in the region
  2110. oldGroupPosition.X = Util.Clamp<float>(oldGroupPosition.X, 1.0f, (float)(scene.RegionInfo.RegionSizeX - 1));
  2111. oldGroupPosition.Y = Util.Clamp<float>(oldGroupPosition.Y, 1.0f, (float)(scene.RegionInfo.RegionSizeY - 1));
  2112. oldGroupPosition.Z = Util.Clamp<float>(oldGroupPosition.Z, 1.0f, Constants.RegionHeight);
  2113. grp.AbsolutePosition = oldGroupPosition;
  2114. grp.Velocity = Vector3.Zero;
  2115. if (grp.RootPart.PhysActor != null)
  2116. grp.RootPart.PhysActor.CrossingFailure();
  2117. if (grp.RootPart.KeyframeMotion != null)
  2118. grp.RootPart.KeyframeMotion.CrossingFailure();
  2119. grp.ScheduleGroupForFullUpdate();
  2120. }
  2121. }
  2122. /// <summary>
  2123. /// Move the given scene object into a new region
  2124. /// </summary>
  2125. /// <param name="newRegionHandle"></param>
  2126. /// <param name="grp">Scene Object Group that we're crossing</param>
  2127. /// <returns>
  2128. /// true if the crossing itself was successful, false on failure
  2129. /// FIMXE: we still return true if the crossing object was not successfully deleted from the originating region
  2130. /// </returns>
  2131. protected bool CrossPrimGroupIntoNewRegion(GridRegion destination, Vector3 newPosition, SceneObjectGroup grp, bool silent)
  2132. {
  2133. //m_log.Debug(" >>> CrossPrimGroupIntoNewRegion <<<");
  2134. bool successYN = false;
  2135. grp.RootPart.ClearUpdateSchedule();
  2136. //int primcrossingXMLmethod = 0;
  2137. if (destination != null)
  2138. {
  2139. //string objectState = grp.GetStateSnapshot();
  2140. //successYN
  2141. // = m_sceneGridService.PrimCrossToNeighboringRegion(
  2142. // newRegionHandle, grp.UUID, m_serialiser.SaveGroupToXml2(grp), primcrossingXMLmethod);
  2143. //if (successYN && (objectState != "") && m_allowScriptCrossings)
  2144. //{
  2145. // successYN = m_sceneGridService.PrimCrossToNeighboringRegion(
  2146. // newRegionHandle, grp.UUID, objectState, 100);
  2147. //}
  2148. //// And the new channel...
  2149. //if (m_interregionCommsOut != null)
  2150. // successYN = m_interregionCommsOut.SendCreateObject(newRegionHandle, grp, true);
  2151. if (Scene.SimulationService != null)
  2152. successYN = Scene.SimulationService.CreateObject(destination, newPosition, grp, true);
  2153. if (successYN)
  2154. {
  2155. // We remove the object here
  2156. try
  2157. {
  2158. grp.Scene.DeleteSceneObject(grp, silent);
  2159. }
  2160. catch (Exception e)
  2161. {
  2162. m_log.ErrorFormat(
  2163. "[ENTITY TRANSFER MODULE]: Exception deleting the old object left behind on a border crossing for {0}, {1}",
  2164. grp, e);
  2165. }
  2166. }
  2167. /*
  2168. * done on caller ( not in attachments crossing for now)
  2169. else
  2170. {
  2171. if (!grp.IsDeleted)
  2172. {
  2173. PhysicsActor pa = grp.RootPart.PhysActor;
  2174. if (pa != null)
  2175. {
  2176. pa.CrossingFailure();
  2177. if (grp.RootPart.KeyframeMotion != null)
  2178. {
  2179. // moved to KeyframeMotion.CrossingFailure
  2180. // grp.RootPart.Velocity = Vector3.Zero;
  2181. grp.RootPart.KeyframeMotion.CrossingFailure();
  2182. // grp.SendGroupRootTerseUpdate();
  2183. }
  2184. }
  2185. }
  2186. m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: Prim crossing failed for {0}", grp);
  2187. }
  2188. */
  2189. }
  2190. else
  2191. {
  2192. m_log.Error("[ENTITY TRANSFER MODULE]: destination was unexpectedly null in Scene.CrossPrimGroupIntoNewRegion()");
  2193. }
  2194. return successYN;
  2195. }
  2196. /// <summary>
  2197. /// Cross the attachments for an avatar into the destination region.
  2198. /// </summary>
  2199. /// <remarks>
  2200. /// This is only invoked for simulators released prior to April 2011. Versions of OpenSimulator since then
  2201. /// transfer attachments in one go as part of the ChildAgentDataUpdate data passed in the update agent call.
  2202. /// </remarks>
  2203. /// <param name='destination'></param>
  2204. /// <param name='sp'></param>
  2205. /// <param name='silent'></param>
  2206. protected void CrossAttachmentsIntoNewRegion(GridRegion destination, ScenePresence sp, bool silent)
  2207. {
  2208. List<SceneObjectGroup> attachments = sp.GetAttachments();
  2209. // m_log.DebugFormat(
  2210. // "[ENTITY TRANSFER MODULE]: Crossing {0} attachments into {1} for {2}",
  2211. // m_attachments.Count, destination.RegionName, sp.Name);
  2212. foreach (SceneObjectGroup gobj in attachments)
  2213. {
  2214. // If the prim group is null then something must have happened to it!
  2215. if (gobj != null && !gobj.IsDeleted)
  2216. {
  2217. SceneObjectGroup clone = (SceneObjectGroup)gobj.CloneForNewScene();
  2218. clone.RootPart.GroupPosition = gobj.RootPart.AttachedPos;
  2219. clone.IsAttachment = false;
  2220. //gobj.RootPart.LastOwnerID = gobj.GetFromAssetID();
  2221. m_log.DebugFormat(
  2222. "[ENTITY TRANSFER MODULE]: Sending attachment {0} to region {1}",
  2223. clone.UUID, destination.RegionName);
  2224. CrossPrimGroupIntoNewRegion(destination, Vector3.Zero, clone, silent);
  2225. }
  2226. }
  2227. sp.ClearAttachments();
  2228. }
  2229. #endregion
  2230. #region Misc
  2231. public bool IsInTransit(UUID id)
  2232. {
  2233. return m_entityTransferStateMachine.GetAgentTransferState(id) != null;
  2234. }
  2235. protected void ReInstantiateScripts(ScenePresence sp)
  2236. {
  2237. int i = 0;
  2238. if (sp.InTransitScriptStates.Count > 0)
  2239. {
  2240. List<SceneObjectGroup> attachments = sp.GetAttachments();
  2241. foreach (SceneObjectGroup sog in attachments)
  2242. {
  2243. if (i < sp.InTransitScriptStates.Count)
  2244. {
  2245. sog.SetState(sp.InTransitScriptStates[i++], sp.Scene);
  2246. sog.CreateScriptInstances(0, false, sp.Scene.DefaultScriptEngine, 0);
  2247. sog.ResumeScripts();
  2248. }
  2249. else
  2250. m_log.ErrorFormat(
  2251. "[ENTITY TRANSFER MODULE]: InTransitScriptStates.Count={0} smaller than Attachments.Count={1}",
  2252. sp.InTransitScriptStates.Count, attachments.Count);
  2253. }
  2254. sp.InTransitScriptStates.Clear();
  2255. }
  2256. }
  2257. #endregion
  2258. public virtual bool HandleIncomingSceneObject(SceneObjectGroup so, Vector3 newPosition)
  2259. {
  2260. // If the user is banned, we won't let any of their objects
  2261. // enter. Period.
  2262. //
  2263. if (Scene.RegionInfo.EstateSettings.IsBanned(so.OwnerID))
  2264. {
  2265. m_log.DebugFormat(
  2266. "[ENTITY TRANSFER MODULE]: Denied prim crossing of {0} {1} into {2} for banned avatar {3}",
  2267. so.Name, so.UUID, Scene.Name, so.OwnerID);
  2268. return false;
  2269. }
  2270. if (newPosition != Vector3.Zero)
  2271. so.RootPart.GroupPosition = newPosition;
  2272. if (!Scene.AddSceneObject(so))
  2273. {
  2274. m_log.DebugFormat(
  2275. "[ENTITY TRANSFER MODULE]: Problem adding scene object {0} {1} into {2} ",
  2276. so.Name, so.UUID, Scene.Name);
  2277. return false;
  2278. }
  2279. if (!so.IsAttachment)
  2280. {
  2281. // FIXME: It would be better to never add the scene object at all rather than add it and then delete
  2282. // it
  2283. if (!Scene.Permissions.CanObjectEntry(so.UUID, true, so.AbsolutePosition))
  2284. {
  2285. // Deny non attachments based on parcel settings
  2286. //
  2287. m_log.Info("[ENTITY TRANSFER MODULE]: Denied prim crossing because of parcel settings");
  2288. Scene.DeleteSceneObject(so, false);
  2289. return false;
  2290. }
  2291. // For attachments, we need to wait until the agent is root
  2292. // before we restart the scripts, or else some functions won't work.
  2293. so.RootPart.ParentGroup.CreateScriptInstances(
  2294. 0, false, Scene.DefaultScriptEngine, GetStateSource(so));
  2295. so.ResumeScripts();
  2296. if (so.RootPart.KeyframeMotion != null)
  2297. so.RootPart.KeyframeMotion.UpdateSceneObject(so);
  2298. }
  2299. return true;
  2300. }
  2301. private int GetStateSource(SceneObjectGroup sog)
  2302. {
  2303. ScenePresence sp = Scene.GetScenePresence(sog.OwnerID);
  2304. if (sp != null)
  2305. return sp.GetStateSource();
  2306. return 2; // StateSource.PrimCrossing
  2307. }
  2308. }
  2309. }