EntityTransferModule.cs 126 KB

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