LandObject.cs 79 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103
  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.Reflection;
  30. using System.Runtime.CompilerServices;
  31. using log4net;
  32. using OpenMetaverse;
  33. using OpenSim.Framework;
  34. using OpenSim.Region.Framework.Interfaces;
  35. using OpenSim.Region.Framework.Scenes;
  36. using RegionFlags = OpenMetaverse.RegionFlags;
  37. namespace OpenSim.Region.CoreModules.World.Land
  38. {
  39. /// <summary>
  40. /// Keeps track of a specific piece of land's information
  41. /// </summary>
  42. public class LandObject : ILandObject
  43. {
  44. #region Member Variables
  45. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  46. private static readonly string LogHeader = "[LAND OBJECT]";
  47. protected const int GROUPMEMBERCACHETIMEOUT = 30000; // cache invalidation after 30s
  48. private int m_lastSeqId = 0;
  49. private int m_expiryCounter = 0;
  50. protected readonly Scene m_scene;
  51. protected readonly int m_regionSizeX;
  52. protected readonly int m_regionSizeY;
  53. protected readonly RegionInfo m_regionInfo;
  54. protected readonly RegionSettings m_regionSettings;
  55. protected readonly ScenePermissions m_scenePermissions;
  56. protected readonly EstateSettings m_estateSettings;
  57. protected readonly List<SceneObjectGroup> primsOverMe = new();
  58. private readonly ExpiringCacheOS<uint, UUID> m_listTransactions = new(30000);
  59. private readonly object m_listTransactionsLock = new();
  60. protected readonly ExpiringCacheOS<UUID, bool> m_groupMemberCache = new(30000);
  61. protected readonly IDwellModule m_dwellModule;
  62. private bool[,] m_landBitmap;
  63. public bool[,] LandBitmap
  64. {
  65. get { return m_landBitmap; }
  66. set { m_landBitmap = value; }
  67. }
  68. #endregion
  69. public int GetPrimsFree()
  70. {
  71. m_scene.EventManager.TriggerParcelPrimCountUpdate();
  72. int free = GetSimulatorMaxPrimCount() - LandData.SimwidePrims;
  73. return free;
  74. }
  75. protected LandData m_landData;
  76. public LandData LandData
  77. {
  78. get { return m_landData; }
  79. set { m_landData = value; }
  80. }
  81. public UUID GlobalID
  82. {
  83. get
  84. {
  85. return m_landData is null ? UUID.Zero : m_landData.GlobalID;
  86. }
  87. }
  88. public UUID FakeID
  89. {
  90. get
  91. {
  92. return m_landData is null ? UUID.Zero : m_landData.FakeID;
  93. }
  94. }
  95. public UUID OwnerID
  96. {
  97. get
  98. {
  99. return m_landData is null ? UUID.Zero : m_landData.OwnerID;
  100. }
  101. }
  102. public UUID GroupID
  103. {
  104. get
  105. {
  106. return m_landData is null ? UUID.Zero : m_landData.GroupID;
  107. }
  108. }
  109. public int LocalID
  110. {
  111. get
  112. {
  113. return m_landData is null ? -1 : m_landData.LocalID;
  114. }
  115. }
  116. public IPrimCounts PrimCounts { get; set; }
  117. public UUID RegionUUID
  118. {
  119. get { return m_regionInfo.RegionID; }
  120. }
  121. private Vector2 m_startPoint = Vector2.Zero;
  122. private Vector2 m_endPoint = Vector2.Zero;
  123. private Vector2 m_centerPoint = Vector2.Zero;
  124. private Vector2 m_AABBmin = Vector2.Zero;
  125. private Vector2 m_AABBmax = Vector2.Zero;
  126. public Vector2 StartPoint
  127. {
  128. get
  129. {
  130. return m_startPoint;
  131. }
  132. }
  133. public Vector2 EndPoint
  134. {
  135. get
  136. {
  137. return m_endPoint;
  138. }
  139. }
  140. //estimate a center point of a parcel
  141. public Vector2 CenterPoint
  142. {
  143. get
  144. {
  145. return m_centerPoint;
  146. }
  147. }
  148. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  149. public ISceneObject[] GetSceneObjectGroups()
  150. {
  151. return primsOverMe.ToArray();
  152. }
  153. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  154. public Vector2? GetNearestPoint(Vector3 pos)
  155. {
  156. return GetNearestPointAlongDirection(pos, new Vector2(m_centerPoint.X - pos.X, m_centerPoint.Y - pos.Y));
  157. }
  158. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  159. public Vector2? GetNearestPointAlongDirection(Vector3 pos, Vector3 pdirection)
  160. {
  161. return GetNearestPointAlongDirection(pos, new Vector2(pdirection.X, pdirection.Y));
  162. }
  163. public Vector2? GetNearestPointAlongDirection(Vector3 pos, Vector2 direction)
  164. {
  165. Vector2 testpos;
  166. testpos.X = pos.X / Constants.LandUnit;
  167. testpos.Y = pos.Y / Constants.LandUnit;
  168. if(LandBitmap[(int)testpos.X, (int)testpos.Y])
  169. return new Vector2(pos.X, pos.Y); // we are already here
  170. if(direction.X == 0f && direction.Y == 0f)
  171. return null; // we can't look anywhere
  172. direction.Normalize();
  173. int minx = (int)(m_AABBmin.X / Constants.LandUnit);
  174. int maxx = (int)(m_AABBmax.X / Constants.LandUnit);
  175. // check against AABB
  176. if(direction.X > 0f)
  177. {
  178. if(testpos.X >= maxx)
  179. return null; // will never get there
  180. if(testpos.X < minx)
  181. testpos.X = minx;
  182. }
  183. else if(direction.X < 0f)
  184. {
  185. if(testpos.X < minx)
  186. return null; // will never get there
  187. if(testpos.X >= maxx)
  188. testpos.X = maxx - 1;
  189. }
  190. else
  191. {
  192. if(testpos.X < minx)
  193. return null; // will never get there
  194. else if(testpos.X >= maxx)
  195. return null; // will never get there
  196. }
  197. int miny = (int)(m_AABBmin.Y / Constants.LandUnit);
  198. int maxy = (int)(m_AABBmax.Y / Constants.LandUnit);
  199. if(direction.Y > 0f)
  200. {
  201. if(testpos.Y >= maxy)
  202. return null; // will never get there
  203. if(testpos.Y < miny)
  204. testpos.Y = miny;
  205. }
  206. else if(direction.Y < 0f)
  207. {
  208. if(testpos.Y < miny)
  209. return null; // will never get there
  210. if(testpos.Y >= maxy)
  211. testpos.Y = maxy - 1;
  212. }
  213. else
  214. {
  215. if(testpos.Y < miny)
  216. return null; // will never get there
  217. else if(testpos.Y >= maxy)
  218. return null; // will never get there
  219. }
  220. while(!LandBitmap[(int)testpos.X, (int)testpos.Y])
  221. {
  222. testpos += direction;
  223. if(testpos.X < minx)
  224. return null;
  225. if (testpos.X >= maxx)
  226. return null;
  227. if(testpos.Y < miny)
  228. return null;
  229. if (testpos.Y >= maxy)
  230. return null;
  231. }
  232. testpos *= Constants.LandUnit;
  233. float ftmp;
  234. if(Math.Abs(direction.X) > Math.Abs(direction.Y))
  235. {
  236. if(direction.X < 0)
  237. testpos.X += Constants.LandUnit - 0.5f;
  238. else
  239. testpos.X += 0.5f;
  240. ftmp = testpos.X - pos.X;
  241. ftmp /= direction.X;
  242. ftmp = Math.Abs(ftmp);
  243. ftmp *= direction.Y;
  244. ftmp += pos.Y;
  245. if(ftmp < testpos.Y + .5f)
  246. ftmp = testpos.Y + .5f;
  247. else
  248. {
  249. testpos.Y += Constants.LandUnit - 0.5f;
  250. if(ftmp > testpos.Y)
  251. ftmp = testpos.Y;
  252. }
  253. testpos.Y = ftmp;
  254. }
  255. else
  256. {
  257. if(direction.Y < 0)
  258. testpos.Y += Constants.LandUnit - 0.5f;
  259. else
  260. testpos.Y += 0.5f;
  261. ftmp = testpos.Y - pos.Y;
  262. ftmp /= direction.Y;
  263. ftmp = Math.Abs(ftmp);
  264. ftmp *= direction.X;
  265. ftmp += pos.X;
  266. if(ftmp < testpos.X + .5f)
  267. ftmp = testpos.X + .5f;
  268. else
  269. {
  270. testpos.X += Constants.LandUnit - 0.5f;
  271. if(ftmp > testpos.X)
  272. ftmp = testpos.X;
  273. }
  274. testpos.X = ftmp;
  275. }
  276. return testpos;
  277. }
  278. #region Constructors
  279. public LandObject(LandData landData, Scene scene)
  280. {
  281. LandData = landData.Copy();
  282. m_scene = scene;
  283. m_scenePermissions = scene.Permissions;
  284. m_regionInfo = scene.RegionInfo;
  285. m_regionSettings = scene.RegionInfo.RegionSettings;
  286. m_estateSettings = m_regionInfo.EstateSettings;
  287. m_regionSizeX = (int)m_regionInfo.RegionSizeX;
  288. m_regionSizeY = (int)m_regionInfo.RegionSizeY;
  289. m_scene.EventManager.OnFrame += OnFrame;
  290. m_dwellModule = m_scene.RequestModuleInterface<IDwellModule>();
  291. }
  292. public LandObject(UUID owner_id, bool is_group_owned, Scene scene, LandData data = null)
  293. {
  294. m_scene = scene;
  295. if (m_scene == null)
  296. {
  297. m_regionSizeX = (int)Constants.RegionSize;
  298. m_regionSizeY = (int)Constants.RegionSize;
  299. LandBitmap = new bool[Constants.RegionSize / Constants.LandUnit, Constants.RegionSize / Constants.LandUnit];
  300. }
  301. else
  302. {
  303. m_scenePermissions = scene.Permissions;
  304. m_regionInfo = scene.RegionInfo;
  305. m_regionSettings = scene.RegionInfo.RegionSettings;
  306. m_estateSettings = m_regionInfo.EstateSettings;
  307. m_regionSizeX = (int)m_regionInfo.RegionSizeX;
  308. m_regionSizeY = (int)m_regionInfo.RegionSizeY;
  309. LandBitmap = new bool[m_regionSizeX / Constants.LandUnit, m_regionSizeY / Constants.LandUnit];
  310. m_dwellModule = m_scene.RequestModuleInterface<IDwellModule>();
  311. }
  312. if(data == null)
  313. LandData = new LandData();
  314. else
  315. LandData = data;
  316. LandData.OwnerID = owner_id;
  317. if (is_group_owned)
  318. LandData.GroupID = owner_id;
  319. LandData.IsGroupOwned = is_group_owned;
  320. if(m_dwellModule == null)
  321. LandData.Dwell = 0;
  322. m_scene.EventManager.OnFrame += OnFrame;
  323. }
  324. public void Clear()
  325. {
  326. if(m_scene != null)
  327. m_scene.EventManager.OnFrame -= OnFrame;
  328. LandData = null;
  329. }
  330. #endregion
  331. #region Member Functions
  332. #region General Functions
  333. /// <summary>
  334. /// Checks to see if this land object contains a point
  335. /// </summary>
  336. /// <param name="x"></param>
  337. /// <param name="y"></param>
  338. /// <returns>Returns true if the piece of land contains the specified point</returns>
  339. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  340. public bool ContainsPoint(int x, int y)
  341. {
  342. if (x >= 0 && y >= 0 && x < m_regionSizeX && y < m_regionSizeY)
  343. {
  344. return LandBitmap[x / Constants.LandUnit, y / Constants.LandUnit];
  345. }
  346. else
  347. {
  348. return false;
  349. }
  350. }
  351. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  352. public ILandObject Copy()
  353. {
  354. ILandObject newLand = new LandObject(LandData, m_scene)
  355. {
  356. LandBitmap = (bool[,])(LandBitmap.Clone())
  357. };
  358. return newLand;
  359. }
  360. static overrideParcelMaxPrimCountDelegate overrideParcelMaxPrimCount;
  361. static overrideSimulatorMaxPrimCountDelegate overrideSimulatorMaxPrimCount;
  362. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  363. public void SetParcelObjectMaxOverride(overrideParcelMaxPrimCountDelegate overrideDel)
  364. {
  365. overrideParcelMaxPrimCount = overrideDel;
  366. }
  367. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  368. public void SetSimulatorObjectMaxOverride(overrideSimulatorMaxPrimCountDelegate overrideDel)
  369. {
  370. overrideSimulatorMaxPrimCount = overrideDel;
  371. }
  372. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  373. public int GetParcelMaxPrimCount()
  374. {
  375. if (overrideParcelMaxPrimCount != null)
  376. {
  377. return overrideParcelMaxPrimCount(this);
  378. }
  379. else
  380. {
  381. // Normal Calculations
  382. int parcelMax = (int)(
  383. (double)LandData.Area
  384. * (double)m_regionInfo.ObjectCapacity
  385. * (double)m_regionSettings.ObjectBonus
  386. / (double)(m_regionSizeX * m_regionSizeY)
  387. + 0.5 );
  388. if(parcelMax > m_regionInfo.ObjectCapacity)
  389. parcelMax = m_regionInfo.ObjectCapacity;
  390. //m_log.DebugFormat("Area: {0}, Capacity {1}, Bonus {2}, Parcel {3}", LandData.Area, m_regionInfo.ObjectCapacity, m_regionInfo.RegionSettings.ObjectBonus, parcelMax);
  391. return parcelMax;
  392. }
  393. }
  394. // the total prims a parcel owner can have on a region
  395. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  396. public int GetSimulatorMaxPrimCount()
  397. {
  398. if (overrideSimulatorMaxPrimCount is not null)
  399. {
  400. return overrideSimulatorMaxPrimCount(this);
  401. }
  402. else
  403. {
  404. //Normal Calculations
  405. int simMax = (int)( (double)LandData.SimwideArea
  406. * (double)m_regionInfo.ObjectCapacity
  407. * (double)m_regionSettings.ObjectBonus
  408. / (long)(m_regionSizeX * m_regionSizeY)
  409. +0.5 );
  410. // sanity check
  411. if(simMax > m_regionInfo.ObjectCapacity)
  412. simMax = m_regionInfo.ObjectCapacity;
  413. //m_log.DebugFormat("Simwide Area: {0}, Capacity {1}, SimMax {2}, SimWidePrims {3}",
  414. // LandData.SimwideArea, m_regionInfo.ObjectCapacity, simMax, LandData.SimwidePrims);
  415. return simMax;
  416. }
  417. }
  418. #endregion
  419. #region Packet Request Handling
  420. public void SendLandProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client)
  421. {
  422. if(m_regionSettings.AllowDamage)
  423. remote_client.SceneAgent.Invulnerable = false;
  424. else
  425. remote_client.SceneAgent.Invulnerable = (m_landData.Flags & (uint)ParcelFlags.AllowDamage) == 0;
  426. if (remote_client.SceneAgent.PresenceType == PresenceType.Npc)
  427. return;
  428. IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>();
  429. // uint regionFlags = 336723974 & ~((uint)(RegionFlags.AllowLandmark | RegionFlags.AllowSetHome));
  430. uint regionFlags = (uint)(RegionFlags.PublicAllowed
  431. | RegionFlags.AllowDirectTeleport
  432. | RegionFlags.AllowParcelChanges
  433. | RegionFlags.AllowVoice );
  434. if (estateModule != null)
  435. regionFlags = estateModule.GetRegionFlags();
  436. int seq_id;
  437. if (snap_selection && (sequence_id == 0))
  438. {
  439. seq_id = m_lastSeqId;
  440. }
  441. else
  442. {
  443. seq_id = sequence_id;
  444. m_lastSeqId = seq_id;
  445. }
  446. remote_client.SendLandProperties(seq_id,
  447. snap_selection, request_result, this,
  448. (float)m_regionSettings.ObjectBonus,
  449. GetParcelMaxPrimCount(),
  450. GetSimulatorMaxPrimCount(), regionFlags);
  451. }
  452. public bool UpdateLandProperties(LandUpdateArgs args, IClientAPI remote_client, out bool snap_selection, out bool needOverlay)
  453. {
  454. //Needs later group support
  455. snap_selection = false;
  456. needOverlay = false;
  457. LandData newData = LandData.Copy();
  458. uint allowedDelta = 0;
  459. // These two are always blocked as no client can set them anyway
  460. // ParcelFlags.ForSaleObjects
  461. // ParcelFlags.LindenHome
  462. if (m_scenePermissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions, false))
  463. {
  464. allowedDelta |= (uint)(ParcelFlags.AllowLandmark |
  465. ParcelFlags.AllowTerraform |
  466. ParcelFlags.AllowDamage |
  467. ParcelFlags.CreateObjects |
  468. ParcelFlags.RestrictPushObject |
  469. ParcelFlags.AllowOtherScripts |
  470. ParcelFlags.AllowGroupScripts |
  471. ParcelFlags.CreateGroupObjects |
  472. ParcelFlags.AllowAPrimitiveEntry |
  473. ParcelFlags.AllowGroupObjectEntry |
  474. ParcelFlags.AllowFly);
  475. newData.SeeAVs = args.SeeAVs;
  476. newData.AnyAVSounds = args.AnyAVSounds;
  477. newData.GroupAVSounds = args.GroupAVSounds;
  478. }
  479. if (m_scenePermissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandSetSale, true))
  480. {
  481. if (args.AuthBuyerID != newData.AuthBuyerID ||
  482. args.SalePrice != newData.SalePrice)
  483. {
  484. snap_selection = true;
  485. }
  486. newData.AuthBuyerID = args.AuthBuyerID;
  487. newData.SalePrice = args.SalePrice;
  488. if (!LandData.IsGroupOwned)
  489. {
  490. newData.GroupID = args.GroupID;
  491. if(newData.GroupID != LandData.GroupID)
  492. m_groupMemberCache.Clear();
  493. allowedDelta |= (uint)(ParcelFlags.AllowDeedToGroup |
  494. ParcelFlags.ContributeWithDeed |
  495. ParcelFlags.SellParcelObjects);
  496. }
  497. allowedDelta |= (uint)ParcelFlags.ForSale;
  498. }
  499. if (m_scenePermissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.FindPlaces, false))
  500. {
  501. newData.Category = args.Category;
  502. allowedDelta |= (uint)(ParcelFlags.ShowDirectory |
  503. ParcelFlags.AllowPublish |
  504. ParcelFlags.MaturePublish) | (uint)(1 << 23);
  505. }
  506. if (m_scenePermissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.LandChangeIdentity, false))
  507. {
  508. newData.Description = args.Desc;
  509. newData.Name = args.Name;
  510. newData.SnapshotID = args.SnapshotID;
  511. }
  512. if (m_scenePermissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.SetLandingPoint, false))
  513. {
  514. newData.LandingType = args.LandingType;
  515. newData.UserLocation = args.UserLocation;
  516. newData.UserLookAt = args.UserLookAt;
  517. }
  518. if (m_scenePermissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.ChangeMedia, false))
  519. {
  520. newData.MediaAutoScale = args.MediaAutoScale;
  521. newData.MediaID = args.MediaID;
  522. newData.MediaURL = args.MediaURL;
  523. newData.MusicURL = args.MusicURL;
  524. newData.MediaType = args.MediaType;
  525. newData.MediaDescription = args.MediaDescription;
  526. newData.MediaWidth = args.MediaWidth;
  527. newData.MediaHeight = args.MediaHeight;
  528. newData.MediaLoop = args.MediaLoop;
  529. //newData.ObscureMusic = args.ObscureMusic;
  530. newData.ObscureMusic = false; // obsolete
  531. //newData.ObscureMedia = args.ObscureMedia;
  532. newData.ObscureMedia = args.ObscureMOAP; // obsolete, reuse for moap
  533. allowedDelta |= (uint)(ParcelFlags.SoundLocal |
  534. ParcelFlags.UrlWebPage |
  535. ParcelFlags.UrlRawHtml |
  536. ParcelFlags.AllowVoiceChat |
  537. ParcelFlags.UseEstateVoiceChan);
  538. }
  539. if(!m_estateSettings.TaxFree)
  540. {
  541. // don't allow passes on group owned until we can give money to groups
  542. if (!newData.IsGroupOwned && m_scenePermissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.LandManagePasses, false))
  543. {
  544. newData.PassHours = args.PassHours;
  545. newData.PassPrice = args.PassPrice;
  546. allowedDelta |= (uint)ParcelFlags.UsePassList;
  547. }
  548. if (m_scenePermissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandManageAllowed, false))
  549. {
  550. allowedDelta |= (uint)(ParcelFlags.UseAccessGroup |
  551. ParcelFlags.UseAccessList);
  552. }
  553. if (m_scenePermissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandManageBanned, false))
  554. {
  555. allowedDelta |= (uint)(ParcelFlags.UseBanList |
  556. ParcelFlags.DenyAnonymous |
  557. ParcelFlags.DenyAgeUnverified);
  558. }
  559. }
  560. // enforce estate age and payinfo limitations
  561. if (m_estateSettings.DenyMinors)
  562. {
  563. args.ParcelFlags |= (uint)ParcelFlags.DenyAgeUnverified;
  564. allowedDelta |= (uint)ParcelFlags.DenyAgeUnverified;
  565. }
  566. if (m_estateSettings.DenyAnonymous)
  567. {
  568. args.ParcelFlags |= (uint)ParcelFlags.DenyAnonymous;
  569. allowedDelta |= (uint)ParcelFlags.DenyAnonymous;
  570. }
  571. if (allowedDelta != (uint)ParcelFlags.None)
  572. {
  573. uint preserve = LandData.Flags & ~allowedDelta;
  574. newData.Flags = preserve | (args.ParcelFlags & allowedDelta);
  575. uint curdelta = LandData.Flags ^ newData.Flags;
  576. curdelta &= (uint)(ParcelFlags.SoundLocal);
  577. if(curdelta != 0 || newData.SeeAVs != LandData.SeeAVs)
  578. needOverlay = true;
  579. m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData);
  580. return true;
  581. }
  582. return false;
  583. }
  584. public void UpdateLandSold(UUID avatarID, UUID groupID, bool groupOwned, uint AuctionID, int claimprice, int area)
  585. {
  586. LandData newData = LandData.Copy();
  587. newData.OwnerID = avatarID;
  588. newData.GroupID = groupID;
  589. newData.IsGroupOwned = groupOwned;
  590. //newData.auctionID = AuctionID;
  591. newData.ClaimDate = Util.UnixTimeSinceEpoch();
  592. newData.ClaimPrice = claimprice;
  593. newData.SalePrice = 0;
  594. newData.AuthBuyerID = UUID.Zero;
  595. newData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory);
  596. bool sellObjects = (LandData.Flags & (uint)(ParcelFlags.SellParcelObjects)) != 0
  597. && !LandData.IsGroupOwned && !groupOwned;
  598. UUID previousOwner = LandData.OwnerID;
  599. m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData);
  600. if (sellObjects)
  601. SellLandObjects(previousOwner);
  602. m_scene.EventManager.TriggerParcelPrimCountUpdate();
  603. }
  604. public void DeedToGroup(UUID groupID)
  605. {
  606. LandData newData = LandData.Copy();
  607. newData.OwnerID = groupID;
  608. newData.GroupID = groupID;
  609. newData.IsGroupOwned = true;
  610. // Reset show in directory flag on deed
  611. newData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory);
  612. m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData);
  613. m_scene.EventManager.TriggerParcelPrimCountUpdate();
  614. }
  615. public bool IsEitherBannedOrRestricted(UUID avatar)
  616. {
  617. if (m_estateSettings.TaxFree) // region access control only
  618. return false;
  619. if (m_scenePermissions.IsAdministrator(avatar))
  620. return false;
  621. if (m_estateSettings.IsEstateManagerOrOwner(avatar))
  622. return false;
  623. if (avatar.Equals(LandData.OwnerID))
  624. return false;
  625. if (IsBannedFromLand_inner(avatar))
  626. return true;
  627. if (IsRestrictedFromLand_inner(avatar))
  628. return true;
  629. return false;
  630. }
  631. public bool CanBeOnThisLand(UUID avatar, float posHeight)
  632. {
  633. if (m_estateSettings.TaxFree) // estate access only
  634. return true;
  635. if (m_scenePermissions.IsAdministrator(avatar))
  636. return true;
  637. if (m_estateSettings.IsEstateManagerOrOwner(avatar))
  638. return true;
  639. if (avatar.Equals(LandData.OwnerID))
  640. return true;
  641. if (posHeight < m_scene.LandChannel.BanLineSafeHeight && IsBannedFromLand_inner(avatar))
  642. return false;
  643. else if (IsRestrictedFromLand_inner(avatar))
  644. return false;
  645. return true;
  646. }
  647. public bool HasGroupAccess(UUID avatar)
  648. {
  649. if (LandData.GroupID.IsNotZero() && (LandData.Flags & (uint)ParcelFlags.UseAccessGroup) != 0)
  650. {
  651. if (m_groupMemberCache.TryGetValue(avatar, GROUPMEMBERCACHETIMEOUT, out bool isMember))
  652. return isMember;
  653. if (m_scene.TryGetScenePresence(avatar, out ScenePresence sp))
  654. {
  655. isMember = sp.ControllingClient.IsGroupMember(LandData.GroupID);
  656. m_groupMemberCache.Add(avatar, isMember, GROUPMEMBERCACHETIMEOUT);
  657. return isMember;
  658. }
  659. else
  660. {
  661. IGroupsModule groupsModule = m_scene.RequestModuleInterface<IGroupsModule>();
  662. if (groupsModule == null)
  663. return false;
  664. GroupMembershipData[] membership = groupsModule.GetMembershipData(avatar);
  665. if (membership == null || membership.Length == 0)
  666. {
  667. m_groupMemberCache.Add(avatar, false, GROUPMEMBERCACHETIMEOUT);
  668. return false;
  669. }
  670. foreach (GroupMembershipData d in membership)
  671. {
  672. if (d.GroupID.Equals(LandData.GroupID))
  673. {
  674. m_groupMemberCache.Add(avatar, true, GROUPMEMBERCACHETIMEOUT);
  675. return true;
  676. }
  677. }
  678. m_groupMemberCache.Add(avatar, false, GROUPMEMBERCACHETIMEOUT);
  679. return false;
  680. }
  681. }
  682. return false;
  683. }
  684. public bool IsBannedFromLand(UUID avatar)
  685. {
  686. if (m_estateSettings.TaxFree) // region access control only
  687. return false;
  688. if (m_scenePermissions.IsAdministrator(avatar))
  689. return false;
  690. if (m_estateSettings.IsEstateManagerOrOwner(avatar))
  691. return false;
  692. if (avatar.Equals(LandData.OwnerID))
  693. return false;
  694. return IsBannedFromLand_inner(avatar);
  695. }
  696. private bool IsBannedFromLand_inner(UUID avatar)
  697. {
  698. if ((LandData.Flags & (uint) ParcelFlags.UseBanList) > 0)
  699. {
  700. int now = Util.UnixTimeSinceEpoch();
  701. foreach (LandAccessEntry e in LandData.ParcelAccessList)
  702. {
  703. if (e.Flags == AccessList.Ban && e.AgentID.Equals(avatar))
  704. return e.Expires == 0 || e.Expires > now;
  705. }
  706. }
  707. return false;
  708. }
  709. public bool IsRestrictedFromLand(UUID avatar)
  710. {
  711. if (m_estateSettings.TaxFree) // estate access only
  712. return false;
  713. if (m_scenePermissions.IsAdministrator(avatar))
  714. return false;
  715. if (m_estateSettings.IsEstateManagerOrOwner(avatar))
  716. return false;
  717. if (avatar.Equals(LandData.OwnerID))
  718. return false;
  719. return IsRestrictedFromLand_inner(avatar);
  720. }
  721. private bool IsRestrictedFromLand_inner(UUID avatar)
  722. {
  723. if ((LandData.Flags & (uint) ParcelFlags.UseAccessList) == 0)
  724. {
  725. bool adults = m_estateSettings.DoDenyMinors &&
  726. (m_estateSettings.DenyMinors || ((LandData.Flags & (uint)ParcelFlags.DenyAgeUnverified) != 0));
  727. bool anonymous = m_estateSettings.DoDenyAnonymous &&
  728. (m_estateSettings.DenyAnonymous || ((LandData.Flags & (uint)ParcelFlags.DenyAnonymous) != 0));
  729. if(adults || anonymous)
  730. {
  731. int userflags;
  732. if(m_scene.TryGetScenePresence(avatar, out ScenePresence snp))
  733. {
  734. if(snp.IsNPC)
  735. return false;
  736. userflags = snp.UserFlags;
  737. }
  738. else
  739. userflags = m_scene.GetUserFlags(avatar);
  740. if(adults && ((userflags & (int)ProfileFlags.AgeVerified) == 0))
  741. return true;
  742. if(anonymous && ((userflags & (int)ProfileFlags.Identified) == 0))
  743. return true;
  744. }
  745. return false;
  746. }
  747. if (HasGroupAccess(avatar))
  748. return false;
  749. if(IsInLandAccessList(avatar))
  750. return false;
  751. // check for a NPC
  752. if (!m_scene.TryGetScenePresence(avatar, out ScenePresence sp))
  753. return true;
  754. if(sp is null || !sp.IsNPC)
  755. return true;
  756. INPC npccli = (INPC)sp.ControllingClient;
  757. if(npccli is null)
  758. return true;
  759. UUID owner = npccli.Owner;
  760. if(owner.IsZero())
  761. return true;
  762. if (owner.Equals(LandData.OwnerID))
  763. return false;
  764. return !IsInLandAccessList(owner);
  765. }
  766. public bool IsInLandAccessList(UUID avatar)
  767. {
  768. foreach(LandAccessEntry e in LandData.ParcelAccessList)
  769. {
  770. int now = Util.UnixTimeSinceEpoch();
  771. if (e.Flags == AccessList.Access && e.AgentID.Equals(avatar))
  772. return e.Expires == 0 || e.Expires > now;
  773. }
  774. return false;
  775. }
  776. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  777. public void SendLandUpdateToClient(IClientAPI remote_client)
  778. {
  779. SendLandProperties(0, false, 0, remote_client);
  780. }
  781. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  782. public void SendLandUpdateToClient(bool snap_selection, IClientAPI remote_client)
  783. {
  784. m_scene.EventManager.TriggerParcelPrimCountUpdate();
  785. SendLandProperties(0, snap_selection, 0, remote_client);
  786. }
  787. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  788. public void SendLandUpdateToAvatarsOverMe()
  789. {
  790. SendLandUpdateToAvatarsOverMe(false);
  791. }
  792. public void SendLandUpdateToAvatarsOverMe(bool snap_selection)
  793. {
  794. m_scene.EventManager.TriggerParcelPrimCountUpdate();
  795. m_scene.ForEachRootScenePresence(delegate(ScenePresence avatar)
  796. {
  797. if (avatar.IsNPC)
  798. return;
  799. if(ContainsPoint((int)avatar.AbsolutePosition.X, (int)avatar.AbsolutePosition.Y))
  800. {
  801. if(m_regionSettings.AllowDamage)
  802. avatar.Invulnerable = false;
  803. else
  804. avatar.Invulnerable = (LandData.Flags & (uint)ParcelFlags.AllowDamage) == 0;
  805. SendLandUpdateToClient(snap_selection, avatar.ControllingClient);
  806. avatar.currentParcelUUID = LandData.GlobalID;
  807. }
  808. });
  809. }
  810. public void SendLandUpdateToAvatars()
  811. {
  812. m_scene.ForEachScenePresence(delegate (ScenePresence avatar)
  813. {
  814. if (avatar.IsNPC)
  815. return;
  816. if(avatar.IsChildAgent)
  817. {
  818. SendLandProperties(-10000, false, LandChannel.LAND_RESULT_SINGLE, avatar.ControllingClient);
  819. return;
  820. }
  821. if (ContainsPoint((int)avatar.AbsolutePosition.X, (int)avatar.AbsolutePosition.Y))
  822. {
  823. if (m_regionSettings.AllowDamage)
  824. avatar.Invulnerable = false;
  825. else
  826. avatar.Invulnerable = (LandData.Flags & (uint)ParcelFlags.AllowDamage) == 0;
  827. avatar.currentParcelUUID = LandData.GlobalID;
  828. SendLandProperties(0, true, LandChannel.LAND_RESULT_SINGLE, avatar.ControllingClient);
  829. return;
  830. }
  831. SendLandProperties(-10000, false, LandChannel.LAND_RESULT_SINGLE, avatar.ControllingClient);
  832. });
  833. }
  834. #endregion
  835. #region AccessList Functions
  836. //legacy
  837. public List<LandAccessEntry> CreateAccessListArrayByFlag(AccessList flag)
  838. {
  839. int now = Util.UnixTimeSinceEpoch();
  840. List<LandAccessEntry> list = new();
  841. foreach (LandAccessEntry entry in LandData.ParcelAccessList)
  842. {
  843. if (entry.Flags == flag && (entry.Expires > now || entry.Expires == 0))
  844. list.Add(entry);
  845. }
  846. if (list.Count == 0)
  847. list.Add(new LandAccessEntry());
  848. return list;
  849. }
  850. public void SendAccessList(UUID agentID, UUID sessionID, uint flags, int sequenceID,
  851. IClientAPI remote_client)
  852. {
  853. int now = Util.UnixTimeSinceEpoch();
  854. List<LandAccessEntry> accesslist = new();
  855. List<LandAccessEntry> banlist = new();
  856. foreach (LandAccessEntry entry in LandData.ParcelAccessList)
  857. {
  858. if(entry.Expires > now || entry.Expires == 0)
  859. {
  860. if (entry.Flags == AccessList.Access)
  861. accesslist.Add(entry);
  862. else if (entry.Flags == AccessList.Ban)
  863. banlist.Add(entry);
  864. }
  865. }
  866. if (accesslist.Count == 0)
  867. {
  868. remote_client.SendLandAccessListData(new List<LandAccessEntry>() { new LandAccessEntry() },
  869. (uint)AccessList.Access, LandData.LocalID);
  870. }
  871. else
  872. remote_client.SendLandAccessListData(accesslist, (uint)AccessList.Access, LandData.LocalID);
  873. if (banlist.Count == 0)
  874. {
  875. remote_client.SendLandAccessListData(new List<LandAccessEntry>() { new LandAccessEntry() },
  876. (uint)AccessList.Ban, LandData.LocalID);
  877. }
  878. else
  879. remote_client.SendLandAccessListData(banlist, (uint)AccessList.Ban, LandData.LocalID);
  880. }
  881. public void UpdateAccessList(uint flags, UUID transactionID, List<LandAccessEntry> entries)
  882. {
  883. flags &= 0x03;
  884. if (flags == 0)
  885. return; // we only have access and ban
  886. // get a work copy of lists
  887. List<LandAccessEntry> parcelAccessList = new(LandData.ParcelAccessList);
  888. // first packet on a transaction clears before adding
  889. // we need to this way because viewer protocol does not seem reliable
  890. lock (m_listTransactionsLock)
  891. {
  892. if ((!m_listTransactions.TryGetValue(flags, out UUID flagsID)) || flagsID.NotEqual(transactionID))
  893. {
  894. m_listTransactions.Add(flags, transactionID);
  895. List<LandAccessEntry> toRemove = new();
  896. foreach (LandAccessEntry entry in parcelAccessList)
  897. {
  898. if (((uint)entry.Flags & flags) != 0)
  899. toRemove.Add(entry);
  900. }
  901. foreach (LandAccessEntry entry in toRemove)
  902. parcelAccessList.Remove(entry);
  903. // a delete all command ?
  904. if (entries.Count == 1 && entries[0].AgentID.IsZero())
  905. {
  906. LandData.ParcelAccessList = parcelAccessList;
  907. if ((flags & (uint)AccessList.Access) != 0)
  908. LandData.Flags &= ~(uint)ParcelFlags.UseAccessList;
  909. if ((flags & (uint)AccessList.Ban) != 0)
  910. LandData.Flags &= ~(uint)ParcelFlags.UseBanList;
  911. m_listTransactions.Remove(flags);
  912. return;
  913. }
  914. }
  915. }
  916. foreach (LandAccessEntry entry in entries)
  917. {
  918. LandAccessEntry temp = new()
  919. {
  920. AgentID = entry.AgentID,
  921. Expires = entry.Expires,
  922. Flags = (AccessList)flags
  923. };
  924. parcelAccessList.Add(temp);
  925. }
  926. LandData.ParcelAccessList = parcelAccessList;
  927. if ((flags & (uint)AccessList.Access) != 0)
  928. LandData.Flags |= (uint)ParcelFlags.UseAccessList;
  929. if ((flags & (uint)AccessList.Ban) != 0)
  930. LandData.Flags |= (uint)ParcelFlags.UseBanList;
  931. }
  932. #endregion
  933. #region Update Functions
  934. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  935. public void UpdateLandBitmapByteArray()
  936. {
  937. LandData.Bitmap = ConvertLandBitmapToBytes();
  938. }
  939. /// <summary>
  940. /// Update all settings in land such as area, bitmap byte array, etc
  941. /// </summary>
  942. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  943. public void ForceUpdateLandInfo()
  944. {
  945. UpdateGeometryValues();
  946. UpdateLandBitmapByteArray();
  947. }
  948. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  949. public void SetLandBitmapFromByteArray()
  950. {
  951. LandBitmap = ConvertBytesToLandBitmap();
  952. }
  953. /// <summary>
  954. /// Updates geomtric values after area/shape modification of the land object
  955. /// </summary>
  956. private void UpdateGeometryValues()
  957. {
  958. int min_x = Int32.MaxValue;
  959. int min_y = Int32.MaxValue;
  960. int max_x = Int32.MinValue;
  961. int max_y = Int32.MinValue;
  962. int tempArea = 0;
  963. int x, y;
  964. int lastX = 0;
  965. int lastY = 0;
  966. float avgx = 0f;
  967. float avgy = 0f;
  968. bool needFirst = true;
  969. for (x = 0; x < LandBitmap.GetLength(0); x++)
  970. {
  971. for (y = 0; y < LandBitmap.GetLength(1); y++)
  972. {
  973. if (LandBitmap[x, y])
  974. {
  975. if (min_x > x)
  976. min_x = x;
  977. if (min_y > y)
  978. min_y = y;
  979. if (max_x < x)
  980. max_x = x;
  981. if (max_y < y)
  982. max_y = y;
  983. if(needFirst)
  984. {
  985. avgx = x;
  986. avgy = y;
  987. m_startPoint.X = x * Constants.LandUnit;
  988. m_startPoint.Y = y * Constants.LandUnit;
  989. needFirst = false;
  990. }
  991. else
  992. {
  993. // keeping previous odd average
  994. avgx = (avgx * tempArea + x) / (tempArea + 1);
  995. avgy = (avgy * tempArea + y) / (tempArea + 1);
  996. }
  997. tempArea++;
  998. lastX = x;
  999. lastY = y;
  1000. }
  1001. }
  1002. }
  1003. if(tempArea == 0)
  1004. {
  1005. m_centerPoint = Vector2.Zero;
  1006. m_endPoint = Vector2.Zero;
  1007. m_AABBmin = Vector2.Zero;
  1008. m_AABBmax = Vector2.Zero;
  1009. LandData.AABBMin = Vector3.Zero;
  1010. LandData.AABBMax = Vector3.Zero;
  1011. LandData.Area = 0;
  1012. if (m_scene != null)
  1013. {
  1014. //create a fake ID
  1015. LandData.FakeID = Util.BuildFakeParcelID(m_regionInfo.RegionHandle, 0, 0);
  1016. }
  1017. return;
  1018. }
  1019. const int halfunit = Constants.LandUnit / 2;
  1020. m_centerPoint.X = avgx * Constants.LandUnit + halfunit;
  1021. m_centerPoint.Y = avgy * Constants.LandUnit + halfunit;
  1022. m_endPoint.X = lastX * Constants.LandUnit + Constants.LandUnit;
  1023. m_endPoint.Y = lastY * Constants.LandUnit + Constants.LandUnit;
  1024. // next tests should not be needed
  1025. // if they fail, something is wrong
  1026. ulong regionHandle;
  1027. if(m_scene != null)
  1028. {
  1029. regionHandle = m_regionInfo.RegionHandle;
  1030. //create a fake ID
  1031. LandData.FakeID = Util.BuildFakeParcelID(regionHandle, (uint)(lastX * Constants.LandUnit), (uint)(lastY * Constants.LandUnit));
  1032. }
  1033. int tx = min_x * Constants.LandUnit;
  1034. if (tx >= m_regionSizeX)
  1035. tx = m_regionSizeX - 1;
  1036. int ty = min_y * Constants.LandUnit;
  1037. if (ty >= m_regionSizeY)
  1038. ty = m_regionSizeY - 1;
  1039. m_AABBmin.X = tx;
  1040. m_AABBmin.Y = ty;
  1041. if(m_scene == null || m_scene.Heightmap == null)
  1042. LandData.AABBMin = new Vector3(tx, ty, 0f);
  1043. else
  1044. LandData.AABBMin = new Vector3(tx, ty, (float)m_scene.Heightmap[tx, ty]);
  1045. max_x++;
  1046. tx = max_x * Constants.LandUnit;
  1047. if (tx > m_regionSizeX)
  1048. tx = m_regionSizeX;
  1049. max_y++;
  1050. ty = max_y * Constants.LandUnit;
  1051. if (ty > m_regionSizeY)
  1052. ty = m_regionSizeY;
  1053. m_AABBmax.X = tx;
  1054. m_AABBmax.Y = ty;
  1055. if(m_scene == null || m_scene.Heightmap == null)
  1056. LandData.AABBMax = new Vector3(tx, ty, 0f);
  1057. else
  1058. LandData.AABBMax = new Vector3(tx, ty, (float)m_scene.Heightmap[tx - 1, ty - 1]);
  1059. tempArea *= Constants.LandUnit * Constants.LandUnit;
  1060. LandData.Area = tempArea;
  1061. }
  1062. #endregion
  1063. #region Land Bitmap Functions
  1064. /// <summary>
  1065. /// Sets the land's bitmap manually
  1066. /// </summary>
  1067. /// <param name="bitmap">block representing where this land is on a map mapped in a 4x4 meter grid</param>
  1068. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  1069. public void SetLandBitmap(bool[,] bitmap)
  1070. {
  1071. LandBitmap = bitmap;
  1072. ForceUpdateLandInfo();
  1073. }
  1074. /// <summary>
  1075. /// Gets the land's bitmap manually
  1076. /// </summary>
  1077. /// <returns></returns>
  1078. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  1079. public bool[,] GetLandBitmap()
  1080. {
  1081. return LandBitmap;
  1082. }
  1083. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  1084. public bool[,] BasicFullRegionLandBitmap()
  1085. {
  1086. return GetSquareLandBitmap(0, 0, m_regionSizeX, m_regionSizeY, true);
  1087. }
  1088. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  1089. public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y, bool set_value = true)
  1090. {
  1091. bool[,] tempBitmap = ModifyLandBitmapSquare(null, start_x, start_y, end_x, end_y, set_value);
  1092. return tempBitmap;
  1093. }
  1094. /// <summary>
  1095. /// Change a land bitmap at within a square and set those points to a specific value
  1096. /// </summary>
  1097. /// <param name="land_bitmap"></param>
  1098. /// <param name="start_x"></param>
  1099. /// <param name="start_y"></param>
  1100. /// <param name="end_x"></param>
  1101. /// <param name="end_y"></param>
  1102. /// <param name="set_value"></param>
  1103. /// <returns></returns>
  1104. public bool[,] ModifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y,
  1105. bool set_value)
  1106. {
  1107. if(land_bitmap == null)
  1108. {
  1109. land_bitmap = new bool[m_regionSizeX / Constants.LandUnit, m_regionSizeY / Constants.LandUnit];
  1110. if(!set_value)
  1111. return land_bitmap;
  1112. }
  1113. start_x /= Constants.LandUnit;
  1114. end_x /= Constants.LandUnit;
  1115. start_y /= Constants.LandUnit;
  1116. end_y /= Constants.LandUnit;
  1117. for (int x = start_x; x < end_x; ++x)
  1118. {
  1119. for (int y = start_y; y < end_y; ++y)
  1120. {
  1121. land_bitmap[x, y] = set_value;
  1122. }
  1123. }
  1124. // m_log.DebugFormat("{0} ModifyLandBitmapSquare. startXY=<{1},{2}>, endXY=<{3},{4}>, val={5}, landBitmapSize=<{6},{7}>",
  1125. // LogHeader, start_x, start_y, end_x, end_y, set_value, land_bitmap.GetLength(0), land_bitmap.GetLength(1));
  1126. return land_bitmap;
  1127. }
  1128. /// <summary>
  1129. /// Join the true values of 2 bitmaps together
  1130. /// </summary>
  1131. /// <param name="bitmap_base"></param>
  1132. /// <param name="bitmap_add"></param>
  1133. /// <returns></returns>
  1134. public bool[,] MergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add)
  1135. {
  1136. if (bitmap_base.GetLength(0) != bitmap_add.GetLength(0)
  1137. || bitmap_base.GetLength(1) != bitmap_add.GetLength(1))
  1138. {
  1139. throw new Exception(
  1140. String.Format("{0} MergeLandBitmaps. merging maps not same size. baseSizeXY=<{1},{2}>, addSizeXY=<{3},{4}>",
  1141. LogHeader, bitmap_base.GetLength(0), bitmap_base.GetLength(1), bitmap_add.GetLength(0), bitmap_add.GetLength(1))
  1142. );
  1143. }
  1144. for (int x = 0; x < bitmap_add.GetLength(0); x++)
  1145. {
  1146. for (int y = 0; y < bitmap_base.GetLength(1); y++)
  1147. {
  1148. bitmap_base[x, y] |= bitmap_add[x, y];
  1149. }
  1150. }
  1151. return bitmap_base;
  1152. }
  1153. /// <summary>
  1154. /// Remap a land bitmap. Takes the supplied land bitmap and rotates it, crops it and finally offsets it into
  1155. /// a final land bitmap of the target region size.
  1156. /// </summary>
  1157. /// <param name="bitmap_base">The original parcel bitmap</param>
  1158. /// <param name="rotationDegrees"></param>
  1159. /// <param name="displacement">&lt;x,y,?&gt;</param>
  1160. /// <param name="boundingOrigin">&lt;x,y,?&gt;</param>
  1161. /// <param name="boundingSize">&lt;x,y,?&gt;</param>
  1162. /// <param name="newRegionSize">&lt;x,y,?&gt;</param>
  1163. /// <param name="isEmptyNow">out: This is set if the resultant bitmap is now empty</param>
  1164. /// <param name="AABBMin">out: parcel.AABBMin &lt;x,y,0&gt</param>
  1165. /// <param name="AABBMax">out: parcel.AABBMax &lt;x,y,0&gt</param>
  1166. /// <returns>New parcel bitmap</returns>
  1167. public bool[,] RemapLandBitmap(bool[,] bitmap_base, Vector2 displacement, float rotationDegrees, Vector2 boundingOrigin, Vector2 boundingSize, Vector2 newRegionSize, out bool isEmptyNow)
  1168. {
  1169. // get the size of the incoming bitmap
  1170. int baseX = bitmap_base.GetLength(0);
  1171. int baseY = bitmap_base.GetLength(1);
  1172. // create an intermediate bitmap that is 25% bigger on each side that we can work with to handle rotations
  1173. int offsetX = baseX / 4; // the original origin will now be at these coordinates so now we can have imaginary negative coordinates ;)
  1174. int offsetY = baseY / 4;
  1175. int tmpX = baseX + baseX / 2;
  1176. int tmpY = baseY + baseY / 2;
  1177. int centreX = tmpX / 2;
  1178. int centreY = tmpY / 2;
  1179. bool[,] bitmap_tmp = new bool[tmpX, tmpY];
  1180. double radianRotation = Math.PI * rotationDegrees / 180f;
  1181. double cosR = Math.Cos(radianRotation);
  1182. double sinR = Math.Sin(radianRotation);
  1183. if (rotationDegrees < 0f) rotationDegrees += 360f; //-90=270 -180=180 -270=90
  1184. // So first we apply the rotation to the incoming bitmap, storing the result in bitmap_tmp
  1185. // We special case orthogonal rotations for accuracy because even using double precision math, Math.Cos(90 degrees) is never fully 0
  1186. // and we can never rotate around a centre pixel because the bitmap size is always even
  1187. int x, y, sx, sy;
  1188. for (y = 0; y <= tmpY; y++)
  1189. {
  1190. for (x = 0; x <= tmpX; x++)
  1191. {
  1192. if (rotationDegrees == 0f)
  1193. {
  1194. sx = x - offsetX;
  1195. sy = y - offsetY;
  1196. }
  1197. else if (rotationDegrees == 90f)
  1198. {
  1199. sx = y - offsetX;
  1200. sy = tmpY - 1 - x - offsetY;
  1201. }
  1202. else if (rotationDegrees == 180f)
  1203. {
  1204. sx = tmpX - 1 - x - offsetX;
  1205. sy = tmpY - 1 - y - offsetY;
  1206. }
  1207. else if (rotationDegrees == 270f)
  1208. {
  1209. sx = tmpX - 1 - y - offsetX;
  1210. sy = x - offsetY;
  1211. }
  1212. else
  1213. {
  1214. // arbitary rotation: hmmm should I be using (centreX - 0.5) and (centreY - 0.5) and round cosR and sinR to say only 5 decimal places?
  1215. sx = centreX + (int)Math.Round((((double)x - centreX) * cosR) + (((double)y - centreY) * sinR)) - offsetX;
  1216. sy = centreY + (int)Math.Round((((double)y - centreY) * cosR) - (((double)x - centreX) * sinR)) - offsetY;
  1217. }
  1218. if (sx >= 0 && sx < baseX && sy >= 0 && sy < baseY)
  1219. {
  1220. try
  1221. {
  1222. if (bitmap_base[sx, sy]) bitmap_tmp[x, y] = true;
  1223. }
  1224. catch (Exception) //just in case we've still not taken care of every way the arrays might go out of bounds! ;)
  1225. {
  1226. m_log.DebugFormat("{0} RemapLandBitmap Rotate: Out of Bounds sx={1} sy={2} dx={3} dy={4}", LogHeader, sx, sy, x, y);
  1227. }
  1228. }
  1229. }
  1230. }
  1231. // We could also incorporate the next steps, bounding-rectangle and displacement in the loop above, but it's simpler to visualise if done separately
  1232. // and will also make it much easier when later I want the option for maybe a circular or oval bounding shape too ;).
  1233. // So... our output land bitmap must be the size of the current region but rememeber, parcel landbitmaps are landUnit metres (4x4 metres) per point,
  1234. // and region sizes, boundaries and displacements are in metres so we need to scale down
  1235. int newX = (int)(newRegionSize.X / Constants.LandUnit);
  1236. int newY = (int)(newRegionSize.Y / Constants.LandUnit);
  1237. bool[,] bitmap_new = new bool[newX, newY];
  1238. // displacement is relative to <0,0> in the destination region and defines where the origin of the data selected by the bounding-rectangle is placed
  1239. int dispX = (int)Math.Floor(displacement.X / Constants.LandUnit);
  1240. int dispY = (int)Math.Floor(displacement.Y / Constants.LandUnit);
  1241. // startX/Y and endX/Y are coordinates in bitmap_tmp
  1242. int startX = (int)Math.Floor(boundingOrigin.X / Constants.LandUnit) + offsetX;
  1243. if (startX > tmpX) startX = tmpX;
  1244. if (startX < 0) startX = 0;
  1245. int startY = (int)Math.Floor(boundingOrigin.Y / Constants.LandUnit) + offsetY;
  1246. if (startY > tmpY) startY = tmpY;
  1247. if (startY < 0) startY = 0;
  1248. int endX = (int)Math.Floor((boundingOrigin.X + boundingSize.X) / Constants.LandUnit) + offsetX;
  1249. if (endX > tmpX) endX = tmpX;
  1250. if (endX < 0) endX = 0;
  1251. int endY = (int)Math.Floor((boundingOrigin.Y + boundingSize.Y) / Constants.LandUnit) + offsetY;
  1252. if (endY > tmpY) endY = tmpY;
  1253. if (endY < 0) endY = 0;
  1254. //m_log.DebugFormat("{0} RemapLandBitmap: inSize=<{1},{2}>, disp=<{3},{4}> rot={5}, offset=<{6},{7}>, boundingStart=<{8},{9}>, boundingEnd=<{10},{11}>, cosR={12}, sinR={13}, outSize=<{14},{15}>", LogHeader,
  1255. // baseX, baseY, dispX, dispY, radianRotation, offsetX, offsetY, startX, startY, endX, endY, cosR, sinR, newX, newY);
  1256. isEmptyNow = true;
  1257. int dx, dy;
  1258. for (y = startY; y < endY; y++)
  1259. {
  1260. for (x = startX; x < endX; x++)
  1261. {
  1262. dx = x - startX + dispX;
  1263. dy = y - startY + dispY;
  1264. if (dx >= 0 && dx < newX && dy >= 0 && dy < newY)
  1265. {
  1266. try
  1267. {
  1268. if (bitmap_tmp[x, y])
  1269. {
  1270. bitmap_new[dx, dy] = true;
  1271. isEmptyNow = false;
  1272. }
  1273. }
  1274. catch (Exception) //just in case we've still not taken care of every way the arrays might go out of bounds! ;)
  1275. {
  1276. m_log.DebugFormat("{0} RemapLandBitmap - Bound & Displace: Out of Bounds sx={1} sy={2} dx={3} dy={4}", LogHeader, x, y, dx, dy);
  1277. }
  1278. }
  1279. }
  1280. }
  1281. return bitmap_new;
  1282. }
  1283. /// <summary>
  1284. /// Clears any parcel data in bitmap_base where there exists parcel data in bitmap_new. In other words the parcel data
  1285. /// in bitmap_new takes over the space of the parcel data in bitmap_base.
  1286. /// </summary>
  1287. /// <param name="bitmap_base"></param>
  1288. /// <param name="bitmap_new"></param>
  1289. /// <param name="isEmptyNow">out: This is set if the resultant bitmap is now empty</param>
  1290. /// <param name="AABBMin">out: parcel.AABBMin &lt;x,y,0&gt</param>
  1291. /// <param name="AABBMax">out: parcel.AABBMax &lt;x,y,0&gt</param>
  1292. /// <returns>New parcel bitmap</returns>
  1293. public bool[,] RemoveFromLandBitmap(bool[,] bitmap_base, bool[,] bitmap_new, out bool isEmptyNow)
  1294. {
  1295. // get the size of the incoming bitmaps
  1296. int baseX = bitmap_base.GetLength(0);
  1297. int baseY = bitmap_base.GetLength(1);
  1298. int newX = bitmap_new.GetLength(0);
  1299. int newY = bitmap_new.GetLength(1);
  1300. if (baseX != newX || baseY != newY)
  1301. {
  1302. throw new Exception(
  1303. String.Format("{0} RemoveFromLandBitmap: Land bitmaps are not the same size! baseX={1} baseY={2} newX={3} newY={4}", LogHeader, baseX, baseY, newX, newY));
  1304. }
  1305. isEmptyNow = true;
  1306. for (int x = 0; x < baseX; x++)
  1307. {
  1308. for (int y = 0; y < baseY; y++)
  1309. {
  1310. if (bitmap_new[x, y]) bitmap_base[x, y] = false;
  1311. if (bitmap_base[x, y])
  1312. {
  1313. isEmptyNow = false;
  1314. }
  1315. }
  1316. }
  1317. return bitmap_base;
  1318. }
  1319. /// <summary>
  1320. /// Converts the land bitmap to a packet friendly byte array
  1321. /// </summary>
  1322. /// <returns></returns>
  1323. public byte[] ConvertLandBitmapToBytes()
  1324. {
  1325. byte[] tempConvertArr = new byte[LandBitmap.GetLength(0) * LandBitmap.GetLength(1) / 8];
  1326. int tempByte = 0;
  1327. int byteNum = 0;
  1328. int mask = 1;
  1329. for (int y = 0; y < LandBitmap.GetLength(1); y++)
  1330. {
  1331. for (int x = 0; x < LandBitmap.GetLength(0); x++)
  1332. {
  1333. if (LandBitmap[x, y])
  1334. tempByte |= mask;
  1335. mask <<= 1;
  1336. if (mask == 0x100)
  1337. {
  1338. mask = 1;
  1339. tempConvertArr[byteNum++] = (byte)tempByte;
  1340. tempByte = 0;
  1341. }
  1342. }
  1343. }
  1344. if(tempByte != 0 && byteNum < 512)
  1345. tempConvertArr[byteNum] = (byte)tempByte;
  1346. return tempConvertArr;
  1347. }
  1348. public bool[,] ConvertBytesToLandBitmap(bool overrideRegionSize = false)
  1349. {
  1350. int bitmapLen;
  1351. int xLen;
  1352. bool[,] tempConvertMap;
  1353. if (overrideRegionSize)
  1354. {
  1355. // Importing land parcel data from an OAR where the source region is a different size to the dest region requires us
  1356. // to make a LandBitmap that's not derived from the current region's size. We use the LandData.Bitmap size in bytes
  1357. // to figure out what the OAR's region dimensions are. (Is there a better way to get the src region x and y from the OAR?)
  1358. // This method assumes we always will have square regions
  1359. bitmapLen = LandData.Bitmap.Length;
  1360. xLen = (int)Math.Abs(Math.Sqrt(bitmapLen * 8));
  1361. tempConvertMap = new bool[xLen, xLen];
  1362. tempConvertMap.Initialize();
  1363. }
  1364. else
  1365. {
  1366. tempConvertMap = new bool[m_regionSizeX / Constants.LandUnit, m_regionSizeY / Constants.LandUnit];
  1367. tempConvertMap.Initialize();
  1368. // Math.Min overcomes an old bug that might have made it into the database. Only use the bytes that fit into convertMap.
  1369. bitmapLen = Math.Min(LandData.Bitmap.Length, tempConvertMap.GetLength(0) * tempConvertMap.GetLength(1) / 8);
  1370. xLen = (m_regionSizeX / Constants.LandUnit);
  1371. if (bitmapLen == 512)
  1372. {
  1373. // Legacy bitmap being passed in. Use the legacy region size
  1374. // and only set the lower area of the larger region.
  1375. xLen = (int)(Constants.RegionSize / Constants.LandUnit);
  1376. }
  1377. }
  1378. // m_log.DebugFormat("{0} ConvertBytesToLandBitmap: bitmapLen={1}, xLen={2}", LogHeader, bitmapLen, xLen);
  1379. byte tempByte;
  1380. int x = 0, y = 0;
  1381. for (int i = 0; i < bitmapLen; i++)
  1382. {
  1383. tempByte = LandData.Bitmap[i];
  1384. for (int bitmask = 0x01; bitmask < 0x100; bitmask <<= 1)
  1385. {
  1386. bool bit = (tempByte & bitmask) == bitmask;
  1387. try
  1388. {
  1389. tempConvertMap[x, y] = bit;
  1390. }
  1391. catch (Exception)
  1392. {
  1393. m_log.DebugFormat("{0} ConvertBytestoLandBitmap: i={1}, x={2}, y={3}", LogHeader, i, x, y);
  1394. }
  1395. x++;
  1396. if (x >= xLen)
  1397. {
  1398. x = 0;
  1399. y++;
  1400. }
  1401. }
  1402. }
  1403. return tempConvertMap;
  1404. }
  1405. public bool IsLandBitmapEmpty(bool[,] landBitmap)
  1406. {
  1407. for (int y = 0; y < landBitmap.GetLength(1); y++)
  1408. {
  1409. for (int x = 0; x < landBitmap.GetLength(0); x++)
  1410. {
  1411. if (landBitmap[x, y]) return false;
  1412. }
  1413. }
  1414. return true;
  1415. }
  1416. public void DebugLandBitmap(bool[,] landBitmap)
  1417. {
  1418. m_log.InfoFormat("{0}: Map Key: #=claimed land .=unclaimed land.", LogHeader);
  1419. for (int y = landBitmap.GetLength(1) - 1; y >= 0; y--)
  1420. {
  1421. string row = "";
  1422. for (int x = 0; x < landBitmap.GetLength(0); x++)
  1423. {
  1424. row += landBitmap[x, y] ? "#" : ".";
  1425. }
  1426. m_log.InfoFormat("{0}: {1}", LogHeader, row);
  1427. }
  1428. }
  1429. #endregion
  1430. #region Object Select and Object Owner Listing
  1431. public void SendForceObjectSelect(int local_id, int request_type, List<UUID> returnIDs, IClientAPI remote_client)
  1432. {
  1433. if (m_scenePermissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions, true))
  1434. {
  1435. List<uint> resultLocalIDs = new();
  1436. try
  1437. {
  1438. lock (primsOverMe)
  1439. {
  1440. foreach (SceneObjectGroup obj in primsOverMe)
  1441. {
  1442. if (obj.LocalId > 0)
  1443. {
  1444. if (request_type == LandChannel.LAND_SELECT_OBJECTS_OWNER && obj.OwnerID.Equals(LandData.OwnerID))
  1445. {
  1446. resultLocalIDs.Add(obj.LocalId);
  1447. }
  1448. else if (request_type == LandChannel.LAND_SELECT_OBJECTS_GROUP && obj.GroupID.Equals(LandData.GroupID) && !LandData.GroupID.IsZero())
  1449. {
  1450. resultLocalIDs.Add(obj.LocalId);
  1451. }
  1452. else if (request_type == LandChannel.LAND_SELECT_OBJECTS_OTHER && obj.OwnerID.NotEqual(remote_client.AgentId))
  1453. {
  1454. resultLocalIDs.Add(obj.LocalId);
  1455. }
  1456. else if (request_type == (int)ObjectReturnType.List && returnIDs.Contains(obj.OwnerID))
  1457. {
  1458. resultLocalIDs.Add(obj.LocalId);
  1459. }
  1460. }
  1461. }
  1462. }
  1463. } catch (InvalidOperationException)
  1464. {
  1465. m_log.Error("[LAND]: Unable to force select the parcel objects. Arr.");
  1466. }
  1467. remote_client.SendForceClientSelectObjects(resultLocalIDs);
  1468. }
  1469. }
  1470. /// <summary>
  1471. /// Notify the parcel owner each avatar that owns prims situated on their land. This notification includes
  1472. /// aggreagete details such as the number of prims.
  1473. ///
  1474. /// </summary>
  1475. /// <param name="remote_client">
  1476. /// A <see cref="IClientAPI"/>
  1477. /// </param>
  1478. public void SendLandObjectOwners(IClientAPI remote_client)
  1479. {
  1480. if (m_scenePermissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions, true))
  1481. {
  1482. Dictionary<UUID, int> primCount = new();
  1483. List<UUID> groups = new();
  1484. lock (primsOverMe)
  1485. {
  1486. //m_log.DebugFormat(
  1487. // "[LAND OBJECT]: Request for SendLandObjectOwners() from {0} with {1} known prims on region",
  1488. // remote_client.Name, primsOverMe.Count);
  1489. try
  1490. {
  1491. foreach (SceneObjectGroup obj in primsOverMe)
  1492. {
  1493. try
  1494. {
  1495. if (!primCount.ContainsKey(obj.OwnerID))
  1496. {
  1497. primCount.Add(obj.OwnerID, 0);
  1498. }
  1499. }
  1500. catch (NullReferenceException)
  1501. {
  1502. m_log.Error("[LAND]: " + "Got Null Reference when searching land owners from the parcel panel");
  1503. }
  1504. try
  1505. {
  1506. primCount[obj.OwnerID] += obj.PrimCount;
  1507. }
  1508. catch (KeyNotFoundException)
  1509. {
  1510. m_log.Error("[LAND]: Unable to match a prim with it's owner.");
  1511. }
  1512. if (obj.OwnerID.Equals(obj.GroupID) && (!groups.Contains(obj.OwnerID)))
  1513. groups.Add(obj.OwnerID);
  1514. }
  1515. }
  1516. catch (InvalidOperationException)
  1517. {
  1518. m_log.Error("[LAND]: Unable to Enumerate Land object arr.");
  1519. }
  1520. }
  1521. remote_client.SendLandObjectOwners(LandData, groups, primCount);
  1522. }
  1523. }
  1524. public Dictionary<UUID, int> GetLandObjectOwners()
  1525. {
  1526. Dictionary<UUID, int> ownersAndCount = new();
  1527. lock (primsOverMe)
  1528. {
  1529. try
  1530. {
  1531. foreach (SceneObjectGroup obj in primsOverMe)
  1532. {
  1533. if (!ownersAndCount.ContainsKey(obj.OwnerID))
  1534. {
  1535. ownersAndCount.Add(obj.OwnerID, 0);
  1536. }
  1537. ownersAndCount[obj.OwnerID] += obj.PrimCount;
  1538. }
  1539. }
  1540. catch (InvalidOperationException)
  1541. {
  1542. m_log.Error("[LAND]: Unable to enumerate land owners. arr.");
  1543. }
  1544. }
  1545. return ownersAndCount;
  1546. }
  1547. #endregion
  1548. #region Object Sales
  1549. public void SellLandObjects(UUID previousOwner)
  1550. {
  1551. // m_log.DebugFormat(
  1552. // "[LAND OBJECT]: Request to sell objects in {0} from {1}", LandData.Name, previousOwner);
  1553. if (LandData.IsGroupOwned)
  1554. return;
  1555. IBuySellModule m_BuySellModule = m_scene.RequestModuleInterface<IBuySellModule>();
  1556. if (m_BuySellModule == null)
  1557. {
  1558. m_log.Error("[LAND OBJECT]: BuySellModule not found");
  1559. return;
  1560. }
  1561. if (!m_scene.TryGetScenePresence(LandData.OwnerID, out ScenePresence sp))
  1562. {
  1563. m_log.Error("[LAND OBJECT]: New owner is not present in scene");
  1564. return;
  1565. }
  1566. lock (primsOverMe)
  1567. {
  1568. foreach (SceneObjectGroup obj in primsOverMe)
  1569. {
  1570. if(m_scenePermissions.CanSellObject(previousOwner,obj, (byte)SaleType.Original))
  1571. m_BuySellModule.BuyObject(sp.ControllingClient, UUID.Zero, obj.LocalId, (byte)SaleType.Original, 0);
  1572. }
  1573. }
  1574. }
  1575. #endregion
  1576. #region Object Returning
  1577. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  1578. public void ReturnObject(SceneObjectGroup obj)
  1579. {
  1580. m_scene.returnObjects(new SceneObjectGroup[] { obj }, null);
  1581. }
  1582. public void ReturnLandObjects(uint type, UUID[] owners, UUID[] tasks, IClientAPI remote_client)
  1583. {
  1584. //m_log.DebugFormat(
  1585. // "[LAND OBJECT]: Request to return objects in {0} from {1}", LandData.Name, remote_client.Name);
  1586. Dictionary<UUID,List<SceneObjectGroup>> returns = new();
  1587. lock (primsOverMe)
  1588. {
  1589. if (type == (uint)ObjectReturnType.Owner)
  1590. {
  1591. foreach (SceneObjectGroup obj in primsOverMe)
  1592. {
  1593. if (obj.OwnerID.Equals(LandData.OwnerID))
  1594. {
  1595. if (returns.TryGetValue(obj.OwnerID, out List<SceneObjectGroup> rol))
  1596. rol.Add(obj);
  1597. else
  1598. returns[obj.OwnerID] = new List<SceneObjectGroup>() { obj };
  1599. }
  1600. }
  1601. }
  1602. else if (type == (uint)ObjectReturnType.Group && LandData.GroupID.IsNotZero())
  1603. {
  1604. foreach (SceneObjectGroup obj in primsOverMe)
  1605. {
  1606. if (obj.GroupID.Equals(LandData.GroupID))
  1607. {
  1608. if (obj.OwnerID.Equals(LandData.OwnerID))
  1609. continue;
  1610. if (returns.TryGetValue(obj.OwnerID, out List<SceneObjectGroup> rol))
  1611. rol.Add(obj);
  1612. else
  1613. returns[obj.OwnerID] = new List<SceneObjectGroup>() { obj };
  1614. }
  1615. }
  1616. }
  1617. else if (type == (uint)ObjectReturnType.Other)
  1618. {
  1619. foreach (SceneObjectGroup obj in primsOverMe)
  1620. {
  1621. if (obj.OwnerID.NotEqual(LandData.OwnerID) &&
  1622. (obj.GroupID.NotEqual(LandData.GroupID) ||
  1623. LandData.GroupID.IsZero()))
  1624. {
  1625. if (returns.TryGetValue(obj.OwnerID, out List<SceneObjectGroup> rol))
  1626. rol.Add(obj);
  1627. else
  1628. returns[obj.OwnerID] = new List<SceneObjectGroup>() { obj };
  1629. }
  1630. }
  1631. }
  1632. else if (type == (uint)ObjectReturnType.List)
  1633. {
  1634. List<UUID> ownerlist = new(owners);
  1635. foreach (SceneObjectGroup obj in primsOverMe)
  1636. {
  1637. if (ownerlist.Contains(obj.OwnerID))
  1638. {
  1639. if (returns.TryGetValue(obj.OwnerID, out List<SceneObjectGroup> rol))
  1640. rol.Add(obj);
  1641. else
  1642. returns[obj.OwnerID] = new List<SceneObjectGroup>() { obj };
  1643. }
  1644. }
  1645. }
  1646. }
  1647. foreach (List<SceneObjectGroup> ol in returns.Values)
  1648. {
  1649. if (m_scenePermissions.CanReturnObjects(this, remote_client, ol))
  1650. m_scene.returnObjects(ol.ToArray(), remote_client);
  1651. }
  1652. }
  1653. #endregion
  1654. #region Object Adding/Removing from Parcel
  1655. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  1656. public void ResetOverMeRecord()
  1657. {
  1658. lock (primsOverMe)
  1659. primsOverMe.Clear();
  1660. }
  1661. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  1662. public void AddPrimOverMe(SceneObjectGroup obj)
  1663. {
  1664. // m_log.DebugFormat("[LAND OBJECT]: Adding scene object {0} {1} over {2}", obj.Name, obj.LocalId, LandData.Name);
  1665. lock (primsOverMe)
  1666. primsOverMe.Add(obj);
  1667. }
  1668. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  1669. public void RemovePrimFromOverMe(SceneObjectGroup obj)
  1670. {
  1671. //m_log.DebugFormat("[LAND OBJECT]: Removing scene object {0} {1} from over {2}", obj.Name, obj.LocalId, LandData.Name);
  1672. lock (primsOverMe)
  1673. primsOverMe.Remove(obj);
  1674. }
  1675. #endregion
  1676. /// <summary>
  1677. /// Set the media url for this land parcel
  1678. /// </summary>
  1679. /// <param name="url"></param>
  1680. public void SetMediaUrl(string url)
  1681. {
  1682. if (String.IsNullOrWhiteSpace(url))
  1683. LandData.MediaURL = String.Empty;
  1684. else
  1685. {
  1686. try
  1687. {
  1688. Uri dummmy = new(url, UriKind.Absolute);
  1689. LandData.MediaURL = url;
  1690. }
  1691. catch (Exception e)
  1692. {
  1693. m_log.ErrorFormat("[LAND OBJECT]: SetMediaUrl error: {0}", e.Message);
  1694. return;
  1695. }
  1696. }
  1697. m_scene.LandChannel.UpdateLandObject(LandData.LocalID, LandData);
  1698. SendLandUpdateToAvatarsOverMe();
  1699. }
  1700. /// <summary>
  1701. /// Set the music url for this land parcel
  1702. /// </summary>
  1703. /// <param name="url"></param>
  1704. public void SetMusicUrl(string url)
  1705. {
  1706. if (String.IsNullOrWhiteSpace(url))
  1707. LandData.MusicURL = String.Empty;
  1708. else
  1709. {
  1710. try
  1711. {
  1712. Uri dummmy = new(url, UriKind.Absolute);
  1713. LandData.MusicURL = url;
  1714. }
  1715. catch (Exception e)
  1716. {
  1717. m_log.ErrorFormat("[LAND OBJECT]: SetMusicUrl error: {0}", e.Message);
  1718. return;
  1719. }
  1720. }
  1721. m_scene.LandChannel.UpdateLandObject(LandData.LocalID, LandData);
  1722. SendLandUpdateToAvatarsOverMe();
  1723. }
  1724. /// <summary>
  1725. /// Get the music url for this land parcel
  1726. /// </summary>
  1727. /// <returns>The music url.</returns>
  1728. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  1729. public string GetMusicUrl()
  1730. {
  1731. return LandData.MusicURL;
  1732. }
  1733. #endregion
  1734. private void OnFrame()
  1735. {
  1736. m_expiryCounter++;
  1737. if (m_expiryCounter >= 50)
  1738. {
  1739. ExpireAccessList();
  1740. m_expiryCounter = 0;
  1741. }
  1742. // need to update dwell here bc landdata has no parent info
  1743. if(LandData is not null && m_dwellModule is not null)
  1744. {
  1745. double now = Util.GetTimeStampMS();
  1746. double elapsed = now - LandData.LastDwellTimeMS;
  1747. if(elapsed > 150000) //2.5 minutes resolution / throttle
  1748. {
  1749. float dwell = LandData.Dwell;
  1750. double cur = dwell * 60000.0;
  1751. double decay = 1.5e-8 * cur * elapsed;
  1752. cur -= decay;
  1753. if (cur < 0)
  1754. cur = 0;
  1755. UUID lgid = LandData.GlobalID;
  1756. m_scene.ForEachRootScenePresence(delegate(ScenePresence sp)
  1757. {
  1758. if(sp.IsNPC || sp.IsDeleted || sp.currentParcelUUID.NotEqual(lgid))
  1759. return;
  1760. cur += (now - sp.ParcelDwellTickMS);
  1761. sp.ParcelDwellTickMS = now;
  1762. });
  1763. float newdwell = (float)(cur * 1.666666666667e-5);
  1764. LandData.Dwell = newdwell;
  1765. if(Math.Abs(newdwell - dwell) >= 0.9)
  1766. m_scene.EventManager.TriggerLandObjectAdded(this);
  1767. }
  1768. }
  1769. }
  1770. private void ExpireAccessList()
  1771. {
  1772. List<LandAccessEntry> delete = new();
  1773. int now = Util.UnixTimeSinceEpoch();
  1774. foreach (LandAccessEntry entry in LandData.ParcelAccessList)
  1775. {
  1776. if (entry.Expires != 0 && entry.Expires < now)
  1777. delete.Add(entry);
  1778. }
  1779. foreach (LandAccessEntry entry in delete)
  1780. {
  1781. LandData.ParcelAccessList.Remove(entry);
  1782. if ((entry.Flags & AccessList.Access) != 0 && m_scene.TryGetScenePresence(entry.AgentID, out ScenePresence presence) && (!presence.IsChildAgent))
  1783. {
  1784. ILandObject land = m_scene.LandChannel.GetLandObject(presence.AbsolutePosition.X, presence.AbsolutePosition.Y);
  1785. if (land.LandData.LocalID == LandData.LocalID)
  1786. {
  1787. Vector3 pos = m_scene.GetNearestAllowedPosition(presence, land);
  1788. presence.TeleportOnEject(pos);
  1789. presence.ControllingClient.SendAlertMessage("You have been ejected from this land");
  1790. }
  1791. }
  1792. m_log.DebugFormat("[LAND]: Removing entry {0} because it has expired", entry.AgentID);
  1793. }
  1794. if (delete.Count > 0)
  1795. m_scene.EventManager.TriggerLandObjectUpdated((uint)LandData.LocalID, this);
  1796. }
  1797. public void StoreEnvironment(ViewerEnvironment VEnv)
  1798. {
  1799. int lastVersion = LandData.EnvironmentVersion;
  1800. LandData.Environment = VEnv;
  1801. if (VEnv == null)
  1802. LandData.EnvironmentVersion = -1;
  1803. else
  1804. {
  1805. ++LandData.EnvironmentVersion;
  1806. VEnv.version = LandData.EnvironmentVersion;
  1807. }
  1808. if(lastVersion != LandData.EnvironmentVersion)
  1809. {
  1810. m_scene.LandChannel.UpdateLandObject(LandData.LocalID, LandData);
  1811. SendLandUpdateToAvatarsOverMe();
  1812. }
  1813. }
  1814. }
  1815. }