EntityTransferModule.cs 119 KB

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