LandObject.cs 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections.Generic;
  29. using System.Reflection;
  30. using log4net;
  31. using OpenMetaverse;
  32. using OpenSim.Framework;
  33. using OpenSim.Region.Framework.Interfaces;
  34. using OpenSim.Region.Framework.Scenes;
  35. using RegionFlags = OpenMetaverse.RegionFlags;
  36. namespace OpenSim.Region.CoreModules.World.Land
  37. {
  38. /// <summary>
  39. /// Keeps track of a specific piece of land's information
  40. /// </summary>
  41. public class LandObject : ILandObject
  42. {
  43. #region Member Variables
  44. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  45. private static readonly string LogHeader = "[LAND OBJECT]";
  46. private bool[,] m_landBitmap;
  47. private readonly int landUnit = 4;
  48. private int m_lastSeqId = 0;
  49. protected LandData m_landData = new LandData();
  50. protected Scene m_scene;
  51. protected List<SceneObjectGroup> primsOverMe = new List<SceneObjectGroup>();
  52. protected Dictionary<uint, UUID> m_listTransactions = new Dictionary<uint, UUID>();
  53. protected ExpiringCache<UUID, bool> m_groupMemberCache = new ExpiringCache<UUID, bool>();
  54. protected TimeSpan m_groupMemberCacheTimeout = TimeSpan.FromSeconds(30); // cache invalidation after 30 seconds
  55. public bool[,] LandBitmap
  56. {
  57. get { return m_landBitmap; }
  58. set { m_landBitmap = value; }
  59. }
  60. #endregion
  61. public int GetPrimsFree()
  62. {
  63. m_scene.EventManager.TriggerParcelPrimCountUpdate();
  64. int free = GetSimulatorMaxPrimCount() - m_landData.SimwidePrims;
  65. return free;
  66. }
  67. public LandData LandData
  68. {
  69. get { return m_landData; }
  70. set { m_landData = value; }
  71. }
  72. public IPrimCounts PrimCounts { get; set; }
  73. public UUID RegionUUID
  74. {
  75. get { return m_scene.RegionInfo.RegionID; }
  76. }
  77. public Vector3 StartPoint
  78. {
  79. get
  80. {
  81. for (int y = 0; y < LandBitmap.GetLength(1); y++)
  82. {
  83. for (int x = 0; x < LandBitmap.GetLength(0); x++)
  84. {
  85. if (LandBitmap[x, y])
  86. return new Vector3(x * landUnit, y * landUnit, 0);
  87. }
  88. }
  89. m_log.ErrorFormat("{0} StartPoint. No start point found. bitmapSize=<{1},{2}>",
  90. LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1));
  91. return new Vector3(-1, -1, -1);
  92. }
  93. }
  94. public Vector3 EndPoint
  95. {
  96. get
  97. {
  98. for (int y = LandBitmap.GetLength(1) - 1; y >= 0; y--)
  99. {
  100. for (int x = LandBitmap.GetLength(0) - 1; x >= 0; x--)
  101. {
  102. if (LandBitmap[x, y])
  103. {
  104. return new Vector3(x * landUnit + landUnit, y * landUnit + landUnit, 0);
  105. }
  106. }
  107. }
  108. m_log.ErrorFormat("{0} EndPoint. No end point found. bitmapSize=<{1},{2}>",
  109. LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1));
  110. return new Vector3(-1, -1, -1);
  111. }
  112. }
  113. #region Constructors
  114. public LandObject(UUID owner_id, bool is_group_owned, Scene scene)
  115. {
  116. m_scene = scene;
  117. if (m_scene == null)
  118. m_landBitmap = new bool[Constants.RegionSize / landUnit, Constants.RegionSize / landUnit];
  119. else
  120. m_landBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
  121. LandData.OwnerID = owner_id;
  122. if (is_group_owned)
  123. LandData.GroupID = owner_id;
  124. else
  125. LandData.GroupID = UUID.Zero;
  126. LandData.IsGroupOwned = is_group_owned;
  127. }
  128. #endregion
  129. #region Member Functions
  130. #region General Functions
  131. /// <summary>
  132. /// Checks to see if this land object contains a point
  133. /// </summary>
  134. /// <param name="x"></param>
  135. /// <param name="y"></param>
  136. /// <returns>Returns true if the piece of land contains the specified point</returns>
  137. public bool ContainsPoint(int x, int y)
  138. {
  139. if (x >= 0 && y >= 0 && x < m_scene.RegionInfo.RegionSizeX && y < m_scene.RegionInfo.RegionSizeY)
  140. {
  141. return (LandBitmap[x / landUnit, y / landUnit] == true);
  142. }
  143. else
  144. {
  145. return false;
  146. }
  147. }
  148. public ILandObject Copy()
  149. {
  150. ILandObject newLand = new LandObject(LandData.OwnerID, LandData.IsGroupOwned, m_scene);
  151. //Place all new variables here!
  152. newLand.LandBitmap = (bool[,]) (LandBitmap.Clone());
  153. newLand.LandData = LandData.Copy();
  154. return newLand;
  155. }
  156. static overrideParcelMaxPrimCountDelegate overrideParcelMaxPrimCount;
  157. static overrideSimulatorMaxPrimCountDelegate overrideSimulatorMaxPrimCount;
  158. public void SetParcelObjectMaxOverride(overrideParcelMaxPrimCountDelegate overrideDel)
  159. {
  160. overrideParcelMaxPrimCount = overrideDel;
  161. }
  162. public void SetSimulatorObjectMaxOverride(overrideSimulatorMaxPrimCountDelegate overrideDel)
  163. {
  164. overrideSimulatorMaxPrimCount = overrideDel;
  165. }
  166. public int GetParcelMaxPrimCount()
  167. {
  168. if (overrideParcelMaxPrimCount != null)
  169. {
  170. return overrideParcelMaxPrimCount(this);
  171. }
  172. else
  173. {
  174. // Normal Calculations
  175. int parcelMax = (int)(((float)LandData.Area / (m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY))
  176. * (float)m_scene.RegionInfo.ObjectCapacity
  177. * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus);
  178. // TODO: The calculation of ObjectBonus should be refactored. It does still not work in the same manner as SL!
  179. return parcelMax;
  180. }
  181. }
  182. public int GetSimulatorMaxPrimCount()
  183. {
  184. if (overrideSimulatorMaxPrimCount != null)
  185. {
  186. return overrideSimulatorMaxPrimCount(this);
  187. }
  188. else
  189. {
  190. //Normal Calculations
  191. int simMax = (int)(((float)LandData.SimwideArea / (m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY))
  192. * (float)m_scene.RegionInfo.ObjectCapacity);
  193. return simMax;
  194. }
  195. }
  196. #endregion
  197. #region Packet Request Handling
  198. public void SendLandProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client)
  199. {
  200. IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>();
  201. // uint regionFlags = 336723974 & ~((uint)(RegionFlags.AllowLandmark | RegionFlags.AllowSetHome));
  202. uint regionFlags = (uint)(RegionFlags.PublicAllowed
  203. | RegionFlags.AllowDirectTeleport
  204. | RegionFlags.AllowParcelChanges
  205. | RegionFlags.AllowVoice );
  206. if (estateModule != null)
  207. regionFlags = estateModule.GetRegionFlags();
  208. int seq_id;
  209. if (snap_selection && (sequence_id == 0))
  210. {
  211. seq_id = m_lastSeqId;
  212. }
  213. else
  214. {
  215. seq_id = sequence_id;
  216. m_lastSeqId = seq_id;
  217. }
  218. remote_client.SendLandProperties(seq_id,
  219. snap_selection, request_result, this,
  220. (float)m_scene.RegionInfo.RegionSettings.ObjectBonus,
  221. GetParcelMaxPrimCount(),
  222. GetSimulatorMaxPrimCount(), regionFlags);
  223. }
  224. public void UpdateLandProperties(LandUpdateArgs args, IClientAPI remote_client)
  225. {
  226. //Needs later group support
  227. bool snap_selection = false;
  228. LandData newData = LandData.Copy();
  229. uint allowedDelta = 0;
  230. // These two are always blocked as no client can set them anyway
  231. // ParcelFlags.ForSaleObjects
  232. // ParcelFlags.LindenHome
  233. if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions))
  234. {
  235. allowedDelta |= (uint)(ParcelFlags.AllowLandmark |
  236. ParcelFlags.AllowTerraform |
  237. ParcelFlags.AllowDamage |
  238. ParcelFlags.CreateObjects |
  239. ParcelFlags.RestrictPushObject |
  240. ParcelFlags.AllowOtherScripts |
  241. ParcelFlags.AllowGroupScripts |
  242. ParcelFlags.CreateGroupObjects |
  243. ParcelFlags.AllowAPrimitiveEntry |
  244. ParcelFlags.AllowGroupObjectEntry |
  245. ParcelFlags.AllowFly);
  246. }
  247. if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandSetSale))
  248. {
  249. if (args.AuthBuyerID != newData.AuthBuyerID ||
  250. args.SalePrice != newData.SalePrice)
  251. {
  252. snap_selection = true;
  253. }
  254. newData.AuthBuyerID = args.AuthBuyerID;
  255. newData.SalePrice = args.SalePrice;
  256. if (!LandData.IsGroupOwned)
  257. {
  258. newData.GroupID = args.GroupID;
  259. allowedDelta |= (uint)(ParcelFlags.AllowDeedToGroup |
  260. ParcelFlags.ContributeWithDeed |
  261. ParcelFlags.SellParcelObjects);
  262. }
  263. allowedDelta |= (uint)ParcelFlags.ForSale;
  264. }
  265. if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.FindPlaces))
  266. {
  267. newData.Category = args.Category;
  268. allowedDelta |= (uint)(ParcelFlags.ShowDirectory |
  269. ParcelFlags.AllowPublish |
  270. ParcelFlags.MaturePublish);
  271. }
  272. if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.LandChangeIdentity))
  273. {
  274. newData.Description = args.Desc;
  275. newData.Name = args.Name;
  276. newData.SnapshotID = args.SnapshotID;
  277. }
  278. if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.SetLandingPoint))
  279. {
  280. newData.LandingType = args.LandingType;
  281. newData.UserLocation = args.UserLocation;
  282. newData.UserLookAt = args.UserLookAt;
  283. }
  284. if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.ChangeMedia))
  285. {
  286. newData.MediaAutoScale = args.MediaAutoScale;
  287. newData.MediaID = args.MediaID;
  288. newData.MediaURL = args.MediaURL;
  289. newData.MusicURL = args.MusicURL;
  290. newData.MediaType = args.MediaType;
  291. newData.MediaDescription = args.MediaDescription;
  292. newData.MediaWidth = args.MediaWidth;
  293. newData.MediaHeight = args.MediaHeight;
  294. newData.MediaLoop = args.MediaLoop;
  295. newData.ObscureMusic = args.ObscureMusic;
  296. newData.ObscureMedia = args.ObscureMedia;
  297. allowedDelta |= (uint)(ParcelFlags.SoundLocal |
  298. ParcelFlags.UrlWebPage |
  299. ParcelFlags.UrlRawHtml |
  300. ParcelFlags.AllowVoiceChat |
  301. ParcelFlags.UseEstateVoiceChan);
  302. }
  303. if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.LandManagePasses))
  304. {
  305. newData.PassHours = args.PassHours;
  306. newData.PassPrice = args.PassPrice;
  307. allowedDelta |= (uint)ParcelFlags.UsePassList;
  308. }
  309. if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandManageAllowed))
  310. {
  311. allowedDelta |= (uint)(ParcelFlags.UseAccessGroup |
  312. ParcelFlags.UseAccessList);
  313. }
  314. if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandManageBanned))
  315. {
  316. allowedDelta |= (uint)(ParcelFlags.UseBanList |
  317. ParcelFlags.DenyAnonymous |
  318. ParcelFlags.DenyAgeUnverified);
  319. }
  320. uint preserve = LandData.Flags & ~allowedDelta;
  321. newData.Flags = preserve | (args.ParcelFlags & allowedDelta);
  322. m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData);
  323. SendLandUpdateToAvatarsOverMe(snap_selection);
  324. }
  325. public void UpdateLandSold(UUID avatarID, UUID groupID, bool groupOwned, uint AuctionID, int claimprice, int area)
  326. {
  327. LandData newData = LandData.Copy();
  328. newData.OwnerID = avatarID;
  329. newData.GroupID = groupID;
  330. newData.IsGroupOwned = groupOwned;
  331. //newData.auctionID = AuctionID;
  332. newData.ClaimDate = Util.UnixTimeSinceEpoch();
  333. newData.ClaimPrice = claimprice;
  334. newData.SalePrice = 0;
  335. newData.AuthBuyerID = UUID.Zero;
  336. newData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory);
  337. m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData);
  338. m_scene.EventManager.TriggerParcelPrimCountUpdate();
  339. SendLandUpdateToAvatarsOverMe(true);
  340. }
  341. public void DeedToGroup(UUID groupID)
  342. {
  343. LandData newData = LandData.Copy();
  344. newData.OwnerID = groupID;
  345. newData.GroupID = groupID;
  346. newData.IsGroupOwned = true;
  347. // Reset show in directory flag on deed
  348. newData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory);
  349. m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData);
  350. m_scene.EventManager.TriggerParcelPrimCountUpdate();
  351. SendLandUpdateToAvatarsOverMe(true);
  352. }
  353. public bool IsEitherBannedOrRestricted(UUID avatar)
  354. {
  355. if (IsBannedFromLand(avatar))
  356. {
  357. return true;
  358. }
  359. else if (IsRestrictedFromLand(avatar))
  360. {
  361. return true;
  362. }
  363. return false;
  364. }
  365. public bool CanBeOnThisLand(UUID avatar, float posHeight)
  366. {
  367. if (posHeight < LandChannel.BAN_LINE_SAFETY_HIEGHT && IsBannedFromLand(avatar))
  368. {
  369. return false;
  370. }
  371. else if (IsRestrictedFromLand(avatar))
  372. {
  373. return false;
  374. }
  375. return true;
  376. }
  377. public bool HasGroupAccess(UUID avatar)
  378. {
  379. if (LandData.GroupID != UUID.Zero && (LandData.Flags & (uint)ParcelFlags.UseAccessGroup) == (uint)ParcelFlags.UseAccessGroup)
  380. {
  381. ScenePresence sp;
  382. if (!m_scene.TryGetScenePresence(avatar, out sp))
  383. {
  384. bool isMember;
  385. if (m_groupMemberCache.TryGetValue(avatar, out isMember))
  386. {
  387. m_groupMemberCache.Update(avatar, isMember, m_groupMemberCacheTimeout);
  388. return isMember;
  389. }
  390. IGroupsModule groupsModule = m_scene.RequestModuleInterface<IGroupsModule>();
  391. if (groupsModule == null)
  392. return false;
  393. GroupMembershipData[] membership = groupsModule.GetMembershipData(avatar);
  394. if (membership == null || membership.Length == 0)
  395. {
  396. m_groupMemberCache.Add(avatar, false, m_groupMemberCacheTimeout);
  397. return false;
  398. }
  399. foreach (GroupMembershipData d in membership)
  400. {
  401. if (d.GroupID == LandData.GroupID)
  402. {
  403. m_groupMemberCache.Add(avatar, true, m_groupMemberCacheTimeout);
  404. return true;
  405. }
  406. }
  407. m_groupMemberCache.Add(avatar, false, m_groupMemberCacheTimeout);
  408. return false;
  409. }
  410. return sp.ControllingClient.IsGroupMember(LandData.GroupID);
  411. }
  412. return false;
  413. }
  414. public bool IsBannedFromLand(UUID avatar)
  415. {
  416. ExpireAccessList();
  417. if (m_scene.Permissions.IsAdministrator(avatar))
  418. return false;
  419. if (m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(avatar))
  420. return false;
  421. if (avatar == LandData.OwnerID)
  422. return false;
  423. if ((LandData.Flags & (uint) ParcelFlags.UseBanList) > 0)
  424. {
  425. if (LandData.ParcelAccessList.FindIndex(
  426. delegate(LandAccessEntry e)
  427. {
  428. if (e.AgentID == avatar && e.Flags == AccessList.Ban)
  429. return true;
  430. return false;
  431. }) != -1)
  432. {
  433. return true;
  434. }
  435. }
  436. return false;
  437. }
  438. public bool IsRestrictedFromLand(UUID avatar)
  439. {
  440. if ((LandData.Flags & (uint) ParcelFlags.UseAccessList) == 0)
  441. return false;
  442. if (m_scene.Permissions.IsAdministrator(avatar))
  443. return false;
  444. if (m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(avatar))
  445. return false;
  446. if (avatar == LandData.OwnerID)
  447. return false;
  448. if (HasGroupAccess(avatar))
  449. return false;
  450. return !IsInLandAccessList(avatar);
  451. }
  452. public bool IsInLandAccessList(UUID avatar)
  453. {
  454. ExpireAccessList();
  455. if (LandData.ParcelAccessList.FindIndex(
  456. delegate(LandAccessEntry e)
  457. {
  458. if (e.AgentID == avatar && e.Flags == AccessList.Access)
  459. return true;
  460. return false;
  461. }) == -1)
  462. {
  463. return false;
  464. }
  465. return true;
  466. }
  467. public void SendLandUpdateToClient(IClientAPI remote_client)
  468. {
  469. SendLandProperties(0, false, 0, remote_client);
  470. }
  471. public void SendLandUpdateToClient(bool snap_selection, IClientAPI remote_client)
  472. {
  473. m_scene.EventManager.TriggerParcelPrimCountUpdate();
  474. SendLandProperties(0, snap_selection, 0, remote_client);
  475. }
  476. public void SendLandUpdateToAvatarsOverMe()
  477. {
  478. SendLandUpdateToAvatarsOverMe(false);
  479. }
  480. public void SendLandUpdateToAvatarsOverMe(bool snap_selection)
  481. {
  482. m_scene.ForEachRootScenePresence(delegate(ScenePresence avatar)
  483. {
  484. ILandObject over = null;
  485. try
  486. {
  487. over =
  488. m_scene.LandChannel.GetLandObject(Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.X), 0, ((int)m_scene.RegionInfo.RegionSizeX - 1)),
  489. Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.Y), 0, ((int)m_scene.RegionInfo.RegionSizeY - 1)));
  490. }
  491. catch (Exception)
  492. {
  493. m_log.Warn("[LAND]: " + "unable to get land at x: " + Math.Round(avatar.AbsolutePosition.X) + " y: " +
  494. Math.Round(avatar.AbsolutePosition.Y));
  495. }
  496. if (over != null)
  497. {
  498. if (over.LandData.LocalID == LandData.LocalID)
  499. {
  500. if (((over.LandData.Flags & (uint)ParcelFlags.AllowDamage) != 0) &&
  501. m_scene.RegionInfo.RegionSettings.AllowDamage)
  502. avatar.Invulnerable = false;
  503. else
  504. avatar.Invulnerable = true;
  505. SendLandUpdateToClient(snap_selection, avatar.ControllingClient);
  506. }
  507. }
  508. });
  509. }
  510. #endregion
  511. #region AccessList Functions
  512. public List<LandAccessEntry> CreateAccessListArrayByFlag(AccessList flag)
  513. {
  514. ExpireAccessList();
  515. List<LandAccessEntry> list = new List<LandAccessEntry>();
  516. foreach (LandAccessEntry entry in LandData.ParcelAccessList)
  517. {
  518. if (entry.Flags == flag)
  519. list.Add(entry);
  520. }
  521. if (list.Count == 0)
  522. {
  523. LandAccessEntry e = new LandAccessEntry();
  524. e.AgentID = UUID.Zero;
  525. e.Flags = 0;
  526. e.Expires = 0;
  527. list.Add(e);
  528. }
  529. return list;
  530. }
  531. public void SendAccessList(UUID agentID, UUID sessionID, uint flags, int sequenceID,
  532. IClientAPI remote_client)
  533. {
  534. if (flags == (uint) AccessList.Access || flags == (uint) AccessList.Both)
  535. {
  536. List<LandAccessEntry> accessEntries = CreateAccessListArrayByFlag(AccessList.Access);
  537. remote_client.SendLandAccessListData(accessEntries,(uint) AccessList.Access,LandData.LocalID);
  538. }
  539. if (flags == (uint) AccessList.Ban || flags == (uint) AccessList.Both)
  540. {
  541. List<LandAccessEntry> accessEntries = CreateAccessListArrayByFlag(AccessList.Ban);
  542. remote_client.SendLandAccessListData(accessEntries, (uint)AccessList.Ban, LandData.LocalID);
  543. }
  544. }
  545. public void UpdateAccessList(uint flags, UUID transactionID,
  546. int sequenceID, int sections,
  547. List<LandAccessEntry> entries,
  548. IClientAPI remote_client)
  549. {
  550. LandData newData = LandData.Copy();
  551. if ((!m_listTransactions.ContainsKey(flags)) ||
  552. m_listTransactions[flags] != transactionID)
  553. {
  554. m_listTransactions[flags] = transactionID;
  555. List<LandAccessEntry> toRemove =
  556. new List<LandAccessEntry>();
  557. foreach (LandAccessEntry entry in newData.ParcelAccessList)
  558. {
  559. if (entry.Flags == (AccessList)flags)
  560. toRemove.Add(entry);
  561. }
  562. foreach (LandAccessEntry entry in toRemove)
  563. {
  564. newData.ParcelAccessList.Remove(entry);
  565. }
  566. // Checked here because this will always be the first
  567. // and only packet in a transaction
  568. if (entries.Count == 1 && entries[0].AgentID == UUID.Zero)
  569. {
  570. m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData);
  571. return;
  572. }
  573. }
  574. foreach (LandAccessEntry entry in entries)
  575. {
  576. LandAccessEntry temp =
  577. new LandAccessEntry();
  578. temp.AgentID = entry.AgentID;
  579. temp.Expires = entry.Expires;
  580. temp.Flags = (AccessList)flags;
  581. newData.ParcelAccessList.Add(temp);
  582. }
  583. m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData);
  584. }
  585. #endregion
  586. #region Update Functions
  587. public void UpdateLandBitmapByteArray()
  588. {
  589. LandData.Bitmap = ConvertLandBitmapToBytes();
  590. }
  591. /// <summary>
  592. /// Update all settings in land such as area, bitmap byte array, etc
  593. /// </summary>
  594. public void ForceUpdateLandInfo()
  595. {
  596. UpdateAABBAndAreaValues();
  597. UpdateLandBitmapByteArray();
  598. }
  599. public void SetLandBitmapFromByteArray()
  600. {
  601. LandBitmap = ConvertBytesToLandBitmap();
  602. }
  603. /// <summary>
  604. /// Updates the AABBMin and AABBMax values after area/shape modification of the land object
  605. /// </summary>
  606. private void UpdateAABBAndAreaValues()
  607. {
  608. int min_x = 10000;
  609. int min_y = 10000;
  610. int max_x = 0;
  611. int max_y = 0;
  612. int tempArea = 0;
  613. int x, y;
  614. for (x = 0; x < LandBitmap.GetLength(0); x++)
  615. {
  616. for (y = 0; y < LandBitmap.GetLength(1); y++)
  617. {
  618. if (LandBitmap[x, y] == true)
  619. {
  620. if (min_x > x) min_x = x;
  621. if (min_y > y) min_y = y;
  622. if (max_x < x) max_x = x;
  623. if (max_y < y) max_y = y;
  624. tempArea += landUnit * landUnit; //16sqm peice of land
  625. }
  626. }
  627. }
  628. int tx = min_x * landUnit;
  629. if (tx > ((int)m_scene.RegionInfo.RegionSizeX - 1))
  630. tx = ((int)m_scene.RegionInfo.RegionSizeX - 1);
  631. int ty = min_y * landUnit;
  632. if (ty > ((int)m_scene.RegionInfo.RegionSizeY - 1))
  633. ty = ((int)m_scene.RegionInfo.RegionSizeY - 1);
  634. LandData.AABBMin =
  635. new Vector3(
  636. (float)(min_x * landUnit), (float)(min_y * landUnit), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0);
  637. tx = max_x * landUnit;
  638. if (tx > ((int)m_scene.RegionInfo.RegionSizeX - 1))
  639. tx = ((int)m_scene.RegionInfo.RegionSizeX - 1);
  640. ty = max_y * landUnit;
  641. if (ty > ((int)m_scene.RegionInfo.RegionSizeY - 1))
  642. ty = ((int)m_scene.RegionInfo.RegionSizeY - 1);
  643. LandData.AABBMax
  644. = new Vector3(
  645. (float)(max_x * landUnit), (float)(max_y * landUnit), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0);
  646. LandData.Area = tempArea;
  647. }
  648. #endregion
  649. #region Land Bitmap Functions
  650. /// <summary>
  651. /// Sets the land's bitmap manually
  652. /// </summary>
  653. /// <param name="bitmap">block representing where this land is on a map mapped in a 4x4 meter grid</param>
  654. public void SetLandBitmap(bool[,] bitmap)
  655. {
  656. LandBitmap = bitmap;
  657. // m_log.DebugFormat("{0} SetLandBitmap. BitmapSize=<{1},{2}>", LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1));
  658. ForceUpdateLandInfo();
  659. }
  660. /// <summary>
  661. /// Gets the land's bitmap manually
  662. /// </summary>
  663. /// <returns></returns>
  664. public bool[,] GetLandBitmap()
  665. {
  666. return LandBitmap;
  667. }
  668. public bool[,] BasicFullRegionLandBitmap()
  669. {
  670. return GetSquareLandBitmap(0, 0, (int)m_scene.RegionInfo.RegionSizeX, (int) m_scene.RegionInfo.RegionSizeY);
  671. }
  672. public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y)
  673. {
  674. // Empty bitmap for the whole region
  675. bool[,] tempBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
  676. tempBitmap.Initialize();
  677. // Fill the bitmap square area specified by state and end
  678. tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true);
  679. // m_log.DebugFormat("{0} GetSquareLandBitmap. tempBitmapSize=<{1},{2}>",
  680. // LogHeader, tempBitmap.GetLength(0), tempBitmap.GetLength(1));
  681. return tempBitmap;
  682. }
  683. /// <summary>
  684. /// Change a land bitmap at within a square and set those points to a specific value
  685. /// </summary>
  686. /// <param name="land_bitmap"></param>
  687. /// <param name="start_x"></param>
  688. /// <param name="start_y"></param>
  689. /// <param name="end_x"></param>
  690. /// <param name="end_y"></param>
  691. /// <param name="set_value"></param>
  692. /// <returns></returns>
  693. public bool[,] ModifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y,
  694. bool set_value)
  695. {
  696. int x, y;
  697. for (y = 0; y < land_bitmap.GetLength(1); y++)
  698. {
  699. for (x = 0; x < land_bitmap.GetLength(0); x++)
  700. {
  701. if (x >= start_x / landUnit && x < end_x / landUnit
  702. && y >= start_y / landUnit && y < end_y / landUnit)
  703. {
  704. land_bitmap[x, y] = set_value;
  705. }
  706. }
  707. }
  708. // m_log.DebugFormat("{0} ModifyLandBitmapSquare. startXY=<{1},{2}>, endXY=<{3},{4}>, val={5}, landBitmapSize=<{6},{7}>",
  709. // LogHeader, start_x, start_y, end_x, end_y, set_value, land_bitmap.GetLength(0), land_bitmap.GetLength(1));
  710. return land_bitmap;
  711. }
  712. /// <summary>
  713. /// Join the true values of 2 bitmaps together
  714. /// </summary>
  715. /// <param name="bitmap_base"></param>
  716. /// <param name="bitmap_add"></param>
  717. /// <returns></returns>
  718. public bool[,] MergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add)
  719. {
  720. if (bitmap_base.GetLength(0) != bitmap_add.GetLength(0)
  721. || bitmap_base.GetLength(1) != bitmap_add.GetLength(1)
  722. || bitmap_add.Rank != 2
  723. || bitmap_base.Rank != 2)
  724. {
  725. throw new Exception(
  726. String.Format("{0} MergeLandBitmaps. merging maps not same size. baseSizeXY=<{1},{2}>, addSizeXY=<{3},{4}>",
  727. LogHeader, bitmap_base.GetLength(0), bitmap_base.GetLength(1), bitmap_add.GetLength(0), bitmap_add.GetLength(1))
  728. );
  729. }
  730. int x, y;
  731. for (y = 0; y < bitmap_base.GetLength(1); y++)
  732. {
  733. for (x = 0; x < bitmap_add.GetLength(0); x++)
  734. {
  735. if (bitmap_add[x, y])
  736. {
  737. bitmap_base[x, y] = true;
  738. }
  739. }
  740. }
  741. return bitmap_base;
  742. }
  743. /// <summary>
  744. /// Converts the land bitmap to a packet friendly byte array
  745. /// </summary>
  746. /// <returns></returns>
  747. private byte[] ConvertLandBitmapToBytes()
  748. {
  749. byte[] tempConvertArr = new byte[LandBitmap.GetLength(0) * LandBitmap.GetLength(1) / 8];
  750. byte tempByte = 0;
  751. int byteNum = 0;
  752. int i = 0;
  753. for (int y = 0; y < LandBitmap.GetLength(1); y++)
  754. {
  755. for (int x = 0; x < LandBitmap.GetLength(0); x++)
  756. {
  757. tempByte = Convert.ToByte(tempByte | Convert.ToByte(LandBitmap[x, y]) << (i++ % 8));
  758. if (i % 8 == 0)
  759. {
  760. tempConvertArr[byteNum] = tempByte;
  761. tempByte = (byte) 0;
  762. i = 0;
  763. byteNum++;
  764. }
  765. }
  766. }
  767. // m_log.DebugFormat("{0} ConvertLandBitmapToBytes. BitmapSize=<{1},{2}>",
  768. // LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1));
  769. return tempConvertArr;
  770. }
  771. private bool[,] ConvertBytesToLandBitmap()
  772. {
  773. bool[,] tempConvertMap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
  774. tempConvertMap.Initialize();
  775. byte tempByte = 0;
  776. // Math.Min overcomes an old bug that might have made it into the database. Only use the bytes that fit into convertMap.
  777. int bitmapLen = Math.Min(LandData.Bitmap.Length, tempConvertMap.GetLength(0) * tempConvertMap.GetLength(1) / 8);
  778. int xLen = (int)(m_scene.RegionInfo.RegionSizeX / landUnit);
  779. if (bitmapLen == 512)
  780. {
  781. // Legacy bitmap being passed in. Use the legacy region size
  782. // and only set the lower area of the larger region.
  783. xLen = (int)(Constants.RegionSize / landUnit);
  784. }
  785. // m_log.DebugFormat("{0} ConvertBytesToLandBitmap: bitmapLen={1}, xLen={2}", LogHeader, bitmapLen, xLen);
  786. int x = 0, y = 0;
  787. for (int i = 0; i < bitmapLen; i++)
  788. {
  789. tempByte = LandData.Bitmap[i];
  790. for (int bitNum = 0; bitNum < 8; bitNum++)
  791. {
  792. bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1);
  793. try
  794. {
  795. tempConvertMap[x, y] = bit;
  796. }
  797. catch (Exception e)
  798. {
  799. m_log.DebugFormat("{0} ConvertBytestoLandBitmap: i={1}, x={2}, y={3}", LogHeader, i, x, y);
  800. }
  801. x++;
  802. if (x >= xLen)
  803. {
  804. x = 0;
  805. y++;
  806. }
  807. }
  808. }
  809. return tempConvertMap;
  810. }
  811. #endregion
  812. #region Object Select and Object Owner Listing
  813. public void SendForceObjectSelect(int local_id, int request_type, List<UUID> returnIDs, IClientAPI remote_client)
  814. {
  815. if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions))
  816. {
  817. List<uint> resultLocalIDs = new List<uint>();
  818. try
  819. {
  820. lock (primsOverMe)
  821. {
  822. foreach (SceneObjectGroup obj in primsOverMe)
  823. {
  824. if (obj.LocalId > 0)
  825. {
  826. if (request_type == LandChannel.LAND_SELECT_OBJECTS_OWNER && obj.OwnerID == LandData.OwnerID)
  827. {
  828. resultLocalIDs.Add(obj.LocalId);
  829. }
  830. else if (request_type == LandChannel.LAND_SELECT_OBJECTS_GROUP && obj.GroupID == LandData.GroupID && LandData.GroupID != UUID.Zero)
  831. {
  832. resultLocalIDs.Add(obj.LocalId);
  833. }
  834. else if (request_type == LandChannel.LAND_SELECT_OBJECTS_OTHER &&
  835. obj.OwnerID != remote_client.AgentId)
  836. {
  837. resultLocalIDs.Add(obj.LocalId);
  838. }
  839. else if (request_type == (int)ObjectReturnType.List && returnIDs.Contains(obj.OwnerID))
  840. {
  841. resultLocalIDs.Add(obj.LocalId);
  842. }
  843. }
  844. }
  845. }
  846. } catch (InvalidOperationException)
  847. {
  848. m_log.Error("[LAND]: Unable to force select the parcel objects. Arr.");
  849. }
  850. remote_client.SendForceClientSelectObjects(resultLocalIDs);
  851. }
  852. }
  853. /// <summary>
  854. /// Notify the parcel owner each avatar that owns prims situated on their land. This notification includes
  855. /// aggreagete details such as the number of prims.
  856. ///
  857. /// </summary>
  858. /// <param name="remote_client">
  859. /// A <see cref="IClientAPI"/>
  860. /// </param>
  861. public void SendLandObjectOwners(IClientAPI remote_client)
  862. {
  863. if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions))
  864. {
  865. Dictionary<UUID, int> primCount = new Dictionary<UUID, int>();
  866. List<UUID> groups = new List<UUID>();
  867. lock (primsOverMe)
  868. {
  869. // m_log.DebugFormat(
  870. // "[LAND OBJECT]: Request for SendLandObjectOwners() from {0} with {1} known prims on region",
  871. // remote_client.Name, primsOverMe.Count);
  872. try
  873. {
  874. foreach (SceneObjectGroup obj in primsOverMe)
  875. {
  876. try
  877. {
  878. if (!primCount.ContainsKey(obj.OwnerID))
  879. {
  880. primCount.Add(obj.OwnerID, 0);
  881. }
  882. }
  883. catch (NullReferenceException)
  884. {
  885. m_log.Error("[LAND]: " + "Got Null Reference when searching land owners from the parcel panel");
  886. }
  887. try
  888. {
  889. primCount[obj.OwnerID] += obj.PrimCount;
  890. }
  891. catch (KeyNotFoundException)
  892. {
  893. m_log.Error("[LAND]: Unable to match a prim with it's owner.");
  894. }
  895. if (obj.OwnerID == obj.GroupID && (!groups.Contains(obj.OwnerID)))
  896. groups.Add(obj.OwnerID);
  897. }
  898. }
  899. catch (InvalidOperationException)
  900. {
  901. m_log.Error("[LAND]: Unable to Enumerate Land object arr.");
  902. }
  903. }
  904. remote_client.SendLandObjectOwners(LandData, groups, primCount);
  905. }
  906. }
  907. public Dictionary<UUID, int> GetLandObjectOwners()
  908. {
  909. Dictionary<UUID, int> ownersAndCount = new Dictionary<UUID, int>();
  910. lock (primsOverMe)
  911. {
  912. try
  913. {
  914. foreach (SceneObjectGroup obj in primsOverMe)
  915. {
  916. if (!ownersAndCount.ContainsKey(obj.OwnerID))
  917. {
  918. ownersAndCount.Add(obj.OwnerID, 0);
  919. }
  920. ownersAndCount[obj.OwnerID] += obj.PrimCount;
  921. }
  922. }
  923. catch (InvalidOperationException)
  924. {
  925. m_log.Error("[LAND]: Unable to enumerate land owners. arr.");
  926. }
  927. }
  928. return ownersAndCount;
  929. }
  930. #endregion
  931. #region Object Returning
  932. public void ReturnObject(SceneObjectGroup obj)
  933. {
  934. SceneObjectGroup[] objs = new SceneObjectGroup[1];
  935. objs[0] = obj;
  936. m_scene.returnObjects(objs, obj.OwnerID);
  937. }
  938. public void ReturnLandObjects(uint type, UUID[] owners, UUID[] tasks, IClientAPI remote_client)
  939. {
  940. // m_log.DebugFormat(
  941. // "[LAND OBJECT]: Request to return objects in {0} from {1}", LandData.Name, remote_client.Name);
  942. Dictionary<UUID,List<SceneObjectGroup>> returns = new Dictionary<UUID,List<SceneObjectGroup>>();
  943. lock (primsOverMe)
  944. {
  945. if (type == (uint)ObjectReturnType.Owner)
  946. {
  947. foreach (SceneObjectGroup obj in primsOverMe)
  948. {
  949. if (obj.OwnerID == m_landData.OwnerID)
  950. {
  951. if (!returns.ContainsKey(obj.OwnerID))
  952. returns[obj.OwnerID] =
  953. new List<SceneObjectGroup>();
  954. returns[obj.OwnerID].Add(obj);
  955. }
  956. }
  957. }
  958. else if (type == (uint)ObjectReturnType.Group && m_landData.GroupID != UUID.Zero)
  959. {
  960. foreach (SceneObjectGroup obj in primsOverMe)
  961. {
  962. if (obj.GroupID == m_landData.GroupID)
  963. {
  964. if (!returns.ContainsKey(obj.OwnerID))
  965. returns[obj.OwnerID] =
  966. new List<SceneObjectGroup>();
  967. returns[obj.OwnerID].Add(obj);
  968. }
  969. }
  970. }
  971. else if (type == (uint)ObjectReturnType.Other)
  972. {
  973. foreach (SceneObjectGroup obj in primsOverMe)
  974. {
  975. if (obj.OwnerID != m_landData.OwnerID &&
  976. (obj.GroupID != m_landData.GroupID ||
  977. m_landData.GroupID == UUID.Zero))
  978. {
  979. if (!returns.ContainsKey(obj.OwnerID))
  980. returns[obj.OwnerID] =
  981. new List<SceneObjectGroup>();
  982. returns[obj.OwnerID].Add(obj);
  983. }
  984. }
  985. }
  986. else if (type == (uint)ObjectReturnType.List)
  987. {
  988. List<UUID> ownerlist = new List<UUID>(owners);
  989. foreach (SceneObjectGroup obj in primsOverMe)
  990. {
  991. if (ownerlist.Contains(obj.OwnerID))
  992. {
  993. if (!returns.ContainsKey(obj.OwnerID))
  994. returns[obj.OwnerID] =
  995. new List<SceneObjectGroup>();
  996. returns[obj.OwnerID].Add(obj);
  997. }
  998. }
  999. }
  1000. }
  1001. foreach (List<SceneObjectGroup> ol in returns.Values)
  1002. {
  1003. if (m_scene.Permissions.CanReturnObjects(this, remote_client.AgentId, ol))
  1004. m_scene.returnObjects(ol.ToArray(), remote_client.AgentId);
  1005. }
  1006. }
  1007. #endregion
  1008. #region Object Adding/Removing from Parcel
  1009. public void ResetOverMeRecord()
  1010. {
  1011. lock (primsOverMe)
  1012. primsOverMe.Clear();
  1013. }
  1014. public void AddPrimOverMe(SceneObjectGroup obj)
  1015. {
  1016. // m_log.DebugFormat("[LAND OBJECT]: Adding scene object {0} {1} over {2}", obj.Name, obj.LocalId, LandData.Name);
  1017. lock (primsOverMe)
  1018. primsOverMe.Add(obj);
  1019. }
  1020. public void RemovePrimFromOverMe(SceneObjectGroup obj)
  1021. {
  1022. // m_log.DebugFormat("[LAND OBJECT]: Removing scene object {0} {1} from over {2}", obj.Name, obj.LocalId, LandData.Name);
  1023. lock (primsOverMe)
  1024. primsOverMe.Remove(obj);
  1025. }
  1026. #endregion
  1027. /// <summary>
  1028. /// Set the media url for this land parcel
  1029. /// </summary>
  1030. /// <param name="url"></param>
  1031. public void SetMediaUrl(string url)
  1032. {
  1033. LandData.MediaURL = url;
  1034. SendLandUpdateToAvatarsOverMe();
  1035. }
  1036. /// <summary>
  1037. /// Set the music url for this land parcel
  1038. /// </summary>
  1039. /// <param name="url"></param>
  1040. public void SetMusicUrl(string url)
  1041. {
  1042. LandData.MusicURL = url;
  1043. SendLandUpdateToAvatarsOverMe();
  1044. }
  1045. /// <summary>
  1046. /// Get the music url for this land parcel
  1047. /// </summary>
  1048. /// <returns>The music url.</returns>
  1049. public string GetMusicUrl()
  1050. {
  1051. return LandData.MusicURL;
  1052. }
  1053. #endregion
  1054. private void ExpireAccessList()
  1055. {
  1056. List<LandAccessEntry> delete = new List<LandAccessEntry>();
  1057. foreach (LandAccessEntry entry in LandData.ParcelAccessList)
  1058. {
  1059. if (entry.Expires != 0 && entry.Expires < Util.UnixTimeSinceEpoch())
  1060. delete.Add(entry);
  1061. }
  1062. foreach (LandAccessEntry entry in delete)
  1063. LandData.ParcelAccessList.Remove(entry);
  1064. if (delete.Count > 0)
  1065. m_scene.EventManager.TriggerLandObjectUpdated((uint)LandData.LocalID, this);
  1066. }
  1067. }
  1068. }