EntityTransferModule.cs 121 KB

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