LandManagementModule.cs 112 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections.Generic;
  29. using System.Net;
  30. using System.Reflection;
  31. using System.Runtime.CompilerServices;
  32. using System.Text;
  33. using log4net;
  34. using Nini.Config;
  35. using OpenMetaverse;
  36. using OpenMetaverse.StructuredData;
  37. using OpenMetaverse.Messages.Linden;
  38. using Mono.Addins;
  39. using OpenSim.Framework;
  40. using OpenSim.Framework.Console;
  41. using OpenSim.Framework.Monitoring;
  42. using OpenSim.Framework.Servers.HttpServer;
  43. using OpenSim.Region.Framework.Interfaces;
  44. using OpenSim.Region.Framework.Scenes;
  45. using OpenSim.Services.Interfaces;
  46. using Caps = OpenSim.Framework.Capabilities.Caps;
  47. using GridRegion = OpenSim.Services.Interfaces.GridRegion;
  48. using OSDMap = OpenMetaverse.StructuredData.OSDMap;
  49. using OSDArray = OpenMetaverse.StructuredData.OSDArray;
  50. using Extension = Mono.Addins.ExtensionAttribute;
  51. namespace OpenSim.Region.CoreModules.World.Land
  52. {
  53. // used for caching
  54. internal class ExtendedLandData
  55. {
  56. public LandData LandData;
  57. public ulong RegionHandle;
  58. public uint X, Y;
  59. public byte RegionAccess;
  60. }
  61. [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LandManagementModule")]
  62. public class LandManagementModule : INonSharedRegionModule , ILandChannel
  63. {
  64. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  65. private Scene m_scene;
  66. //private LandChannel m_landChannel;
  67. private ulong m_regionHandler;
  68. private int m_regionSizeX;
  69. private int m_regionSizeY;
  70. protected IGroupsModule m_groupManager;
  71. protected IUserManagement m_userManager;
  72. protected IPrimCountModule m_primCountModule;
  73. protected IDialogModule m_Dialog;
  74. /// <value>
  75. /// Local land ids at specified region co-ordinates (region size / 4)
  76. /// </value>
  77. private int[,] m_landIDList;
  78. /// <value>
  79. /// Land objects keyed by local id
  80. /// </value>
  81. private readonly Dictionary<int, ILandObject> m_landList = new();
  82. private readonly Dictionary<UUID, int> m_landGlobalIDs = new();
  83. private readonly Dictionary<UUID, int> m_landFakeIDs = new();
  84. private int m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1;
  85. private bool m_allowedForcefulBans = true;
  86. private bool m_showBansLines = true;
  87. private UUID DefaultGodParcelGroup;
  88. private string DefaultGodParcelName;
  89. private UUID DefaultGodParcelOwner;
  90. // caches ExtendedLandData
  91. static private readonly ExpiringCacheOS<UUID,ExtendedLandData> m_parcelInfoCache = new(10000);
  92. /// <summary>
  93. /// Record positions that avatar's are currently being forced to move to due to parcel entry restrictions.
  94. /// </summary>
  95. private readonly HashSet<UUID> forcedPosition = new();
  96. // Enables limiting parcel layer info transmission when doing simple updates
  97. private bool shouldLimitParcelLayerInfoToViewDistance { get; set; }
  98. // "View distance" for sending parcel layer info if asked for from a view point in the region
  99. private int parcelLayerViewDistance { get; set; }
  100. private float m_BanLineSafeHeight = 100.0f;
  101. public float BanLineSafeHeight
  102. {
  103. get { return m_BanLineSafeHeight; }
  104. private set
  105. {
  106. if (value > 20f && value <= 5000f)
  107. m_BanLineSafeHeight = value;
  108. else
  109. m_BanLineSafeHeight = 100.0f;
  110. }
  111. }
  112. #region INonSharedRegionModule Members
  113. public Type ReplaceableInterface
  114. {
  115. get { return null; }
  116. }
  117. public void Initialise(IConfigSource source)
  118. {
  119. shouldLimitParcelLayerInfoToViewDistance = true;
  120. parcelLayerViewDistance = 128;
  121. IConfig landManagementConfig = source.Configs["LandManagement"];
  122. if (landManagementConfig is not null)
  123. {
  124. shouldLimitParcelLayerInfoToViewDistance = landManagementConfig.GetBoolean("LimitParcelLayerUpdateDistance", shouldLimitParcelLayerInfoToViewDistance);
  125. parcelLayerViewDistance = landManagementConfig.GetInt("ParcelLayerViewDistance", parcelLayerViewDistance);
  126. DefaultGodParcelGroup = new UUID(landManagementConfig.GetString("DefaultAdministratorGroupUUID", UUID.Zero.ToString()));
  127. DefaultGodParcelName = landManagementConfig.GetString("DefaultAdministratorParcelName", "Admin Parcel");
  128. DefaultGodParcelOwner = new UUID(landManagementConfig.GetString("DefaultAdministratorOwnerUUID", UUID.Zero.ToString()));
  129. bool disablebans = landManagementConfig.GetBoolean("DisableParcelBans", !m_allowedForcefulBans);
  130. m_allowedForcefulBans = !disablebans;
  131. m_showBansLines = landManagementConfig.GetBoolean("ShowParcelBansLines", m_showBansLines);
  132. m_BanLineSafeHeight = landManagementConfig.GetFloat("BanLineSafeHeight", m_BanLineSafeHeight);
  133. if(!m_allowedForcefulBans)
  134. m_showBansLines = false;
  135. }
  136. }
  137. public void AddRegion(Scene scene)
  138. {
  139. m_scene = scene;
  140. m_regionHandler = m_scene.RegionInfo.RegionHandle;
  141. m_regionSizeX = (int)m_scene.RegionInfo.RegionSizeX;
  142. m_regionSizeY = (int)m_scene.RegionInfo.RegionSizeY;
  143. m_landIDList = new int[m_regionSizeX / Constants.LandUnit, m_regionSizeY / Constants.LandUnit];
  144. m_scene.LandChannel = this;
  145. m_scene.EventManager.OnObjectAddedToScene += EventManagerOnParcelPrimCountAdd;
  146. m_scene.EventManager.OnParcelPrimCountAdd += EventManagerOnParcelPrimCountAdd;
  147. m_scene.EventManager.OnObjectBeingRemovedFromScene += EventManagerOnObjectBeingRemovedFromScene;
  148. m_scene.EventManager.OnParcelPrimCountUpdate += EventManagerOnParcelPrimCountUpdate;
  149. m_scene.EventManager.OnRequestParcelPrimCountUpdate += EventManagerOnRequestParcelPrimCountUpdate;
  150. m_scene.EventManager.OnAvatarEnteringNewParcel += EventManagerOnAvatarEnteringNewParcel;
  151. m_scene.EventManager.OnClientMovement += EventManagerOnClientMovement;
  152. m_scene.EventManager.OnValidateLandBuy += EventManagerOnValidateLandBuy;
  153. m_scene.EventManager.OnLandBuy += EventManagerOnLandBuy;
  154. m_scene.EventManager.OnNewClient += EventManagerOnNewClient;
  155. m_scene.EventManager.OnMakeChildAgent += EventMakeChildAgent;
  156. m_scene.EventManager.OnSignificantClientMovement += EventManagerOnSignificantClientMovement;
  157. m_scene.EventManager.OnNoticeNoLandDataFromStorage += EventManagerOnNoLandDataFromStorage;
  158. m_scene.EventManager.OnIncomingLandDataFromStorage += EventManagerOnIncomingLandDataFromStorage;
  159. m_scene.EventManager.OnSetAllowForcefulBan += EventManagerOnSetAllowedForcefulBan;
  160. m_scene.EventManager.OnRegisterCaps += EventManagerOnRegisterCaps;
  161. RegisterCommands();
  162. }
  163. public void RegionLoaded(Scene scene)
  164. {
  165. m_userManager = m_scene.RequestModuleInterface<IUserManagement>();
  166. m_groupManager = m_scene.RequestModuleInterface<IGroupsModule>();
  167. m_primCountModule = m_scene.RequestModuleInterface<IPrimCountModule>();
  168. m_Dialog = m_scene.RequestModuleInterface<IDialogModule>();
  169. }
  170. public void RemoveRegion(Scene scene)
  171. {
  172. // TODO: Release event manager listeners here
  173. }
  174. /*
  175. private bool OnVerifyUserConnection(ScenePresence scenePresence, out string reason)
  176. {
  177. ILandObject nearestParcel = m_scene.GetNearestAllowedParcel(scenePresence.UUID, scenePresence.AbsolutePosition.X, scenePresence.AbsolutePosition.Y);
  178. "You are not allowed to enter this sim.";
  179. return nearestParcel != null;
  180. }
  181. */
  182. void EventManagerOnNewClient(IClientAPI client)
  183. {
  184. //Register some client events
  185. client.OnParcelPropertiesRequest += ClientOnParcelPropertiesRequest;
  186. client.OnParcelDivideRequest += ClientOnParcelDivideRequest;
  187. client.OnParcelJoinRequest += ClientOnParcelJoinRequest;
  188. client.OnParcelPropertiesUpdateRequest += ClientOnParcelPropertiesUpdateRequest;
  189. client.OnParcelSelectObjects += ClientOnParcelSelectObjects;
  190. client.OnParcelObjectOwnerRequest += ClientOnParcelObjectOwnerRequest;
  191. client.OnParcelAccessListRequest += ClientOnParcelAccessListRequest;
  192. client.OnParcelAccessListUpdateRequest += ClientOnParcelAccessListUpdateRequest;
  193. client.OnParcelAbandonRequest += ClientOnParcelAbandonRequest;
  194. client.OnParcelGodForceOwner += ClientOnParcelGodForceOwner;
  195. client.OnParcelReclaim += ClientOnParcelReclaim;
  196. client.OnParcelInfoRequest += ClientOnParcelInfoRequest;
  197. client.OnParcelDeedToGroup += ClientOnParcelDeedToGroup;
  198. client.OnParcelEjectUser += ClientOnParcelEjectUser;
  199. client.OnParcelFreezeUser += ClientOnParcelFreezeUser;
  200. client.OnSetStartLocationRequest += ClientOnSetHome;
  201. client.OnParcelBuyPass += ClientParcelBuyPass;
  202. client.OnParcelGodMark += ClientOnParcelGodMark;
  203. }
  204. public void EventMakeChildAgent(ScenePresence avatar)
  205. {
  206. avatar.currentParcelUUID = UUID.Zero;
  207. }
  208. public void Close()
  209. {
  210. }
  211. public string Name
  212. {
  213. get { return "LandManagementModule"; }
  214. }
  215. #endregion
  216. #region Parcel Add/Remove/Get/Create
  217. public void EventManagerOnSetAllowedForcefulBan(bool forceful)
  218. {
  219. AllowedForcefulBans = forceful;
  220. }
  221. public void UpdateLandObject(int local_id, LandData data)
  222. {
  223. LandData newData = data.Copy();
  224. newData.LocalID = local_id;
  225. ILandObject land;
  226. lock (m_landList)
  227. {
  228. if (m_landList.TryGetValue(local_id, out land))
  229. {
  230. m_landGlobalIDs.Remove(land.LandData.GlobalID);
  231. if (land.LandData.FakeID.IsNotZero())
  232. m_landFakeIDs.Remove(land.LandData.FakeID);
  233. land.LandData = newData;
  234. m_landGlobalIDs[newData.GlobalID] = local_id;
  235. if (newData.FakeID.IsNotZero())
  236. m_landFakeIDs[newData.FakeID] = local_id;
  237. }
  238. else
  239. return;
  240. }
  241. m_scene.EventManager.TriggerLandObjectUpdated((uint)local_id, land);
  242. }
  243. public bool IsForcefulBansAllowed()
  244. {
  245. return AllowedForcefulBans;
  246. }
  247. public bool AllowedForcefulBans
  248. {
  249. get { return m_allowedForcefulBans; }
  250. set { m_allowedForcefulBans = value; }
  251. }
  252. /// <summary>
  253. /// Resets the sim to the default land object (full sim piece of land owned by the default user)
  254. /// </summary>
  255. public void ResetSimLandObjects()
  256. {
  257. //Remove all the land objects in the sim and add a blank, full sim land object set to public
  258. lock (m_landList)
  259. {
  260. foreach(ILandObject parcel in m_landList.Values)
  261. parcel.Clear();
  262. m_landList.Clear();
  263. m_landGlobalIDs.Clear();
  264. m_landFakeIDs.Clear();
  265. m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1;
  266. m_landIDList = new int[m_regionSizeX / Constants.LandUnit, m_regionSizeY / Constants.LandUnit];
  267. }
  268. }
  269. /// <summary>
  270. /// Create a default parcel that spans the entire region and is owned by the estate owner.
  271. /// </summary>
  272. /// <returns>The parcel created.</returns>
  273. protected ILandObject CreateDefaultParcel()
  274. {
  275. m_log.Debug("[LAND MANAGEMENT MODULE]: Creating default parcel for region " + m_scene.RegionInfo.RegionName);
  276. ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene);
  277. fullSimParcel.SetLandBitmap(fullSimParcel.GetSquareLandBitmap(0, 0, m_regionSizeX, m_regionSizeY));
  278. LandData ldata = fullSimParcel.LandData;
  279. ldata.SimwideArea = ldata.Area;
  280. ldata.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
  281. ldata.ClaimDate = Util.UnixTimeSinceEpoch();
  282. return AddLandObject(fullSimParcel);
  283. }
  284. public List<ILandObject> AllParcels()
  285. {
  286. lock (m_landList)
  287. {
  288. return new List<ILandObject>(m_landList.Values);
  289. }
  290. }
  291. public List<ILandObject> ParcelsNearPoint(Vector3 position)
  292. {
  293. List<ILandObject> parcelsNear = new();
  294. for (int x = -8; x <= 8; x += 4)
  295. {
  296. for (int y = -8; y <= 8; y += 4)
  297. {
  298. ILandObject check = GetLandObject(position.X + x, position.Y + y);
  299. if (check is not null)
  300. {
  301. if (!parcelsNear.Contains(check))
  302. {
  303. parcelsNear.Add(check);
  304. }
  305. }
  306. }
  307. }
  308. return parcelsNear;
  309. }
  310. // checks and enforces bans or restrictions
  311. // returns true if enforced
  312. public bool EnforceBans(ILandObject land, ScenePresence avatar)
  313. {
  314. Vector3 agentpos = avatar.AbsolutePosition;
  315. float h = m_scene.GetGroundHeight(agentpos.X, agentpos.Y) + m_scene.LandChannel.BanLineSafeHeight;
  316. float zdif = avatar.AbsolutePosition.Z - h;
  317. if (zdif > 0 )
  318. {
  319. forcedPosition.Remove(avatar.UUID);
  320. avatar.lastKnownAllowedPosition = agentpos;
  321. return false;
  322. }
  323. bool ban = false;
  324. string reason = "";
  325. if (land.IsRestrictedFromLand(avatar.UUID))
  326. {
  327. reason = "You do not have access to the parcel";
  328. ban = true;
  329. }
  330. if (land.IsBannedFromLand(avatar.UUID))
  331. {
  332. if ( m_allowedForcefulBans)
  333. {
  334. reason ="You are banned from parcel";
  335. ban = true;
  336. }
  337. else if(!ban)
  338. {
  339. if (forcedPosition.Contains(avatar.UUID))
  340. avatar.ControllingClient.SendAlertMessage("You are banned from parcel, please leave by your own will");
  341. forcedPosition.Remove(avatar.UUID);
  342. avatar.lastKnownAllowedPosition = agentpos;
  343. return false;
  344. }
  345. }
  346. if(ban)
  347. {
  348. if (!forcedPosition.Contains(avatar.UUID))
  349. avatar.ControllingClient.SendAlertMessage(reason);
  350. if(zdif > -4f)
  351. {
  352. agentpos.Z = h + 4.0f;
  353. ForceAvatarToPosition(avatar, agentpos);
  354. return true;
  355. }
  356. if (land.ContainsPoint((int)avatar.lastKnownAllowedPosition.X,
  357. (int) avatar.lastKnownAllowedPosition.Y))
  358. {
  359. Vector3? pos = m_scene.GetNearestAllowedPosition(avatar);
  360. if (pos is null)
  361. {
  362. forcedPosition.Remove(avatar.UUID);
  363. m_scene.TeleportClientHome(avatar.UUID, avatar.ControllingClient);
  364. }
  365. else
  366. ForceAvatarToPosition(avatar, (Vector3)pos);
  367. }
  368. else
  369. {
  370. ForceAvatarToPosition(avatar, avatar.lastKnownAllowedPosition);
  371. }
  372. return true;
  373. }
  374. else
  375. {
  376. forcedPosition.Remove(avatar.UUID);
  377. avatar.lastKnownAllowedPosition = agentpos;
  378. return false;
  379. }
  380. }
  381. private void ForceAvatarToPosition(ScenePresence avatar, Vector3? position)
  382. {
  383. if (m_scene.Permissions.IsGod(avatar.UUID)) return;
  384. if (!position.HasValue) return;
  385. if(avatar.MovingToTarget)
  386. avatar.ResetMoveToTarget();
  387. avatar.AbsolutePosition = position.Value;
  388. avatar.lastKnownAllowedPosition = position.Value;
  389. avatar.Velocity = Vector3.Zero;
  390. if(avatar.IsSitting)
  391. avatar.StandUp();
  392. forcedPosition.Add(avatar.UUID);
  393. }
  394. public void EventManagerOnAvatarEnteringNewParcel(ScenePresence avatar, int localLandID, UUID regionID)
  395. {
  396. if (m_scene.RegionInfo.RegionID.Equals(regionID))
  397. {
  398. ILandObject parcelAvatarIsEntering;
  399. lock (m_landList)
  400. {
  401. parcelAvatarIsEntering = m_landList[localLandID];
  402. }
  403. if (parcelAvatarIsEntering is not null &&
  404. avatar.currentParcelUUID.NotEqual(parcelAvatarIsEntering.LandData.GlobalID))
  405. {
  406. SendLandUpdate(avatar, parcelAvatarIsEntering);
  407. avatar.currentParcelUUID = parcelAvatarIsEntering.LandData.GlobalID;
  408. EnforceBans(parcelAvatarIsEntering, avatar);
  409. }
  410. }
  411. }
  412. public void SendOutNearestBanLine(IClientAPI client)
  413. {
  414. ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
  415. if (sp is null || sp.IsDeleted)
  416. return;
  417. List<ILandObject> checkLandParcels = ParcelsNearPoint(sp.AbsolutePosition);
  418. foreach (ILandObject checkBan in checkLandParcels)
  419. {
  420. if (checkBan.IsBannedFromLand(client.AgentId))
  421. {
  422. checkBan.SendLandProperties((int)ParcelPropertiesStatus.CollisionBanned, false, (int)ParcelResult.Single, client);
  423. return; //Only send one
  424. }
  425. if (checkBan.IsRestrictedFromLand(client.AgentId))
  426. {
  427. checkBan.SendLandProperties((int)ParcelPropertiesStatus.CollisionNotOnAccessList, false, (int)ParcelResult.Single, client);
  428. return; //Only send one
  429. }
  430. }
  431. return;
  432. }
  433. public void sendClientInitialLandInfo(IClientAPI remoteClient, bool overlay)
  434. {
  435. if (!m_scene.TryGetScenePresence(remoteClient.AgentId, out ScenePresence avatar))
  436. return;
  437. if (!avatar.IsChildAgent)
  438. {
  439. ILandObject over = GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
  440. if (over is null)
  441. return;
  442. avatar.currentParcelUUID = over.LandData.GlobalID;
  443. over.SendLandUpdateToClient(avatar.ControllingClient);
  444. }
  445. if (overlay)
  446. SendParcelOverlay(remoteClient);
  447. }
  448. public void SendLandUpdate(ScenePresence avatar, ILandObject over)
  449. {
  450. if (avatar.IsChildAgent)
  451. return;
  452. if (over is not null)
  453. {
  454. over.SendLandUpdateToClient(avatar.ControllingClient);
  455. // sl doesnt seem to send this now, as it used 2
  456. //SendParcelOverlay(avatar.ControllingClient);
  457. }
  458. }
  459. public void EventManagerOnSignificantClientMovement(ScenePresence avatar)
  460. {
  461. if (avatar.IsChildAgent || avatar.IsNPC)
  462. return;
  463. if (m_showBansLines && !m_scene.RegionInfo.EstateSettings.TaxFree)
  464. SendOutNearestBanLine(avatar.ControllingClient);
  465. }
  466. /// <summary>
  467. /// Like handleEventManagerOnSignificantClientMovement, but called with an AgentUpdate regardless of distance.
  468. /// </summary>
  469. /// <param name="avatar"></param>
  470. public void EventManagerOnClientMovement(ScenePresence avatar)
  471. {
  472. if (avatar.IsChildAgent)
  473. return;
  474. Vector3 pos = avatar.AbsolutePosition;
  475. ILandObject over = GetLandObject(pos.X, pos.Y);
  476. if (over is not null)
  477. {
  478. EnforceBans(over, avatar);
  479. pos = avatar.AbsolutePosition;
  480. ILandObject newover = GetLandObject(pos.X, pos.Y);
  481. if(over != newover || avatar.currentParcelUUID.NotEqual(newover.LandData.GlobalID))
  482. {
  483. m_scene.EventManager.TriggerAvatarEnteringNewParcel(avatar,
  484. newover.LandData.LocalID, m_scene.RegionInfo.RegionID);
  485. }
  486. }
  487. }
  488. public void ClientParcelBuyPass(IClientAPI remote_client, UUID targetID, int landLocalID)
  489. {
  490. ILandObject land;
  491. lock (m_landList)
  492. {
  493. m_landList.TryGetValue(landLocalID, out land);
  494. }
  495. // trivial checks
  496. if(land is null)
  497. return;
  498. LandData ldata = land.LandData;
  499. if(ldata is null)
  500. return;
  501. if (ldata.PassHours == 0)
  502. return;
  503. if (ldata.OwnerID.Equals(targetID))
  504. return;
  505. if (m_scene.RegionInfo.EstateSettings.TaxFree)
  506. return;
  507. // don't allow passes on group owned until we can give money to groups
  508. if (ldata.IsGroupOwned)
  509. {
  510. remote_client.SendAgentAlertMessage("pass to group owned parcel not suported", false);
  511. return;
  512. }
  513. if((ldata.Flags & (uint)ParcelFlags.UsePassList) == 0)
  514. return;
  515. int cost = ldata.PassPrice;
  516. int idx = land.LandData.ParcelAccessList.FindIndex(
  517. delegate(LandAccessEntry e)
  518. {
  519. if (e.Flags == AccessList.Access && e.AgentID.Equals(targetID))
  520. return true;
  521. return false;
  522. });
  523. int now = Util.UnixTimeSinceEpoch();
  524. int expires = (int)(3600.0 * ldata.PassHours + 0.5f);
  525. int currenttime = -1;
  526. if (idx != -1)
  527. {
  528. if(ldata.ParcelAccessList[idx].Expires == 0)
  529. {
  530. remote_client.SendAgentAlertMessage("You already have access to parcel", false);
  531. return;
  532. }
  533. currenttime = ldata.ParcelAccessList[idx].Expires - now;
  534. if(currenttime > (int)(0.25f * expires + 0.5f))
  535. {
  536. if(currenttime > 3600)
  537. remote_client.SendAgentAlertMessage(string.Format("You already have a pass valid for {0:0.###} hours",
  538. currenttime/3600f), false);
  539. else if(currenttime > 60)
  540. remote_client.SendAgentAlertMessage(string.Format("You already have a pass valid for {0:0.##} minutes",
  541. currenttime/60f), false);
  542. else
  543. remote_client.SendAgentAlertMessage(string.Format("You already have a pass valid for {0:0.#} seconds",
  544. currenttime), false);
  545. return;
  546. }
  547. }
  548. LandAccessEntry entry = new()
  549. {
  550. AgentID = targetID,
  551. Flags = AccessList.Access,
  552. Expires = now + expires
  553. };
  554. if (currenttime > 0)
  555. entry.Expires += currenttime;
  556. IMoneyModule mm = m_scene.RequestModuleInterface<IMoneyModule>();
  557. if(cost != 0 && mm is not null)
  558. {
  559. WorkManager.RunInThreadPool(
  560. delegate
  561. {
  562. string regionName = m_scene.RegionInfo.RegionName;
  563. if (!mm.AmountCovered(remote_client.AgentId, cost))
  564. {
  565. remote_client.SendAgentAlertMessage($"Insufficient funds in region '{regionName}' money system", true);
  566. return;
  567. }
  568. string payDescription = String.Format("Parcel '{0}' at region '{1} {2:0.###} hours access pass", ldata.Name, regionName, ldata.PassHours);
  569. if(!mm.MoveMoney(remote_client.AgentId, ldata.OwnerID, cost,MoneyTransactionType.LandPassSale, payDescription))
  570. {
  571. remote_client.SendAgentAlertMessage("Sorry pass payment processing failed, please try again later", true);
  572. return;
  573. }
  574. if (idx != -1)
  575. ldata.ParcelAccessList.RemoveAt(idx);
  576. ldata.ParcelAccessList.Add(entry);
  577. m_scene.EventManager.TriggerLandObjectUpdated((uint)land.LandData.LocalID, land);
  578. return;
  579. }, null, "ParcelBuyPass");
  580. }
  581. else
  582. {
  583. if (idx != -1)
  584. ldata.ParcelAccessList.RemoveAt(idx);
  585. ldata.ParcelAccessList.Add(entry);
  586. m_scene.EventManager.TriggerLandObjectUpdated((uint)land.LandData.LocalID, land);
  587. }
  588. }
  589. public void ClientOnParcelAccessListRequest(UUID agentID, UUID sessionID, uint flags, int sequenceID,
  590. int landLocalID, IClientAPI remote_client)
  591. {
  592. ILandObject land;
  593. lock (m_landList)
  594. {
  595. m_landList.TryGetValue(landLocalID, out land);
  596. }
  597. land?.SendAccessList(agentID, sessionID, flags, sequenceID, remote_client);
  598. }
  599. public void ClientOnParcelAccessListUpdateRequest(UUID agentID,
  600. uint flags, UUID transactionID, int landLocalID, List<LandAccessEntry> entries,
  601. IClientAPI remote_client)
  602. {
  603. if ((flags & 0x03) == 0)
  604. return; // we only have access and ban
  605. if(m_scene.RegionInfo.EstateSettings.TaxFree)
  606. return;
  607. ILandObject land;
  608. lock (m_landList)
  609. {
  610. _ = m_landList.TryGetValue(landLocalID, out land);
  611. }
  612. if (land is not null)
  613. {
  614. GroupPowers requiredPowers = GroupPowers.None;
  615. if ((flags & (uint)AccessList.Access) != 0)
  616. requiredPowers |= GroupPowers.LandManageAllowed;
  617. if ((flags & (uint)AccessList.Ban) != 0)
  618. requiredPowers |= GroupPowers.LandManageBanned;
  619. if(requiredPowers == GroupPowers.None)
  620. return;
  621. if (m_scene.Permissions.CanEditParcelProperties(agentID,
  622. land, requiredPowers, false))
  623. {
  624. land.UpdateAccessList(flags, transactionID, entries);
  625. }
  626. }
  627. else
  628. {
  629. m_log.Warn("[LAND MANAGEMENT MODULE]: Invalid local land ID " + landLocalID.ToString());
  630. }
  631. }
  632. /// <summary>
  633. /// Adds a land object to the stored list and adds them to the landIDList to what they own
  634. /// </summary>
  635. /// <param name="new_land">
  636. /// The land object being added.
  637. /// Will return null if this overlaps with an existing parcel that has not had its bitmap adjusted.
  638. /// </param>
  639. public ILandObject AddLandObject(ILandObject new_land)
  640. {
  641. // Only now can we add the prim counts to the land object - we rely on the global ID which is generated
  642. // as a random UUID inside LandData initialization
  643. if (m_primCountModule is not null)
  644. new_land.PrimCounts = m_primCountModule.GetPrimCounts(new_land.LandData.GlobalID);
  645. lock (m_landList)
  646. {
  647. int newLandLocalID = m_lastLandLocalID + 1;
  648. new_land.LandData.LocalID = newLandLocalID;
  649. bool[,] landBitmap = new_land.GetLandBitmap();
  650. if (landBitmap.GetLength(0) != m_landIDList.GetLength(0) || landBitmap.GetLength(1) != m_landIDList.GetLength(1))
  651. {
  652. // Going to variable sized regions can cause mismatches
  653. m_log.ErrorFormat("[LAND MANAGEMENT MODULE]: Added land bitmap has different size than region ID map. bitmapSize=({0},{1}), landIDSize=({2},{3})",
  654. landBitmap.GetLength(0), landBitmap.GetLength(1), m_landIDList.GetLength(0), m_landIDList.GetLength(1));
  655. }
  656. else
  657. {
  658. // If other land objects still believe that they occupy any parts of the same space,
  659. // then do not allow the add to proceed.
  660. for (int x = 0; x < landBitmap.GetLength(0); x++)
  661. {
  662. for (int y = 0; y < landBitmap.GetLength(1); y++)
  663. {
  664. if (landBitmap[x, y])
  665. {
  666. int lastRecordedLandId = m_landIDList[x, y];
  667. if (lastRecordedLandId > 0)
  668. {
  669. ILandObject lastRecordedLo = m_landList[lastRecordedLandId];
  670. if (lastRecordedLo.LandBitmap[x, y])
  671. {
  672. m_log.ErrorFormat(
  673. "[LAND MANAGEMENT MODULE]: Cannot add parcel \"{0}\", local ID {1} at tile {2},{3} because this is still occupied by parcel \"{4}\", local ID {5} in {6}",
  674. new_land.LandData.Name, new_land.LandData.LocalID, x, y,
  675. lastRecordedLo.LandData.Name, lastRecordedLo.LandData.LocalID, m_scene.Name);
  676. return null;
  677. }
  678. }
  679. }
  680. }
  681. }
  682. for (int x = 0; x < landBitmap.GetLength(0); x++)
  683. {
  684. for (int y = 0; y < landBitmap.GetLength(1); y++)
  685. {
  686. if (landBitmap[x, y])
  687. {
  688. //m_log.DebugFormat(
  689. // "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}",
  690. // new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName);
  691. m_landIDList[x, y] = newLandLocalID;
  692. }
  693. }
  694. }
  695. }
  696. m_landList.Add(newLandLocalID, new_land);
  697. m_landGlobalIDs[new_land.LandData.GlobalID] = newLandLocalID;
  698. m_landFakeIDs[new_land.LandData.FakeID] = newLandLocalID;
  699. m_lastLandLocalID++;
  700. }
  701. new_land.ForceUpdateLandInfo();
  702. m_scene.EventManager.TriggerLandObjectAdded(new_land);
  703. return new_land;
  704. }
  705. /// <summary>
  706. /// Removes a land object from the list. Will not remove if local_id is still owning an area in landIDList
  707. /// </summary>
  708. /// <param name="local_id">Land.localID of the peice of land to remove.</param>
  709. public void removeLandObject(int local_id)
  710. {
  711. ILandObject land;
  712. UUID landGlobalID = UUID.Zero;
  713. lock (m_landList)
  714. {
  715. for (int x = 0; x < m_landIDList.GetLength(0); x++)
  716. {
  717. for (int y = 0; y < m_landIDList.GetLength(1); y++)
  718. {
  719. if (m_landIDList[x, y] == local_id)
  720. {
  721. m_log.WarnFormat("[LAND MANAGEMENT MODULE]: Not removing land object {0}; still being used at {1}, {2}",
  722. local_id, x, y);
  723. return;
  724. //throw new Exception("Could not remove land object. Still being used at " + x + ", " + y);
  725. }
  726. }
  727. }
  728. land = m_landList[local_id];
  729. m_landList.Remove(local_id);
  730. if(land is not null && land.LandData is not null)
  731. {
  732. landGlobalID = land.LandData.GlobalID;
  733. m_landGlobalIDs.Remove(landGlobalID);
  734. m_landFakeIDs.Remove(land.LandData.FakeID);
  735. }
  736. }
  737. if(landGlobalID.IsNotZero())
  738. {
  739. m_scene.EventManager.TriggerLandObjectRemoved(landGlobalID);
  740. land.Clear();
  741. }
  742. }
  743. /// <summary>
  744. /// Clear the scene of all parcels
  745. /// </summary>
  746. public void Clear(bool setupDefaultParcel)
  747. {
  748. List<UUID> landworkList = new(m_landList.Count);
  749. // move to work pointer since we are deleting it all
  750. lock (m_landList)
  751. {
  752. foreach (ILandObject lo in m_landList.Values)
  753. landworkList.Add(lo.LandData.GlobalID);
  754. }
  755. // this 2 methods have locks (now)
  756. ResetSimLandObjects();
  757. if (setupDefaultParcel)
  758. CreateDefaultParcel();
  759. // fire outside events unlocked
  760. foreach (UUID id in landworkList)
  761. {
  762. //m_scene.SimulationDataService.RemoveLandObject(lo.LandData.GlobalID);
  763. m_scene.EventManager.TriggerLandObjectRemoved(id);
  764. }
  765. landworkList.Clear();
  766. }
  767. private void performFinalLandJoin(ILandObject master, ILandObject slave)
  768. {
  769. bool[,] landBitmapSlave = slave.GetLandBitmap();
  770. lock (m_landList)
  771. {
  772. for (int x = 0; x < landBitmapSlave.GetLength(0); x++)
  773. {
  774. for (int y = 0; y < landBitmapSlave.GetLength(1); y++)
  775. {
  776. if (landBitmapSlave[x, y])
  777. {
  778. m_landIDList[x, y] = master.LandData.LocalID;
  779. }
  780. }
  781. }
  782. }
  783. master.LandData.Dwell += slave.LandData.Dwell;
  784. removeLandObject(slave.LandData.LocalID);
  785. UpdateLandObject(master.LandData.LocalID, master.LandData);
  786. }
  787. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  788. public ILandObject GetLandObject(UUID globalID)
  789. {
  790. lock (m_landList)
  791. {
  792. if (m_landGlobalIDs.TryGetValue(globalID, out int lid))
  793. {
  794. if (m_landList.TryGetValue(lid, out ILandObject land))
  795. return land;
  796. else
  797. m_landGlobalIDs.Remove(globalID);
  798. }
  799. }
  800. return null;
  801. }
  802. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  803. public ILandObject GetLandObjectByfakeID(UUID fakeID)
  804. {
  805. lock (m_landList)
  806. {
  807. if (m_landFakeIDs.TryGetValue(fakeID, out int lid))
  808. {
  809. if (m_landList.TryGetValue(lid, out ILandObject land))
  810. return land;
  811. else
  812. m_landFakeIDs.Remove(fakeID);
  813. }
  814. }
  815. if(Util.ParseFakeParcelID(fakeID, out ulong rhandle, out uint x, out uint y) && rhandle == m_regionHandler)
  816. {
  817. return GetLandObjectClippedXY(x, y);
  818. }
  819. return null;
  820. }
  821. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  822. public ILandObject GetLandObject(int parcelLocalID)
  823. {
  824. lock (m_landList)
  825. {
  826. return m_landList.TryGetValue(parcelLocalID, out ILandObject land) ? land : null;
  827. }
  828. }
  829. /// <summary>
  830. /// Get the land object at the specified point
  831. /// </summary>
  832. /// <param name="x_float">Value between 0 - 256 on the x axis of the point</param>
  833. /// <param name="y_float">Value between 0 - 256 on the y axis of the point</param>
  834. /// <returns>Land object at the point supplied</returns>
  835. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  836. public ILandObject GetLandObject(float x_float, float y_float)
  837. {
  838. return GetLandObject((int)x_float, (int)y_float, true);
  839. }
  840. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  841. public ILandObject GetLandObject(Vector3 position)
  842. {
  843. return GetLandObject(position.X, position.Y);
  844. }
  845. // if x,y is off region this will return the parcel at cliped x,y
  846. // as did code it replaces
  847. public ILandObject GetLandObjectClippedXY(float x, float y)
  848. {
  849. int avx = (int)MathF.Round(x);
  850. if (avx < 0)
  851. avx = 0;
  852. else
  853. {
  854. if (avx >= m_regionSizeX)
  855. avx = m_regionSizeX - 1;
  856. avx /= Constants.LandUnit;
  857. }
  858. int avy = (int)MathF.Round(y);
  859. if (avy < 0)
  860. avy = 0;
  861. else
  862. {
  863. if (avy >= m_regionSizeY)
  864. avy = m_regionSizeY - 1;
  865. avy /= Constants.LandUnit;
  866. }
  867. lock (m_landIDList)
  868. {
  869. try
  870. {
  871. return m_landList[m_landIDList[avx, avy]];
  872. }
  873. catch (IndexOutOfRangeException)
  874. {
  875. return null;
  876. }
  877. }
  878. }
  879. // Public entry.
  880. // Throws exception if land object is not found
  881. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  882. public ILandObject GetLandObject(int x, int y)
  883. {
  884. return GetLandObject(x, y, false /* returnNullIfLandObjectNotFound */);
  885. }
  886. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  887. public ILandObject GetLandObject(int x, int y, bool returnNullIfLandObjectOutsideBounds)
  888. {
  889. if (x >= m_regionSizeX || y >= m_regionSizeY || x < 0 || y < 0)
  890. {
  891. // These exceptions here will cause a lot of complaints from the users specifically because
  892. // they happen every time at border crossings
  893. if (returnNullIfLandObjectOutsideBounds)
  894. return null;
  895. else
  896. throw new Exception("Error: Parcel not found at point " + x + ", " + y);
  897. }
  898. if(m_landList.Count == 0 || m_landIDList is null)
  899. return null;
  900. lock (m_landIDList)
  901. {
  902. try
  903. {
  904. return m_landList[m_landIDList[x / Constants.LandUnit, y / Constants.LandUnit]];
  905. }
  906. catch (IndexOutOfRangeException)
  907. {
  908. return null;
  909. }
  910. }
  911. }
  912. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  913. public ILandObject GetLandObjectinLandUnits(int x, int y)
  914. {
  915. if (m_landList.Count == 0 || m_landIDList is null)
  916. return null;
  917. lock (m_landIDList)
  918. {
  919. try
  920. {
  921. return m_landList[m_landIDList[x, y]];
  922. }
  923. catch (IndexOutOfRangeException)
  924. {
  925. return null;
  926. }
  927. }
  928. }
  929. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  930. public ILandObject GetLandObjectinLandUnitsInt(int x, int y)
  931. {
  932. lock (m_landIDList)
  933. {
  934. try
  935. {
  936. return m_landList[m_landIDList[x, y]];
  937. }
  938. catch (IndexOutOfRangeException)
  939. {
  940. return null;
  941. }
  942. }
  943. }
  944. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  945. public int GetLandObjectIDinLandUnits(int x, int y)
  946. {
  947. lock (m_landIDList)
  948. {
  949. try
  950. {
  951. return m_landIDList[x, y];
  952. }
  953. catch (IndexOutOfRangeException)
  954. {
  955. return -1;
  956. }
  957. }
  958. }
  959. // Create a 'parcel is here' bitmap for the parcel identified by the passed landID
  960. private bool[,] CreateBitmapForID(int landID)
  961. {
  962. bool[,] ret = new bool[m_landIDList.GetLength(0), m_landIDList.GetLength(1)];
  963. for (int xx = 0; xx < m_landIDList.GetLength(0); xx++)
  964. for (int yy = 0; yy < m_landIDList.GetLength(1); yy++)
  965. if (m_landIDList[xx, yy] == landID)
  966. ret[xx, yy] = true;
  967. return ret;
  968. }
  969. #endregion
  970. #region Parcel Modification
  971. public void ResetOverMeRecords()
  972. {
  973. lock (m_landList)
  974. {
  975. foreach (LandObject p in m_landList.Values)
  976. {
  977. p.ResetOverMeRecord();
  978. }
  979. }
  980. }
  981. public void EventManagerOnParcelPrimCountAdd(SceneObjectGroup obj)
  982. {
  983. Vector3 position = obj.AbsolutePosition;
  984. ILandObject landUnderPrim = GetLandObject(position.X, position.Y);
  985. if (landUnderPrim is not null)
  986. {
  987. ((LandObject)landUnderPrim).AddPrimOverMe(obj);
  988. }
  989. }
  990. public void EventManagerOnObjectBeingRemovedFromScene(SceneObjectGroup obj)
  991. {
  992. lock (m_landList)
  993. {
  994. foreach (LandObject p in m_landList.Values)
  995. {
  996. p.RemovePrimFromOverMe(obj);
  997. }
  998. }
  999. }
  1000. private void FinalizeLandPrimCountUpdate()
  1001. {
  1002. //Get Simwide prim count for owner
  1003. Dictionary<UUID, List<LandObject>> landOwnersAndParcels = new();
  1004. lock (m_landList)
  1005. {
  1006. foreach (LandObject p in m_landList.Values)
  1007. {
  1008. if (!landOwnersAndParcels.TryGetValue(p.LandData.OwnerID, out List<LandObject> ownerlist))
  1009. {
  1010. ownerlist = new(){ p };
  1011. landOwnersAndParcels.Add(p.LandData.OwnerID, ownerlist);
  1012. }
  1013. else
  1014. {
  1015. ownerlist.Add(p);
  1016. }
  1017. }
  1018. }
  1019. foreach (UUID owner in landOwnersAndParcels.Keys)
  1020. {
  1021. int simArea = 0;
  1022. int simPrims = 0;
  1023. foreach (LandObject p in landOwnersAndParcels[owner])
  1024. {
  1025. simArea += p.LandData.Area;
  1026. simPrims += p.PrimCounts.Total;
  1027. }
  1028. foreach (LandObject p in landOwnersAndParcels[owner])
  1029. {
  1030. p.LandData.SimwideArea = simArea;
  1031. p.LandData.SimwidePrims = simPrims;
  1032. }
  1033. }
  1034. }
  1035. public void EventManagerOnParcelPrimCountUpdate()
  1036. {
  1037. //m_log.DebugFormat(
  1038. // "[land management module]: triggered eventmanageronparcelprimcountupdate() for {0}",
  1039. // m_scene.RegionInfo.RegionName);
  1040. ResetOverMeRecords();
  1041. EntityBase[] entities = m_scene.Entities.GetEntities();
  1042. foreach (EntityBase obj in entities)
  1043. {
  1044. if (obj is SceneObjectGroup sog && !sog.IsDeleted && !sog.IsAttachment)
  1045. {
  1046. m_scene.EventManager.TriggerParcelPrimCountAdd(sog);
  1047. }
  1048. }
  1049. FinalizeLandPrimCountUpdate();
  1050. }
  1051. public void EventManagerOnRequestParcelPrimCountUpdate()
  1052. {
  1053. ResetOverMeRecords();
  1054. m_scene.EventManager.TriggerParcelPrimCountUpdate();
  1055. FinalizeLandPrimCountUpdate();
  1056. }
  1057. /// <summary>
  1058. /// Subdivides a piece of land
  1059. /// </summary>
  1060. /// <param name="start_x">West Point</param>
  1061. /// <param name="start_y">South Point</param>
  1062. /// <param name="end_x">East Point</param>
  1063. /// <param name="end_y">North Point</param>
  1064. /// <param name="attempting_user_id">UUID of user who is trying to subdivide</param>
  1065. /// <returns>Returns true if successful</returns>
  1066. public void Subdivide(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id)
  1067. {
  1068. //First, lets loop through the points and make sure they are all in the same peice of land
  1069. //Get the land object at start
  1070. ILandObject startLandObject = GetLandObject(start_x, start_y);
  1071. if (startLandObject is null)
  1072. return;
  1073. if (!m_scene.Permissions.CanEditParcelProperties(attempting_user_id, startLandObject, GroupPowers.LandDivideJoin, true))
  1074. return;
  1075. //Loop through the points
  1076. int area = 0;
  1077. try
  1078. {
  1079. for (int x = start_x; x < end_x; x++)
  1080. {
  1081. for (int y = start_y; y < end_y; y++)
  1082. {
  1083. ILandObject tempLandObject = GetLandObject(x, y);
  1084. if (tempLandObject is null)
  1085. return;
  1086. if (tempLandObject != startLandObject)
  1087. return;
  1088. area++;
  1089. }
  1090. }
  1091. }
  1092. catch (Exception)
  1093. {
  1094. return;
  1095. }
  1096. LandData startLandData = startLandObject.LandData;
  1097. if (area >= startLandData.Area)
  1098. {
  1099. // split is a replace, keep as is
  1100. return;
  1101. }
  1102. //Lets create a new land object with bitmap activated at that point (keeping the old land objects info)
  1103. ILandObject newLand = startLandObject.Copy();
  1104. LandData newLandData = newLand.LandData;
  1105. newLandData.GlobalID = UUID.Random();
  1106. newLandData.Dwell = 0;
  1107. // Clear "Show in search" on the cut out parcel to prevent double-charging
  1108. newLandData.Flags &= ~(uint)ParcelFlags.ShowDirectory;
  1109. // invalidate landing point
  1110. newLandData.LandingType = (byte)LandingType.Direct;
  1111. newLandData.UserLocation = Vector3.Zero;
  1112. newLandData.UserLookAt = Vector3.Zero;
  1113. newLand.SetLandBitmap(newLand.GetSquareLandBitmap(start_x, start_y, end_x, end_y));
  1114. //lets set the subdivision area of the original to false
  1115. int startLandObjectIndex = startLandObject.LandData.LocalID;
  1116. lock (m_landList)
  1117. {
  1118. m_landList[startLandObjectIndex].SetLandBitmap(newLand.ModifyLandBitmapSquare(startLandObject.GetLandBitmap(), start_x, start_y, end_x, end_y, false));
  1119. //m_landList[startLandObjectIndex].ForceUpdateLandInfo();
  1120. }
  1121. UpdateLandObject(startLandObject.LandData.LocalID, startLandObject.LandData);
  1122. //add the new land object
  1123. ILandObject result = AddLandObject(newLand);
  1124. if (startLandObject.LandData.LandingType == (byte)LandingType.LandingPoint)
  1125. {
  1126. int x = (int)startLandObject.LandData.UserLocation.X;
  1127. int y = (int)startLandObject.LandData.UserLocation.Y;
  1128. if(!startLandObject.ContainsPoint(x, y))
  1129. {
  1130. startLandObject.LandData.LandingType = (byte)LandingType.Direct;
  1131. startLandObject.LandData.UserLocation = Vector3.Zero;
  1132. startLandObject.LandData.UserLookAt = Vector3.Zero;
  1133. }
  1134. }
  1135. m_scene.EventManager.TriggerParcelPrimCountTainted();
  1136. result.SendLandUpdateToAvatarsOverMe();
  1137. startLandObject.SendLandUpdateToAvatarsOverMe();
  1138. m_scene.ForEachClient(SendParcelOverlay);
  1139. }
  1140. /// <summary>
  1141. /// Join 2 land objects together
  1142. /// </summary>
  1143. /// <param name="start_x">start x of selection area</param>
  1144. /// <param name="start_y">start y of selection area</param>
  1145. /// <param name="end_x">end x of selection area</param>
  1146. /// <param name="end_y">end y of selection area</param>
  1147. /// <param name="attempting_user_id">UUID of the avatar trying to join the land objects</param>
  1148. /// <returns>Returns true if successful</returns>
  1149. public void Join(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id)
  1150. {
  1151. int index = 0;
  1152. int maxindex = -1;
  1153. int maxArea = 0;
  1154. List<ILandObject> selectedLandObjects = new();
  1155. for (int x = start_x; x < end_x; x += 4)
  1156. {
  1157. for (int y = start_y; y < end_y; y += 4)
  1158. {
  1159. ILandObject p = GetLandObject(x, y);
  1160. if (p is not null)
  1161. {
  1162. if (!selectedLandObjects.Contains(p))
  1163. {
  1164. selectedLandObjects.Add(p);
  1165. if(p.LandData.Area > maxArea)
  1166. {
  1167. maxArea = p.LandData.Area;
  1168. maxindex = index;
  1169. }
  1170. index++;
  1171. }
  1172. }
  1173. }
  1174. }
  1175. if(maxindex < 0 || selectedLandObjects.Count < 2)
  1176. return;
  1177. ILandObject masterLandObject = selectedLandObjects[maxindex];
  1178. selectedLandObjects.RemoveAt(maxindex);
  1179. if (!m_scene.Permissions.CanEditParcelProperties(attempting_user_id, masterLandObject, GroupPowers.LandDivideJoin, true))
  1180. {
  1181. return;
  1182. }
  1183. UUID masterOwner = masterLandObject.LandData.OwnerID;
  1184. foreach (ILandObject p in selectedLandObjects)
  1185. {
  1186. if (p.LandData.OwnerID.NotEqual(masterOwner))
  1187. return;
  1188. }
  1189. lock (m_landList)
  1190. {
  1191. foreach (ILandObject slaveLandObject in selectedLandObjects)
  1192. {
  1193. m_landList[masterLandObject.LandData.LocalID].SetLandBitmap(
  1194. slaveLandObject.MergeLandBitmaps(masterLandObject.GetLandBitmap(), slaveLandObject.GetLandBitmap()));
  1195. performFinalLandJoin(masterLandObject, slaveLandObject);
  1196. }
  1197. }
  1198. m_scene.EventManager.TriggerParcelPrimCountTainted();
  1199. masterLandObject.SendLandUpdateToAvatarsOverMe();
  1200. m_scene.ForEachClient(SendParcelOverlay);
  1201. }
  1202. #endregion
  1203. #region Parcel Updating
  1204. //legacy name
  1205. public void SendParcelsOverlay(IClientAPI client)
  1206. {
  1207. SendParcelOverlay(client);
  1208. }
  1209. /// <summary>
  1210. /// Send the parcel overlay blocks to the client.
  1211. /// </summary>
  1212. /// <param name="remote_client">The object representing the client</param>
  1213. public void SendParcelOverlay(IClientAPI remote_client)
  1214. {
  1215. if (remote_client.SceneAgent.PresenceType == PresenceType.Npc)
  1216. return;
  1217. const int LAND_BLOCKS_PER_PACKET = 1024;
  1218. int curID;
  1219. int southID;
  1220. byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET];
  1221. int byteArrayCount = 0;
  1222. int sequenceID = 0;
  1223. int sx = m_regionSizeX / Constants.LandUnit;
  1224. byte curByte;
  1225. byte tmpByte;
  1226. // Layer data is in LandUnit (4m) chunks
  1227. for (int y = 0; y < m_regionSizeY / Constants.LandUnit; ++y)
  1228. {
  1229. for (int x = 0; x < sx;)
  1230. {
  1231. curID = GetLandObjectIDinLandUnits(x,y);
  1232. if(curID < 0)
  1233. continue;
  1234. ILandObject currentParcel = GetLandObject(curID);
  1235. if (currentParcel is null)
  1236. continue;
  1237. LandData currentParcelLandData = currentParcel.LandData;
  1238. if (currentParcelLandData is null)
  1239. continue;
  1240. // types
  1241. if (currentParcelLandData.OwnerID.Equals(remote_client.AgentId))
  1242. {
  1243. //Owner Flag
  1244. curByte = LandChannel.LAND_TYPE_OWNED_BY_REQUESTER;
  1245. }
  1246. else if (currentParcelLandData.IsGroupOwned && remote_client.IsGroupMember(currentParcelLandData.GroupID))
  1247. {
  1248. curByte = LandChannel.LAND_TYPE_OWNED_BY_GROUP;
  1249. }
  1250. else if (currentParcelLandData.SalePrice > 0 &&
  1251. (currentParcelLandData.AuthBuyerID.IsZero() ||
  1252. currentParcelLandData.AuthBuyerID.Equals(remote_client.AgentId)))
  1253. {
  1254. //Sale type
  1255. curByte = LandChannel.LAND_TYPE_IS_FOR_SALE;
  1256. }
  1257. else if (currentParcelLandData.OwnerID.IsZero())
  1258. {
  1259. //Public type
  1260. curByte = LandChannel.LAND_TYPE_PUBLIC; // this does nothing, its zero
  1261. }
  1262. // LAND_TYPE_IS_BEING_AUCTIONED still unsuported
  1263. else
  1264. {
  1265. //Other
  1266. curByte = LandChannel.LAND_TYPE_OWNED_BY_OTHER;
  1267. }
  1268. // now flags
  1269. // local sound
  1270. if ((currentParcelLandData.Flags & (uint)ParcelFlags.SoundLocal) != 0)
  1271. curByte |= (byte)LandChannel.LAND_FLAG_LOCALSOUND;
  1272. // hide avatars
  1273. if (!currentParcelLandData.SeeAVs)
  1274. curByte |= (byte)LandChannel.LAND_FLAG_HIDEAVATARS;
  1275. // border flags for current
  1276. if (y == 0)
  1277. {
  1278. curByte |= LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH;
  1279. tmpByte = curByte;
  1280. }
  1281. else
  1282. {
  1283. tmpByte = curByte;
  1284. southID = GetLandObjectIDinLandUnits(x, (y - 1));
  1285. if (southID >= 0 && southID != curID)
  1286. tmpByte |= LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH;
  1287. }
  1288. tmpByte |= LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST;
  1289. byteArray[byteArrayCount] = tmpByte;
  1290. byteArrayCount++;
  1291. if (byteArrayCount >= LAND_BLOCKS_PER_PACKET)
  1292. {
  1293. remote_client.SendLandParcelOverlay(byteArray, sequenceID);
  1294. byteArrayCount = 0;
  1295. sequenceID++;
  1296. byteArray = new byte[LAND_BLOCKS_PER_PACKET];
  1297. }
  1298. // keep adding while on same parcel, checking south border
  1299. if (y == 0)
  1300. {
  1301. // all have south border and that is already on curByte
  1302. while (++x < sx && GetLandObjectIDinLandUnits(x, y) == curID)
  1303. {
  1304. byteArray[byteArrayCount] = curByte;
  1305. byteArrayCount++;
  1306. if (byteArrayCount >= LAND_BLOCKS_PER_PACKET)
  1307. {
  1308. remote_client.SendLandParcelOverlay(byteArray, sequenceID);
  1309. byteArrayCount = 0;
  1310. sequenceID++;
  1311. byteArray = new byte[LAND_BLOCKS_PER_PACKET];
  1312. }
  1313. }
  1314. }
  1315. else
  1316. {
  1317. while (++x < sx && GetLandObjectIDinLandUnits(x, y) == curID)
  1318. {
  1319. // need to check south one by one
  1320. southID = GetLandObjectIDinLandUnits(x, (y - 1));
  1321. if (southID >= 0 && southID != curID)
  1322. {
  1323. tmpByte = curByte;
  1324. tmpByte |= LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH;
  1325. byteArray[byteArrayCount] = tmpByte;
  1326. }
  1327. else
  1328. byteArray[byteArrayCount] = curByte;
  1329. byteArrayCount++;
  1330. if (byteArrayCount >= LAND_BLOCKS_PER_PACKET)
  1331. {
  1332. remote_client.SendLandParcelOverlay(byteArray, sequenceID);
  1333. byteArrayCount = 0;
  1334. sequenceID++;
  1335. byteArray = new byte[LAND_BLOCKS_PER_PACKET];
  1336. }
  1337. }
  1338. }
  1339. }
  1340. }
  1341. if (byteArrayCount > 0)
  1342. {
  1343. remote_client.SendLandParcelOverlay(byteArray, sequenceID);
  1344. }
  1345. }
  1346. public void ClientOnParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id,
  1347. bool snap_selection, IClientAPI remote_client)
  1348. {
  1349. if (m_landList.Count == 0 || m_landIDList is null)
  1350. return;
  1351. if (start_x < 0 || start_y < 0 || end_x < 0 || end_y < 0)
  1352. return;
  1353. if (start_x >= m_regionSizeX || start_y >= m_regionSizeX || end_x > m_regionSizeX || end_y > m_regionSizeY)
  1354. return;
  1355. if (end_x - start_x <= Constants.LandUnit &&
  1356. end_y - start_y <= Constants.LandUnit)
  1357. {
  1358. ILandObject parcel = GetLandObject(start_x, start_y);
  1359. parcel?.SendLandProperties(sequence_id, snap_selection, LandChannel.LAND_RESULT_SINGLE, remote_client);
  1360. return;
  1361. }
  1362. start_x /= Constants.LandUnit;
  1363. start_y /= Constants.LandUnit;
  1364. end_x /= Constants.LandUnit;
  1365. end_y /= Constants.LandUnit;
  1366. //Get the land objects within the bounds
  1367. Dictionary<int, ILandObject> temp = new();
  1368. for (int x = start_x; x < end_x; ++x)
  1369. {
  1370. for (int y = start_y; y < end_y; ++y)
  1371. {
  1372. ILandObject currentParcel = GetLandObjectinLandUnits(x, y);
  1373. if (currentParcel is not null)
  1374. {
  1375. if (!temp.ContainsKey(currentParcel.LandData.LocalID))
  1376. {
  1377. if (!currentParcel.IsBannedFromLand(remote_client.AgentId))
  1378. {
  1379. temp[currentParcel.LandData.LocalID] = currentParcel;
  1380. }
  1381. }
  1382. }
  1383. }
  1384. }
  1385. int requestResult = (temp.Count > 1) ? LandChannel.LAND_RESULT_MULTIPLE : LandChannel.LAND_RESULT_SINGLE;
  1386. foreach(ILandObject lo in temp.Values)
  1387. {
  1388. lo.SendLandProperties(sequence_id, snap_selection, requestResult, remote_client);
  1389. }
  1390. //SendParcelOverlay(remote_client);
  1391. }
  1392. public void UpdateLandProperties(ILandObject land, LandUpdateArgs args, IClientAPI remote_client)
  1393. {
  1394. if (land.UpdateLandProperties(args, remote_client, out bool snap_selection, out bool needOverlay))
  1395. {
  1396. UUID parcelID = land.LandData.GlobalID;
  1397. m_scene.ForEachScenePresence(delegate (ScenePresence avatar)
  1398. {
  1399. if (avatar.IsDeleted || avatar.IsNPC)
  1400. return;
  1401. IClientAPI client = avatar.ControllingClient;
  1402. if (needOverlay)
  1403. SendParcelOverlay(client);
  1404. if (avatar.IsChildAgent)
  1405. {
  1406. land.SendLandProperties(-10000, false, LandChannel.LAND_RESULT_SINGLE, client);
  1407. return;
  1408. }
  1409. ILandObject aland = GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
  1410. if (aland is not null)
  1411. {
  1412. if (land != aland)
  1413. land.SendLandProperties(-10000, false, LandChannel.LAND_RESULT_SINGLE, client);
  1414. else if (land == aland)
  1415. aland.SendLandProperties(0, true, LandChannel.LAND_RESULT_SINGLE, client);
  1416. }
  1417. if (avatar.currentParcelUUID.Equals(parcelID))
  1418. avatar.currentParcelUUID = parcelID; // force parcel flags review
  1419. });
  1420. }
  1421. }
  1422. public void ClientOnParcelPropertiesUpdateRequest(LandUpdateArgs args, int localID, IClientAPI remote_client)
  1423. {
  1424. ILandObject land;
  1425. lock (m_landList)
  1426. {
  1427. if(!m_landList.TryGetValue(localID, out land) || land is null)
  1428. return;
  1429. }
  1430. UpdateLandProperties(land, args, remote_client);
  1431. m_scene.EventManager.TriggerOnParcelPropertiesUpdateRequest(args, localID, remote_client);
  1432. }
  1433. public void ClientOnParcelDivideRequest(int west, int south, int east, int north, IClientAPI remote_client)
  1434. {
  1435. Subdivide(west, south, east, north, remote_client.AgentId);
  1436. }
  1437. public void ClientOnParcelJoinRequest(int west, int south, int east, int north, IClientAPI remote_client)
  1438. {
  1439. Join(west, south, east, north, remote_client.AgentId);
  1440. }
  1441. public void ClientOnParcelSelectObjects(int local_id, int request_type,
  1442. List<UUID> returnIDs, IClientAPI remote_client)
  1443. {
  1444. m_landList[local_id].SendForceObjectSelect(local_id, request_type, returnIDs, remote_client);
  1445. }
  1446. public void ClientOnParcelObjectOwnerRequest(int local_id, IClientAPI remote_client)
  1447. {
  1448. ILandObject land;
  1449. lock (m_landList)
  1450. {
  1451. if(!m_landList.TryGetValue(local_id, out land) || land is null)
  1452. return;
  1453. }
  1454. m_scene.EventManager.TriggerParcelPrimCountUpdate();
  1455. land.SendLandObjectOwners(remote_client);
  1456. }
  1457. public void ClientOnParcelGodForceOwner(int local_id, UUID ownerID, IClientAPI remote_client)
  1458. {
  1459. if (!m_scene.Permissions.IsGod(remote_client.AgentId))
  1460. return;
  1461. ILandObject land;
  1462. lock (m_landList)
  1463. {
  1464. if (!m_landList.TryGetValue(local_id, out land) || land is null)
  1465. return;
  1466. }
  1467. land.LandData.OwnerID = ownerID;
  1468. land.LandData.GroupID = UUID.Zero;
  1469. land.LandData.IsGroupOwned = false;
  1470. land.LandData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory);
  1471. UpdateLandObject(land.LandData.LocalID, land.LandData);
  1472. m_scene.ForEachClient(SendParcelOverlay);
  1473. land.SendLandUpdateToClient(true, remote_client);
  1474. }
  1475. public void ClientOnParcelAbandonRequest(int local_id, IClientAPI remote_client)
  1476. {
  1477. ILandObject land;
  1478. lock (m_landList)
  1479. {
  1480. if (!m_landList.TryGetValue(local_id, out land) || land is null)
  1481. return;
  1482. }
  1483. if (m_scene.Permissions.CanAbandonParcel(remote_client.AgentId, land))
  1484. {
  1485. land.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
  1486. land.LandData.GroupID = UUID.Zero;
  1487. land.LandData.IsGroupOwned = false;
  1488. land.LandData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory);
  1489. UpdateLandObject(land.LandData.LocalID, land.LandData);
  1490. m_scene.ForEachClient(SendParcelOverlay);
  1491. land.SendLandUpdateToAvatars();
  1492. }
  1493. }
  1494. public void ClientOnParcelReclaim(int local_id, IClientAPI remote_client)
  1495. {
  1496. ILandObject land;
  1497. lock (m_landList)
  1498. {
  1499. if (!m_landList.TryGetValue(local_id, out land) || land is null)
  1500. return;
  1501. }
  1502. if (m_scene.Permissions.CanReclaimParcel(remote_client.AgentId, land))
  1503. {
  1504. land.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
  1505. land.LandData.ClaimDate = Util.UnixTimeSinceEpoch();
  1506. land.LandData.GroupID = UUID.Zero;
  1507. land.LandData.IsGroupOwned = false;
  1508. land.LandData.SalePrice = 0;
  1509. land.LandData.AuthBuyerID = UUID.Zero;
  1510. land.LandData.SeeAVs = true;
  1511. land.LandData.AnyAVSounds = true;
  1512. land.LandData.GroupAVSounds = true;
  1513. land.LandData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory);
  1514. UpdateLandObject(land.LandData.LocalID, land.LandData);
  1515. m_scene.ForEachClient(SendParcelOverlay);
  1516. land.SendLandUpdateToAvatars();
  1517. }
  1518. }
  1519. #endregion
  1520. // If the economy has been validated by the economy module,
  1521. // and land has been validated as well, this method transfers
  1522. // the land ownership
  1523. public void EventManagerOnLandBuy(Object o, EventManager.LandBuyArgs e)
  1524. {
  1525. if (e.economyValidated && e.landValidated)
  1526. {
  1527. ILandObject land;
  1528. lock (m_landList)
  1529. {
  1530. if (!m_landList.TryGetValue(e.parcelLocalID, out land) || land is null)
  1531. return;
  1532. }
  1533. land.UpdateLandSold(e.agentId, e.groupId, e.groupOwned, (uint)e.transactionID, e.parcelPrice, e.parcelArea);
  1534. m_scene.ForEachClient(SendParcelOverlay);
  1535. land.SendLandUpdateToAvatars();
  1536. }
  1537. }
  1538. // After receiving a land buy packet, first the data needs to
  1539. // be validated. This method validates the right to buy the
  1540. // parcel
  1541. public void EventManagerOnValidateLandBuy(Object o, EventManager.LandBuyArgs e)
  1542. {
  1543. if (e.landValidated == false)
  1544. {
  1545. ILandObject land;
  1546. lock (m_landList)
  1547. {
  1548. if (!m_landList.TryGetValue(e.parcelLocalID, out land) || land is null)
  1549. return;
  1550. }
  1551. UUID AuthorizedID = land.LandData.AuthBuyerID;
  1552. int saleprice = land.LandData.SalePrice;
  1553. UUID pOwnerID = land.LandData.OwnerID;
  1554. bool landforsale = ((land.LandData.Flags &
  1555. (uint)(ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects)) != 0);
  1556. if ((AuthorizedID.IsZero() || AuthorizedID.Equals(e.agentId)) && e.parcelPrice >= saleprice && landforsale)
  1557. {
  1558. // TODO I don't think we have to lock it here, no?
  1559. //lock (e)
  1560. //{
  1561. e.parcelOwnerID = pOwnerID;
  1562. e.landValidated = true;
  1563. //}
  1564. }
  1565. }
  1566. }
  1567. void ClientOnParcelDeedToGroup(int parcelLocalID, UUID groupID, IClientAPI remote_client)
  1568. {
  1569. ILandObject land;
  1570. lock (m_landList)
  1571. {
  1572. if(!m_landList.TryGetValue(parcelLocalID, out land) || land is null)
  1573. return;
  1574. }
  1575. if (!m_scene.Permissions.CanDeedParcel(remote_client.AgentId, land))
  1576. return;
  1577. land.DeedToGroup(groupID);
  1578. m_scene.ForEachClient(SendParcelOverlay);
  1579. land.SendLandUpdateToAvatars();
  1580. }
  1581. #region Land Object From Storage Functions
  1582. private void EventManagerOnIncomingLandDataFromStorage(List<LandData> data)
  1583. {
  1584. lock (m_landList)
  1585. {
  1586. for (int i = 0; i < data.Count; i++)
  1587. IncomingLandObjectFromStorage(data[i]);
  1588. // Layer data is in LandUnit (4m) chunks
  1589. for (int y = 0; y < m_regionSizeY / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / Constants.LandUnit); y++)
  1590. {
  1591. for (int x = 0; x < m_regionSizeX / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / Constants.LandUnit); x++)
  1592. {
  1593. if (m_landIDList[x, y] == 0)
  1594. {
  1595. if (m_landList.Count == 1)
  1596. {
  1597. m_log.DebugFormat(
  1598. "[LAND MANAGEMENT MODULE]: Auto-extending land parcel as landID at {0},{1} is 0 and only one land parcel is present in {2}",
  1599. x, y, m_scene.Name);
  1600. int onlyParcelID = 0;
  1601. ILandObject onlyLandObject = null;
  1602. foreach (KeyValuePair<int, ILandObject> kvp in m_landList)
  1603. {
  1604. onlyParcelID = kvp.Key;
  1605. onlyLandObject = kvp.Value;
  1606. break;
  1607. }
  1608. // There is only one parcel. Grow it to fill all the unallocated spaces.
  1609. for (int xx = 0; xx < m_landIDList.GetLength(0); xx++)
  1610. for (int yy = 0; yy < m_landIDList.GetLength(1); yy++)
  1611. if (m_landIDList[xx, yy] == 0)
  1612. m_landIDList[xx, yy] = onlyParcelID;
  1613. onlyLandObject.LandBitmap = CreateBitmapForID(onlyParcelID);
  1614. }
  1615. else if (m_landList.Count > 1)
  1616. {
  1617. m_log.DebugFormat(
  1618. "[LAND MANAGEMENT MODULE]: Auto-creating land parcel as landID at {0},{1} is 0 and more than one land parcel is present in {2}",
  1619. x, y, m_scene.Name);
  1620. // There are several other parcels so we must create a new one for the unassigned space
  1621. ILandObject newLand = new LandObject(UUID.Zero, false, m_scene);
  1622. // Claim all the unclaimed "0" ids
  1623. newLand.SetLandBitmap(CreateBitmapForID(0));
  1624. newLand.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
  1625. newLand.LandData.ClaimDate = Util.UnixTimeSinceEpoch();
  1626. newLand = AddLandObject(newLand);
  1627. }
  1628. else
  1629. {
  1630. // We should never reach this point as the separate code path when no land data exists should have fired instead.
  1631. m_log.Warn(
  1632. "[LAND MANAGEMENT MODULE]: Ignoring request to auto-create parcel in {1} as there are no other parcels present" + m_scene.Name);
  1633. }
  1634. }
  1635. }
  1636. }
  1637. FinalizeLandPrimCountUpdate(); // update simarea information
  1638. lock (m_landList)
  1639. {
  1640. foreach(LandObject lo in m_landList.Values)
  1641. lo.SendLandUpdateToAvatarsOverMe();
  1642. }
  1643. }
  1644. }
  1645. private void IncomingLandObjectFromStorage(LandData data)
  1646. {
  1647. ILandObject new_land = new LandObject(data.OwnerID, data.IsGroupOwned, m_scene, data);
  1648. new_land.SetLandBitmapFromByteArray();
  1649. AddLandObject(new_land);
  1650. }
  1651. public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient)
  1652. {
  1653. if (localID != -1)
  1654. {
  1655. ILandObject selectedParcel;
  1656. lock (m_landList)
  1657. {
  1658. if(!m_landList.TryGetValue(localID, out selectedParcel) || selectedParcel is null)
  1659. return;
  1660. }
  1661. selectedParcel.ReturnLandObjects(returnType, agentIDs, taskIDs, remoteClient);
  1662. }
  1663. else
  1664. {
  1665. if (returnType != 1)
  1666. {
  1667. m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: unknown return type {0}", returnType);
  1668. return;
  1669. }
  1670. // We get here when the user returns objects from the list of Top Colliders or Top Scripts.
  1671. // In that case we receive specific object UUID's, but no parcel ID.
  1672. Dictionary<UUID, HashSet<SceneObjectGroup>> returns = new();
  1673. foreach (UUID groupID in taskIDs)
  1674. {
  1675. SceneObjectGroup obj = m_scene.GetSceneObjectGroup(groupID);
  1676. if (obj is not null)
  1677. {
  1678. if (!returns.TryGetValue(obj.OwnerID, out HashSet<SceneObjectGroup> howner))
  1679. {
  1680. howner = new HashSet<SceneObjectGroup>();
  1681. returns[obj.OwnerID] = howner;
  1682. }
  1683. howner.Add(obj);
  1684. }
  1685. else
  1686. {
  1687. m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: unknown object {0}", groupID);
  1688. }
  1689. }
  1690. int num = 0;
  1691. foreach (HashSet<SceneObjectGroup> objs in returns.Values)
  1692. num += objs.Count;
  1693. m_log.DebugFormat("[LAND MANAGEMENT MODULE]: Returning {0} specific object(s)", num);
  1694. foreach (HashSet<SceneObjectGroup> objs in returns.Values)
  1695. {
  1696. List<SceneObjectGroup> objs2 = new(objs);
  1697. if (m_scene.Permissions.CanReturnObjects(null, remoteClient, objs2))
  1698. {
  1699. m_scene.returnObjects(objs2.ToArray(), remoteClient);
  1700. }
  1701. else
  1702. {
  1703. m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: not permitted to return {0} object(s) belonging to user {1}",
  1704. objs2.Count, objs2[0].OwnerID);
  1705. }
  1706. }
  1707. }
  1708. }
  1709. public void EventManagerOnNoLandDataFromStorage()
  1710. {
  1711. ResetSimLandObjects();
  1712. CreateDefaultParcel();
  1713. }
  1714. #endregion
  1715. public void setParcelObjectMaxOverride(overrideParcelMaxPrimCountDelegate overrideDel)
  1716. {
  1717. lock (m_landList)
  1718. {
  1719. foreach (LandObject obj in m_landList.Values)
  1720. {
  1721. obj.SetParcelObjectMaxOverride(overrideDel);
  1722. }
  1723. }
  1724. }
  1725. public void setSimulatorObjectMaxOverride(overrideSimulatorMaxPrimCountDelegate overrideDel)
  1726. {
  1727. }
  1728. #region CAPS handler
  1729. private void EventManagerOnRegisterCaps(UUID agentID, Caps caps)
  1730. {
  1731. caps.RegisterSimpleHandler("RemoteParcelRequest", new SimpleOSDMapHandler("POST","/" + UUID.Random(), RemoteParcelRequest));
  1732. caps.RegisterSimpleHandler("ParcelPropertiesUpdate", new SimpleStreamHandler("/" + UUID.Random(),
  1733. delegate (IOSHttpRequest request, IOSHttpResponse response)
  1734. {
  1735. ProcessPropertiesUpdate(request, response, agentID);
  1736. }));
  1737. }
  1738. private void ProcessPropertiesUpdate(IOSHttpRequest request, IOSHttpResponse response, UUID agentID)
  1739. {
  1740. if (request.HttpMethod != "POST")
  1741. {
  1742. response.StatusCode = (int)HttpStatusCode.NotFound;
  1743. return;
  1744. }
  1745. if (!m_scene.TryGetClient(agentID, out IClientAPI client))
  1746. {
  1747. m_log.WarnFormat("[LAND MANAGEMENT MODULE]: Unable to retrieve IClientAPI for {0}", agentID);
  1748. response.StatusCode = (int)HttpStatusCode.Gone;
  1749. return;
  1750. }
  1751. OSDMap args;
  1752. ParcelPropertiesUpdateMessage properties;
  1753. try
  1754. {
  1755. args = (OSDMap)OSDParser.DeserializeLLSDXml(request.InputStream);
  1756. properties = new ParcelPropertiesUpdateMessage();
  1757. properties.Deserialize(args);
  1758. }
  1759. catch
  1760. {
  1761. response.StatusCode = (int)HttpStatusCode.BadRequest;
  1762. return;
  1763. }
  1764. int parcelID = properties.LocalID;
  1765. ILandObject land = null;
  1766. lock (m_landList)
  1767. {
  1768. _ = m_landList.TryGetValue(parcelID, out land);
  1769. }
  1770. if (land is null)
  1771. {
  1772. m_log.WarnFormat("[LAND MANAGEMENT MODULE]: Unable to find parcelID {0}", parcelID);
  1773. response.StatusCode = (int)HttpStatusCode.NotFound;
  1774. return;
  1775. }
  1776. try
  1777. {
  1778. LandUpdateArgs land_update = new()
  1779. {
  1780. AuthBuyerID = properties.AuthBuyerID,
  1781. Category = properties.Category,
  1782. Desc = properties.Desc,
  1783. GroupID = properties.GroupID,
  1784. LandingType = (byte)properties.Landing,
  1785. MediaAutoScale = (byte)Convert.ToInt32(properties.MediaAutoScale),
  1786. MediaID = properties.MediaID,
  1787. MediaURL = properties.MediaURL,
  1788. MusicURL = properties.MusicURL,
  1789. Name = properties.Name,
  1790. ParcelFlags = (uint)properties.ParcelFlags,
  1791. PassHours = properties.PassHours,
  1792. PassPrice = (int)properties.PassPrice,
  1793. SalePrice = (int)properties.SalePrice,
  1794. SnapshotID = properties.SnapshotID,
  1795. UserLocation = properties.UserLocation,
  1796. UserLookAt = properties.UserLookAt,
  1797. MediaDescription = properties.MediaDesc,
  1798. MediaType = properties.MediaType,
  1799. MediaWidth = properties.MediaWidth,
  1800. MediaHeight = properties.MediaHeight,
  1801. MediaLoop = properties.MediaLoop
  1802. };
  1803. if (args.TryGetValue("obscure_moap", out OSD omoap))
  1804. land_update.ObscureMOAP = omoap.AsBoolean();
  1805. if (args.ContainsKey("see_avs"))
  1806. {
  1807. land_update.SeeAVs = args["see_avs"].AsBoolean();
  1808. land_update.AnyAVSounds = args["any_av_sounds"].AsBoolean();
  1809. land_update.GroupAVSounds = args["group_av_sounds"].AsBoolean();
  1810. }
  1811. else
  1812. {
  1813. land_update.SeeAVs = true;
  1814. land_update.AnyAVSounds = true;
  1815. land_update.GroupAVSounds = true;
  1816. }
  1817. UpdateLandProperties(land,land_update, client);
  1818. m_scene.EventManager.TriggerOnParcelPropertiesUpdateRequest(land_update, parcelID, client);
  1819. }
  1820. catch
  1821. {
  1822. response.StatusCode = (int)HttpStatusCode.InternalServerError;
  1823. return;
  1824. }
  1825. response.StatusCode = (int)HttpStatusCode.OK;
  1826. }
  1827. // we cheat here: As we don't have (and want) a grid-global parcel-store, we can't return the
  1828. // "real" parcelID, because we wouldn't be able to map that to the region the parcel belongs to.
  1829. // So, we create a "fake" parcelID by using the regionHandle (64 bit), and the local (integer) x
  1830. // and y coordinate (each 8 bit), encoded in a UUID (128 bit).
  1831. //
  1832. // Request format:
  1833. // <llsd>
  1834. // <map>
  1835. // <key>location</key>
  1836. // <array>
  1837. // <real>1.23</real>
  1838. // <real>45..6</real>
  1839. // <real>78.9</real>
  1840. // </array>
  1841. // <key>region_id</key>
  1842. // <uuid>xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx</uuid>
  1843. // </map>
  1844. // </llsd>
  1845. private void RemoteParcelRequest(IOSHttpRequest request, IOSHttpResponse response, OSDMap args)
  1846. {
  1847. UUID parcelID = new();
  1848. try
  1849. {
  1850. if (args.TryGetValue("location", out OSD tmp) && tmp is OSDArray olist)
  1851. {
  1852. UUID scope = m_scene.RegionInfo.ScopeID;
  1853. uint x = (uint)(double)olist[0];
  1854. uint y = (uint)(double)olist[1];
  1855. ulong myHandle = m_scene.RegionInfo.RegionHandle;
  1856. if (args.TryGetValue("region_handle", out tmp) && tmp is OSDBinary)
  1857. {
  1858. // if you do a "About Landmark" on a landmark a second time, the viewer sends the
  1859. // region_handle it got earlier via RegionHandleRequest
  1860. ulong regionHandle = Util.BytesToUInt64Big((byte[])tmp);
  1861. if(regionHandle == myHandle)
  1862. {
  1863. ILandObject l = GetLandObjectClippedXY(x, y);
  1864. parcelID = l is null ? Util.BuildFakeParcelID(myHandle, x, y) : l.LandData.FakeID;
  1865. }
  1866. else
  1867. {
  1868. Util.RegionHandleToWorldLoc(regionHandle, out uint wx, out uint wy);
  1869. GridRegion info = m_scene.GridService.GetRegionByPosition(scope, (int)wx, (int)wy);
  1870. if (info is not null)
  1871. {
  1872. wx -= (uint)info.RegionLocX;
  1873. wy -= (uint)info.RegionLocY;
  1874. wx += x;
  1875. wy += y;
  1876. if (wx >= info.RegionSizeX || wy >= info.RegionSizeY)
  1877. {
  1878. wx = x;
  1879. wy = y;
  1880. }
  1881. if (info.RegionHandle == myHandle)
  1882. {
  1883. ILandObject l = GetLandObjectClippedXY(wx, wy);
  1884. parcelID = l is null ? Util.BuildFakeParcelID(myHandle, wx, wy) : l.LandData.FakeID;
  1885. }
  1886. else
  1887. {
  1888. parcelID = Util.BuildFakeParcelID(info.RegionHandle, wx, wy);
  1889. }
  1890. }
  1891. }
  1892. }
  1893. else if (args.TryGetValue("region_id", out tmp) && tmp is OSDUUID)
  1894. {
  1895. UUID regionID = tmp.AsUUID();
  1896. if (regionID.Equals(m_scene.RegionInfo.RegionID))
  1897. {
  1898. ILandObject l = GetLandObjectClippedXY(x, y);
  1899. parcelID = l is null ? Util.BuildFakeParcelID(myHandle, x, y) : l.LandData.FakeID;
  1900. }
  1901. else
  1902. {
  1903. // a parcel request for a parcel in another region. Ask the grid about the region
  1904. GridRegion info = m_scene.GridService.GetRegionByUUID(scope, regionID);
  1905. if (info is not null)
  1906. parcelID = Util.BuildFakeParcelID(info.RegionHandle, x, y);
  1907. }
  1908. }
  1909. }
  1910. }
  1911. catch
  1912. {
  1913. m_log.Error("[LAND MANAGEMENT MODULE]: RemoteParcelRequest failed");
  1914. response.StatusCode = (int)HttpStatusCode.BadRequest;
  1915. return;
  1916. }
  1917. //m_log.DebugFormat("[LAND MANAGEMENT MODULE]: Got parcelID {0} {1}", parcelID, parcelID.IsZero() ? args.ToString() :"");
  1918. osUTF8 sb = LLSDxmlEncode2.Start();
  1919. LLSDxmlEncode2.AddMap(sb);
  1920. LLSDxmlEncode2.AddElem("parcel_id", parcelID,sb);
  1921. LLSDxmlEncode2.AddEndMap(sb);
  1922. response.RawBuffer = LLSDxmlEncode2.EndToBytes(sb);
  1923. response.StatusCode = (int)HttpStatusCode.OK;
  1924. }
  1925. #endregion
  1926. private void ClientOnParcelInfoRequest(IClientAPI remoteClient, UUID parcelID)
  1927. {
  1928. if (parcelID.IsZero())
  1929. return;
  1930. if(!m_parcelInfoCache.TryGetValue(parcelID, 30000, out ExtendedLandData data))
  1931. {
  1932. data = null;
  1933. ExtendedLandData extLandData = new();
  1934. while(true)
  1935. {
  1936. if(!Util.ParseFakeParcelID(parcelID, out extLandData.RegionHandle,
  1937. out extLandData.X, out extLandData.Y))
  1938. break;
  1939. //m_log.DebugFormat("[LAND MANAGEMENT MODULE]: Got parcelinfo request for regionHandle {0}, x/y {1}/{2}",
  1940. // extLandData.RegionHandle, extLandData.X, extLandData.Y);
  1941. // for this region or for somewhere else?
  1942. if (extLandData.RegionHandle == m_scene.RegionInfo.RegionHandle)
  1943. {
  1944. ILandObject extLandObject = GetLandObjectByfakeID(parcelID);
  1945. if (extLandObject is null)
  1946. break;
  1947. extLandData.LandData = extLandObject.LandData;
  1948. extLandData.RegionAccess = m_scene.RegionInfo.AccessLevel;
  1949. if (extLandData.LandData is not null)
  1950. data = extLandData;
  1951. break;
  1952. }
  1953. else
  1954. {
  1955. ILandService landService = m_scene.RequestModuleInterface<ILandService>();
  1956. extLandData.LandData = landService.GetLandData(m_scene.RegionInfo.ScopeID,
  1957. extLandData.RegionHandle, extLandData.X, extLandData.Y,
  1958. out extLandData.RegionAccess);
  1959. if (extLandData.LandData is not null)
  1960. data = extLandData;
  1961. break;
  1962. }
  1963. }
  1964. m_parcelInfoCache.Add(parcelID, data, 30000);
  1965. }
  1966. if (data is not null) // if we found some data, send it
  1967. {
  1968. GridRegion info;
  1969. if (data.RegionHandle == m_scene.RegionInfo.RegionHandle)
  1970. {
  1971. info = new GridRegion(m_scene.RegionInfo);
  1972. IDwellModule dwellModule = m_scene.RequestModuleInterface<IDwellModule>();
  1973. if (dwellModule is not null)
  1974. data.LandData.Dwell = dwellModule.GetDwell(data.LandData);
  1975. }
  1976. else
  1977. {
  1978. // most likely still cached from building the extLandData entry
  1979. info = m_scene.GridService.GetRegionByHandle(m_scene.RegionInfo.ScopeID, data.RegionHandle);
  1980. }
  1981. // we need to transfer the fake parcelID, not the one in landData, so the viewer can match it to the landmark.
  1982. //m_log.DebugFormat("[LAND MANAGEMENT MODULE]: got parcelinfo for parcel {0} in region {1}; sending...",
  1983. // data.LandData.Name, data.RegionHandle);
  1984. // HACK for now
  1985. RegionInfo r = new()
  1986. {
  1987. RegionName = info.RegionName,
  1988. RegionLocX = (uint)info.RegionLocX,
  1989. RegionLocY = (uint)info.RegionLocY
  1990. };
  1991. r.RegionSettings.Maturity = (int)Util.ConvertAccessLevelToMaturity(data.RegionAccess);
  1992. remoteClient.SendParcelInfo(r, data.LandData, parcelID, data.X, data.Y);
  1993. }
  1994. else
  1995. m_log.Debug("[LAND MANAGEMENT MODULE]: got no parcelinfo; not sending");
  1996. }
  1997. public void SetParcelOtherCleanTime(IClientAPI remoteClient, int localID, int otherCleanTime)
  1998. {
  1999. ILandObject land;
  2000. lock (m_landList)
  2001. {
  2002. if(!m_landList.TryGetValue(localID, out land) || land is null)
  2003. return;
  2004. }
  2005. if (!m_scene.Permissions.CanEditParcelProperties(remoteClient.AgentId, land, GroupPowers.LandOptions, false))
  2006. return;
  2007. land.LandData.OtherCleanTime = otherCleanTime;
  2008. UpdateLandObject(localID, land.LandData);
  2009. }
  2010. public void ClientOnParcelGodMark(IClientAPI client, UUID god, int landID)
  2011. {
  2012. if(!((Scene)client.Scene).TryGetScenePresence(client.AgentId, out ScenePresence sp) || sp is null)
  2013. return;
  2014. if (sp.IsChildAgent || sp.IsDeleted || sp.IsInTransit || sp.IsNPC)
  2015. return;
  2016. if (!sp.IsGod)
  2017. {
  2018. client.SendAlertMessage("Request denied. You're not priviliged.");
  2019. return;
  2020. }
  2021. ILandObject land = null;
  2022. List<ILandObject> Lands = ((Scene)client.Scene).LandChannel.AllParcels();
  2023. foreach (ILandObject landObject in Lands)
  2024. {
  2025. if (landObject.LandData.LocalID == landID)
  2026. {
  2027. land = landObject;
  2028. break;
  2029. }
  2030. }
  2031. if (land is null)
  2032. return;
  2033. bool validParcelOwner = DefaultGodParcelOwner.IsNotZero() && m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, DefaultGodParcelOwner) is not null;
  2034. bool validParcelGroup = false;
  2035. if (m_groupManager is not null)
  2036. {
  2037. if (DefaultGodParcelGroup.IsNotZero() && m_groupManager.GetGroupRecord(DefaultGodParcelGroup) is not null)
  2038. validParcelGroup = true;
  2039. }
  2040. if (!validParcelOwner && !validParcelGroup)
  2041. {
  2042. client.SendAlertMessage("Please check ini files.\n[LandManagement] config section.");
  2043. return;
  2044. }
  2045. land.LandData.AnyAVSounds = true;
  2046. land.LandData.SeeAVs = true;
  2047. land.LandData.GroupAVSounds = true;
  2048. land.LandData.AuthBuyerID = UUID.Zero;
  2049. land.LandData.Category = ParcelCategory.None;
  2050. land.LandData.ClaimDate = Util.UnixTimeSinceEpoch();
  2051. land.LandData.Description = String.Empty;
  2052. land.LandData.Dwell = 0;
  2053. land.LandData.Flags = (uint)ParcelFlags.AllowFly | (uint)ParcelFlags.AllowLandmark |
  2054. (uint)ParcelFlags.AllowAPrimitiveEntry |
  2055. (uint)ParcelFlags.AllowDeedToGroup |
  2056. (uint)ParcelFlags.CreateObjects | (uint)ParcelFlags.AllowOtherScripts |
  2057. (uint)ParcelFlags.AllowVoiceChat;
  2058. land.LandData.LandingType = (byte)LandingType.Direct;
  2059. land.LandData.LastDwellTimeMS = Util.GetTimeStampMS();
  2060. land.LandData.MediaAutoScale = 0;
  2061. land.LandData.MediaDescription = "";
  2062. land.LandData.MediaHeight = 0;
  2063. land.LandData.MediaID = UUID.Zero;
  2064. land.LandData.MediaLoop = false;
  2065. land.LandData.MediaType = "none/none";
  2066. land.LandData.MediaURL = String.Empty;
  2067. land.LandData.MediaWidth = 0;
  2068. land.LandData.MusicURL = String.Empty;
  2069. land.LandData.ObscureMedia = false;
  2070. land.LandData.ObscureMusic = false;
  2071. land.LandData.OtherCleanTime = 0;
  2072. land.LandData.ParcelAccessList = new List<LandAccessEntry>();
  2073. land.LandData.PassHours = 0;
  2074. land.LandData.PassPrice = 0;
  2075. land.LandData.SalePrice = 0;
  2076. land.LandData.SnapshotID = UUID.Zero;
  2077. land.LandData.Status = ParcelStatus.Leased;
  2078. if (validParcelOwner)
  2079. {
  2080. land.LandData.OwnerID = DefaultGodParcelOwner;
  2081. land.LandData.IsGroupOwned = false;
  2082. }
  2083. else
  2084. {
  2085. land.LandData.OwnerID = DefaultGodParcelGroup;
  2086. land.LandData.IsGroupOwned = true;
  2087. }
  2088. if (validParcelGroup)
  2089. land.LandData.GroupID = DefaultGodParcelGroup;
  2090. else
  2091. land.LandData.GroupID = UUID.Zero;
  2092. land.LandData.Name = DefaultGodParcelName;
  2093. UpdateLandObject(land.LandData.LocalID, land.LandData);
  2094. //m_scene.EventManager.TriggerParcelPrimCountUpdate();
  2095. m_scene.ForEachClient(SendParcelOverlay);
  2096. land.SendLandUpdateToClient(true, client);
  2097. }
  2098. private void ClientOnSimWideDeletes(IClientAPI client, UUID agentID, int flags, UUID targetID)
  2099. {
  2100. if(!((Scene)client.Scene).TryGetScenePresence(client.AgentId, out ScenePresence SP))
  2101. return;
  2102. List<SceneObjectGroup> returns = new();
  2103. if (SP.GodController.UserLevel != 0)
  2104. {
  2105. if (flags == 0) //All parcels, scripted or not
  2106. {
  2107. ((Scene)client.Scene).ForEachSOG(delegate(SceneObjectGroup e)
  2108. {
  2109. if (e.OwnerID.Equals(targetID))
  2110. {
  2111. returns.Add(e);
  2112. }
  2113. });
  2114. }
  2115. if (flags == 4) //All parcels, scripted object
  2116. {
  2117. ((Scene)client.Scene).ForEachSOG(delegate(SceneObjectGroup e)
  2118. {
  2119. if (e.OwnerID.Equals(targetID))
  2120. {
  2121. if (e.ContainsScripts())
  2122. {
  2123. returns.Add(e);
  2124. }
  2125. }
  2126. });
  2127. }
  2128. if (flags == 4) //not target parcel, scripted object
  2129. {
  2130. ((Scene)client.Scene).ForEachSOG(delegate(SceneObjectGroup e)
  2131. {
  2132. if (e.OwnerID.Equals(targetID))
  2133. {
  2134. ILandObject landobject = ((Scene)client.Scene).LandChannel.GetLandObject(e.AbsolutePosition.X, e.AbsolutePosition.Y);
  2135. if (landobject.LandData.OwnerID != e.OwnerID)
  2136. {
  2137. if (e.ContainsScripts())
  2138. {
  2139. returns.Add(e);
  2140. }
  2141. }
  2142. }
  2143. });
  2144. }
  2145. foreach (SceneObjectGroup ol in returns)
  2146. {
  2147. ReturnObject(ol, client);
  2148. }
  2149. }
  2150. }
  2151. public void ReturnObject(SceneObjectGroup obj, IClientAPI client)
  2152. {
  2153. SceneObjectGroup[] objs = new SceneObjectGroup[1];
  2154. objs[0] = obj;
  2155. ((Scene)client.Scene).returnObjects(objs, client);
  2156. }
  2157. private readonly Dictionary<UUID, System.Threading.Timer> Timers = new();
  2158. public void ClientOnParcelFreezeUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
  2159. {
  2160. Scene clientScene = client.Scene as Scene;
  2161. if (!clientScene.TryGetScenePresence(target, out ScenePresence targetAvatar))
  2162. return;
  2163. if(!clientScene.TryGetScenePresence(client.AgentId, out ScenePresence parcelManager))
  2164. return;
  2165. System.Threading.Timer Timer;
  2166. if (targetAvatar.GodController.UserLevel < 200)
  2167. {
  2168. ILandObject land = clientScene.LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
  2169. if (!clientScene.Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze, true))
  2170. return;
  2171. if ((flags & 1) == 0) // only lowest bit has meaning for now
  2172. {
  2173. targetAvatar.AllowMovement = false;
  2174. targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has frozen you for 30 seconds. You cannot move or interact with the world.");
  2175. parcelManager.ControllingClient.SendAlertMessage("Avatar Frozen.");
  2176. System.Threading.TimerCallback timeCB = new(OnEndParcelFrozen);
  2177. Timer = new System.Threading.Timer(timeCB, targetAvatar, 30000, 0);
  2178. Timers.Add(targetAvatar.UUID, Timer);
  2179. }
  2180. else
  2181. {
  2182. targetAvatar.AllowMovement = true;
  2183. targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has unfrozen you.");
  2184. parcelManager.ControllingClient.SendAlertMessage("Avatar Unfrozen.");
  2185. if(Timers.Remove(targetAvatar.UUID, out Timer))
  2186. Timer.Dispose();
  2187. }
  2188. }
  2189. }
  2190. private void OnEndParcelFrozen(object avatar)
  2191. {
  2192. ScenePresence targetAvatar = (ScenePresence)avatar;
  2193. if (Timers.Remove(targetAvatar.UUID, out System.Threading.Timer Timer))
  2194. Timer.Dispose();
  2195. targetAvatar.AllowMovement = true;
  2196. targetAvatar.ControllingClient.SendAgentAlertMessage("The freeze has worn off; you may go about your business.", false);
  2197. }
  2198. public void ClientOnParcelEjectUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
  2199. {
  2200. // Must have presences
  2201. if (!m_scene.TryGetScenePresence(target, out ScenePresence targetAvatar) ||
  2202. !m_scene.TryGetScenePresence(client.AgentId, out ScenePresence parcelManager))
  2203. return;
  2204. // Cannot eject estate managers or gods
  2205. if (m_scene.Permissions.IsAdministrator(target))
  2206. return;
  2207. // Check if you even have permission to do this
  2208. ILandObject land = m_scene.LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
  2209. if (!m_scene.Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze, true) &&
  2210. !m_scene.Permissions.IsAdministrator(client.AgentId))
  2211. return;
  2212. Vector3 pos = m_scene.GetNearestAllowedPosition(targetAvatar, land);
  2213. targetAvatar.TeleportOnEject(pos);
  2214. targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname);
  2215. parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected.");
  2216. if ((flags & 1) != 0) // Ban TODO: Remove magic number
  2217. {
  2218. LandAccessEntry entry = new()
  2219. {
  2220. AgentID = targetAvatar.UUID,
  2221. Flags = AccessList.Ban,
  2222. Expires = 0 // Perm
  2223. };
  2224. land.LandData.ParcelAccessList.Add(entry);
  2225. }
  2226. }
  2227. public void ClearAllEnvironments()
  2228. {
  2229. List<ILandObject> parcels = AllParcels();
  2230. for (int i = 0; i < parcels.Count; ++i)
  2231. parcels[i].StoreEnvironment(null);
  2232. }
  2233. /// <summary>
  2234. /// Sets the Home Point. The LoginService uses this to know where to put a user when they log-in
  2235. /// </summary>
  2236. /// <param name="remoteClient"></param>
  2237. /// <param name="regionHandle"></param>
  2238. /// <param name="position"></param>
  2239. /// <param name="lookAt"></param>
  2240. /// <param name="flags"></param>
  2241. public virtual void ClientOnSetHome(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags)
  2242. {
  2243. // Let's find the parcel in question
  2244. ILandObject land = GetLandObject(position);
  2245. if (land is null || m_scene.GridUserService is null)
  2246. {
  2247. m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed.");
  2248. return;
  2249. }
  2250. // Gather some data
  2251. ulong gpowers = remoteClient.GetGroupPowers(land.LandData.GroupID);
  2252. SceneObjectGroup telehub = m_scene.RegionInfo.RegionSettings.TelehubObject.IsNotZero() ?
  2253. m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject) : null;
  2254. // Can the user set home here?
  2255. if (// Required: local user; foreign users cannot set home
  2256. m_scene.UserManagementModule.IsLocalGridUser(remoteClient.AgentId) &&
  2257. (// (a) gods and land managers can set home
  2258. m_scene.Permissions.IsAdministrator(remoteClient.AgentId) ||
  2259. m_scene.Permissions.IsGod(remoteClient.AgentId) ||
  2260. // (b) land owners can set home
  2261. remoteClient.AgentId.Equals(land.LandData.OwnerID) ||
  2262. // (c) members of the land-associated group in roles that can set home
  2263. ((gpowers & (ulong)GroupPowers.AllowSetHome) == (ulong)GroupPowers.AllowSetHome) ||
  2264. // (d) parcels with telehubs can be the home of anyone
  2265. (telehub is not null && land.ContainsPoint((int)telehub.AbsolutePosition.X, (int)telehub.AbsolutePosition.Y))))
  2266. {
  2267. if (!m_scene.UserManagementModule.GetUserUUI(remoteClient.AgentId, out string userId))
  2268. {
  2269. /* Do not set a home position in this grid for a HG visitor */
  2270. m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed. (User Lookup)");
  2271. }
  2272. else if (!UUID.TryParse(userId, out UUID _))
  2273. {
  2274. m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed. (HG visitor)");
  2275. }
  2276. else if (m_scene.GridUserService.SetHome(userId, land.RegionUUID, position, lookAt))
  2277. {
  2278. // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot.
  2279. m_Dialog.SendAlertToUser(remoteClient, "Home position set.");
  2280. }
  2281. else
  2282. {
  2283. m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed.");
  2284. }
  2285. }
  2286. else
  2287. m_Dialog.SendAlertToUser(remoteClient, "You are not allowed to set your home location in this parcel.");
  2288. }
  2289. protected void RegisterCommands()
  2290. {
  2291. ICommands commands = MainConsole.Instance.Commands;
  2292. commands.AddCommand(
  2293. "Land", false, "land clear",
  2294. "land clear",
  2295. "Clear all the parcels from the region.",
  2296. "Command will ask for confirmation before proceeding.",
  2297. HandleClearCommand);
  2298. commands.AddCommand(
  2299. "Land", false, "land show",
  2300. "land show [<local-land-id>]",
  2301. "Show information about the parcels on the region.",
  2302. "If no local land ID is given, then summary information about all the parcels is shown.\n"
  2303. + "If a local land ID is given then full information about that parcel is shown.",
  2304. HandleShowCommand);
  2305. }
  2306. protected void HandleClearCommand(string module, string[] args)
  2307. {
  2308. if (!(MainConsole.Instance.ConsoleScene is null || MainConsole.Instance.ConsoleScene == m_scene))
  2309. return;
  2310. string response = MainConsole.Instance.Prompt(
  2311. $"Are you sure that you want to clear all land parcels from {m_scene.Name} (y or n)", "n");
  2312. if (response.Equals("y", StringComparison.InvariantCultureIgnoreCase))
  2313. {
  2314. Clear(true);
  2315. MainConsole.Instance.Output("Cleared all parcels from {0}", m_scene.Name);
  2316. }
  2317. else
  2318. {
  2319. MainConsole.Instance.Output("Aborting clear of all parcels from {0}", m_scene.Name);
  2320. }
  2321. }
  2322. protected void HandleShowCommand(string module, string[] args)
  2323. {
  2324. if (!(MainConsole.Instance.ConsoleScene is null || MainConsole.Instance.ConsoleScene == m_scene))
  2325. return;
  2326. StringBuilder report = new();
  2327. if (args.Length <= 2)
  2328. {
  2329. AppendParcelsSummaryReport(report);
  2330. }
  2331. else
  2332. {
  2333. if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[2], out int landLocalId))
  2334. return;
  2335. ILandObject lo = null;
  2336. lock (m_landList)
  2337. {
  2338. if (!m_landList.TryGetValue(landLocalId, out lo))
  2339. {
  2340. MainConsole.Instance.Output($"No parcel found with local ID {landLocalId}");
  2341. return;
  2342. }
  2343. }
  2344. AppendParcelReport(report, lo);
  2345. }
  2346. MainConsole.Instance.Output(report.ToString());
  2347. }
  2348. private void AppendParcelsSummaryReport(StringBuilder report)
  2349. {
  2350. report.AppendFormat("Land information for {0}\n", m_scene.Name);
  2351. ConsoleDisplayTable cdt = new();
  2352. cdt.AddColumn("Parcel Name", ConsoleDisplayUtil.ParcelNameSize);
  2353. cdt.AddColumn("ID", 3);
  2354. cdt.AddColumn("Area", 6);
  2355. cdt.AddColumn("Starts", ConsoleDisplayUtil.VectorSize);
  2356. cdt.AddColumn("Ends", ConsoleDisplayUtil.VectorSize);
  2357. cdt.AddColumn("Owner", ConsoleDisplayUtil.UserNameSize);
  2358. cdt.AddColumn("fakeID", 38);
  2359. lock (m_landList)
  2360. {
  2361. foreach (ILandObject lo in m_landList.Values)
  2362. {
  2363. LandData ld = lo.LandData;
  2364. string ownerName;
  2365. if (ld.IsGroupOwned)
  2366. {
  2367. GroupRecord rec = m_groupManager.GetGroupRecord(ld.GroupID);
  2368. ownerName = (rec is not null) ? rec.GroupName : "Unknown Group";
  2369. }
  2370. else
  2371. {
  2372. ownerName = m_userManager.GetUserName(ld.OwnerID);
  2373. }
  2374. cdt.AddRow(
  2375. ld.Name, ld.LocalID, ld.Area, lo.StartPoint, lo.EndPoint, ownerName, lo.FakeID);
  2376. }
  2377. }
  2378. report.Append(cdt.ToString());
  2379. }
  2380. private void AppendParcelReport(StringBuilder report, ILandObject lo)
  2381. {
  2382. LandData ld = lo.LandData;
  2383. ConsoleDisplayList cdl = new();
  2384. cdl.AddRow("Parcel name", ld.Name);
  2385. cdl.AddRow("Local ID", ld.LocalID);
  2386. cdl.AddRow("Fake ID", ld.FakeID);
  2387. cdl.AddRow("Description", ld.Description);
  2388. cdl.AddRow("Snapshot ID", ld.SnapshotID);
  2389. cdl.AddRow("Area", ld.Area);
  2390. cdl.AddRow("AABB Min", ld.AABBMin);
  2391. cdl.AddRow("AABB Max", ld.AABBMax);
  2392. string ownerName;
  2393. if (ld.IsGroupOwned)
  2394. {
  2395. GroupRecord rec = m_groupManager.GetGroupRecord(ld.GroupID);
  2396. ownerName = (rec != null) ? rec.GroupName : "Unknown Group";
  2397. }
  2398. else
  2399. {
  2400. ownerName = m_userManager.GetUserName(ld.OwnerID);
  2401. }
  2402. cdl.AddRow("Owner", ownerName);
  2403. cdl.AddRow("Is group owned?", ld.IsGroupOwned);
  2404. cdl.AddRow("GroupID", ld.GroupID);
  2405. cdl.AddRow("Status", ld.Status);
  2406. cdl.AddRow("Flags", (ParcelFlags)ld.Flags);
  2407. cdl.AddRow("Landing Type", (LandingType)ld.LandingType);
  2408. cdl.AddRow("User Location", ld.UserLocation);
  2409. cdl.AddRow("User look at", ld.UserLookAt);
  2410. cdl.AddRow("Other clean time", ld.OtherCleanTime);
  2411. cdl.AddRow("Max Prims", lo.GetParcelMaxPrimCount());
  2412. cdl.AddRow("Simwide Max Prims (owner)", lo.GetSimulatorMaxPrimCount());
  2413. IPrimCounts pc = lo.PrimCounts;
  2414. cdl.AddRow("Owner Prims", pc.Owner);
  2415. cdl.AddRow("Group Prims", pc.Group);
  2416. cdl.AddRow("Other Prims", pc.Others);
  2417. cdl.AddRow("Selected Prims", pc.Selected);
  2418. cdl.AddRow("Total Prims", pc.Total);
  2419. cdl.AddRow("SimWide Prims (owner)", pc.Simulator);
  2420. cdl.AddRow("Music URL", ld.MusicURL);
  2421. cdl.AddRow("Obscure Music", ld.ObscureMusic);
  2422. cdl.AddRow("Media ID", ld.MediaID);
  2423. cdl.AddRow("Media Autoscale", Convert.ToBoolean(ld.MediaAutoScale));
  2424. cdl.AddRow("Media URL", ld.MediaURL);
  2425. cdl.AddRow("Media Type", ld.MediaType);
  2426. cdl.AddRow("Media Description", ld.MediaDescription);
  2427. cdl.AddRow("Media Width", ld.MediaWidth);
  2428. cdl.AddRow("Media Height", ld.MediaHeight);
  2429. cdl.AddRow("Media Loop", ld.MediaLoop);
  2430. cdl.AddRow("Obscure MOAP", ld.ObscureMedia);
  2431. cdl.AddRow("Parcel Category", ld.Category);
  2432. cdl.AddRow("Claim Date", ld.ClaimDate);
  2433. cdl.AddRow("Claim Price", ld.ClaimPrice);
  2434. cdl.AddRow("Pass Hours", ld.PassHours);
  2435. cdl.AddRow("Pass Price", ld.PassPrice);
  2436. cdl.AddRow("Auction ID", ld.AuctionID);
  2437. cdl.AddRow("Authorized Buyer ID", ld.AuthBuyerID);
  2438. cdl.AddRow("Sale Price", ld.SalePrice);
  2439. cdl.AddToStringBuilder(report);
  2440. }
  2441. }
  2442. }