/Aurora/Modules/World/Land/ParcelManagementModule.cs
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
- /*
- * Copyright (c) Contributors, http://aurora-sim.org/, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the Aurora-Sim Project nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
- using Aurora.Framework;
- using Aurora.Framework.ClientInterfaces;
- using Aurora.Framework.ConsoleFramework;
- using Aurora.Framework.DatabaseInterfaces;
- using Aurora.Framework.Modules;
- using Aurora.Framework.PresenceInfo;
- using Aurora.Framework.SceneInfo;
- using Aurora.Framework.SceneInfo.Entities;
- using Aurora.Framework.Servers.HttpServer;
- using Aurora.Framework.Servers.HttpServer.Implementation;
- using Aurora.Framework.Servers.HttpServer.Interfaces;
- using Aurora.Framework.Services;
- using Aurora.Framework.Utilities;
- using Nini.Config;
- using OpenMetaverse;
- using OpenMetaverse.Messages.Linden;
- using OpenMetaverse.StructuredData;
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Timers;
- using GridRegion = Aurora.Framework.Services.GridRegion;
-
- namespace Aurora.Modules.Land
- {
- public class ParcelManagementModule : INonSharedRegionModule, IParcelManagementModule
- {
- #region Constants
-
- //Land types set with flags in ParcelOverlay.
- //Only one of these can be used.
- public const float BAN_LINE_SAFETY_HEIGHT = 100;
- public const int LAND_RESULT_NO_DATA = -1; // The request they made had no data
- public const int LAND_RESULT_SINGLE = 0; // The request they made contained only a single piece of land
- public const int LAND_RESULT_MULTIPLE = 1; // The request they made contained more than a single peice of land
-
- //ParcelSelectObjects
- public const int LAND_SELECT_OBJECTS_GROUP = 4;
- public const int LAND_SELECT_OBJECTS_OTHER = 8;
- public const int LAND_SELECT_OBJECTS_OWNER = 2;
- public const byte LAND_TYPE_IS_BEING_AUCTIONED = 5; //Equals 00000101
- public const byte LAND_TYPE_IS_FOR_SALE = 4; //Equals 00000100
- public const byte LAND_TYPE_OWNED_BY_GROUP = 2; //Equals 00000010
- public const byte LAND_TYPE_OWNED_BY_OTHER = 1; //Equals 00000001
- public const byte LAND_TYPE_OWNED_BY_REQUESTER = 3; //Equals 00000011
- public const byte LAND_TYPE_PUBLIC = 0; //Equals 00000000
-
- public const int LAND_OVERLAY_CHUNKS = 4; //The number of land chunks to send to the client
-
- public const int LAND_MAX_ENTRIES_PER_PACKET = 48; //Max number of access/ban entry updates
-
- //These are other constants. Yay!
- public const int START_LAND_LOCAL_ID = 0;
-
- #endregion
-
- #region Declares
-
- private static readonly string remoteParcelRequestPath = "0009/";
-
- private readonly List<UUID> m_hasSentParcelOverLay = new List<UUID>();
-
- /// <value>
- /// Land objects keyed by local id
- /// </value>
- private readonly Dictionary<int, ILandObject> m_landList = new Dictionary<int, ILandObject>();
-
- private readonly object m_landListLock = new object();
- private bool UseDwell = true;
- private bool m_TaintedLandData;
-
- private bool m_UpdateDirectoryOnTimer = true;
- private bool m_UpdateDirectoryOnUpdate;
- private Timer m_UpdateDirectoryTimer = new Timer();
- public UUID GodParcelOwner { get; set; }
- private string _godParcelOwner = "";
-
- /// <value>
- /// Local land ids at specified region co-ordinates (region size / 4)
- /// </value>
- private int[,] m_landIDList;
-
- private int m_lastLandLocalID = START_LAND_LOCAL_ID;
- private int m_minutesBeforeTimer = 1;
-
- protected Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>();
- private IScene m_scene;
-
- private int m_update_land = 200;
- //Check whether we need to rebuild the parcel prim count and other land related functions
-
- public int[,] LandIDList
- {
- get { return m_landIDList; }
- }
-
- #endregion
-
- #region INonSharedRegionModule Members
-
- public Type ReplaceableInterface
- {
- get { return null; }
- }
-
- public void Initialise(IConfigSource source)
- {
- IConfig config = source.Configs["LandManagement"];
- if (config != null)
- {
- m_UpdateDirectoryOnTimer = config.GetBoolean("UpdateOnTimer", m_UpdateDirectoryOnTimer);
- m_UpdateDirectoryOnUpdate = config.GetBoolean("UpdateOnUpdate", m_UpdateDirectoryOnUpdate);
- m_minutesBeforeTimer = config.GetInt("MinutesBeforeTimerUpdate", m_minutesBeforeTimer);
- _godParcelOwner = config.GetString("GodParcelOwner", "");
- UseDwell = config.GetBoolean("AllowDwell", true);
- }
- }
-
- public void AddRegion(IScene scene)
- {
- m_scene = scene;
-
- m_landIDList = new int[m_scene.RegionInfo.RegionSizeX/4,m_scene.RegionInfo.RegionSizeY/4];
-
- if (m_UpdateDirectoryOnTimer)
- {
- m_UpdateDirectoryTimer.Interval = 1000*60*m_minutesBeforeTimer;
- m_UpdateDirectoryTimer.Elapsed += UpdateDirectoryTimerElapsed;
- m_UpdateDirectoryTimer.Start();
- }
-
- UUID godParcelOwner = UUID.Zero;
- if (_godParcelOwner != "")
- {
- UserAccount acc = m_scene.UserAccountService.GetUserAccount(null, _godParcelOwner);
- if (acc != null)
- godParcelOwner = acc.PrincipalID;
- }
- GodParcelOwner = godParcelOwner;
-
- m_scene.EventManager.OnAvatarEnteringNewParcel += EventManagerOnAvatarEnteringNewParcel;
- m_scene.EventManager.OnValidateBuyLand += EventManagerOnValidateLandBuy;
- m_scene.EventManager.OnNewClient += EventManagerOnNewClient;
- m_scene.EventManager.OnMakeRootAgent += CheckEnteringNewParcel;
- m_scene.EventManager.OnClientMovement += EventManagerOnSignificantClientMovement;
- m_scene.EventManager.OnSignificantObjectMovement += EventManagerOnSignificantObjectMovement;
- m_scene.EventManager.OnIncomingLandDataFromStorage += EventManagerOnIncomingLandDataFromStorage;
- m_scene.EventManager.OnRegisterCaps += EventManagerOnRegisterCaps;
- m_scene.EventManager.OnClosingClient += OnClosingClient;
- m_scene.EventManager.OnFrame += EventManager_OnFrame;
- m_scene.AuroraEventManager.RegisterEventHandler("ObjectAddedFlag", AuroraEventManager_OnGenericEvent);
- m_scene.AuroraEventManager.RegisterEventHandler("ObjectRemovedFlag", AuroraEventManager_OnGenericEvent);
- if (m_UpdateDirectoryOnTimer)
- m_scene.EventManager.OnStartupComplete += EventManager_OnStartupComplete;
-
- m_scene.RegisterModuleInterface<IParcelManagementModule>(this);
- }
-
- public void RegionLoaded(IScene scene)
- {
- IScheduledMoneyModule moneyModule = m_scene.RequestModuleInterface<IScheduledMoneyModule>();
- if (moneyModule != null)
- {
- moneyModule.OnUserDidNotPay += moneyModule_OnUserDidNotPay;
- moneyModule.OnCheckWhetherUserShouldPay += moneyModule_OnCheckWhetherUserShouldPay;
- }
- }
-
- public void RemoveRegion(IScene scene)
- {
- List<ILandObject> parcels = AllParcels();
- foreach (ILandObject land in parcels)
- {
- UpdateLandObject(land);
- }
-
- if (m_UpdateDirectoryOnTimer)
- {
- m_UpdateDirectoryTimer.Stop();
- m_UpdateDirectoryTimer = null;
- }
-
- m_scene.EventManager.OnAvatarEnteringNewParcel -= EventManagerOnAvatarEnteringNewParcel;
- m_scene.EventManager.OnValidateBuyLand -= EventManagerOnValidateLandBuy;
- m_scene.EventManager.OnNewClient -= EventManagerOnNewClient;
- m_scene.EventManager.OnMakeRootAgent -= CheckEnteringNewParcel;
- m_scene.EventManager.OnSignificantClientMovement -= EventManagerOnSignificantClientMovement;
- m_scene.EventManager.OnSignificantObjectMovement -= EventManagerOnSignificantObjectMovement;
- m_scene.EventManager.OnIncomingLandDataFromStorage -= EventManagerOnIncomingLandDataFromStorage;
- m_scene.EventManager.OnRegisterCaps -= EventManagerOnRegisterCaps;
- m_scene.EventManager.OnClosingClient -= OnClosingClient;
- m_scene.UnregisterModuleInterface<IParcelManagementModule>(this);
- }
-
- public void Close()
- {
- }
-
- public string Name
- {
- get { return "LandManagementModule"; }
- }
-
- #endregion
-
- #region MoneyModule pieces (for parcel directory payment)
-
- private bool moneyModule_OnCheckWhetherUserShouldPay(UUID agentID, string paymentTextThatFailed)
- {
- if (paymentTextThatFailed.StartsWith("Parcel Show in Search Fee - "))
- {
- UUID parcelGlobalID = UUID.Parse(paymentTextThatFailed.Substring("Parcel Show in Search Fee - ".Length));
- //Only charge if the parcel still exists
- return GetLandObject(parcelGlobalID) != null;
- }
- return true;
- }
-
- private void moneyModule_OnUserDidNotPay(UUID agentID, string paymentTextThatFailed)
- {
- UUID parcelGlobalID = UUID.Parse(paymentTextThatFailed.Substring("Parcel Show in Search Fee - ".Length));
- ILandObject parcel;
- if ((parcel = GetLandObject(parcelGlobalID)) != null)
- parcel.LandData.Flags &= (uint) ParcelFlags.ShowDirectory;
- }
-
- #endregion
-
- #region Heartbeat Tick, Parcel Returns, Clean temp objects
-
- private readonly HashSet<ISceneEntity> m_entitiesInAutoReturnQueue = new HashSet<ISceneEntity>();
-
- /// <summary>
- /// Return object to avatar Message
- /// </summary>
- /// <param name="agentID">Avatar Unique Id</param>
- /// <param name="objectName">Name of object returned</param>
- /// <param name="location">Location of object returned</param>
- /// <param name="reason">Reasion for object return</param>
- /// <param name="groups">The objects to return</param>
- public void AddReturns(UUID agentID, string objectName, Vector3 location, string reason,
- List<ISceneEntity> groups)
- {
- lock (m_returns)
- {
- if (m_returns.ContainsKey(agentID))
- {
- ReturnInfo info = m_returns[agentID];
- info.count += groups.Count;
- info.Groups.AddRange(groups);
- m_returns[agentID] = info;
- }
- else
- {
- ReturnInfo info = new ReturnInfo
- {
- count = groups.Count,
- objectName = objectName,
- location = location,
- reason = reason,
- Groups = groups
- };
- m_returns[agentID] = info;
- }
- }
- }
-
- private void EventManager_OnFrame()
- {
- if (m_scene.Frame%m_update_land == 0)
- {
- //It's time, check the parts we have
- CheckFrameEvents();
- }
- }
-
- private object AuroraEventManager_OnGenericEvent(string FunctionName, object parameters)
- {
- if (FunctionName == "ObjectAddedFlag")
- {
- object[] param = (object[]) parameters;
- ISceneChildEntity child = (ISceneChildEntity) param[0];
- PrimFlags flag = (PrimFlags) param[1];
- if (flag == PrimFlags.TemporaryOnRez)
- m_entitiesInAutoReturnQueue.Add(child.ParentEntity);
- }
- else if (FunctionName == "ObjectRemovedFlag")
- {
- object[] param = (object[]) parameters;
- ISceneChildEntity child = (ISceneChildEntity) param[0];
- PrimFlags flag = (PrimFlags) param[1];
- if (flag == PrimFlags.TemporaryOnRez)
- m_entitiesInAutoReturnQueue.Remove(child.ParentEntity);
- }
- return null;
- }
-
- /// <summary>
- /// This deals with sending the return IMs as well as actually returning the objects
- /// </summary>
- protected internal void CheckFrameEvents()
- {
- // Go through all updates and check for temp and auto return
- CheckPrimForAutoReturn();
- CheckPrimForTemperary();
- lock (m_returns)
- {
- foreach (KeyValuePair<UUID, ReturnInfo> ret in m_returns)
- {
- if (ret.Value.reason != "")
- {
- UUID transaction = UUID.Random();
-
- GridInstantMessage msg = new GridInstantMessage
- {
- fromAgentID = UUID.Zero,
- toAgentID = ret.Key,
- imSessionID = transaction,
- timestamp = (uint) Util.UnixTimeSinceEpoch(),
- fromAgentName = "Server",
- dialog = 19,
- fromGroup = false,
- offline = 1,
- ParentEstateID =
- m_scene.RegionInfo.EstateSettings.ParentEstateID,
- Position = Vector3.Zero,
- RegionID = m_scene.RegionInfo.RegionID,
- binaryBucket = Util.StringToBytes256("\0")
- };
- // From server
- // Object msg
- // We must fill in a null-terminated 'empty' string here since bytes[0] will crash viewer 3.
-
- if (ret.Value.count > 1)
- msg.message =
- string.Format("Your {0} objects were returned from {1} in region {2} due to {3}",
- ret.Value.count, ret.Value.location.ToString(),
- m_scene.RegionInfo.RegionName, ret.Value.reason);
- else
- msg.message = string.Format(
- "Your object {0} was returned from {1} in region {2} due to {3}", ret.Value.objectName,
- ret.Value.location.ToString(), m_scene.RegionInfo.RegionName, ret.Value.reason);
-
- IMessageTransferModule tr = m_scene.RequestModuleInterface<IMessageTransferModule>();
- if (tr != null)
- tr.SendInstantMessage(msg);
-
- if (ret.Value.Groups.Count > 1)
- MainConsole.Instance.InfoFormat(
- "[LandManagement]: Returning {0} objects due to parcel auto return.",
- ret.Value.Groups.Count);
- else
- MainConsole.Instance.Info("[LandManagement]: Returning 1 object due to parcel auto return.");
- }
- IAsyncSceneObjectGroupDeleter asyncDelete =
- m_scene.RequestModuleInterface<IAsyncSceneObjectGroupDeleter>();
- if (asyncDelete != null)
- {
- asyncDelete.DeleteToInventory(
- DeRezAction.Return, ret.Value.Groups[0].RootChild.OwnerID, ret.Value.Groups,
- ret.Value.Groups[0].RootChild.OwnerID,
- true, true);
- }
- }
- m_returns.Clear();
- }
- }
-
- protected void CheckPrimForTemperary()
- {
- HashSet<ISceneEntity> entitiesToRemove = new HashSet<ISceneEntity>();
-
- foreach (
- ISceneEntity entity in
- m_entitiesInAutoReturnQueue.Where(entity => entity.RootChild.Expires <= DateTime.Now))
- {
- entitiesToRemove.Add(entity);
- //Temporary objects don't get a reason, they return quietly
- AddReturns(entity.OwnerID, entity.Name, entity.AbsolutePosition, "", new List<ISceneEntity> {entity});
- }
-
- foreach (ISceneEntity entity in entitiesToRemove)
- {
- m_entitiesInAutoReturnQueue.Remove(entity);
- }
- }
-
- protected void CheckPrimForAutoReturn()
- {
- // Don't abort the whole thing if one entity happens to give us an exception.
- try
- {
- IPrimCountModule primCount = m_scene.RequestModuleInterface<IPrimCountModule>();
- if (primCount == null)
- return;
- List<ISceneEntity> entities = new List<ISceneEntity>();
- foreach (ISceneEntity sog in from parcel in AllParcels()
- where parcel != null && parcel.LandData != null &&
- parcel.LandData.OtherCleanTime != 0
- from sog in primCount.GetPrimCounts(parcel.LandData.GlobalID).Objects
- where parcel.LandData.OwnerID != sog.OwnerID &&
- ((parcel.LandData.GroupID == UUID.Zero) ||
- //If there is no group, don't check the groups part
- ((parcel.LandData.GroupID != UUID.Zero) &&
- //If there is a group, check for group rezzed prims and group owned prims
- (parcel.LandData.GroupID != sog.GroupID &&
- //Allow prims set to the group
- parcel.LandData.GroupID != sog.OwnerID &&
- //Allow group deeded prims!
- parcel.LandData.OwnerID != sog.GroupID)
- //Allow group deeded prims!
- )) &&
- !m_scene.Permissions.IsAdministrator(sog.OwnerID)
- where (DateTime.UtcNow - sog.RootChild.Rezzed).TotalSeconds >
- parcel.LandData.OtherCleanTime*60
- select sog)
- {
- entities.Add(sog);
- }
- if (entities.Count > 0)
- AddReturns(entities[0].OwnerID, entities[0].Name, entities[0].AbsolutePosition, "Auto Parcel Return",
- entities);
- }
- catch (Exception e)
- {
- MainConsole.Instance.ErrorFormat(
- "[LandManagement]: Failed to check for parcel returns: {0}", e);
- }
- }
-
- #endregion
-
- #region Parcel Add/Remove/Get/Create
-
- private readonly Dictionary<UUID, ParcelResult> m_lastDataResults = new Dictionary<UUID, ParcelResult>();
- private readonly Dictionary<UUID, ILandObject> m_lastLandObject = new Dictionary<UUID, ILandObject>();
- private readonly Dictionary<UUID, int> m_lastResults = new Dictionary<UUID, int>();
-
- public void UpdateLandObject(ILandObject lo)
- {
- AddLandObjectToSearch(lo);
- m_scene.EventManager.TriggerLandObjectAdded(lo.LandData);
-
- foreach (IScenePresence sp in m_scene.GetScenePresences())
- {
- if (sp.CurrentParcelUUID == lo.LandData.GlobalID)
- {
- if (lo.IsEitherBannedOrRestricted(sp.UUID))
- {
- SendYouAreRestrictedNotice(sp);
- Vector3 pos = GetNearestAllowedPosition(sp);
- pos.Z -= sp.PhysicsActor.Size.Z;
- sp.Teleport(pos);
- }
- }
- }
- }
-
- /// <summary>
- /// Resets the sim to have no land objects
- /// </summary>
- public void ClearAllParcels()
- {
- //Remove all the land objects in the sim and add a blank, full sim land object set to public
- List<ILandObject> parcels = new List<ILandObject>(m_landList.Values);
- foreach (ILandObject land in parcels)
- {
- m_scene.EventManager.TriggerLandObjectRemoved(land.LandData.RegionID, land.LandData.GlobalID);
- }
- lock (m_landListLock)
- {
- m_landList.Clear();
- m_lastLandLocalID = START_LAND_LOCAL_ID;
- }
- }
-
- /// <summary>
- /// Resets the sim to the default land object (full sim piece of land owned by the default user)
- /// </summary>
- public ILandObject ResetSimLandObjects()
- {
- ClearAllParcels();
- ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene);
- if (fullSimParcel.LandData.OwnerID == UUID.Zero)
- fullSimParcel.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
-
- UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.AllScopeIDs,
- fullSimParcel.LandData.OwnerID);
-
- while (fullSimParcel.LandData.OwnerID == UUID.Zero || account == null)
- {
- MainConsole.Instance.Warn(
- "[ParcelManagement]: Could not find user for parcel, please give a valid user to make the owner");
- string userName = MainConsole.Instance.Prompt("User Name:", "");
- if (userName == "")
- {
- MainConsole.Instance.Warn("Put in a valid username.");
- continue;
- }
- account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.AllScopeIDs, userName);
- if (account != null)
- fullSimParcel.LandData.OwnerID = account.PrincipalID;
- else
- MainConsole.Instance.Warn("Could not find the user.");
- }
- MainConsole.Instance.Info("[ParcelManagement]: No land found for region " + m_scene.RegionInfo.RegionName +
- ", setting owner to " + fullSimParcel.LandData.OwnerID);
- fullSimParcel.LandData.ClaimDate = Util.UnixTimeSinceEpoch();
- fullSimParcel.SetInfoID();
- fullSimParcel.LandData.Bitmap =
- new byte[(m_scene.RegionInfo.RegionSizeX/4)*(m_scene.RegionInfo.RegionSizeY/4)/8];
- fullSimParcel = AddLandObject(fullSimParcel);
- ModifyLandBitmapSquare(0, 0,
- m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY,
- fullSimParcel);
- return fullSimParcel;
- }
-
- public List<ILandObject> AllParcels()
- {
- lock (m_landListLock)
- return new List<ILandObject>(m_landList.Values);
- }
-
- public List<ILandObject> ParcelsNearPoint(Vector3 position)
- {
- List<ILandObject> parcelsNear = new List<ILandObject>();
- for (int x = -4; x <= 4; x += 4)
- {
- for (int y = -4; y <= 4; y += 4)
- {
- ILandObject check = GetLandObject((int) (position.X + x), (int) (position.Y + y));
- if (check != null)
- {
- if (!parcelsNear.Contains(check))
- {
- parcelsNear.Add(check);
- }
- }
- }
- }
-
- return parcelsNear;
- }
-
- public ILandObject GetLandObject(int parcelLocalID)
- {
- lock (m_landListLock)
- {
- ILandObject land = null;
- m_landList.TryGetValue(parcelLocalID, out land);
- return land;
- }
- }
-
- public ILandObject GetLandObject(UUID GlobalID)
- {
- return AllParcels().FirstOrDefault(land => land.LandData.GlobalID == GlobalID);
- }
-
- public ILandObject GetLandObject(float x, float y)
- {
- return GetLandObject((int) x, (int) y);
- }
-
- public ILandObject GetLandObject(int x, int y)
- {
- RegionInfo r = m_scene.RegionInfo;
- if (x >= r.RegionSizeX || y >= r.RegionSizeY || x < 0 || y < 0)
- {
- if (x >= r.RegionSizeX)
- x = r.RegionSizeX - 1;
- if (x < 0)
- x = 1;
- if (y >= r.RegionSizeY)
- y = r.RegionSizeY - 1;
- if (y < 0)
- y = 1;
- }
-
- lock (m_landListLock)
- {
- try
- {
- return m_landList[m_landIDList[x/4, y/4]];
- }
- catch (IndexOutOfRangeException)
- {
- return null;
- }
- catch (KeyNotFoundException)
- {
- return null;
- }
- }
- }
-
- protected void AddLandObjectToSearch(ILandObject parcel)
- {
- IDirectoryServiceConnector DSC = Framework.Utilities.DataManager.RequestPlugin<IDirectoryServiceConnector>();
- if (DSC != null)
- {
- if (m_UpdateDirectoryOnUpdate)
- //Update search database
- DoSearchUpdate();
- else if (m_UpdateDirectoryOnTimer)
- m_TaintedLandData = true;
- }
- }
-
- private void RemoveLandObjectFromSearch(ILandObject iLandObject)
- {
- IDirectoryServiceConnector DSC = Framework.Utilities.DataManager.RequestPlugin<IDirectoryServiceConnector>();
- if (DSC != null)
- {
- if (m_UpdateDirectoryOnUpdate)
- //Update search database
- DoSearchUpdate();
- else if (m_UpdateDirectoryOnTimer)
- m_TaintedLandData = true;
- }
- }
-
- /// <summary>
- /// Adds a land object to the stored list and adds them to the landIDList to what they own
- /// </summary>
- /// <param name="land">The land object being added</param>
- public ILandObject AddLandObject(ILandObject land)
- {
- return AddLandObject(land, false);
- }
-
- protected ILandObject AddLandObject(ILandObject land, bool incomingFromDatabase)
- {
- //Don't make a copy unless necessary
- ILandObject new_land = incomingFromDatabase ? land : land.Copy();
- new_land.LandData.RegionID = m_scene.RegionInfo.RegionID;
- new_land.LandData.RegionHandle = m_scene.RegionInfo.RegionHandle;
-
- lock (m_landListLock)
- {
- //Update the localID
- int newLandLocalID = ++m_lastLandLocalID;
- new_land.LandData.LocalID = newLandLocalID;
-
- //Add it to the list of land in this region
- m_landList.Add(newLandLocalID, new_land);
- }
- new_land.ForceUpdateLandInfo();
- //If it isn't coming in from the database, make sure to save the new parcel and add it to search
- if (!incomingFromDatabase)
- {
- AddLandObjectToSearch(new_land);
- }
- //Trigger the event for any interested listeners
- m_scene.EventManager.TriggerLandObjectAdded(new_land.LandData);
- return new_land;
- }
-
- public void SendYouAreBannedNotice(IScenePresence avatar)
- {
- avatar.ControllingClient.SendAlertMessage(
- "You are not allowed on this parcel because you are banned.");
- }
-
- public void SendYouAreRestrictedNotice(IScenePresence avatar)
- {
- avatar.ControllingClient.SendAlertMessage(
- "You are not allowed on this parcel because the land owner has restricted access.");
- }
-
- public void EventManagerOnAvatarEnteringNewParcel(IScenePresence avatar, ILandObject oldParcel)
- {
- if (avatar.CurrentParcel != null)
- {
- //Tell the clint about it
- avatar.CurrentParcel.SendLandUpdateToClient(avatar.ControllingClient);
-
- //Gotta kill all avatars outside the parcel
- foreach (
- IScenePresence sp in
- avatar.Scene.Entities.GetPresences()
- .Where(sp => sp.UUID != avatar.UUID)
- .Where(sp => sp.CurrentParcel != null))
- {
- if (sp.CurrentParcelUUID == avatar.CurrentParcelUUID) //Send full updates for those in the sim
- {
- if (avatar.CurrentParcel.LandData.Private || (oldParcel != null && oldParcel.LandData.Private))
- //Either one, we gotta send an update
- {
- sp.SceneViewer.RemoveAvatarFromView(avatar);
- avatar.SceneViewer.RemoveAvatarFromView(sp);
- sp.SceneViewer.QueuePresenceForFullUpdate(avatar, true);
- avatar.SceneViewer.QueuePresenceForFullUpdate(sp, true);
- }
- }
- else //Kill those outside the parcel
- {
- if (sp.CurrentParcel.LandData.Private || avatar.CurrentParcel.LandData.Private)
- {
- sp.ControllingClient.SendKillObject(sp.Scene.RegionInfo.RegionHandle,
- new IEntity[1] {avatar});
- avatar.ControllingClient.SendKillObject(sp.Scene.RegionInfo.RegionHandle,
- new IEntity[1] {sp});
- sp.SceneViewer.RemoveAvatarFromView(avatar);
- avatar.SceneViewer.RemoveAvatarFromView(sp);
- }
- }
- }
-
- if (UseDwell)
- avatar.CurrentParcel.LandData.Dwell += 1;
- if (avatar.AbsolutePosition.Z < BAN_LINE_SAFETY_HEIGHT)
- {
- if (avatar.CurrentParcel.IsBannedFromLand(avatar.UUID))
- {
- SendYouAreBannedNotice(avatar);
- Vector3 pos = GetNearestAllowedPosition(avatar);
- pos.Z -= avatar.PhysicsActor.Size.Z;
- avatar.Teleport(pos);
- }
- else if (avatar.CurrentParcel.IsRestrictedFromLand(avatar.UUID))
- {
- SendYouAreRestrictedNotice(avatar);
- Vector3 pos = GetNearestAllowedPosition(avatar);
- pos.Z -= avatar.PhysicsActor.Size.Z;
- avatar.Teleport(pos);
- }
- }
- }
- }
-
- private void SendOutNearestBanLine(IScenePresence sp, ILandObject ourLandObject)
- {
- int multiple = 0;
- int result = 0;
- Vector3 spAbs = sp.AbsolutePosition;
- foreach (ILandObject parcel in from parcel in AllParcels()
- let aamax = parcel.LandData.AABBMax
- let aamin = parcel.LandData.AABBMin
- where Math.Abs(aamax.X - spAbs.X) < 4 ||
- Math.Abs(aamax.Y - spAbs.Y) < 4 ||
- Math.Abs(aamin.X - spAbs.X) < 4 ||
- Math.Abs(aamin.Y - spAbs.Y) < 4
- select parcel)
- {
- //Do the & since we don't need to check again if we have already set the ban flag
- if ((result & (int) ParcelPropertiesStatus.CollisionBanned) !=
- (int) ParcelPropertiesStatus.CollisionBanned &&
- parcel.IsBannedFromLand(sp.UUID))
- {
- multiple++;
- result |= (int) ParcelPropertiesStatus.CollisionBanned;
- continue; //Only send one
- }
- else if ((result & (int) ParcelPropertiesStatus.CollisionNotOnAccessList) !=
- (int) ParcelPropertiesStatus.CollisionNotOnAccessList &&
- parcel.IsRestrictedFromLand(sp.UUID))
- {
- multiple++;
- result |= (int) ParcelPropertiesStatus.CollisionNotOnAccessList;
- continue; //Only send one
- }
- }
- ParcelResult dataResult = ParcelResult.NoData;
- if (multiple > 1)
- dataResult = ParcelResult.Multiple;
- else if (multiple == 1)
- dataResult = ParcelResult.Single;
-
- m_lastDataResults[sp.UUID] = dataResult;
- m_lastResults[sp.UUID] = result;
- m_lastLandObject[sp.UUID] = ourLandObject;
-
- if (multiple == 0) //If there is no result, don't send anything
- return;
- ourLandObject.SendLandProperties(result, false, (int) dataResult, sp.ControllingClient);
- }
-
- private void CheckEnteringNewParcel(IScenePresence avatar)
- {
- ILandObject over = GetLandObject((int) avatar.AbsolutePosition.X,
- (int) avatar.AbsolutePosition.Y);
-
- CheckEnteringNewParcel(avatar, over);
- }
-
- private void CheckEnteringNewParcel(IScenePresence avatar, ILandObject over)
- {
- if (over != null)
- {
- if (avatar.CurrentParcelUUID != over.LandData.GlobalID)
- {
- if (!avatar.IsChildAgent)
- {
- ILandObject oldParcel = avatar.CurrentParcel;
- avatar.CurrentParcelUUID = over.LandData.GlobalID;
- avatar.CurrentParcel = over;
- m_scene.EventManager.TriggerAvatarEnteringNewParcel(avatar, oldParcel);
- }
- }
- }
- }
-
- public void EventManagerOnSignificantClientMovement(IScenePresence sp)
- {
- IScenePresence clientAvatar = m_scene.GetScenePresence(sp.UUID);
- if (clientAvatar != null)
- {
- ILandObject over = GetLandObject((int) clientAvatar.AbsolutePosition.X,
- (int) clientAvatar.AbsolutePosition.Y);
- if (over != null)
- {
- if (!over.IsRestrictedFromLand(clientAvatar.UUID) &&
- (!over.IsBannedFromLand(clientAvatar.UUID) ||
- clientAvatar.AbsolutePosition.Z >= BAN_LINE_SAFETY_HEIGHT))
- //Allow for the flying over of ban lines
- {
- clientAvatar.LastKnownAllowedPosition =
- new Vector3(clientAvatar.AbsolutePosition.X, clientAvatar.AbsolutePosition.Y,
- clientAvatar.AbsolutePosition.Z);
- }
- else
- {
- //Kick them out
- Vector3 pos = clientAvatar.LastKnownAllowedPosition == Vector3.Zero
- ? GetNearestAllowedPosition(clientAvatar)
- : clientAvatar.LastKnownAllowedPosition;
- pos.Z = clientAvatar.AbsolutePosition.Z - clientAvatar.PhysicsActor.Size.Z;
- clientAvatar.Teleport(pos);
- }
- CheckEnteringNewParcel(clientAvatar, over);
- SendOutNearestBanLine(clientAvatar, over);
- }
- }
- }
-
- //Like handleEventManagerOnSignificantClientMovement, but for objects for parcel incoming object permissions
- public void EventManagerOnSignificantObjectMovement(ISceneEntity group)
- {
- ILandObject over = GetLandObject((int) group.AbsolutePosition.X, (int) group.AbsolutePosition.Y);
- if (over != null)
- {
- //Entered this new parcel
- if (over.LandData.GlobalID != group.LastParcelUUID)
- {
- if (!m_scene.Permissions.CanObjectEntry(group.UUID,
- false, group.AbsolutePosition, group.OwnerID))
- {
- //Revert the position and do not update the parcel ID
- group.AbsolutePosition = group.LastSignificantPosition;
-
- //If the object has physics, stop it from moving
- if ((group.RootChild.Flags & PrimFlags.Physics) == PrimFlags.Physics)
- {
- bool wasTemporary = ((group.RootChild.Flags & PrimFlags.TemporaryOnRez) != 0);
- bool wasPhantom = ((group.RootChild.Flags & PrimFlags.Phantom) != 0);
- bool wasVD = group.RootChild.VolumeDetectActive;
- bool needsPhysicalRebuild = group.RootChild.UpdatePrimFlags(false,
- wasTemporary,
- wasPhantom,
- wasVD, null);
- if (needsPhysicalRebuild)
- group.RebuildPhysicalRepresentation(true);
- }
- //Send an update so that all clients see it
- group.ScheduleGroupTerseUpdate();
- }
- else
- {
- UUID oldParcelUUID = group.LastParcelUUID;
- //Update the UUID then
- group.LastParcelUUID = over.LandData.GlobalID;
- //Trigger the event
- object[] param = new object[3];
- param[0] = group;
- param[1] = over.LandData.GlobalID;
- param[2] = oldParcelUUID;
- m_scene.AuroraEventManager.FireGenericEventHandler("ObjectEnteringNewParcel", param);
- }
- }
- }
- }
-
- public void ClientOnParcelAccessListRequest(UUID agentID, UUID sessionID, uint flags, int sequenceID,
- int landLocalID, IClientAPI remote_client)
- {
- ILandObject land = GetLandObject(landLocalID);
-
- if (land != null)
- {
- land.SendAccessList(agentID, sessionID, flags, sequenceID, remote_client);
- }
- }
-
- public void ClientOnParcelAccessUpdateListRequest(UUID agentID, UUID sessionID, uint flags, int landLocalID,
- List<ParcelManager.ParcelAccessEntry> entries,
- IClientAPI remote_client)
- {
- ILandObject land = GetLandObject(landLocalID);
-
- if (land != null)
- {
- if (m_scene.Permissions.CanEditParcelAccessList(remote_client.AgentId, land, flags))
- {
- land.UpdateAccessList(flags, entries, remote_client);
- }
- }
- else
- {
- MainConsole.Instance.WarnFormat("[LAND]: Invalid local land ID {0}", landLocalID);
- }
- }
-
- /// <summary>
- /// Removes a land object from the list. Will not remove if local_id is still owning an area in landIDList
- /// </summary>
- /// <param name="local_id">Land.localID of the peice of land to remove.</param>
- public void removeLandObject(int local_id)
- {
- lock (m_landListLock)
- {
- for (int x = 0; x < m_scene.RegionInfo.RegionSizeX/4; x++)
- {
- for (int y = 0; y < m_scene.RegionInfo.RegionSizeY/4; y++)
- {
- if (m_landIDList[x, y] == local_id)
- {
- MainConsole.Instance.WarnFormat(
- "[LAND]: Not removing land object {0}; still being used at {1}, {2}",
- local_id, x, y);
- return;
- //throw new Exception("Could not remove land object. Still being used at " + x + ", " + y);
- }
- }
- }
- ILandObject land = m_landList[local_id];
- m_scene.EventManager.TriggerLandObjectRemoved(land.LandData.RegionID, land.LandData.GlobalID);
- m_landList.Remove(local_id);
- RemoveLandObjectFromSearch(land);
- }
- }
-
- public void ParcelBuyPass(IClientAPI client, UUID agentID, int ParcelLocalID)
- {
- ILandObject landObject = GetLandObject(ParcelLocalID);
- if (landObject == null)
- {
- client.SendAlertMessage("Could not find the parcel you are currently on.");
- return;
- }
-
- if (landObject.IsBannedFromLand(agentID))
- {
- client.SendAlertMessage("You cannot buy a pass as you are banned from this parcel.");
- return;
- }
-
- IMoneyModule module = m_scene.RequestModuleInterface<IMoneyModule>();
- if (module != null)
- if (
- !module.Transfer(landObject.LandData.OwnerID, client.AgentId, landObject.LandData.PassPrice,
- "Parcel Pass"))
- {
- client.SendAlertMessage("You do not have enough funds to complete this transaction.");
- return;
- }
-
- ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry
- {
- AgentID = agentID,
- Flags = AccessList.Access,
- Time = DateTime.Now.AddHours(landObject.LandData.PassHours)
- };
- landObject.LandData.ParcelAccessList.Add(entry);
- client.SendAgentAlertMessage("You have been added to the parcel access list.", false);
- }
-
- #endregion
-
- #region Parcel Modification
-
- public void Join(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id)
- {
- join(start_x, start_y, end_x, end_y, attempting_user_id);
- }
-
- public void Subdivide(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id)
- {
- subdivide(start_x, start_y, end_x, end_y, attempting_user_id);
- }
-
- /// <summary>
- /// Subdivides a piece of land
- /// </summary>
- /// <param name="start_x">West Point</param>
- /// <param name="start_y">South Point</param>
- /// <param name="end_x">East Point</param>
- /// <param name="end_y">North Point</param>
- /// <param name="attempting_user_id">UUID of user who is trying to subdivide</param>
- /// <returns>Returns true if successful</returns>
- private void subdivide(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id)
- {
- //First, lets loop through the points and make sure they are all in the same peice of land
- //Get the land object at start
-
- ILandObject startLandObject = GetLandObject(start_x, start_y);
-
- if (startLandObject == null) return;
-
- //Loop through the points
- try
- {
- int totalX = end_x - start_x;
- int totalY = end_y - start_y;
- for (int y = 0; y < totalY; y += 2)
- {
- for (int x = 0; x < totalX; x += 2)
- {
- ILandObject tempLandObject = GetLandObject(start_x + x, start_y + y);
- if (tempLandObject == null) return;
- if (tempLandObject != startLandObject) return;
- }
- }
- }
- catch (Exception)
- {
- return;
- }
-
- //If we are still here, then they are subdividing within one piece of land
- //Check owner
- IClientAPI client;
- m_scene.ClientManager.TryGetValue(attempting_user_id, out client);
-
- if (!m_scene.Permissions.CanSubdivideParcel(attempting_user_id, startLandObject) &&
- (!(m_scene.RegionInfo.RegionSettings.AllowLandJoinDivide &&
- m_scene.Permissions.IsGod(attempting_user_id))))
- {
- client.SendAlertMessage("Permissions: you cannot split this parcel.");
- return;
- }
-
- //Lets create a new land object with bitmap activated at that point (keeping the old land objects info)
- ILandObject newLand = startLandObject.Copy();
- newLand.LandData.G…
Large files files are truncated, but you can click here to view the full file