PageRenderTime 53ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/Aurora/Modules/World/Land/ParcelManagementModule.cs

https://bitbucket.org/VirtualReality/async-sim-testing
C# | 2423 lines | 1961 code | 256 blank | 206 comment | 371 complexity | 807f802677270bd1e7d9342a0c190f90 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (c) Contributors, http://aurora-sim.org/, 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 Aurora-Sim 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 Aurora.Framework;
  28. using Aurora.Framework.ClientInterfaces;
  29. using Aurora.Framework.ConsoleFramework;
  30. using Aurora.Framework.DatabaseInterfaces;
  31. using Aurora.Framework.Modules;
  32. using Aurora.Framework.PresenceInfo;
  33. using Aurora.Framework.SceneInfo;
  34. using Aurora.Framework.SceneInfo.Entities;
  35. using Aurora.Framework.Servers.HttpServer;
  36. using Aurora.Framework.Servers.HttpServer.Implementation;
  37. using Aurora.Framework.Servers.HttpServer.Interfaces;
  38. using Aurora.Framework.Services;
  39. using Aurora.Framework.Utilities;
  40. using Nini.Config;
  41. using OpenMetaverse;
  42. using OpenMetaverse.Messages.Linden;
  43. using OpenMetaverse.StructuredData;
  44. using System;
  45. using System.Collections.Generic;
  46. using System.IO;
  47. using System.Linq;
  48. using System.Timers;
  49. using GridRegion = Aurora.Framework.Services.GridRegion;
  50. namespace Aurora.Modules.Land
  51. {
  52. public class ParcelManagementModule : INonSharedRegionModule, IParcelManagementModule
  53. {
  54. #region Constants
  55. //Land types set with flags in ParcelOverlay.
  56. //Only one of these can be used.
  57. public const float BAN_LINE_SAFETY_HEIGHT = 100;
  58. public const int LAND_RESULT_NO_DATA = -1; // The request they made had no data
  59. public const int LAND_RESULT_SINGLE = 0; // The request they made contained only a single piece of land
  60. public const int LAND_RESULT_MULTIPLE = 1; // The request they made contained more than a single peice of land
  61. //ParcelSelectObjects
  62. public const int LAND_SELECT_OBJECTS_GROUP = 4;
  63. public const int LAND_SELECT_OBJECTS_OTHER = 8;
  64. public const int LAND_SELECT_OBJECTS_OWNER = 2;
  65. public const byte LAND_TYPE_IS_BEING_AUCTIONED = 5; //Equals 00000101
  66. public const byte LAND_TYPE_IS_FOR_SALE = 4; //Equals 00000100
  67. public const byte LAND_TYPE_OWNED_BY_GROUP = 2; //Equals 00000010
  68. public const byte LAND_TYPE_OWNED_BY_OTHER = 1; //Equals 00000001
  69. public const byte LAND_TYPE_OWNED_BY_REQUESTER = 3; //Equals 00000011
  70. public const byte LAND_TYPE_PUBLIC = 0; //Equals 00000000
  71. public const int LAND_OVERLAY_CHUNKS = 4; //The number of land chunks to send to the client
  72. public const int LAND_MAX_ENTRIES_PER_PACKET = 48; //Max number of access/ban entry updates
  73. //These are other constants. Yay!
  74. public const int START_LAND_LOCAL_ID = 0;
  75. #endregion
  76. #region Declares
  77. private static readonly string remoteParcelRequestPath = "0009/";
  78. private readonly List<UUID> m_hasSentParcelOverLay = new List<UUID>();
  79. /// <value>
  80. /// Land objects keyed by local id
  81. /// </value>
  82. private readonly Dictionary<int, ILandObject> m_landList = new Dictionary<int, ILandObject>();
  83. private readonly object m_landListLock = new object();
  84. private bool UseDwell = true;
  85. private bool m_TaintedLandData;
  86. private bool m_UpdateDirectoryOnTimer = true;
  87. private bool m_UpdateDirectoryOnUpdate;
  88. private Timer m_UpdateDirectoryTimer = new Timer();
  89. public UUID GodParcelOwner { get; set; }
  90. private string _godParcelOwner = "";
  91. /// <value>
  92. /// Local land ids at specified region co-ordinates (region size / 4)
  93. /// </value>
  94. private int[,] m_landIDList;
  95. private int m_lastLandLocalID = START_LAND_LOCAL_ID;
  96. private int m_minutesBeforeTimer = 1;
  97. protected Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>();
  98. private IScene m_scene;
  99. private int m_update_land = 200;
  100. //Check whether we need to rebuild the parcel prim count and other land related functions
  101. public int[,] LandIDList
  102. {
  103. get { return m_landIDList; }
  104. }
  105. #endregion
  106. #region INonSharedRegionModule Members
  107. public Type ReplaceableInterface
  108. {
  109. get { return null; }
  110. }
  111. public void Initialise(IConfigSource source)
  112. {
  113. IConfig config = source.Configs["LandManagement"];
  114. if (config != null)
  115. {
  116. m_UpdateDirectoryOnTimer = config.GetBoolean("UpdateOnTimer", m_UpdateDirectoryOnTimer);
  117. m_UpdateDirectoryOnUpdate = config.GetBoolean("UpdateOnUpdate", m_UpdateDirectoryOnUpdate);
  118. m_minutesBeforeTimer = config.GetInt("MinutesBeforeTimerUpdate", m_minutesBeforeTimer);
  119. _godParcelOwner = config.GetString("GodParcelOwner", "");
  120. UseDwell = config.GetBoolean("AllowDwell", true);
  121. }
  122. }
  123. public void AddRegion(IScene scene)
  124. {
  125. m_scene = scene;
  126. m_landIDList = new int[m_scene.RegionInfo.RegionSizeX/4,m_scene.RegionInfo.RegionSizeY/4];
  127. if (m_UpdateDirectoryOnTimer)
  128. {
  129. m_UpdateDirectoryTimer.Interval = 1000*60*m_minutesBeforeTimer;
  130. m_UpdateDirectoryTimer.Elapsed += UpdateDirectoryTimerElapsed;
  131. m_UpdateDirectoryTimer.Start();
  132. }
  133. UUID godParcelOwner = UUID.Zero;
  134. if (_godParcelOwner != "")
  135. {
  136. UserAccount acc = m_scene.UserAccountService.GetUserAccount(null, _godParcelOwner);
  137. if (acc != null)
  138. godParcelOwner = acc.PrincipalID;
  139. }
  140. GodParcelOwner = godParcelOwner;
  141. m_scene.EventManager.OnAvatarEnteringNewParcel += EventManagerOnAvatarEnteringNewParcel;
  142. m_scene.EventManager.OnValidateBuyLand += EventManagerOnValidateLandBuy;
  143. m_scene.EventManager.OnNewClient += EventManagerOnNewClient;
  144. m_scene.EventManager.OnMakeRootAgent += CheckEnteringNewParcel;
  145. m_scene.EventManager.OnClientMovement += EventManagerOnSignificantClientMovement;
  146. m_scene.EventManager.OnSignificantObjectMovement += EventManagerOnSignificantObjectMovement;
  147. m_scene.EventManager.OnIncomingLandDataFromStorage += EventManagerOnIncomingLandDataFromStorage;
  148. m_scene.EventManager.OnRegisterCaps += EventManagerOnRegisterCaps;
  149. m_scene.EventManager.OnClosingClient += OnClosingClient;
  150. m_scene.EventManager.OnFrame += EventManager_OnFrame;
  151. m_scene.AuroraEventManager.RegisterEventHandler("ObjectAddedFlag", AuroraEventManager_OnGenericEvent);
  152. m_scene.AuroraEventManager.RegisterEventHandler("ObjectRemovedFlag", AuroraEventManager_OnGenericEvent);
  153. if (m_UpdateDirectoryOnTimer)
  154. m_scene.EventManager.OnStartupComplete += EventManager_OnStartupComplete;
  155. m_scene.RegisterModuleInterface<IParcelManagementModule>(this);
  156. }
  157. public void RegionLoaded(IScene scene)
  158. {
  159. IScheduledMoneyModule moneyModule = m_scene.RequestModuleInterface<IScheduledMoneyModule>();
  160. if (moneyModule != null)
  161. {
  162. moneyModule.OnUserDidNotPay += moneyModule_OnUserDidNotPay;
  163. moneyModule.OnCheckWhetherUserShouldPay += moneyModule_OnCheckWhetherUserShouldPay;
  164. }
  165. }
  166. public void RemoveRegion(IScene scene)
  167. {
  168. List<ILandObject> parcels = AllParcels();
  169. foreach (ILandObject land in parcels)
  170. {
  171. UpdateLandObject(land);
  172. }
  173. if (m_UpdateDirectoryOnTimer)
  174. {
  175. m_UpdateDirectoryTimer.Stop();
  176. m_UpdateDirectoryTimer = null;
  177. }
  178. m_scene.EventManager.OnAvatarEnteringNewParcel -= EventManagerOnAvatarEnteringNewParcel;
  179. m_scene.EventManager.OnValidateBuyLand -= EventManagerOnValidateLandBuy;
  180. m_scene.EventManager.OnNewClient -= EventManagerOnNewClient;
  181. m_scene.EventManager.OnMakeRootAgent -= CheckEnteringNewParcel;
  182. m_scene.EventManager.OnSignificantClientMovement -= EventManagerOnSignificantClientMovement;
  183. m_scene.EventManager.OnSignificantObjectMovement -= EventManagerOnSignificantObjectMovement;
  184. m_scene.EventManager.OnIncomingLandDataFromStorage -= EventManagerOnIncomingLandDataFromStorage;
  185. m_scene.EventManager.OnRegisterCaps -= EventManagerOnRegisterCaps;
  186. m_scene.EventManager.OnClosingClient -= OnClosingClient;
  187. m_scene.UnregisterModuleInterface<IParcelManagementModule>(this);
  188. }
  189. public void Close()
  190. {
  191. }
  192. public string Name
  193. {
  194. get { return "LandManagementModule"; }
  195. }
  196. #endregion
  197. #region MoneyModule pieces (for parcel directory payment)
  198. private bool moneyModule_OnCheckWhetherUserShouldPay(UUID agentID, string paymentTextThatFailed)
  199. {
  200. if (paymentTextThatFailed.StartsWith("Parcel Show in Search Fee - "))
  201. {
  202. UUID parcelGlobalID = UUID.Parse(paymentTextThatFailed.Substring("Parcel Show in Search Fee - ".Length));
  203. //Only charge if the parcel still exists
  204. return GetLandObject(parcelGlobalID) != null;
  205. }
  206. return true;
  207. }
  208. private void moneyModule_OnUserDidNotPay(UUID agentID, string paymentTextThatFailed)
  209. {
  210. UUID parcelGlobalID = UUID.Parse(paymentTextThatFailed.Substring("Parcel Show in Search Fee - ".Length));
  211. ILandObject parcel;
  212. if ((parcel = GetLandObject(parcelGlobalID)) != null)
  213. parcel.LandData.Flags &= (uint) ParcelFlags.ShowDirectory;
  214. }
  215. #endregion
  216. #region Heartbeat Tick, Parcel Returns, Clean temp objects
  217. private readonly HashSet<ISceneEntity> m_entitiesInAutoReturnQueue = new HashSet<ISceneEntity>();
  218. /// <summary>
  219. /// Return object to avatar Message
  220. /// </summary>
  221. /// <param name="agentID">Avatar Unique Id</param>
  222. /// <param name="objectName">Name of object returned</param>
  223. /// <param name="location">Location of object returned</param>
  224. /// <param name="reason">Reasion for object return</param>
  225. /// <param name="groups">The objects to return</param>
  226. public void AddReturns(UUID agentID, string objectName, Vector3 location, string reason,
  227. List<ISceneEntity> groups)
  228. {
  229. lock (m_returns)
  230. {
  231. if (m_returns.ContainsKey(agentID))
  232. {
  233. ReturnInfo info = m_returns[agentID];
  234. info.count += groups.Count;
  235. info.Groups.AddRange(groups);
  236. m_returns[agentID] = info;
  237. }
  238. else
  239. {
  240. ReturnInfo info = new ReturnInfo
  241. {
  242. count = groups.Count,
  243. objectName = objectName,
  244. location = location,
  245. reason = reason,
  246. Groups = groups
  247. };
  248. m_returns[agentID] = info;
  249. }
  250. }
  251. }
  252. private void EventManager_OnFrame()
  253. {
  254. if (m_scene.Frame%m_update_land == 0)
  255. {
  256. //It's time, check the parts we have
  257. CheckFrameEvents();
  258. }
  259. }
  260. private object AuroraEventManager_OnGenericEvent(string FunctionName, object parameters)
  261. {
  262. if (FunctionName == "ObjectAddedFlag")
  263. {
  264. object[] param = (object[]) parameters;
  265. ISceneChildEntity child = (ISceneChildEntity) param[0];
  266. PrimFlags flag = (PrimFlags) param[1];
  267. if (flag == PrimFlags.TemporaryOnRez)
  268. m_entitiesInAutoReturnQueue.Add(child.ParentEntity);
  269. }
  270. else if (FunctionName == "ObjectRemovedFlag")
  271. {
  272. object[] param = (object[]) parameters;
  273. ISceneChildEntity child = (ISceneChildEntity) param[0];
  274. PrimFlags flag = (PrimFlags) param[1];
  275. if (flag == PrimFlags.TemporaryOnRez)
  276. m_entitiesInAutoReturnQueue.Remove(child.ParentEntity);
  277. }
  278. return null;
  279. }
  280. /// <summary>
  281. /// This deals with sending the return IMs as well as actually returning the objects
  282. /// </summary>
  283. protected internal void CheckFrameEvents()
  284. {
  285. // Go through all updates and check for temp and auto return
  286. CheckPrimForAutoReturn();
  287. CheckPrimForTemperary();
  288. lock (m_returns)
  289. {
  290. foreach (KeyValuePair<UUID, ReturnInfo> ret in m_returns)
  291. {
  292. if (ret.Value.reason != "")
  293. {
  294. UUID transaction = UUID.Random();
  295. GridInstantMessage msg = new GridInstantMessage
  296. {
  297. fromAgentID = UUID.Zero,
  298. toAgentID = ret.Key,
  299. imSessionID = transaction,
  300. timestamp = (uint) Util.UnixTimeSinceEpoch(),
  301. fromAgentName = "Server",
  302. dialog = 19,
  303. fromGroup = false,
  304. offline = 1,
  305. ParentEstateID =
  306. m_scene.RegionInfo.EstateSettings.ParentEstateID,
  307. Position = Vector3.Zero,
  308. RegionID = m_scene.RegionInfo.RegionID,
  309. binaryBucket = Util.StringToBytes256("\0")
  310. };
  311. // From server
  312. // Object msg
  313. // We must fill in a null-terminated 'empty' string here since bytes[0] will crash viewer 3.
  314. if (ret.Value.count > 1)
  315. msg.message =
  316. string.Format("Your {0} objects were returned from {1} in region {2} due to {3}",
  317. ret.Value.count, ret.Value.location.ToString(),
  318. m_scene.RegionInfo.RegionName, ret.Value.reason);
  319. else
  320. msg.message = string.Format(
  321. "Your object {0} was returned from {1} in region {2} due to {3}", ret.Value.objectName,
  322. ret.Value.location.ToString(), m_scene.RegionInfo.RegionName, ret.Value.reason);
  323. IMessageTransferModule tr = m_scene.RequestModuleInterface<IMessageTransferModule>();
  324. if (tr != null)
  325. tr.SendInstantMessage(msg);
  326. if (ret.Value.Groups.Count > 1)
  327. MainConsole.Instance.InfoFormat(
  328. "[LandManagement]: Returning {0} objects due to parcel auto return.",
  329. ret.Value.Groups.Count);
  330. else
  331. MainConsole.Instance.Info("[LandManagement]: Returning 1 object due to parcel auto return.");
  332. }
  333. IAsyncSceneObjectGroupDeleter asyncDelete =
  334. m_scene.RequestModuleInterface<IAsyncSceneObjectGroupDeleter>();
  335. if (asyncDelete != null)
  336. {
  337. asyncDelete.DeleteToInventory(
  338. DeRezAction.Return, ret.Value.Groups[0].RootChild.OwnerID, ret.Value.Groups,
  339. ret.Value.Groups[0].RootChild.OwnerID,
  340. true, true);
  341. }
  342. }
  343. m_returns.Clear();
  344. }
  345. }
  346. protected void CheckPrimForTemperary()
  347. {
  348. HashSet<ISceneEntity> entitiesToRemove = new HashSet<ISceneEntity>();
  349. foreach (
  350. ISceneEntity entity in
  351. m_entitiesInAutoReturnQueue.Where(entity => entity.RootChild.Expires <= DateTime.Now))
  352. {
  353. entitiesToRemove.Add(entity);
  354. //Temporary objects don't get a reason, they return quietly
  355. AddReturns(entity.OwnerID, entity.Name, entity.AbsolutePosition, "", new List<ISceneEntity> {entity});
  356. }
  357. foreach (ISceneEntity entity in entitiesToRemove)
  358. {
  359. m_entitiesInAutoReturnQueue.Remove(entity);
  360. }
  361. }
  362. protected void CheckPrimForAutoReturn()
  363. {
  364. // Don't abort the whole thing if one entity happens to give us an exception.
  365. try
  366. {
  367. IPrimCountModule primCount = m_scene.RequestModuleInterface<IPrimCountModule>();
  368. if (primCount == null)
  369. return;
  370. List<ISceneEntity> entities = new List<ISceneEntity>();
  371. foreach (ISceneEntity sog in from parcel in AllParcels()
  372. where parcel != null && parcel.LandData != null &&
  373. parcel.LandData.OtherCleanTime != 0
  374. from sog in primCount.GetPrimCounts(parcel.LandData.GlobalID).Objects
  375. where parcel.LandData.OwnerID != sog.OwnerID &&
  376. ((parcel.LandData.GroupID == UUID.Zero) ||
  377. //If there is no group, don't check the groups part
  378. ((parcel.LandData.GroupID != UUID.Zero) &&
  379. //If there is a group, check for group rezzed prims and group owned prims
  380. (parcel.LandData.GroupID != sog.GroupID &&
  381. //Allow prims set to the group
  382. parcel.LandData.GroupID != sog.OwnerID &&
  383. //Allow group deeded prims!
  384. parcel.LandData.OwnerID != sog.GroupID)
  385. //Allow group deeded prims!
  386. )) &&
  387. !m_scene.Permissions.IsAdministrator(sog.OwnerID)
  388. where (DateTime.UtcNow - sog.RootChild.Rezzed).TotalSeconds >
  389. parcel.LandData.OtherCleanTime*60
  390. select sog)
  391. {
  392. entities.Add(sog);
  393. }
  394. if (entities.Count > 0)
  395. AddReturns(entities[0].OwnerID, entities[0].Name, entities[0].AbsolutePosition, "Auto Parcel Return",
  396. entities);
  397. }
  398. catch (Exception e)
  399. {
  400. MainConsole.Instance.ErrorFormat(
  401. "[LandManagement]: Failed to check for parcel returns: {0}", e);
  402. }
  403. }
  404. #endregion
  405. #region Parcel Add/Remove/Get/Create
  406. private readonly Dictionary<UUID, ParcelResult> m_lastDataResults = new Dictionary<UUID, ParcelResult>();
  407. private readonly Dictionary<UUID, ILandObject> m_lastLandObject = new Dictionary<UUID, ILandObject>();
  408. private readonly Dictionary<UUID, int> m_lastResults = new Dictionary<UUID, int>();
  409. public void UpdateLandObject(ILandObject lo)
  410. {
  411. AddLandObjectToSearch(lo);
  412. m_scene.EventManager.TriggerLandObjectAdded(lo.LandData);
  413. foreach (IScenePresence sp in m_scene.GetScenePresences())
  414. {
  415. if (sp.CurrentParcelUUID == lo.LandData.GlobalID)
  416. {
  417. if (lo.IsEitherBannedOrRestricted(sp.UUID))
  418. {
  419. SendYouAreRestrictedNotice(sp);
  420. Vector3 pos = GetNearestAllowedPosition(sp);
  421. pos.Z -= sp.PhysicsActor.Size.Z;
  422. sp.Teleport(pos);
  423. }
  424. }
  425. }
  426. }
  427. /// <summary>
  428. /// Resets the sim to have no land objects
  429. /// </summary>
  430. public void ClearAllParcels()
  431. {
  432. //Remove all the land objects in the sim and add a blank, full sim land object set to public
  433. List<ILandObject> parcels = new List<ILandObject>(m_landList.Values);
  434. foreach (ILandObject land in parcels)
  435. {
  436. m_scene.EventManager.TriggerLandObjectRemoved(land.LandData.RegionID, land.LandData.GlobalID);
  437. }
  438. lock (m_landListLock)
  439. {
  440. m_landList.Clear();
  441. m_lastLandLocalID = START_LAND_LOCAL_ID;
  442. }
  443. }
  444. /// <summary>
  445. /// Resets the sim to the default land object (full sim piece of land owned by the default user)
  446. /// </summary>
  447. public ILandObject ResetSimLandObjects()
  448. {
  449. ClearAllParcels();
  450. ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene);
  451. if (fullSimParcel.LandData.OwnerID == UUID.Zero)
  452. fullSimParcel.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
  453. UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.AllScopeIDs,
  454. fullSimParcel.LandData.OwnerID);
  455. while (fullSimParcel.LandData.OwnerID == UUID.Zero || account == null)
  456. {
  457. MainConsole.Instance.Warn(
  458. "[ParcelManagement]: Could not find user for parcel, please give a valid user to make the owner");
  459. string userName = MainConsole.Instance.Prompt("User Name:", "");
  460. if (userName == "")
  461. {
  462. MainConsole.Instance.Warn("Put in a valid username.");
  463. continue;
  464. }
  465. account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.AllScopeIDs, userName);
  466. if (account != null)
  467. fullSimParcel.LandData.OwnerID = account.PrincipalID;
  468. else
  469. MainConsole.Instance.Warn("Could not find the user.");
  470. }
  471. MainConsole.Instance.Info("[ParcelManagement]: No land found for region " + m_scene.RegionInfo.RegionName +
  472. ", setting owner to " + fullSimParcel.LandData.OwnerID);
  473. fullSimParcel.LandData.ClaimDate = Util.UnixTimeSinceEpoch();
  474. fullSimParcel.SetInfoID();
  475. fullSimParcel.LandData.Bitmap =
  476. new byte[(m_scene.RegionInfo.RegionSizeX/4)*(m_scene.RegionInfo.RegionSizeY/4)/8];
  477. fullSimParcel = AddLandObject(fullSimParcel);
  478. ModifyLandBitmapSquare(0, 0,
  479. m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY,
  480. fullSimParcel);
  481. return fullSimParcel;
  482. }
  483. public List<ILandObject> AllParcels()
  484. {
  485. lock (m_landListLock)
  486. return new List<ILandObject>(m_landList.Values);
  487. }
  488. public List<ILandObject> ParcelsNearPoint(Vector3 position)
  489. {
  490. List<ILandObject> parcelsNear = new List<ILandObject>();
  491. for (int x = -4; x <= 4; x += 4)
  492. {
  493. for (int y = -4; y <= 4; y += 4)
  494. {
  495. ILandObject check = GetLandObject((int) (position.X + x), (int) (position.Y + y));
  496. if (check != null)
  497. {
  498. if (!parcelsNear.Contains(check))
  499. {
  500. parcelsNear.Add(check);
  501. }
  502. }
  503. }
  504. }
  505. return parcelsNear;
  506. }
  507. public ILandObject GetLandObject(int parcelLocalID)
  508. {
  509. lock (m_landListLock)
  510. {
  511. ILandObject land = null;
  512. m_landList.TryGetValue(parcelLocalID, out land);
  513. return land;
  514. }
  515. }
  516. public ILandObject GetLandObject(UUID GlobalID)
  517. {
  518. return AllParcels().FirstOrDefault(land => land.LandData.GlobalID == GlobalID);
  519. }
  520. public ILandObject GetLandObject(float x, float y)
  521. {
  522. return GetLandObject((int) x, (int) y);
  523. }
  524. public ILandObject GetLandObject(int x, int y)
  525. {
  526. RegionInfo r = m_scene.RegionInfo;
  527. if (x >= r.RegionSizeX || y >= r.RegionSizeY || x < 0 || y < 0)
  528. {
  529. if (x >= r.RegionSizeX)
  530. x = r.RegionSizeX - 1;
  531. if (x < 0)
  532. x = 1;
  533. if (y >= r.RegionSizeY)
  534. y = r.RegionSizeY - 1;
  535. if (y < 0)
  536. y = 1;
  537. }
  538. lock (m_landListLock)
  539. {
  540. try
  541. {
  542. return m_landList[m_landIDList[x/4, y/4]];
  543. }
  544. catch (IndexOutOfRangeException)
  545. {
  546. return null;
  547. }
  548. catch (KeyNotFoundException)
  549. {
  550. return null;
  551. }
  552. }
  553. }
  554. protected void AddLandObjectToSearch(ILandObject parcel)
  555. {
  556. IDirectoryServiceConnector DSC = Framework.Utilities.DataManager.RequestPlugin<IDirectoryServiceConnector>();
  557. if (DSC != null)
  558. {
  559. if (m_UpdateDirectoryOnUpdate)
  560. //Update search database
  561. DoSearchUpdate();
  562. else if (m_UpdateDirectoryOnTimer)
  563. m_TaintedLandData = true;
  564. }
  565. }
  566. private void RemoveLandObjectFromSearch(ILandObject iLandObject)
  567. {
  568. IDirectoryServiceConnector DSC = Framework.Utilities.DataManager.RequestPlugin<IDirectoryServiceConnector>();
  569. if (DSC != null)
  570. {
  571. if (m_UpdateDirectoryOnUpdate)
  572. //Update search database
  573. DoSearchUpdate();
  574. else if (m_UpdateDirectoryOnTimer)
  575. m_TaintedLandData = true;
  576. }
  577. }
  578. /// <summary>
  579. /// Adds a land object to the stored list and adds them to the landIDList to what they own
  580. /// </summary>
  581. /// <param name="land">The land object being added</param>
  582. public ILandObject AddLandObject(ILandObject land)
  583. {
  584. return AddLandObject(land, false);
  585. }
  586. protected ILandObject AddLandObject(ILandObject land, bool incomingFromDatabase)
  587. {
  588. //Don't make a copy unless necessary
  589. ILandObject new_land = incomingFromDatabase ? land : land.Copy();
  590. new_land.LandData.RegionID = m_scene.RegionInfo.RegionID;
  591. new_land.LandData.RegionHandle = m_scene.RegionInfo.RegionHandle;
  592. lock (m_landListLock)
  593. {
  594. //Update the localID
  595. int newLandLocalID = ++m_lastLandLocalID;
  596. new_land.LandData.LocalID = newLandLocalID;
  597. //Add it to the list of land in this region
  598. m_landList.Add(newLandLocalID, new_land);
  599. }
  600. new_land.ForceUpdateLandInfo();
  601. //If it isn't coming in from the database, make sure to save the new parcel and add it to search
  602. if (!incomingFromDatabase)
  603. {
  604. AddLandObjectToSearch(new_land);
  605. }
  606. //Trigger the event for any interested listeners
  607. m_scene.EventManager.TriggerLandObjectAdded(new_land.LandData);
  608. return new_land;
  609. }
  610. public void SendYouAreBannedNotice(IScenePresence avatar)
  611. {
  612. avatar.ControllingClient.SendAlertMessage(
  613. "You are not allowed on this parcel because you are banned.");
  614. }
  615. public void SendYouAreRestrictedNotice(IScenePresence avatar)
  616. {
  617. avatar.ControllingClient.SendAlertMessage(
  618. "You are not allowed on this parcel because the land owner has restricted access.");
  619. }
  620. public void EventManagerOnAvatarEnteringNewParcel(IScenePresence avatar, ILandObject oldParcel)
  621. {
  622. if (avatar.CurrentParcel != null)
  623. {
  624. //Tell the clint about it
  625. avatar.CurrentParcel.SendLandUpdateToClient(avatar.ControllingClient);
  626. //Gotta kill all avatars outside the parcel
  627. foreach (
  628. IScenePresence sp in
  629. avatar.Scene.Entities.GetPresences()
  630. .Where(sp => sp.UUID != avatar.UUID)
  631. .Where(sp => sp.CurrentParcel != null))
  632. {
  633. if (sp.CurrentParcelUUID == avatar.CurrentParcelUUID) //Send full updates for those in the sim
  634. {
  635. if (avatar.CurrentParcel.LandData.Private || (oldParcel != null && oldParcel.LandData.Private))
  636. //Either one, we gotta send an update
  637. {
  638. sp.SceneViewer.RemoveAvatarFromView(avatar);
  639. avatar.SceneViewer.RemoveAvatarFromView(sp);
  640. sp.SceneViewer.QueuePresenceForFullUpdate(avatar, true);
  641. avatar.SceneViewer.QueuePresenceForFullUpdate(sp, true);
  642. }
  643. }
  644. else //Kill those outside the parcel
  645. {
  646. if (sp.CurrentParcel.LandData.Private || avatar.CurrentParcel.LandData.Private)
  647. {
  648. sp.ControllingClient.SendKillObject(sp.Scene.RegionInfo.RegionHandle,
  649. new IEntity[1] {avatar});
  650. avatar.ControllingClient.SendKillObject(sp.Scene.RegionInfo.RegionHandle,
  651. new IEntity[1] {sp});
  652. sp.SceneViewer.RemoveAvatarFromView(avatar);
  653. avatar.SceneViewer.RemoveAvatarFromView(sp);
  654. }
  655. }
  656. }
  657. if (UseDwell)
  658. avatar.CurrentParcel.LandData.Dwell += 1;
  659. if (avatar.AbsolutePosition.Z < BAN_LINE_SAFETY_HEIGHT)
  660. {
  661. if (avatar.CurrentParcel.IsBannedFromLand(avatar.UUID))
  662. {
  663. SendYouAreBannedNotice(avatar);
  664. Vector3 pos = GetNearestAllowedPosition(avatar);
  665. pos.Z -= avatar.PhysicsActor.Size.Z;
  666. avatar.Teleport(pos);
  667. }
  668. else if (avatar.CurrentParcel.IsRestrictedFromLand(avatar.UUID))
  669. {
  670. SendYouAreRestrictedNotice(avatar);
  671. Vector3 pos = GetNearestAllowedPosition(avatar);
  672. pos.Z -= avatar.PhysicsActor.Size.Z;
  673. avatar.Teleport(pos);
  674. }
  675. }
  676. }
  677. }
  678. private void SendOutNearestBanLine(IScenePresence sp, ILandObject ourLandObject)
  679. {
  680. int multiple = 0;
  681. int result = 0;
  682. Vector3 spAbs = sp.AbsolutePosition;
  683. foreach (ILandObject parcel in from parcel in AllParcels()
  684. let aamax = parcel.LandData.AABBMax
  685. let aamin = parcel.LandData.AABBMin
  686. where Math.Abs(aamax.X - spAbs.X) < 4 ||
  687. Math.Abs(aamax.Y - spAbs.Y) < 4 ||
  688. Math.Abs(aamin.X - spAbs.X) < 4 ||
  689. Math.Abs(aamin.Y - spAbs.Y) < 4
  690. select parcel)
  691. {
  692. //Do the & since we don't need to check again if we have already set the ban flag
  693. if ((result & (int) ParcelPropertiesStatus.CollisionBanned) !=
  694. (int) ParcelPropertiesStatus.CollisionBanned &&
  695. parcel.IsBannedFromLand(sp.UUID))
  696. {
  697. multiple++;
  698. result |= (int) ParcelPropertiesStatus.CollisionBanned;
  699. continue; //Only send one
  700. }
  701. else if ((result & (int) ParcelPropertiesStatus.CollisionNotOnAccessList) !=
  702. (int) ParcelPropertiesStatus.CollisionNotOnAccessList &&
  703. parcel.IsRestrictedFromLand(sp.UUID))
  704. {
  705. multiple++;
  706. result |= (int) ParcelPropertiesStatus.CollisionNotOnAccessList;
  707. continue; //Only send one
  708. }
  709. }
  710. ParcelResult dataResult = ParcelResult.NoData;
  711. if (multiple > 1)
  712. dataResult = ParcelResult.Multiple;
  713. else if (multiple == 1)
  714. dataResult = ParcelResult.Single;
  715. m_lastDataResults[sp.UUID] = dataResult;
  716. m_lastResults[sp.UUID] = result;
  717. m_lastLandObject[sp.UUID] = ourLandObject;
  718. if (multiple == 0) //If there is no result, don't send anything
  719. return;
  720. ourLandObject.SendLandProperties(result, false, (int) dataResult, sp.ControllingClient);
  721. }
  722. private void CheckEnteringNewParcel(IScenePresence avatar)
  723. {
  724. ILandObject over = GetLandObject((int) avatar.AbsolutePosition.X,
  725. (int) avatar.AbsolutePosition.Y);
  726. CheckEnteringNewParcel(avatar, over);
  727. }
  728. private void CheckEnteringNewParcel(IScenePresence avatar, ILandObject over)
  729. {
  730. if (over != null)
  731. {
  732. if (avatar.CurrentParcelUUID != over.LandData.GlobalID)
  733. {
  734. if (!avatar.IsChildAgent)
  735. {
  736. ILandObject oldParcel = avatar.CurrentParcel;
  737. avatar.CurrentParcelUUID = over.LandData.GlobalID;
  738. avatar.CurrentParcel = over;
  739. m_scene.EventManager.TriggerAvatarEnteringNewParcel(avatar, oldParcel);
  740. }
  741. }
  742. }
  743. }
  744. public void EventManagerOnSignificantClientMovement(IScenePresence sp)
  745. {
  746. IScenePresence clientAvatar = m_scene.GetScenePresence(sp.UUID);
  747. if (clientAvatar != null)
  748. {
  749. ILandObject over = GetLandObject((int) clientAvatar.AbsolutePosition.X,
  750. (int) clientAvatar.AbsolutePosition.Y);
  751. if (over != null)
  752. {
  753. if (!over.IsRestrictedFromLand(clientAvatar.UUID) &&
  754. (!over.IsBannedFromLand(clientAvatar.UUID) ||
  755. clientAvatar.AbsolutePosition.Z >= BAN_LINE_SAFETY_HEIGHT))
  756. //Allow for the flying over of ban lines
  757. {
  758. clientAvatar.LastKnownAllowedPosition =
  759. new Vector3(clientAvatar.AbsolutePosition.X, clientAvatar.AbsolutePosition.Y,
  760. clientAvatar.AbsolutePosition.Z);
  761. }
  762. else
  763. {
  764. //Kick them out
  765. Vector3 pos = clientAvatar.LastKnownAllowedPosition == Vector3.Zero
  766. ? GetNearestAllowedPosition(clientAvatar)
  767. : clientAvatar.LastKnownAllowedPosition;
  768. pos.Z = clientAvatar.AbsolutePosition.Z - clientAvatar.PhysicsActor.Size.Z;
  769. clientAvatar.Teleport(pos);
  770. }
  771. CheckEnteringNewParcel(clientAvatar, over);
  772. SendOutNearestBanLine(clientAvatar, over);
  773. }
  774. }
  775. }
  776. //Like handleEventManagerOnSignificantClientMovement, but for objects for parcel incoming object permissions
  777. public void EventManagerOnSignificantObjectMovement(ISceneEntity group)
  778. {
  779. ILandObject over = GetLandObject((int) group.AbsolutePosition.X, (int) group.AbsolutePosition.Y);
  780. if (over != null)
  781. {
  782. //Entered this new parcel
  783. if (over.LandData.GlobalID != group.LastParcelUUID)
  784. {
  785. if (!m_scene.Permissions.CanObjectEntry(group.UUID,
  786. false, group.AbsolutePosition, group.OwnerID))
  787. {
  788. //Revert the position and do not update the parcel ID
  789. group.AbsolutePosition = group.LastSignificantPosition;
  790. //If the object has physics, stop it from moving
  791. if ((group.RootChild.Flags & PrimFlags.Physics) == PrimFlags.Physics)
  792. {
  793. bool wasTemporary = ((group.RootChild.Flags & PrimFlags.TemporaryOnRez) != 0);
  794. bool wasPhantom = ((group.RootChild.Flags & PrimFlags.Phantom) != 0);
  795. bool wasVD = group.RootChild.VolumeDetectActive;
  796. bool needsPhysicalRebuild = group.RootChild.UpdatePrimFlags(false,
  797. wasTemporary,
  798. wasPhantom,
  799. wasVD, null);
  800. if (needsPhysicalRebuild)
  801. group.RebuildPhysicalRepresentation(true);
  802. }
  803. //Send an update so that all clients see it
  804. group.ScheduleGroupTerseUpdate();
  805. }
  806. else
  807. {
  808. UUID oldParcelUUID = group.LastParcelUUID;
  809. //Update the UUID then
  810. group.LastParcelUUID = over.LandData.GlobalID;
  811. //Trigger the event
  812. object[] param = new object[3];
  813. param[0] = group;
  814. param[1] = over.LandData.GlobalID;
  815. param[2] = oldParcelUUID;
  816. m_scene.AuroraEventManager.FireGenericEventHandler("ObjectEnteringNewParcel", param);
  817. }
  818. }
  819. }
  820. }
  821. public void ClientOnParcelAccessListRequest(UUID agentID, UUID sessionID, uint flags, int sequenceID,
  822. int landLocalID, IClientAPI remote_client)
  823. {
  824. ILandObject land = GetLandObject(landLocalID);
  825. if (land != null)
  826. {
  827. land.SendAccessList(agentID, sessionID, flags, sequenceID, remote_client);
  828. }
  829. }
  830. public void ClientOnParcelAccessUpdateListRequest(UUID agentID, UUID sessionID, uint flags, int landLocalID,
  831. List<ParcelManager.ParcelAccessEntry> entries,
  832. IClientAPI remote_client)
  833. {
  834. ILandObject land = GetLandObject(landLocalID);
  835. if (land != null)
  836. {
  837. if (m_scene.Permissions.CanEditParcelAccessList(remote_client.AgentId, land, flags))
  838. {
  839. land.UpdateAccessList(flags, entries, remote_client);
  840. }
  841. }
  842. else
  843. {
  844. MainConsole.Instance.WarnFormat("[LAND]: Invalid local land ID {0}", landLocalID);
  845. }
  846. }
  847. /// <summary>
  848. /// Removes a land object from the list. Will not remove if local_id is still owning an area in landIDList
  849. /// </summary>
  850. /// <param name="local_id">Land.localID of the peice of land to remove.</param>
  851. public void removeLandObject(int local_id)
  852. {
  853. lock (m_landListLock)
  854. {
  855. for (int x = 0; x < m_scene.RegionInfo.RegionSizeX/4; x++)
  856. {
  857. for (int y = 0; y < m_scene.RegionInfo.RegionSizeY/4; y++)
  858. {
  859. if (m_landIDList[x, y] == local_id)
  860. {
  861. MainConsole.Instance.WarnFormat(
  862. "[LAND]: Not removing land object {0}; still being used at {1}, {2}",
  863. local_id, x, y);
  864. return;
  865. //throw new Exception("Could not remove land object. Still being used at " + x + ", " + y);
  866. }
  867. }
  868. }
  869. ILandObject land = m_landList[local_id];
  870. m_scene.EventManager.TriggerLandObjectRemoved(land.LandData.RegionID, land.LandData.GlobalID);
  871. m_landList.Remove(local_id);
  872. RemoveLandObjectFromSearch(land);
  873. }
  874. }
  875. public void ParcelBuyPass(IClientAPI client, UUID agentID, int ParcelLocalID)
  876. {
  877. ILandObject landObject = GetLandObject(ParcelLocalID);
  878. if (landObject == null)
  879. {
  880. client.SendAlertMessage("Could not find the parcel you are currently on.");
  881. return;
  882. }
  883. if (landObject.IsBannedFromLand(agentID))
  884. {
  885. client.SendAlertMessage("You cannot buy a pass as you are banned from this parcel.");
  886. return;
  887. }
  888. IMoneyModule module = m_scene.RequestModuleInterface<IMoneyModule>();
  889. if (module != null)
  890. if (
  891. !module.Transfer(landObject.LandData.OwnerID, client.AgentId, landObject.LandData.PassPrice,
  892. "Parcel Pass"))
  893. {
  894. client.SendAlertMessage("You do not have enough funds to complete this transaction.");
  895. return;
  896. }
  897. ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry
  898. {
  899. AgentID = agentID,
  900. Flags = AccessList.Access,
  901. Time = DateTime.Now.AddHours(landObject.LandData.PassHours)
  902. };
  903. landObject.LandData.ParcelAccessList.Add(entry);
  904. client.SendAgentAlertMessage("You have been added to the parcel access list.", false);
  905. }
  906. #endregion
  907. #region Parcel Modification
  908. public void Join(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id)
  909. {
  910. join(start_x, start_y, end_x, end_y, attempting_user_id);
  911. }
  912. public void Subdivide(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id)
  913. {
  914. subdivide(start_x, start_y, end_x, end_y, attempting_user_id);
  915. }
  916. /// <summary>
  917. /// Subdivides a piece of land
  918. /// </summary>
  919. /// <param name="start_x">West Point</param>
  920. /// <param name="start_y">South Point</param>
  921. /// <param name="end_x">East Point</param>
  922. /// <param name="end_y">North Point</param>
  923. /// <param name="attempting_user_id">UUID of user who is trying to subdivide</param>
  924. /// <returns>Returns true if successful</returns>
  925. private void subdivide(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id)
  926. {
  927. //First, lets loop through the points and make sure they are all in the same peice of land
  928. //Get the land object at start
  929. ILandObject startLandObject = GetLandObject(start_x, start_y);
  930. if (startLandObject == null) return;
  931. //Loop through the points
  932. try
  933. {
  934. int totalX = end_x - start_x;
  935. int totalY = end_y - start_y;
  936. for (int y = 0; y < totalY; y += 2)
  937. {
  938. for (int x = 0; x < totalX; x += 2)
  939. {
  940. ILandObject tempLandObject = GetLandObject(start_x + x, start_y + y);
  941. if (tempLandObject == null) return;
  942. if (tempLandObject != startLandObject) return;
  943. }
  944. }
  945. }
  946. catch (Exception)
  947. {
  948. return;
  949. }
  950. //If we are still here, then they are subdividing within one piece of land
  951. //Check owner
  952. IClientAPI client;
  953. m_scene.ClientManager.TryGetValue(attempting_user_id, out client);
  954. if (!m_scene.Permissions.CanSubdivideParcel(attempting_user_id, startLandObject) &&
  955. (!(m_scene.RegionInfo.RegionSettings.AllowLandJoinDivide &&
  956. m_scene.Permissions.IsGod(attempting_user_id))))
  957. {
  958. client.SendAlertMessage("Permissions: you cannot split this parcel.");
  959. return;
  960. }
  961. //Lets create a new land object with bitmap activated at that point (keeping the old land objects info)
  962. ILandObject newLand = startLandObject.Copy();
  963. newLand.LandData.G

Large files files are truncated, but you can click here to view the full file