EntityTransferModule.cs 114 KB

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