2009-02-12 09:53:12 +00:00
/ *
2008-05-01 14:31:30 +00:00
* Copyright ( c ) Contributors , 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 .
2009-06-01 06:37:14 +00:00
* * Neither the name of the OpenSimulator Project nor the
2008-05-01 14:31:30 +00:00
* 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 .
* /
2009-02-12 18:59:45 +00:00
using System ;
using System.Collections ;
using System.Collections.Generic ;
2010-03-08 07:19:45 +00:00
using System.Diagnostics ;
2009-02-12 18:59:45 +00:00
using System.Reflection ;
2011-01-26 21:12:41 +00:00
using System.Text ;
2009-02-12 18:59:45 +00:00
using log4net ;
using Nini.Config ;
using OpenMetaverse ;
2010-08-30 01:28:31 +00:00
using OpenMetaverse.StructuredData ;
using OpenMetaverse.Messages.Linden ;
2012-11-13 05:14:58 +00:00
using Mono.Addins ;
2009-02-12 18:59:45 +00:00
using OpenSim.Framework ;
2009-06-18 14:33:35 +00:00
using OpenSim.Framework.Capabilities ;
2011-01-26 21:12:41 +00:00
using OpenSim.Framework.Console ;
2009-02-12 18:59:45 +00:00
using OpenSim.Framework.Servers ;
2009-05-04 20:15:39 +00:00
using OpenSim.Framework.Servers.HttpServer ;
2011-01-26 21:12:41 +00:00
using OpenSim.Region.CoreModules.Framework.InterfaceCommander ;
2009-02-12 18:59:45 +00:00
using OpenSim.Region.Framework.Interfaces ;
using OpenSim.Region.Framework.Scenes ;
using OpenSim.Region.Physics.Manager ;
2011-01-26 21:12:41 +00:00
using OpenSim.Services.Interfaces ;
using Caps = OpenSim . Framework . Capabilities . Caps ;
2009-09-26 14:48:21 +00:00
using GridRegion = OpenSim . Services . Interfaces . GridRegion ;
2009-02-12 18:59:45 +00:00
2009-02-10 13:10:57 +00:00
namespace OpenSim.Region.CoreModules.World.Land
2008-05-01 14:31:30 +00:00
{
2008-10-11 22:42:59 +00:00
// used for caching
2011-01-26 21:12:41 +00:00
internal class ExtendedLandData
{
2009-10-02 09:10:52 +00:00
public LandData LandData ;
public ulong RegionHandle ;
public uint X , Y ;
2010-08-07 03:45:52 +00:00
public byte RegionAccess ;
2008-10-11 22:42:59 +00:00
}
2012-11-13 05:14:58 +00:00
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LandManagementModule")]
2009-09-02 09:00:31 +00:00
public class LandManagementModule : INonSharedRegionModule
2008-05-01 14:31:30 +00:00
{
2011-04-05 21:15:06 +00:00
private static readonly ILog m_log = LogManager . GetLogger ( MethodBase . GetCurrentMethod ( ) . DeclaringType ) ;
2008-08-18 00:39:10 +00:00
2008-08-16 19:20:14 +00:00
private static readonly string remoteParcelRequestPath = "0009/" ;
2008-08-18 00:39:10 +00:00
2008-05-01 14:31:30 +00:00
private LandChannel landChannel ;
private Scene m_scene ;
2011-01-26 21:12:41 +00:00
protected Commander m_commander = new Commander ( "land" ) ;
protected IUserManagement m_userManager ;
2011-03-25 21:47:54 +00:00
protected IPrimCountModule m_primCountModule ;
2008-05-01 14:31:30 +00:00
2009-08-08 04:10:19 +00:00
// Minimum for parcels to work is 64m even if we don't actually use them.
2009-09-02 09:00:31 +00:00
#pragma warning disable 0429
2009-08-08 04:10:19 +00:00
private const int landArrayMax = ( ( int ) ( ( int ) Constants . RegionSize / 4 ) > = 64 ) ? ( int ) ( ( int ) Constants . RegionSize / 4 ) : 64 ;
2009-09-02 09:00:31 +00:00
#pragma warning restore 0429
2009-08-08 04:10:19 +00:00
2009-11-25 17:49:38 +00:00
/// <value>
2010-09-12 17:43:49 +00:00
/// Local land ids at specified region co-ordinates (region size / 4)
2009-11-25 17:49:38 +00:00
/// </value>
2009-08-08 04:10:19 +00:00
private readonly int [ , ] m_landIDList = new int [ landArrayMax , landArrayMax ] ;
2009-11-25 17:49:38 +00:00
/// <value>
2010-09-12 17:43:49 +00:00
/// Land objects keyed by local id
2009-11-25 17:49:38 +00:00
/// </value>
2008-11-08 17:00:42 +00:00
private readonly Dictionary < int , ILandObject > m_landList = new Dictionary < int , ILandObject > ( ) ;
2008-05-23 15:12:15 +00:00
2008-11-08 17:00:42 +00:00
private int m_lastLandLocalID = LandChannel . START_LAND_LOCAL_ID - 1 ;
2008-05-23 15:12:15 +00:00
private bool m_allowedForcefulBans = true ;
2008-10-11 22:42:59 +00:00
// caches ExtendedLandData
private Cache parcelInfoCache ;
2012-02-23 22:56:42 +00:00
/// <summary>
/// Record positions that avatar's are currently being forced to move to due to parcel entry restrictions.
/// </summary>
private Dictionary < UUID , Vector3 > forcedPosition = new Dictionary < UUID , Vector3 > ( ) ;
2008-10-11 22:42:59 +00:00
2009-09-02 09:00:31 +00:00
#region INonSharedRegionModule Members
2008-05-01 14:31:30 +00:00
2010-09-12 17:43:49 +00:00
public Type ReplaceableInterface
{
2009-09-02 09:00:31 +00:00
get { return null ; }
}
public void Initialise ( IConfigSource source )
{
}
public void AddRegion ( Scene scene )
2008-05-01 14:31:30 +00:00
{
m_scene = scene ;
2008-11-08 17:00:42 +00:00
m_landIDList . Initialize ( ) ;
2008-05-23 15:12:15 +00:00
landChannel = new LandChannel ( scene , this ) ;
2008-10-11 22:42:59 +00:00
parcelInfoCache = new Cache ( ) ;
parcelInfoCache . Size = 30 ; // the number of different parcel requests in this region to cache
parcelInfoCache . DefaultTTL = new TimeSpan ( 0 , 5 , 0 ) ;
2009-09-02 09:00:31 +00:00
m_scene . EventManager . OnParcelPrimCountAdd + = EventManagerOnParcelPrimCountAdd ;
m_scene . EventManager . OnParcelPrimCountUpdate + = EventManagerOnParcelPrimCountUpdate ;
2011-04-05 20:25:54 +00:00
m_scene . EventManager . OnObjectBeingRemovedFromScene + = EventManagerOnObjectBeingRemovedFromScene ;
m_scene . EventManager . OnRequestParcelPrimCountUpdate + = EventManagerOnRequestParcelPrimCountUpdate ;
2009-09-02 09:00:31 +00:00
m_scene . EventManager . OnAvatarEnteringNewParcel + = EventManagerOnAvatarEnteringNewParcel ;
m_scene . EventManager . OnClientMovement + = EventManagerOnClientMovement ;
m_scene . EventManager . OnValidateLandBuy + = EventManagerOnValidateLandBuy ;
m_scene . EventManager . OnLandBuy + = EventManagerOnLandBuy ;
m_scene . EventManager . OnNewClient + = EventManagerOnNewClient ;
2012-12-25 08:50:03 +00:00
m_scene . EventManager . OnMakeChildAgent + = EventMakeChildAgent ;
2009-09-02 09:00:31 +00:00
m_scene . EventManager . OnSignificantClientMovement + = EventManagerOnSignificantClientMovement ;
m_scene . EventManager . OnNoticeNoLandDataFromStorage + = EventManagerOnNoLandDataFromStorage ;
m_scene . EventManager . OnIncomingLandDataFromStorage + = EventManagerOnIncomingLandDataFromStorage ;
2011-04-05 20:25:54 +00:00
m_scene . EventManager . OnSetAllowForcefulBan + = EventManagerOnSetAllowedForcefulBan ;
2009-09-02 09:00:31 +00:00
m_scene . EventManager . OnRegisterCaps + = EventManagerOnRegisterCaps ;
2011-01-26 21:12:41 +00:00
m_scene . EventManager . OnPluginConsole + = EventManagerOnPluginConsole ;
2008-05-23 15:12:15 +00:00
2008-05-01 14:31:30 +00:00
lock ( m_scene )
{
2009-03-05 19:32:27 +00:00
m_scene . LandChannel = ( ILandChannel ) landChannel ;
2008-05-01 14:31:30 +00:00
}
2011-01-26 21:12:41 +00:00
InstallInterfaces ( ) ;
2008-05-01 14:31:30 +00:00
}
2009-09-02 09:00:31 +00:00
public void RegionLoaded ( Scene scene )
{
2011-01-26 21:12:41 +00:00
m_userManager = m_scene . RequestModuleInterface < IUserManagement > ( ) ;
2011-03-25 21:47:54 +00:00
m_primCountModule = m_scene . RequestModuleInterface < IPrimCountModule > ( ) ;
2009-09-02 09:00:31 +00:00
}
public void RemoveRegion ( Scene scene )
2011-01-26 21:12:41 +00:00
{
// TODO: Also release other event manager listeners here
m_scene . EventManager . OnPluginConsole - = EventManagerOnPluginConsole ;
m_scene . UnregisterModuleCommander ( m_commander . Name ) ;
2009-09-02 09:00:31 +00:00
}
2010-08-13 22:28:28 +00:00
// private bool OnVerifyUserConnection(ScenePresence scenePresence, out string reason)
// {
// ILandObject nearestParcel = m_scene.GetNearestAllowedParcel(scenePresence.UUID, scenePresence.AbsolutePosition.X, scenePresence.AbsolutePosition.Y);
// reason = "You are not allowed to enter this sim.";
// return nearestParcel != null;
// }
2011-01-26 21:12:41 +00:00
/// <summary>
/// Processes commandline input. Do not call directly.
/// </summary>
/// <param name="args">Commandline arguments</param>
protected void EventManagerOnPluginConsole ( string [ ] args )
{
if ( args [ 0 ] = = "land" )
{
if ( args . Length = = 1 )
{
m_commander . ProcessConsoleCommand ( "help" , new string [ 0 ] ) ;
return ;
}
string [ ] tmpArgs = new string [ args . Length - 2 ] ;
int i ;
for ( i = 2 ; i < args . Length ; i + + )
tmpArgs [ i - 2 ] = args [ i ] ;
m_commander . ProcessConsoleCommand ( args [ 1 ] , tmpArgs ) ;
}
}
2010-03-08 07:19:45 +00:00
2009-09-02 09:00:31 +00:00
void EventManagerOnNewClient ( IClientAPI client )
2008-05-04 18:59:18 +00:00
{
//Register some client events
2009-09-02 09:00:31 +00:00
client . OnParcelPropertiesRequest + = ClientOnParcelPropertiesRequest ;
client . OnParcelDivideRequest + = ClientOnParcelDivideRequest ;
client . OnParcelJoinRequest + = ClientOnParcelJoinRequest ;
client . OnParcelPropertiesUpdateRequest + = ClientOnParcelPropertiesUpdateRequest ;
client . OnParcelSelectObjects + = ClientOnParcelSelectObjects ;
client . OnParcelObjectOwnerRequest + = ClientOnParcelObjectOwnerRequest ;
client . OnParcelAccessListRequest + = ClientOnParcelAccessListRequest ;
2010-12-13 20:35:56 +00:00
client . OnParcelAccessListUpdateRequest + = ClientOnParcelAccessListUpdateRequest ;
2009-09-02 09:00:31 +00:00
client . OnParcelAbandonRequest + = ClientOnParcelAbandonRequest ;
client . OnParcelGodForceOwner + = ClientOnParcelGodForceOwner ;
client . OnParcelReclaim + = ClientOnParcelReclaim ;
client . OnParcelInfoRequest + = ClientOnParcelInfoRequest ;
client . OnParcelDeedToGroup + = ClientOnParcelDeedToGroup ;
2010-03-08 07:19:45 +00:00
client . OnPreAgentUpdate + = ClientOnPreAgentUpdate ;
2009-04-19 00:11:14 +00:00
2009-10-19 22:19:09 +00:00
EntityBase presenceEntity ;
if ( m_scene . Entities . TryGetValue ( client . AgentId , out presenceEntity ) & & presenceEntity is ScenePresence )
2008-05-23 15:12:15 +00:00
{
2009-10-19 22:19:09 +00:00
SendLandUpdate ( ( ScenePresence ) presenceEntity , true ) ;
2008-05-23 15:12:15 +00:00
SendParcelOverlay ( client ) ;
}
2008-05-04 18:59:18 +00:00
}
2012-12-25 08:50:03 +00:00
public void EventMakeChildAgent ( ScenePresence avatar )
{
avatar . currentParcelUUID = UUID . Zero ;
}
2010-03-08 07:19:45 +00:00
void ClientOnPreAgentUpdate ( IClientAPI remoteClient , AgentUpdateArgs agentData )
{
//If we are forcing a position for them to go
2010-11-09 19:18:36 +00:00
if ( forcedPosition . ContainsKey ( remoteClient . AgentId ) )
2010-03-08 07:19:45 +00:00
{
ScenePresence clientAvatar = m_scene . GetScenePresence ( remoteClient . AgentId ) ;
//Putting the user into flying, both keeps the avatar in fligth when it bumps into something and stopped from going another direction AND
//When the avatar walks into a ban line on the ground, it prevents getting stuck
agentData . ControlFlags = ( uint ) AgentManager . ControlFlags . AGENT_CONTROL_FLY ;
//Make sure we stop if they get about to the right place to prevent yoyo and prevents getting stuck on banlines
2010-11-09 19:18:36 +00:00
if ( Vector3 . Distance ( clientAvatar . AbsolutePosition , forcedPosition [ remoteClient . AgentId ] ) < . 2 )
2010-03-08 07:19:45 +00:00
{
2012-02-23 22:56:42 +00:00
// m_log.DebugFormat(
// "[LAND MANAGEMENT MODULE]: Stopping force position of {0} because {1} is close enough to {2}",
// clientAvatar.Name, clientAvatar.AbsolutePosition, forcedPosition[remoteClient.AgentId]);
2010-11-09 19:18:36 +00:00
forcedPosition . Remove ( remoteClient . AgentId ) ;
2010-03-08 07:19:45 +00:00
}
2010-09-12 17:43:49 +00:00
//if we are far away, teleport
2010-11-09 19:18:36 +00:00
else if ( Vector3 . Distance ( clientAvatar . AbsolutePosition , forcedPosition [ remoteClient . AgentId ] ) > 3 )
2010-03-08 07:19:45 +00:00
{
2012-02-23 22:56:42 +00:00
Vector3 forcePosition = forcedPosition [ remoteClient . AgentId ] ;
// m_log.DebugFormat(
// "[LAND MANAGEMENT MODULE]: Teleporting out {0} because {1} is too far from avatar position {2}",
// clientAvatar.Name, clientAvatar.AbsolutePosition, forcePosition);
m_scene . RequestTeleportLocation ( remoteClient , m_scene . RegionInfo . RegionHandle ,
forcePosition , clientAvatar . Lookat , ( uint ) Constants . TeleportFlags . ForceRedirect ) ;
2010-11-09 19:18:36 +00:00
forcedPosition . Remove ( remoteClient . AgentId ) ;
2010-03-08 07:19:45 +00:00
}
else
{
2012-02-23 22:56:42 +00:00
// m_log.DebugFormat(
// "[LAND MANAGEMENT MODULE]: Forcing {0} from {1} to {2}",
// clientAvatar.Name, clientAvatar.AbsolutePosition, forcedPosition[remoteClient.AgentId]);
2010-03-08 07:19:45 +00:00
//Forces them toward the forced position we want if they aren't there yet
agentData . UseClientAgentPosition = true ;
2010-11-09 19:18:36 +00:00
agentData . ClientAgentPosition = forcedPosition [ remoteClient . AgentId ] ;
2010-03-08 07:19:45 +00:00
}
}
}
2008-05-01 14:31:30 +00:00
public void Close ( )
{
}
public string Name
{
get { return "LandManagementModule" ; }
}
# endregion
2008-05-23 15:12:15 +00:00
#region Parcel Add/Remove/Get/Create
2009-09-02 09:00:31 +00:00
public void EventManagerOnSetAllowedForcefulBan ( bool forceful )
2008-05-23 15:12:15 +00:00
{
AllowedForcefulBans = forceful ;
}
2008-11-08 17:00:42 +00:00
public void UpdateLandObject ( int local_id , LandData data )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
LandData newData = data . Copy ( ) ;
newData . LocalID = local_id ;
lock ( m_landList )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
if ( m_landList . ContainsKey ( local_id ) )
{
2009-10-02 09:10:52 +00:00
m_landList [ local_id ] . LandData = newData ;
2009-10-07 00:45:49 +00:00
m_scene . EventManager . TriggerLandObjectUpdated ( ( uint ) local_id , m_landList [ local_id ] ) ;
2008-11-08 17:00:42 +00:00
}
2008-05-23 15:12:15 +00:00
}
}
public bool AllowedForcefulBans
{
get { return m_allowedForcefulBans ; }
set { m_allowedForcefulBans = value ; }
}
/// <summary>
/// Resets the sim to the default land object (full sim piece of land owned by the default user)
/// </summary>
public void ResetSimLandObjects ( )
{
//Remove all the land objects in the sim and add a blank, full sim land object set to public
2008-11-08 17:00:42 +00:00
lock ( m_landList )
{
m_landList . Clear ( ) ;
m_lastLandLocalID = LandChannel . START_LAND_LOCAL_ID - 1 ;
m_landIDList . Initialize ( ) ;
}
2011-01-27 20:29:06 +00:00
}
/// <summary>
/// Create a default parcel that spans the entire region and is owned by the estate owner.
/// </summary>
/// <returns>The parcel created.</returns>
protected ILandObject CreateDefaultParcel ( )
{
2011-04-05 21:15:06 +00:00
m_log . DebugFormat (
"[LAND MANAGEMENT MODULE]: Creating default parcel for region {0}" , m_scene . RegionInfo . RegionName ) ;
2011-03-22 23:47:36 +00:00
2011-03-25 21:47:54 +00:00
ILandObject fullSimParcel = new LandObject ( UUID . Zero , false , m_scene ) ;
2009-10-02 09:10:52 +00:00
fullSimParcel . SetLandBitmap ( fullSimParcel . GetSquareLandBitmap ( 0 , 0 , ( int ) Constants . RegionSize , ( int ) Constants . RegionSize ) ) ;
2010-01-10 22:41:42 +00:00
fullSimParcel . LandData . OwnerID = m_scene . RegionInfo . EstateSettings . EstateOwner ;
2009-10-02 09:10:52 +00:00
fullSimParcel . LandData . ClaimDate = Util . UnixTimeSinceEpoch ( ) ;
2011-03-25 21:47:54 +00:00
2011-01-27 20:29:06 +00:00
return AddLandObject ( fullSimParcel ) ;
2008-05-23 15:12:15 +00:00
}
2008-09-13 17:50:02 +00:00
public List < ILandObject > AllParcels ( )
{
2008-11-08 17:00:42 +00:00
lock ( m_landList )
{
return new List < ILandObject > ( m_landList . Values ) ;
}
2008-09-13 17:50:02 +00:00
}
2008-09-06 07:52:41 +00:00
public List < ILandObject > ParcelsNearPoint ( Vector3 position )
2008-05-23 15:12:15 +00:00
{
List < ILandObject > parcelsNear = new List < ILandObject > ( ) ;
2008-08-18 00:39:10 +00:00
for ( int x = - 4 ; x < = 4 ; x + = 4 )
2008-05-23 15:12:15 +00:00
{
2008-08-18 00:39:10 +00:00
for ( int y = - 4 ; y < = 4 ; y + = 4 )
2008-05-23 15:12:15 +00:00
{
ILandObject check = GetLandObject ( position . X + x , position . Y + y ) ;
if ( check ! = null )
{
if ( ! parcelsNear . Contains ( check ) )
{
parcelsNear . Add ( check ) ;
}
}
}
}
return parcelsNear ;
}
public void SendYouAreBannedNotice ( ScenePresence avatar )
{
if ( AllowedForcefulBans )
{
avatar . ControllingClient . SendAlertMessage (
2008-12-15 12:47:16 +00:00
"You are not allowed on this parcel because you are banned. Please go away." ) ;
2008-05-23 15:12:15 +00:00
}
else
{
avatar . ControllingClient . SendAlertMessage (
2008-12-15 12:47:16 +00:00
"You are not allowed on this parcel because you are banned; however, the grid administrator has disabled ban lines globally. Please obey the land owner's requests or you can be banned from the entire sim!" ) ;
2008-05-23 15:12:15 +00:00
}
}
2010-03-08 07:19:45 +00:00
private void ForceAvatarToPosition ( ScenePresence avatar , Vector3 ? position )
{
if ( m_scene . Permissions . IsGod ( avatar . UUID ) ) return ;
if ( position . HasValue )
{
2010-11-09 19:18:36 +00:00
forcedPosition [ avatar . ControllingClient . AgentId ] = ( Vector3 ) position ;
2010-03-08 07:19:45 +00:00
}
}
public void SendYouAreRestrictedNotice ( ScenePresence avatar )
{
2010-03-10 04:15:36 +00:00
avatar . ControllingClient . SendAlertMessage (
2010-03-08 07:19:45 +00:00
"You are not allowed on this parcel because the land owner has restricted access." ) ;
}
2009-09-02 09:00:31 +00:00
public void EventManagerOnAvatarEnteringNewParcel ( ScenePresence avatar , int localLandID , UUID regionID )
2008-05-23 15:12:15 +00:00
{
if ( m_scene . RegionInfo . RegionID = = regionID )
{
2008-11-08 17:00:42 +00:00
ILandObject parcelAvatarIsEntering ;
lock ( m_landList )
{
parcelAvatarIsEntering = m_landList [ localLandID ] ;
}
if ( parcelAvatarIsEntering ! = null )
2008-05-23 15:12:15 +00:00
{
if ( avatar . AbsolutePosition . Z < LandChannel . BAN_LINE_SAFETY_HIEGHT )
{
2009-10-02 09:10:52 +00:00
if ( parcelAvatarIsEntering . IsBannedFromLand ( avatar . UUID ) )
2008-05-23 15:12:15 +00:00
{
SendYouAreBannedNotice ( avatar ) ;
2010-03-08 07:19:45 +00:00
ForceAvatarToPosition ( avatar , m_scene . GetNearestAllowedPosition ( avatar ) ) ;
2008-05-23 15:12:15 +00:00
}
2009-10-02 09:10:52 +00:00
else if ( parcelAvatarIsEntering . IsRestrictedFromLand ( avatar . UUID ) )
2008-05-23 15:12:15 +00:00
{
2010-03-08 07:19:45 +00:00
SendYouAreRestrictedNotice ( avatar ) ;
ForceAvatarToPosition ( avatar , m_scene . GetNearestAllowedPosition ( avatar ) ) ;
2008-05-23 15:12:15 +00:00
}
else
{
avatar . sentMessageAboutRestrictedParcelFlyingDown = true ;
}
}
else
{
avatar . sentMessageAboutRestrictedParcelFlyingDown = true ;
}
}
}
}
2010-03-19 12:51:16 +00:00
public void SendOutNearestBanLine ( IClientAPI client )
2008-05-23 15:12:15 +00:00
{
2010-03-19 12:51:16 +00:00
ScenePresence sp = m_scene . GetScenePresence ( client . AgentId ) ;
if ( sp = = null | | sp . IsChildAgent )
return ;
List < ILandObject > checkLandParcels = ParcelsNearPoint ( sp . AbsolutePosition ) ;
foreach ( ILandObject checkBan in checkLandParcels )
2008-05-23 15:12:15 +00:00
{
2010-03-19 12:51:16 +00:00
if ( checkBan . IsBannedFromLand ( client . AgentId ) )
2008-05-23 15:12:15 +00:00
{
2010-03-19 12:51:16 +00:00
checkBan . SendLandProperties ( ( int ) ParcelPropertiesStatus . CollisionBanned , false , ( int ) ParcelResult . Single , client ) ;
return ; //Only send one
}
if ( checkBan . IsRestrictedFromLand ( client . AgentId ) )
{
checkBan . SendLandProperties ( ( int ) ParcelPropertiesStatus . CollisionNotOnAccessList , false , ( int ) ParcelResult . Single , client ) ;
return ; //Only send one
2008-05-23 15:12:15 +00:00
}
}
2010-03-19 12:51:16 +00:00
return ;
2008-05-23 15:12:15 +00:00
}
public void SendLandUpdate ( ScenePresence avatar , bool force )
{
2009-08-08 00:31:48 +00:00
ILandObject over = GetLandObject ( ( int ) Math . Min ( ( ( int ) Constants . RegionSize - 1 ) , Math . Max ( 0 , Math . Round ( avatar . AbsolutePosition . X ) ) ) ,
( int ) Math . Min ( ( ( int ) Constants . RegionSize - 1 ) , Math . Max ( 0 , Math . Round ( avatar . AbsolutePosition . Y ) ) ) ) ;
2008-05-23 15:12:15 +00:00
if ( over ! = null )
{
if ( force )
{
if ( ! avatar . IsChildAgent )
{
2009-10-02 09:10:52 +00:00
over . SendLandUpdateToClient ( avatar . ControllingClient ) ;
m_scene . EventManager . TriggerAvatarEnteringNewParcel ( avatar , over . LandData . LocalID ,
2008-05-23 15:12:15 +00:00
m_scene . RegionInfo . RegionID ) ;
}
}
2009-10-02 09:10:52 +00:00
if ( avatar . currentParcelUUID ! = over . LandData . GlobalID )
2008-05-23 15:12:15 +00:00
{
if ( ! avatar . IsChildAgent )
{
2009-10-02 09:10:52 +00:00
over . SendLandUpdateToClient ( avatar . ControllingClient ) ;
avatar . currentParcelUUID = over . LandData . GlobalID ;
m_scene . EventManager . TriggerAvatarEnteringNewParcel ( avatar , over . LandData . LocalID ,
2008-05-23 15:12:15 +00:00
m_scene . RegionInfo . RegionID ) ;
}
}
}
}
public void SendLandUpdate ( ScenePresence avatar )
{
SendLandUpdate ( avatar , false ) ;
}
2011-08-03 03:19:19 +00:00
public void EventManagerOnSignificantClientMovement ( ScenePresence clientAvatar )
2008-05-23 15:12:15 +00:00
{
2011-08-03 03:19:19 +00:00
SendLandUpdate ( clientAvatar ) ;
SendOutNearestBanLine ( clientAvatar . ControllingClient ) ;
ILandObject parcel = GetLandObject ( clientAvatar . AbsolutePosition . X , clientAvatar . AbsolutePosition . Y ) ;
if ( parcel ! = null )
2008-05-23 15:12:15 +00:00
{
2011-08-03 03:19:19 +00:00
if ( clientAvatar . AbsolutePosition . Z < LandChannel . BAN_LINE_SAFETY_HIEGHT & &
clientAvatar . sentMessageAboutRestrictedParcelFlyingDown )
2008-05-23 15:12:15 +00:00
{
2011-08-03 03:19:19 +00:00
EventManagerOnAvatarEnteringNewParcel ( clientAvatar , parcel . LandData . LocalID ,
m_scene . RegionInfo . RegionID ) ;
//They are going under the safety line!
if ( ! parcel . IsBannedFromLand ( clientAvatar . UUID ) )
2008-05-23 15:12:15 +00:00
{
2011-08-03 03:19:19 +00:00
clientAvatar . sentMessageAboutRestrictedParcelFlyingDown = false ;
2008-05-23 15:12:15 +00:00
}
2011-08-03 03:19:19 +00:00
}
else if ( clientAvatar . AbsolutePosition . Z < LandChannel . BAN_LINE_SAFETY_HIEGHT & &
parcel . IsBannedFromLand ( clientAvatar . UUID ) )
{
//once we've sent the message once, keep going toward the target until we are done
if ( forcedPosition . ContainsKey ( clientAvatar . ControllingClient . AgentId ) )
2008-05-23 15:12:15 +00:00
{
2011-08-03 03:19:19 +00:00
SendYouAreBannedNotice ( clientAvatar ) ;
ForceAvatarToPosition ( clientAvatar , m_scene . GetNearestAllowedPosition ( clientAvatar ) ) ;
2010-03-08 07:19:45 +00:00
}
2011-08-03 03:19:19 +00:00
}
else if ( parcel . IsRestrictedFromLand ( clientAvatar . UUID ) )
{
//once we've sent the message once, keep going toward the target until we are done
if ( forcedPosition . ContainsKey ( clientAvatar . ControllingClient . AgentId ) )
2010-03-08 07:19:45 +00:00
{
2011-08-03 03:19:19 +00:00
SendYouAreRestrictedNotice ( clientAvatar ) ;
ForceAvatarToPosition ( clientAvatar , m_scene . GetNearestAllowedPosition ( clientAvatar ) ) ;
2008-05-23 15:12:15 +00:00
}
}
2011-08-03 03:19:19 +00:00
else
{
//when we are finally in a safe place, lets release the forced position lock
forcedPosition . Remove ( clientAvatar . ControllingClient . AgentId ) ;
}
2008-05-23 15:12:15 +00:00
}
}
2011-05-14 00:07:06 +00:00
/// <summary>
/// Like handleEventManagerOnSignificantClientMovement, but called with an AgentUpdate regardless of distance.
/// </summary>
/// <param name="avatar"></param>
2009-09-02 09:00:31 +00:00
public void EventManagerOnClientMovement ( ScenePresence avatar )
2011-05-14 00:07:06 +00:00
/ /
2008-05-23 15:12:15 +00:00
{
ILandObject over = GetLandObject ( avatar . AbsolutePosition . X , avatar . AbsolutePosition . Y ) ;
if ( over ! = null )
{
2010-03-08 07:19:45 +00:00
if ( ! over . IsRestrictedFromLand ( avatar . UUID ) & & ( ! over . IsBannedFromLand ( avatar . UUID ) | | avatar . AbsolutePosition . Z > = LandChannel . BAN_LINE_SAFETY_HIEGHT ) )
2008-05-23 15:12:15 +00:00
{
avatar . lastKnownAllowedPosition =
new Vector3 ( avatar . AbsolutePosition . X , avatar . AbsolutePosition . Y , avatar . AbsolutePosition . Z ) ;
}
}
}
2009-09-02 09:00:31 +00:00
public void ClientOnParcelAccessListRequest ( UUID agentID , UUID sessionID , uint flags , int sequenceID ,
int landLocalID , IClientAPI remote_client )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
ILandObject land ;
lock ( m_landList )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
m_landList . TryGetValue ( landLocalID , out land ) ;
}
if ( land ! = null )
{
2010-12-13 20:35:56 +00:00
land . SendAccessList ( agentID , sessionID , flags , sequenceID , remote_client ) ;
2008-05-23 15:12:15 +00:00
}
}
2010-12-13 20:35:56 +00:00
public void ClientOnParcelAccessListUpdateRequest ( UUID agentID ,
uint flags , int landLocalID , UUID transactionID , int sequenceID ,
2012-02-02 23:40:56 +00:00
int sections , List < LandAccessEntry > entries ,
2010-12-13 20:35:56 +00:00
IClientAPI remote_client )
2008-05-23 15:12:15 +00:00
{
2010-12-13 20:35:56 +00:00
// Flags is the list to update, it can mean either the ban or
// the access list (WTH is a pass list? Mentioned in ParcelFlags)
/ /
// There may be multiple packets, because these can get LONG.
// Use transactionID to determine a new chain of packets since
// packets may have come in out of sequence and that would be
// a big mess if using the sequenceID
2008-11-08 17:00:42 +00:00
ILandObject land ;
lock ( m_landList )
{
m_landList . TryGetValue ( landLocalID , out land ) ;
}
if ( land ! = null )
2008-05-23 15:12:15 +00:00
{
2010-12-13 20:35:56 +00:00
GroupPowers requiredPowers = GroupPowers . LandManageAllowed ;
if ( flags = = ( uint ) AccessList . Ban )
requiredPowers = GroupPowers . LandManageBanned ;
if ( m_scene . Permissions . CanEditParcelProperties ( agentID ,
land , requiredPowers ) )
2008-05-23 15:12:15 +00:00
{
2010-12-13 20:35:56 +00:00
land . UpdateAccessList ( flags , transactionID , sequenceID ,
sections , entries , remote_client ) ;
2008-05-23 15:12:15 +00:00
}
}
else
{
2011-03-22 23:47:36 +00:00
m_log . WarnFormat ( "[LAND MANAGEMENT MODULE]: Invalid local land ID {0}" , landLocalID ) ;
2008-05-23 15:12:15 +00:00
}
}
2008-08-18 00:39:10 +00:00
2008-05-23 15:12:15 +00:00
/// <summary>
/// Adds a land object to the stored list and adds them to the landIDList to what they own
/// </summary>
/// <param name="new_land">The land object being added</param>
2008-11-08 17:00:42 +00:00
public ILandObject AddLandObject ( ILandObject land )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
ILandObject new_land = land . Copy ( ) ;
2011-03-25 21:47:54 +00:00
// Only now can we add the prim counts to the land object - we rely on the global ID which is generated
// as a random UUID inside LandData initialization
if ( m_primCountModule ! = null )
new_land . PrimCounts = m_primCountModule . GetPrimCounts ( new_land . LandData . GlobalID ) ;
2008-05-23 15:12:15 +00:00
2008-11-08 17:00:42 +00:00
lock ( m_landList )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
int newLandLocalID = + + m_lastLandLocalID ;
2009-10-02 09:10:52 +00:00
new_land . LandData . LocalID = newLandLocalID ;
2008-11-08 17:00:42 +00:00
2009-10-02 09:10:52 +00:00
bool [ , ] landBitmap = new_land . GetLandBitmap ( ) ;
2009-08-08 04:10:19 +00:00
for ( int x = 0 ; x < landArrayMax ; x + + )
2008-05-23 15:12:15 +00:00
{
2009-08-08 04:10:19 +00:00
for ( int y = 0 ; y < landArrayMax ; y + + )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
if ( landBitmap [ x , y ] )
{
2011-04-06 17:57:50 +00:00
// m_log.DebugFormat(
// "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}",
// new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName);
2008-11-08 17:00:42 +00:00
m_landIDList [ x , y ] = newLandLocalID ;
}
2008-05-23 15:12:15 +00:00
}
}
2008-11-08 17:00:42 +00:00
m_landList . Add ( newLandLocalID , new_land ) ;
2008-05-23 15:12:15 +00:00
}
2008-11-08 17:00:42 +00:00
2009-10-02 09:10:52 +00:00
new_land . ForceUpdateLandInfo ( ) ;
2008-05-23 15:12:15 +00:00
m_scene . EventManager . TriggerLandObjectAdded ( new_land ) ;
return new_land ;
}
/// <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 )
{
2008-11-08 17:00:42 +00:00
lock ( m_landList )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
for ( int x = 0 ; x < 64 ; x + + )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
for ( int y = 0 ; y < 64 ; y + + )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
if ( m_landIDList [ x , y ] = = local_id )
{
2011-03-22 23:47:36 +00:00
m_log . WarnFormat ( "[LAND MANAGEMENT MODULE]: Not removing land object {0}; still being used at {1}, {2}" ,
2008-11-08 17:00:42 +00:00
local_id , x , y ) ;
return ;
//throw new Exception("Could not remove land object. Still being used at " + x + ", " + y);
}
2008-05-23 15:12:15 +00:00
}
}
2009-10-07 00:45:49 +00:00
m_scene . EventManager . TriggerLandObjectRemoved ( m_landList [ local_id ] . LandData . GlobalID ) ;
2008-11-08 17:00:42 +00:00
m_landList . Remove ( local_id ) ;
}
2008-05-23 15:12:15 +00:00
}
2011-01-27 18:48:48 +00:00
/// <summary>
/// Clear the scene of all parcels
/// </summary>
2011-01-27 20:29:06 +00:00
public void Clear ( bool setupDefaultParcel )
2011-01-27 18:48:48 +00:00
{
lock ( m_landList )
{
foreach ( ILandObject lo in m_landList . Values )
{
//m_scene.SimulationDataService.RemoveLandObject(lo.LandData.GlobalID);
m_scene . EventManager . TriggerLandObjectRemoved ( lo . LandData . GlobalID ) ;
}
2011-05-12 11:42:28 +00:00
2011-01-27 18:48:48 +00:00
m_landList . Clear ( ) ;
2011-05-12 11:42:28 +00:00
ResetSimLandObjects ( ) ;
if ( setupDefaultParcel )
CreateDefaultParcel ( ) ;
2011-01-27 18:48:48 +00:00
}
}
2008-05-23 15:12:15 +00:00
private void performFinalLandJoin ( ILandObject master , ILandObject slave )
{
2009-10-02 09:10:52 +00:00
bool [ , ] landBitmapSlave = slave . GetLandBitmap ( ) ;
2008-11-08 17:00:42 +00:00
lock ( m_landList )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
for ( int x = 0 ; x < 64 ; x + + )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
for ( int y = 0 ; y < 64 ; y + + )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
if ( landBitmapSlave [ x , y ] )
{
2009-10-02 09:10:52 +00:00
m_landIDList [ x , y ] = master . LandData . LocalID ;
2008-11-08 17:00:42 +00:00
}
2008-05-23 15:12:15 +00:00
}
}
}
2009-10-02 09:10:52 +00:00
removeLandObject ( slave . LandData . LocalID ) ;
UpdateLandObject ( master . LandData . LocalID , master . LandData ) ;
2008-05-23 15:12:15 +00:00
}
public ILandObject GetLandObject ( int parcelLocalID )
{
2008-11-08 17:00:42 +00:00
lock ( m_landList )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
if ( m_landList . ContainsKey ( parcelLocalID ) )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
return m_landList [ parcelLocalID ] ;
2008-05-23 15:12:15 +00:00
}
}
return null ;
}
/// <summary>
/// Get the land object at the specified point
/// </summary>
/// <param name="x_float">Value between 0 - 256 on the x axis of the point</param>
/// <param name="y_float">Value between 0 - 256 on the y axis of the point</param>
/// <returns>Land object at the point supplied</returns>
public ILandObject GetLandObject ( float x_float , float y_float )
{
int x ;
int y ;
2011-01-28 02:34:07 +00:00
if ( x_float > = Constants . RegionSize | | x_float < 0 | | y_float > = Constants . RegionSize | | y_float < 0 )
2009-08-21 17:22:49 +00:00
return null ;
2010-09-12 17:43:49 +00:00
2008-05-23 15:12:15 +00:00
try
{
2008-10-08 18:48:49 +00:00
x = Convert . ToInt32 ( Math . Floor ( Convert . ToDouble ( x_float ) / 4.0 ) ) ;
y = Convert . ToInt32 ( Math . Floor ( Convert . ToDouble ( y_float ) / 4.0 ) ) ;
2008-05-23 15:12:15 +00:00
}
catch ( OverflowException )
{
return null ;
}
if ( x > = 64 | | y > = 64 | | x < 0 | | y < 0 )
{
return null ;
}
2010-09-12 17:43:49 +00:00
2008-11-08 17:00:42 +00:00
lock ( m_landList )
{
2008-11-29 13:17:21 +00:00
// Corner case. If an autoreturn happens during sim startup
// we will come here with the list uninitialized
/ /
2011-08-23 20:41:16 +00:00
// int landId = m_landIDList[x, y];
2011-04-06 17:57:50 +00:00
// if (landId == 0)
// m_log.DebugFormat(
// "[LAND MANAGEMENT MODULE]: No land object found at ({0}, {1}) on {2}",
// x, y, m_scene.RegionInfo.RegionName);
2008-11-29 13:17:21 +00:00
if ( m_landList . ContainsKey ( m_landIDList [ x , y ] ) )
return m_landList [ m_landIDList [ x , y ] ] ;
2011-04-06 17:57:50 +00:00
2008-11-29 13:17:21 +00:00
return null ;
2008-11-08 17:00:42 +00:00
}
2008-05-23 15:12:15 +00:00
}
public ILandObject GetLandObject ( int x , int y )
{
if ( x > = Convert . ToInt32 ( Constants . RegionSize ) | | y > = Convert . ToInt32 ( Constants . RegionSize ) | | x < 0 | | y < 0 )
{
// These exceptions here will cause a lot of complaints from the users specifically because
// they happen every time at border crossings
throw new Exception ( "Error: Parcel not found at point " + x + ", " + y ) ;
}
2010-09-12 17:43:49 +00:00
2008-11-08 17:00:42 +00:00
lock ( m_landIDList )
{
2009-08-08 04:10:19 +00:00
try
{
2011-03-31 21:47:18 +00:00
return m_landList [ m_landIDList [ x / 4 , y / 4 ] ] ;
2009-08-08 04:10:19 +00:00
}
catch ( IndexOutOfRangeException )
{
2011-03-31 22:56:26 +00:00
// m_log.WarnFormat(
// "[LAND MANAGEMENT MODULE]: Tried to retrieve land object from out of bounds co-ordinate ({0},{1}) in {2}",
// x, y, m_scene.RegionInfo.RegionName);
2011-03-31 21:47:18 +00:00
2009-08-01 14:26:00 +00:00
return null ;
2009-08-08 04:10:19 +00:00
}
2008-11-08 17:00:42 +00:00
}
2010-01-03 21:10:45 +00:00
}
2008-08-18 00:39:10 +00:00
2008-05-23 15:12:15 +00:00
# endregion
#region Parcel Modification
2011-04-05 21:15:06 +00:00
public void ResetOverMeRecords ( )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
lock ( m_landList )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
foreach ( LandObject p in m_landList . Values )
{
2011-04-05 20:25:54 +00:00
p . ResetOverMeRecord ( ) ;
2008-11-08 17:00:42 +00:00
}
2008-05-23 15:12:15 +00:00
}
}
2009-09-02 09:00:31 +00:00
public void EventManagerOnParcelPrimCountAdd ( SceneObjectGroup obj )
2008-05-23 15:12:15 +00:00
{
2008-09-06 07:52:41 +00:00
Vector3 position = obj . AbsolutePosition ;
2008-05-23 15:12:15 +00:00
ILandObject landUnderPrim = GetLandObject ( position . X , position . Y ) ;
if ( landUnderPrim ! = null )
{
2011-04-05 20:25:54 +00:00
( ( LandObject ) landUnderPrim ) . AddPrimOverMe ( obj ) ;
2008-05-23 15:12:15 +00:00
}
}
2009-09-02 09:00:31 +00:00
public void EventManagerOnObjectBeingRemovedFromScene ( SceneObjectGroup obj )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
lock ( m_landList )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
foreach ( LandObject p in m_landList . Values )
{
2011-04-05 20:25:54 +00:00
p . RemovePrimFromOverMe ( obj ) ;
2008-11-08 17:00:42 +00:00
}
2008-05-23 15:12:15 +00:00
}
}
public void FinalizeLandPrimCountUpdate ( )
{
//Get Simwide prim count for owner
2008-09-06 07:52:41 +00:00
Dictionary < UUID , List < LandObject > > landOwnersAndParcels = new Dictionary < UUID , List < LandObject > > ( ) ;
2008-11-08 17:00:42 +00:00
lock ( m_landList )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
foreach ( LandObject p in m_landList . Values )
2008-05-23 15:12:15 +00:00
{
2009-10-02 09:10:52 +00:00
if ( ! landOwnersAndParcels . ContainsKey ( p . LandData . OwnerID ) )
2008-11-08 17:00:42 +00:00
{
List < LandObject > tempList = new List < LandObject > ( ) ;
tempList . Add ( p ) ;
2009-10-02 09:10:52 +00:00
landOwnersAndParcels . Add ( p . LandData . OwnerID , tempList ) ;
2008-11-08 17:00:42 +00:00
}
else
{
2009-10-02 09:10:52 +00:00
landOwnersAndParcels [ p . LandData . OwnerID ] . Add ( p ) ;
2008-11-08 17:00:42 +00:00
}
2008-05-23 15:12:15 +00:00
}
}
2008-09-06 07:52:41 +00:00
foreach ( UUID owner in landOwnersAndParcels . Keys )
2008-05-23 15:12:15 +00:00
{
int simArea = 0 ;
int simPrims = 0 ;
foreach ( LandObject p in landOwnersAndParcels [ owner ] )
{
2009-10-02 09:10:52 +00:00
simArea + = p . LandData . Area ;
2011-04-05 20:25:54 +00:00
simPrims + = p . PrimCounts . Total ;
2008-05-23 15:12:15 +00:00
}
foreach ( LandObject p in landOwnersAndParcels [ owner ] )
{
2009-10-02 09:10:52 +00:00
p . LandData . SimwideArea = simArea ;
p . LandData . SimwidePrims = simPrims ;
2008-05-23 15:12:15 +00:00
}
}
}
2009-09-02 09:00:31 +00:00
public void EventManagerOnParcelPrimCountUpdate ( )
2008-05-23 15:12:15 +00:00
{
2011-03-23 21:50:56 +00:00
// m_log.DebugFormat(
// "[LAND MANAGEMENT MODULE]: Triggered EventManagerOnParcelPrimCountUpdate() for {0}",
// m_scene.RegionInfo.RegionName);
2011-04-05 21:15:06 +00:00
ResetOverMeRecords ( ) ;
2010-09-10 19:04:12 +00:00
EntityBase [ ] entities = m_scene . Entities . GetEntities ( ) ;
foreach ( EntityBase obj in entities )
2008-05-23 15:12:15 +00:00
{
2008-11-24 15:14:33 +00:00
if ( obj ! = null )
2008-05-23 15:12:15 +00:00
{
2008-11-24 15:14:33 +00:00
if ( ( obj is SceneObjectGroup ) & & ! obj . IsDeleted & & ! ( ( SceneObjectGroup ) obj ) . IsAttachment )
2008-06-07 17:48:45 +00:00
{
2008-11-24 15:14:33 +00:00
m_scene . EventManager . TriggerParcelPrimCountAdd ( ( SceneObjectGroup ) obj ) ;
2008-06-07 17:48:45 +00:00
}
2008-05-23 15:12:15 +00:00
}
}
2008-05-24 21:13:44 +00:00
FinalizeLandPrimCountUpdate ( ) ;
2008-05-23 15:12:15 +00:00
}
2009-09-02 09:00:31 +00:00
public void EventManagerOnRequestParcelPrimCountUpdate ( )
2008-05-23 15:12:15 +00:00
{
2011-04-05 21:15:06 +00:00
ResetOverMeRecords ( ) ;
2008-05-23 15:12:15 +00:00
m_scene . EventManager . TriggerParcelPrimCountUpdate ( ) ;
FinalizeLandPrimCountUpdate ( ) ;
}
/// <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>
2008-09-06 07:52:41 +00:00
/// <param name="attempting_user_id">UUID of user who is trying to subdivide</param>
2008-05-23 15:12:15 +00:00
/// <returns>Returns true if successful</returns>
2008-09-06 07:52:41 +00:00
private void subdivide ( int start_x , int start_y , int end_x , int end_y , UUID attempting_user_id )
2008-05-23 15:12:15 +00:00
{
//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 ;
2008-08-18 00:39:10 +00:00
for ( int y = 0 ; y < totalY ; y + + )
2008-05-23 15:12:15 +00:00
{
2008-08-18 00:39:10 +00:00
for ( int x = 0 ; x < totalX ; x + + )
2008-05-23 15:12:15 +00:00
{
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
2010-12-13 20:35:56 +00:00
if ( ! m_scene . Permissions . CanEditParcelProperties ( attempting_user_id , startLandObject , GroupPowers . LandDivideJoin ) )
2008-05-23 15:12:15 +00:00
{
return ;
}
//Lets create a new land object with bitmap activated at that point (keeping the old land objects info)
ILandObject newLand = startLandObject . Copy ( ) ;
2009-10-02 09:10:52 +00:00
newLand . LandData . Name = newLand . LandData . Name ;
newLand . LandData . GlobalID = UUID . Random ( ) ;
2012-10-21 12:59:22 +00:00
newLand . LandData . Dwell = 0 ;
2008-05-23 15:12:15 +00:00
2009-10-02 09:10:52 +00:00
newLand . SetLandBitmap ( newLand . GetSquareLandBitmap ( start_x , start_y , end_x , end_y ) ) ;
2008-05-23 15:12:15 +00:00
//Now, lets set the subdivision area of the original to false
2009-10-02 09:10:52 +00:00
int startLandObjectIndex = startLandObject . LandData . LocalID ;
2008-11-08 17:00:42 +00:00
lock ( m_landList )
{
2009-10-02 09:10:52 +00:00
m_landList [ startLandObjectIndex ] . SetLandBitmap (
newLand . ModifyLandBitmapSquare ( startLandObject . GetLandBitmap ( ) , start_x , start_y , end_x , end_y , false ) ) ;
m_landList [ startLandObjectIndex ] . ForceUpdateLandInfo ( ) ;
2008-11-08 17:00:42 +00:00
}
2008-05-23 15:12:15 +00:00
//Now add the new land object
ILandObject result = AddLandObject ( newLand ) ;
2009-10-02 09:10:52 +00:00
UpdateLandObject ( startLandObject . LandData . LocalID , startLandObject . LandData ) ;
result . SendLandUpdateToAvatarsOverMe ( ) ;
2008-05-23 15:12:15 +00:00
}
/// <summary>
/// Join 2 land objects together
/// </summary>
/// <param name="start_x">x value in first piece of land</param>
/// <param name="start_y">y value in first piece of land</param>
/// <param name="end_x">x value in second peice of land</param>
/// <param name="end_y">y value in second peice of land</param>
2008-09-06 07:52:41 +00:00
/// <param name="attempting_user_id">UUID of the avatar trying to join the land objects</param>
2008-05-23 15:12:15 +00:00
/// <returns>Returns true if successful</returns>
2008-09-06 07:52:41 +00:00
private void join ( int start_x , int start_y , int end_x , int end_y , UUID attempting_user_id )
2008-05-23 15:12:15 +00:00
{
end_x - = 4 ;
end_y - = 4 ;
List < ILandObject > selectedLandObjects = new List < ILandObject > ( ) ;
int stepYSelected ;
for ( stepYSelected = start_y ; stepYSelected < = end_y ; stepYSelected + = 4 )
{
int stepXSelected ;
for ( stepXSelected = start_x ; stepXSelected < = end_x ; stepXSelected + = 4 )
{
ILandObject p = GetLandObject ( stepXSelected , stepYSelected ) ;
if ( p ! = null )
{
if ( ! selectedLandObjects . Contains ( p ) )
{
selectedLandObjects . Add ( p ) ;
}
}
}
}
ILandObject masterLandObject = selectedLandObjects [ 0 ] ;
selectedLandObjects . RemoveAt ( 0 ) ;
if ( selectedLandObjects . Count < 1 )
{
return ;
}
2010-12-13 20:35:56 +00:00
if ( ! m_scene . Permissions . CanEditParcelProperties ( attempting_user_id , masterLandObject , GroupPowers . LandDivideJoin ) )
2008-05-23 15:12:15 +00:00
{
return ;
}
foreach ( ILandObject p in selectedLandObjects )
{
2009-10-02 09:10:52 +00:00
if ( p . LandData . OwnerID ! = masterLandObject . LandData . OwnerID )
2008-05-23 15:12:15 +00:00
{
return ;
}
}
2010-09-12 17:43:49 +00:00
2008-11-08 17:00:42 +00:00
lock ( m_landList )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
foreach ( ILandObject slaveLandObject in selectedLandObjects )
{
2009-10-02 09:10:52 +00:00
m_landList [ masterLandObject . LandData . LocalID ] . SetLandBitmap (
slaveLandObject . MergeLandBitmaps ( masterLandObject . GetLandBitmap ( ) , slaveLandObject . GetLandBitmap ( ) ) ) ;
2008-11-08 17:00:42 +00:00
performFinalLandJoin ( masterLandObject , slaveLandObject ) ;
}
2008-05-23 15:12:15 +00:00
}
2009-10-02 09:10:52 +00:00
masterLandObject . SendLandUpdateToAvatarsOverMe ( ) ;
2008-05-23 15:12:15 +00:00
}
2010-04-29 18:57:30 +00:00
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 ) ;
}
2008-05-23 15:12:15 +00:00
# endregion
#region Parcel Updating
/// <summary>
/// Where we send the ParcelOverlay packet to the client
/// </summary>
/// <param name="remote_client">The object representing the client</param>
public void SendParcelOverlay ( IClientAPI remote_client )
{
const int LAND_BLOCKS_PER_PACKET = 1024 ;
byte [ ] byteArray = new byte [ LAND_BLOCKS_PER_PACKET ] ;
int byteArrayCount = 0 ;
int sequenceID = 0 ;
2009-08-08 00:31:48 +00:00
int blockmeters = 4 * ( int ) Constants . RegionSize / ( int ) Constants . TerrainPatchSize ;
2008-05-23 15:12:15 +00:00
2009-08-08 00:31:48 +00:00
for ( int y = 0 ; y < blockmeters ; y + + )
2008-05-23 15:12:15 +00:00
{
2009-08-08 00:31:48 +00:00
for ( int x = 0 ; x < blockmeters ; x + + )
2008-05-23 15:12:15 +00:00
{
byte tempByte = 0 ; //This represents the byte for the current 4x4
ILandObject currentParcelBlock = GetLandObject ( x * 4 , y * 4 ) ;
if ( currentParcelBlock ! = null )
{
2009-10-02 09:10:52 +00:00
if ( currentParcelBlock . LandData . OwnerID = = remote_client . AgentId )
2008-05-23 15:12:15 +00:00
{
//Owner Flag
tempByte = Convert . ToByte ( tempByte | LandChannel . LAND_TYPE_OWNED_BY_REQUESTER ) ;
}
2009-10-02 09:10:52 +00:00
else if ( currentParcelBlock . LandData . SalePrice > 0 & &
( currentParcelBlock . LandData . AuthBuyerID = = UUID . Zero | |
currentParcelBlock . LandData . AuthBuyerID = = remote_client . AgentId ) )
2008-05-23 15:12:15 +00:00
{
//Sale Flag
tempByte = Convert . ToByte ( tempByte | LandChannel . LAND_TYPE_IS_FOR_SALE ) ;
}
2009-10-02 09:10:52 +00:00
else if ( currentParcelBlock . LandData . OwnerID = = UUID . Zero )
2008-05-23 15:12:15 +00:00
{
//Public Flag
tempByte = Convert . ToByte ( tempByte | LandChannel . LAND_TYPE_PUBLIC ) ;
}
else
{
//Other Flag
tempByte = Convert . ToByte ( tempByte | LandChannel . LAND_TYPE_OWNED_BY_OTHER ) ;
}
//Now for border control
ILandObject westParcel = null ;
ILandObject southParcel = null ;
if ( x > 0 )
{
westParcel = GetLandObject ( ( x - 1 ) * 4 , y * 4 ) ;
}
if ( y > 0 )
{
southParcel = GetLandObject ( x * 4 , ( y - 1 ) * 4 ) ;
}
if ( x = = 0 )
{
tempByte = Convert . ToByte ( tempByte | LandChannel . LAND_FLAG_PROPERTY_BORDER_WEST ) ;
}
else if ( westParcel ! = null & & westParcel ! = currentParcelBlock )
{
tempByte = Convert . ToByte ( tempByte | LandChannel . LAND_FLAG_PROPERTY_BORDER_WEST ) ;
}
if ( y = = 0 )
{
tempByte = Convert . ToByte ( tempByte | LandChannel . LAND_FLAG_PROPERTY_BORDER_SOUTH ) ;
}
else if ( southParcel ! = null & & southParcel ! = currentParcelBlock )
{
tempByte = Convert . ToByte ( tempByte | LandChannel . LAND_FLAG_PROPERTY_BORDER_SOUTH ) ;
}
byteArray [ byteArrayCount ] = tempByte ;
byteArrayCount + + ;
if ( byteArrayCount > = LAND_BLOCKS_PER_PACKET )
{
2008-07-08 11:30:08 +00:00
remote_client . SendLandParcelOverlay ( byteArray , sequenceID ) ;
2008-05-23 15:12:15 +00:00
byteArrayCount = 0 ;
sequenceID + + ;
byteArray = new byte [ LAND_BLOCKS_PER_PACKET ] ;
}
}
}
}
}
2009-09-02 09:00:31 +00:00
public void ClientOnParcelPropertiesRequest ( int start_x , int start_y , int end_x , int end_y , int sequence_id ,
bool snap_selection , IClientAPI remote_client )
2008-05-23 15:12:15 +00:00
{
//Get the land objects within the bounds
List < ILandObject > temp = new List < ILandObject > ( ) ;
int inc_x = end_x - start_x ;
int inc_y = end_y - start_y ;
2008-08-18 00:39:10 +00:00
for ( int x = 0 ; x < inc_x ; x + + )
2008-05-23 15:12:15 +00:00
{
2008-08-18 00:39:10 +00:00
for ( int y = 0 ; y < inc_y ; y + + )
2008-05-23 15:12:15 +00:00
{
ILandObject currentParcel = GetLandObject ( start_x + x , start_y + y ) ;
if ( currentParcel ! = null )
{
if ( ! temp . Contains ( currentParcel ) )
{
2009-10-02 09:10:52 +00:00
currentParcel . ForceUpdateLandInfo ( ) ;
2008-05-23 15:12:15 +00:00
temp . Add ( currentParcel ) ;
}
}
}
}
int requestResult = LandChannel . LAND_RESULT_SINGLE ;
if ( temp . Count > 1 )
{
requestResult = LandChannel . LAND_RESULT_MULTIPLE ;
}
2008-08-18 00:39:10 +00:00
for ( int i = 0 ; i < temp . Count ; i + + )
2008-05-23 15:12:15 +00:00
{
2009-10-02 09:10:52 +00:00
temp [ i ] . SendLandProperties ( sequence_id , snap_selection , requestResult , remote_client ) ;
2008-05-23 15:12:15 +00:00
}
SendParcelOverlay ( remote_client ) ;
}
2009-09-02 09:00:31 +00:00
public void ClientOnParcelPropertiesUpdateRequest ( LandUpdateArgs args , int localID , IClientAPI remote_client )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
ILandObject land ;
lock ( m_landList )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
m_landList . TryGetValue ( localID , out land ) ;
2008-05-23 15:12:15 +00:00
}
2008-11-08 17:00:42 +00:00
2010-09-06 01:59:48 +00:00
if ( land ! = null )
{
land . UpdateLandProperties ( args , remote_client ) ;
m_scene . EventManager . TriggerOnParcelPropertiesUpdateRequest ( args , localID , remote_client ) ;
}
2008-05-23 15:12:15 +00:00
}
2009-09-02 09:00:31 +00:00
public void ClientOnParcelDivideRequest ( int west , int south , int east , int north , IClientAPI remote_client )
2008-05-23 15:12:15 +00:00
{
subdivide ( west , south , east , north , remote_client . AgentId ) ;
}
2009-09-02 09:00:31 +00:00
public void ClientOnParcelJoinRequest ( int west , int south , int east , int north , IClientAPI remote_client )
2008-05-23 15:12:15 +00:00
{
join ( west , south , east , north , remote_client . AgentId ) ;
}
2010-09-12 17:43:49 +00:00
public void ClientOnParcelSelectObjects ( int local_id , int request_type ,
2009-09-02 09:00:31 +00:00
List < UUID > returnIDs , IClientAPI remote_client )
2008-05-23 15:12:15 +00:00
{
2009-10-02 09:10:52 +00:00
m_landList [ local_id ] . SendForceObjectSelect ( local_id , request_type , returnIDs , remote_client ) ;
2008-05-23 15:12:15 +00:00
}
2009-09-02 09:00:31 +00:00
public void ClientOnParcelObjectOwnerRequest ( int local_id , IClientAPI remote_client )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
ILandObject land ;
lock ( m_landList )
2008-05-24 11:10:21 +00:00
{
2008-11-08 17:00:42 +00:00
m_landList . TryGetValue ( local_id , out land ) ;
}
if ( land ! = null )
{
2011-04-05 21:15:06 +00:00
m_scene . EventManager . TriggerParcelPrimCountUpdate ( ) ;
2009-10-02 09:10:52 +00:00
m_landList [ local_id ] . SendLandObjectOwners ( remote_client ) ;
2008-11-08 17:00:42 +00:00
}
else
{
2011-03-22 23:47:36 +00:00
m_log . WarnFormat ( "[LAND MANAGEMENT MODULE]: Invalid land object {0} passed for parcel object owner request" , local_id ) ;
2008-05-24 11:10:21 +00:00
}
2008-05-23 15:12:15 +00:00
}
2009-09-02 09:00:31 +00:00
public void ClientOnParcelGodForceOwner ( int local_id , UUID ownerID , IClientAPI remote_client )
2008-10-06 08:19:18 +00:00
{
2008-11-08 17:00:42 +00:00
ILandObject land ;
lock ( m_landList )
{
m_landList . TryGetValue ( local_id , out land ) ;
}
if ( land ! = null )
2008-10-06 08:19:18 +00:00
{
2008-11-21 22:14:57 +00:00
if ( m_scene . Permissions . IsGod ( remote_client . AgentId ) )
2008-10-06 08:19:18 +00:00
{
2009-10-02 09:10:52 +00:00
land . LandData . OwnerID = ownerID ;
2009-11-08 20:36:00 +00:00
land . LandData . GroupID = UUID . Zero ;
land . LandData . IsGroupOwned = false ;
2010-05-06 23:52:52 +00:00
land . LandData . Flags & = ~ ( uint ) ( ParcelFlags . ForSale | ParcelFlags . ForSaleObjects | ParcelFlags . SellParcelObjects | ParcelFlags . ShowDirectory ) ;
2008-10-06 08:19:18 +00:00
2009-10-15 22:25:02 +00:00
m_scene . ForEachClient ( SendParcelOverlay ) ;
2009-11-08 20:36:00 +00:00
land . SendLandUpdateToClient ( true , remote_client ) ;
2008-10-06 08:19:18 +00:00
}
}
}
2009-09-02 09:00:31 +00:00
public void ClientOnParcelAbandonRequest ( int local_id , IClientAPI remote_client )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
ILandObject land ;
lock ( m_landList )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
m_landList . TryGetValue ( local_id , out land ) ;
}
if ( land ! = null )
{
2008-11-21 22:14:57 +00:00
if ( m_scene . Permissions . CanAbandonParcel ( remote_client . AgentId , land ) )
2008-05-23 15:12:15 +00:00
{
2010-01-10 22:41:42 +00:00
land . LandData . OwnerID = m_scene . RegionInfo . EstateSettings . EstateOwner ;
2009-11-08 20:36:00 +00:00
land . LandData . GroupID = UUID . Zero ;
land . LandData . IsGroupOwned = false ;
2010-05-06 23:50:26 +00:00
land . LandData . Flags & = ~ ( uint ) ( ParcelFlags . ForSale | ParcelFlags . ForSaleObjects | ParcelFlags . SellParcelObjects | ParcelFlags . ShowDirectory ) ;
2009-10-15 22:25:02 +00:00
m_scene . ForEachClient ( SendParcelOverlay ) ;
2009-11-08 20:36:00 +00:00
land . SendLandUpdateToClient ( true , remote_client ) ;
2008-06-26 13:45:36 +00:00
}
}
}
2009-09-02 09:00:31 +00:00
public void ClientOnParcelReclaim ( int local_id , IClientAPI remote_client )
2008-06-26 13:45:36 +00:00
{
2008-11-08 17:00:42 +00:00
ILandObject land ;
lock ( m_landList )
{
m_landList . TryGetValue ( local_id , out land ) ;
}
if ( land ! = null )
2008-06-26 13:45:36 +00:00
{
2008-11-21 22:14:57 +00:00
if ( m_scene . Permissions . CanReclaimParcel ( remote_client . AgentId , land ) )
2008-06-26 13:45:36 +00:00
{
2010-01-10 22:41:42 +00:00
land . LandData . OwnerID = m_scene . RegionInfo . EstateSettings . EstateOwner ;
2009-10-02 09:10:52 +00:00
land . LandData . ClaimDate = Util . UnixTimeSinceEpoch ( ) ;
2009-11-08 20:36:00 +00:00
land . LandData . GroupID = UUID . Zero ;
2009-10-02 09:10:52 +00:00
land . LandData . IsGroupOwned = false ;
2010-05-06 15:07:15 +00:00
land . LandData . SalePrice = 0 ;
land . LandData . AuthBuyerID = UUID . Zero ;
land . LandData . Flags & = ~ ( uint ) ( ParcelFlags . ForSale | ParcelFlags . ForSaleObjects | ParcelFlags . SellParcelObjects | ParcelFlags . ShowDirectory ) ;
2009-10-15 22:25:02 +00:00
m_scene . ForEachClient ( SendParcelOverlay ) ;
2009-11-08 20:36:00 +00:00
land . SendLandUpdateToClient ( true , remote_client ) ;
2008-05-23 15:12:15 +00:00
}
}
}
# endregion
// If the economy has been validated by the economy module,
// and land has been validated as well, this method transfers
// the land ownership
2009-09-02 09:00:31 +00:00
public void EventManagerOnLandBuy ( Object o , EventManager . LandBuyArgs e )
2008-05-23 15:12:15 +00:00
{
if ( e . economyValidated & & e . landValidated )
{
2008-11-08 17:00:42 +00:00
ILandObject land ;
lock ( m_landList )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
m_landList . TryGetValue ( e . parcelLocalID , out land ) ;
}
if ( land ! = null )
{
2009-10-02 09:10:52 +00:00
land . UpdateLandSold ( e . agentId , e . groupId , e . groupOwned , ( uint ) e . transactionID , e . parcelPrice , e . parcelArea ) ;
2008-05-23 15:12:15 +00:00
}
}
}
// After receiving a land buy packet, first the data needs to
// be validated. This method validates the right to buy the
// parcel
2009-09-02 09:00:31 +00:00
public void EventManagerOnValidateLandBuy ( Object o , EventManager . LandBuyArgs e )
2008-05-23 15:12:15 +00:00
{
if ( e . landValidated = = false )
{
ILandObject lob = null ;
2008-11-08 17:00:42 +00:00
lock ( m_landList )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
m_landList . TryGetValue ( e . parcelLocalID , out lob ) ;
2008-05-23 15:12:15 +00:00
}
2008-11-08 17:00:42 +00:00
2008-05-23 15:12:15 +00:00
if ( lob ! = null )
{
2009-10-02 09:10:52 +00:00
UUID AuthorizedID = lob . LandData . AuthBuyerID ;
int saleprice = lob . LandData . SalePrice ;
UUID pOwnerID = lob . LandData . OwnerID ;
2008-05-23 15:12:15 +00:00
2009-10-02 09:10:52 +00:00
bool landforsale = ( ( lob . LandData . Flags &
2009-07-25 15:49:10 +00:00
( uint ) ( ParcelFlags . ForSale | ParcelFlags . ForSaleObjects | ParcelFlags . SellParcelObjects ) ) ! = 0 ) ;
2008-09-06 07:52:41 +00:00
if ( ( AuthorizedID = = UUID . Zero | | AuthorizedID = = e . agentId ) & & e . parcelPrice > = saleprice & & landforsale )
2008-05-23 15:12:15 +00:00
{
2008-11-08 17:00:42 +00:00
// TODO I don't think we have to lock it here, no?
//lock (e)
//{
2008-05-23 15:12:15 +00:00
e . parcelOwnerID = pOwnerID ;
e . landValidated = true ;
2008-11-08 17:00:42 +00:00
//}
2008-05-23 15:12:15 +00:00
}
}
}
}
2009-09-02 09:00:31 +00:00
void ClientOnParcelDeedToGroup ( int parcelLocalID , UUID groupID , IClientAPI remote_client )
2009-04-19 00:11:14 +00:00
{
ILandObject land ;
lock ( m_landList )
{
m_landList . TryGetValue ( parcelLocalID , out land ) ;
}
2009-05-12 13:41:30 +00:00
if ( ! m_scene . Permissions . CanDeedParcel ( remote_client . AgentId , land ) )
return ;
2009-04-19 00:11:14 +00:00
if ( land ! = null )
{
2009-10-02 09:10:52 +00:00
land . DeedToGroup ( groupID ) ;
2009-04-19 00:11:14 +00:00
}
}
2008-05-23 15:12:15 +00:00
#region Land Object From Storage Functions
2009-09-02 09:00:31 +00:00
public void EventManagerOnIncomingLandDataFromStorage ( List < LandData > data )
2008-05-23 15:12:15 +00:00
{
2012-11-24 02:43:31 +00:00
// m_log.DebugFormat(
// "[LAND MANAGMENT MODULE]: Processing {0} incoming parcels on {1}", data.Count, m_scene.Name);
2008-05-23 15:12:15 +00:00
for ( int i = 0 ; i < data . Count ; i + + )
IncomingLandObjectFromStorage ( data [ i ] ) ;
}
public void IncomingLandObjectFromStorage ( LandData data )
{
2008-07-23 15:50:32 +00:00
ILandObject new_land = new LandObject ( data . OwnerID , data . IsGroupOwned , m_scene ) ;
2009-10-02 09:10:52 +00:00
new_land . LandData = data . Copy ( ) ;
2011-03-25 21:47:54 +00:00
new_land . SetLandBitmapFromByteArray ( ) ;
2008-05-23 15:12:15 +00:00
AddLandObject ( new_land ) ;
}
2008-09-06 07:52:41 +00:00
public void ReturnObjectsInParcel ( int localID , uint returnType , UUID [ ] agentIDs , UUID [ ] taskIDs , IClientAPI remoteClient )
2008-05-24 11:10:21 +00:00
{
2012-12-12 15:10:08 +00:00
if ( localID ! = - 1 )
2008-05-24 11:10:21 +00:00
{
2012-12-12 15:10:08 +00:00
ILandObject selectedParcel = null ;
lock ( m_landList )
{
m_landList . TryGetValue ( localID , out selectedParcel ) ;
}
if ( selectedParcel = = null ) return ;
selectedParcel . ReturnLandObjects ( returnType , agentIDs , taskIDs , remoteClient ) ;
2008-05-24 11:10:21 +00:00
}
2012-12-12 15:10:08 +00:00
else
{
if ( returnType ! = 1 )
{
m_log . WarnFormat ( "[LAND MANAGEMENT MODULE] ReturnObjectsInParcel: unknown return type {0}" , returnType ) ;
return ;
}
// We get here when the user returns objects from the list of Top Colliders or Top Scripts.
// In that case we receive specific object UUID's, but no parcel ID.
2008-11-08 17:00:42 +00:00
2012-12-12 15:10:08 +00:00
Dictionary < UUID , HashSet < SceneObjectGroup > > returns = new Dictionary < UUID , HashSet < SceneObjectGroup > > ( ) ;
2008-05-24 11:10:21 +00:00
2012-12-12 15:10:08 +00:00
foreach ( UUID groupID in taskIDs )
{
SceneObjectGroup obj = m_scene . GetSceneObjectGroup ( groupID ) ;
if ( obj ! = null )
{
if ( ! returns . ContainsKey ( obj . OwnerID ) )
returns [ obj . OwnerID ] = new HashSet < SceneObjectGroup > ( ) ;
returns [ obj . OwnerID ] . Add ( obj ) ;
}
else
{
m_log . WarnFormat ( "[LAND MANAGEMENT MODULE] ReturnObjectsInParcel: unknown object {0}" , groupID ) ;
}
}
int num = 0 ;
foreach ( HashSet < SceneObjectGroup > objs in returns . Values )
num + = objs . Count ;
m_log . DebugFormat ( "[LAND MANAGEMENT MODULE] Returning {0} specific object(s)" , num ) ;
foreach ( HashSet < SceneObjectGroup > objs in returns . Values )
{
List < SceneObjectGroup > objs2 = new List < SceneObjectGroup > ( objs ) ;
if ( m_scene . Permissions . CanReturnObjects ( null , remoteClient . AgentId , objs2 ) )
{
m_scene . returnObjects ( objs2 . ToArray ( ) , remoteClient . AgentId ) ;
}
else
{
m_log . WarnFormat ( "[LAND MANAGEMENT MODULE] ReturnObjectsInParcel: not permitted to return {0} object(s) belonging to user {1}" ,
objs2 . Count , objs2 [ 0 ] . OwnerID ) ;
}
}
}
2008-05-24 11:10:21 +00:00
}
2009-09-02 09:00:31 +00:00
public void EventManagerOnNoLandDataFromStorage ( )
2008-05-23 15:12:15 +00:00
{
2011-05-12 11:42:28 +00:00
lock ( m_landList )
{
ResetSimLandObjects ( ) ;
CreateDefaultParcel ( ) ;
}
2008-05-23 15:12:15 +00:00
}
# endregion
2008-06-11 17:31:43 +00:00
public void setParcelObjectMaxOverride ( overrideParcelMaxPrimCountDelegate overrideDel )
{
2008-11-08 17:00:42 +00:00
lock ( m_landList )
2008-06-11 17:31:43 +00:00
{
2008-11-08 17:00:42 +00:00
foreach ( LandObject obj in m_landList . Values )
{
2009-10-02 09:10:52 +00:00
obj . SetParcelObjectMaxOverride ( overrideDel ) ;
2008-11-08 17:00:42 +00:00
}
2008-06-11 17:31:43 +00:00
}
}
2008-08-18 00:39:10 +00:00
2008-06-11 17:31:43 +00:00
public void setSimulatorObjectMaxOverride ( overrideSimulatorMaxPrimCountDelegate overrideDel )
{
}
2008-08-16 19:20:14 +00:00
#region CAPS handler
2008-08-18 00:39:10 +00:00
2009-09-02 09:00:31 +00:00
private void EventManagerOnRegisterCaps ( UUID agentID , Caps caps )
2008-08-16 19:20:14 +00:00
{
string capsBase = "/CAPS/" + caps . CapsObjectPath ;
2012-05-03 00:45:49 +00:00
caps . RegisterHandler (
"RemoteParcelRequest" ,
new RestStreamHandler (
"POST" ,
capsBase + remoteParcelRequestPath ,
( request , path , param , httpRequest , httpResponse )
= > RemoteParcelRequest ( request , path , param , agentID , caps ) ,
"RemoteParcelRequest" ,
agentID . ToString ( ) ) ) ;
2010-09-12 17:43:49 +00:00
UUID parcelCapID = UUID . Random ( ) ;
2012-05-03 00:45:49 +00:00
caps . RegisterHandler (
"ParcelPropertiesUpdate" ,
new RestStreamHandler (
"POST" ,
"/CAPS/" + parcelCapID ,
( request , path , param , httpRequest , httpResponse )
= > ProcessPropertiesUpdate ( request , path , param , agentID , caps ) ,
"ParcelPropertiesUpdate" ,
agentID . ToString ( ) ) ) ;
2010-09-12 17:43:49 +00:00
}
private string ProcessPropertiesUpdate ( string request , string path , string param , UUID agentID , Caps caps )
{
IClientAPI client ;
2011-04-05 21:15:06 +00:00
if ( ! m_scene . TryGetClient ( agentID , out client ) )
{
2011-03-22 23:47:36 +00:00
m_log . WarnFormat ( "[LAND MANAGEMENT MODULE]: Unable to retrieve IClientAPI for {0}" , agentID ) ;
2010-09-12 17:43:49 +00:00
return LLSDHelpers . SerialiseLLSDReply ( new LLSDEmpty ( ) ) ;
}
ParcelPropertiesUpdateMessage properties = new ParcelPropertiesUpdateMessage ( ) ;
OpenMetaverse . StructuredData . OSDMap args = ( OpenMetaverse . StructuredData . OSDMap ) OSDParser . DeserializeLLSDXml ( request ) ;
properties . Deserialize ( args ) ;
LandUpdateArgs land_update = new LandUpdateArgs ( ) ;
int parcelID = properties . LocalID ;
land_update . AuthBuyerID = properties . AuthBuyerID ;
2010-08-30 01:28:31 +00:00
land_update . Category = properties . Category ;
land_update . Desc = properties . Desc ;
land_update . GroupID = properties . GroupID ;
land_update . LandingType = ( byte ) properties . Landing ;
land_update . MediaAutoScale = ( byte ) Convert . ToInt32 ( properties . MediaAutoScale ) ;
land_update . MediaID = properties . MediaID ;
land_update . MediaURL = properties . MediaURL ;
land_update . MusicURL = properties . MusicURL ;
land_update . Name = properties . Name ;
land_update . ParcelFlags = ( uint ) properties . ParcelFlags ;
land_update . PassHours = ( int ) properties . PassHours ;
land_update . PassPrice = ( int ) properties . PassPrice ;
land_update . SalePrice = ( int ) properties . SalePrice ;
land_update . SnapshotID = properties . SnapshotID ;
land_update . UserLocation = properties . UserLocation ;
land_update . UserLookAt = properties . UserLookAt ;
2010-09-12 17:43:49 +00:00
land_update . MediaDescription = properties . MediaDesc ;
land_update . MediaType = properties . MediaType ;
land_update . MediaWidth = properties . MediaWidth ;
land_update . MediaHeight = properties . MediaHeight ;
land_update . MediaLoop = properties . MediaLoop ;
land_update . ObscureMusic = properties . ObscureMusic ;
land_update . ObscureMedia = properties . ObscureMedia ;
ILandObject land ;
2010-08-30 01:28:31 +00:00
lock ( m_landList )
{
m_landList . TryGetValue ( parcelID , out land ) ;
}
2008-08-18 00:39:10 +00:00
2010-09-06 01:59:48 +00:00
if ( land ! = null )
{
2010-09-12 17:43:49 +00:00
land . UpdateLandProperties ( land_update , client ) ;
2010-09-06 01:59:48 +00:00
m_scene . EventManager . TriggerOnParcelPropertiesUpdateRequest ( land_update , parcelID , client ) ;
2010-09-12 17:43:49 +00:00
}
2010-09-06 01:59:48 +00:00
else
{
2011-03-22 23:47:36 +00:00
m_log . WarnFormat ( "[LAND MANAGEMENT MODULE]: Unable to find parcelID {0}" , parcelID ) ;
2010-09-12 17:43:49 +00:00
}
2010-08-30 01:28:31 +00:00
return LLSDHelpers . SerialiseLLSDReply ( new LLSDEmpty ( ) ) ;
2010-09-12 17:43:49 +00:00
}
2008-08-16 19:20:14 +00:00
// we cheat here: As we don't have (and want) a grid-global parcel-store, we can't return the
// "real" parcelID, because we wouldn't be able to map that to the region the parcel belongs to.
// So, we create a "fake" parcelID by using the regionHandle (64 bit), and the local (integer) x
2008-09-06 07:52:41 +00:00
// and y coordinate (each 8 bit), encoded in a UUID (128 bit).
2008-08-16 19:20:14 +00:00
/ /
// Request format:
// <llsd>
// <map>
// <key>location</key>
// <array>
// <real>1.23</real>
// <real>45..6</real>
// <real>78.9</real>
// </array>
// <key>region_id</key>
// <uuid>xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx</uuid>
// </map>
// </llsd>
2008-09-06 07:52:41 +00:00
private string RemoteParcelRequest ( string request , string path , string param , UUID agentID , Caps caps )
2008-08-16 19:20:14 +00:00
{
2008-09-06 07:52:41 +00:00
UUID parcelID = UUID . Zero ;
2008-08-16 19:20:14 +00:00
try
{
Hashtable hash = new Hashtable ( ) ;
2008-09-06 07:52:41 +00:00
hash = ( Hashtable ) LLSD . LLSDDeserialize ( Utils . StringToBytes ( request ) ) ;
2008-08-17 02:31:45 +00:00
if ( hash . ContainsKey ( "region_id" ) & & hash . ContainsKey ( "location" ) )
2008-08-16 19:20:14 +00:00
{
2008-09-06 07:52:41 +00:00
UUID regionID = ( UUID ) hash [ "region_id" ] ;
2008-08-16 19:20:14 +00:00
ArrayList list = ( ArrayList ) hash [ "location" ] ;
uint x = ( uint ) ( double ) list [ 0 ] ;
uint y = ( uint ) ( double ) list [ 1 ] ;
2008-08-17 02:31:45 +00:00
if ( hash . ContainsKey ( "region_handle" ) )
2008-08-16 19:20:14 +00:00
{
// if you do a "About Landmark" on a landmark a second time, the viewer sends the
// region_handle it got earlier via RegionHandleRequest
2008-09-07 20:09:11 +00:00
ulong regionHandle = Util . BytesToUInt64Big ( ( byte [ ] ) hash [ "region_handle" ] ) ;
2008-08-16 19:20:14 +00:00
parcelID = Util . BuildFakeParcelID ( regionHandle , x , y ) ;
}
2008-08-17 02:31:45 +00:00
else if ( regionID = = m_scene . RegionInfo . RegionID )
2008-08-16 19:20:14 +00:00
{
// a parcel request for a local parcel => no need to query the grid
parcelID = Util . BuildFakeParcelID ( m_scene . RegionInfo . RegionHandle , x , y ) ;
}
else
{
// a parcel request for a parcel in another region. Ask the grid about the region
2009-09-26 14:48:21 +00:00
GridRegion info = m_scene . GridService . GetRegionByUUID ( UUID . Zero , regionID ) ;
2008-08-17 02:31:45 +00:00
if ( info ! = null )
parcelID = Util . BuildFakeParcelID ( info . RegionHandle , x , y ) ;
2008-08-16 19:20:14 +00:00
}
}
}
catch ( LLSD . LLSDParseException e )
{
2011-03-22 23:47:36 +00:00
m_log . ErrorFormat ( "[LAND MANAGEMENT MODULE]: Fetch error: {0}" , e . Message ) ;
m_log . ErrorFormat ( "[LAND MANAGEMENT MODULE]: ... in request {0}" , request ) ;
2008-08-16 19:20:14 +00:00
}
2011-03-22 23:47:36 +00:00
catch ( InvalidCastException )
2008-08-16 19:20:14 +00:00
{
2011-03-22 23:47:36 +00:00
m_log . ErrorFormat ( "[LAND MANAGEMENT MODULE]: Wrong type in request {0}" , request ) ;
2008-08-16 19:20:14 +00:00
}
2008-08-18 00:39:10 +00:00
2008-08-16 19:20:14 +00:00
LLSDRemoteParcelResponse response = new LLSDRemoteParcelResponse ( ) ;
response . parcel_id = parcelID ;
2011-03-22 23:47:36 +00:00
m_log . DebugFormat ( "[LAND MANAGEMENT MODULE]: Got parcelID {0}" , parcelID ) ;
2008-08-18 00:39:10 +00:00
2008-08-16 19:20:14 +00:00
return LLSDHelpers . SerialiseLLSDReply ( response ) ;
}
# endregion
2009-09-02 09:00:31 +00:00
private void ClientOnParcelInfoRequest ( IClientAPI remoteClient , UUID parcelID )
2008-08-16 19:20:14 +00:00
{
2008-09-06 07:52:41 +00:00
if ( parcelID = = UUID . Zero )
2008-08-17 02:31:45 +00:00
return ;
2008-08-16 19:20:14 +00:00
2010-12-31 14:45:08 +00:00
ExtendedLandData data = ( ExtendedLandData ) parcelInfoCache . Get ( parcelID . ToString ( ) ,
delegate ( string id )
{
UUID parcel = UUID . Zero ;
UUID . TryParse ( id , out parcel ) ;
// assume we've got the parcelID we just computed in RemoteParcelRequest
ExtendedLandData extLandData = new ExtendedLandData ( ) ;
Util . ParseFakeParcelID ( parcel , out extLandData . RegionHandle ,
out extLandData . X , out extLandData . Y ) ;
2011-03-22 23:47:36 +00:00
m_log . DebugFormat ( "[LAND MANAGEMENT MODULE]: Got parcelinfo request for regionHandle {0}, x/y {1}/{2}" ,
2010-12-31 14:45:08 +00:00
extLandData . RegionHandle , extLandData . X , extLandData . Y ) ;
// for this region or for somewhere else?
if ( extLandData . RegionHandle = = m_scene . RegionInfo . RegionHandle )
{
extLandData . LandData = this . GetLandObject ( extLandData . X , extLandData . Y ) . LandData ;
extLandData . RegionAccess = m_scene . RegionInfo . AccessLevel ;
}
else
{
ILandService landService = m_scene . RequestModuleInterface < ILandService > ( ) ;
extLandData . LandData = landService . GetLandData ( m_scene . RegionInfo . ScopeID ,
extLandData . RegionHandle ,
extLandData . X ,
extLandData . Y ,
out extLandData . RegionAccess ) ;
if ( extLandData . LandData = = null )
{
// we didn't find the region/land => don't cache
return null ;
}
}
return extLandData ;
} ) ;
2008-08-16 19:20:14 +00:00
2008-10-11 22:42:59 +00:00
if ( data ! = null ) // if we found some data, send it
2008-08-16 19:20:14 +00:00
{
2009-09-26 14:48:21 +00:00
GridRegion info ;
2009-10-02 09:10:52 +00:00
if ( data . RegionHandle = = m_scene . RegionInfo . RegionHandle )
2008-10-11 22:42:59 +00:00
{
2009-09-26 14:48:21 +00:00
info = new GridRegion ( m_scene . RegionInfo ) ;
2008-10-11 22:42:59 +00:00
}
else
{
// most likely still cached from building the extLandData entry
2009-09-26 14:48:21 +00:00
uint x = 0 , y = 0 ;
2009-10-02 09:10:52 +00:00
Utils . LongToUInts ( data . RegionHandle , out x , out y ) ;
2010-12-31 14:53:31 +00:00
info = m_scene . GridService . GetRegionByPosition ( m_scene . RegionInfo . ScopeID , ( int ) x , ( int ) y ) ;
2008-10-11 22:42:59 +00:00
}
2008-08-16 19:20:14 +00:00
// we need to transfer the fake parcelID, not the one in landData, so the viewer can match it to the landmark.
2011-03-22 23:47:36 +00:00
m_log . DebugFormat ( "[LAND MANAGEMENT MODULE]: got parcelinfo for parcel {0} in region {1}; sending..." ,
2009-10-02 09:10:52 +00:00
data . LandData . Name , data . RegionHandle ) ;
2009-09-26 14:48:21 +00:00
// HACK for now
RegionInfo r = new RegionInfo ( ) ;
r . RegionName = info . RegionName ;
r . RegionLocX = ( uint ) info . RegionLocX ;
r . RegionLocY = ( uint ) info . RegionLocY ;
2010-08-07 03:45:52 +00:00
r . RegionSettings . Maturity = ( int ) Util . ConvertAccessLevelToMaturity ( data . RegionAccess ) ;
2009-10-02 09:10:52 +00:00
remoteClient . SendParcelInfo ( r , data . LandData , parcelID , data . X , data . Y ) ;
2008-08-16 19:20:14 +00:00
}
2008-08-17 02:31:45 +00:00
else
2011-03-22 23:47:36 +00:00
m_log . Debug ( "[LAND MANAGEMENT MODULE]: got no parcelinfo; not sending" ) ;
2008-08-16 19:20:14 +00:00
}
2008-10-18 05:51:36 +00:00
2008-11-08 17:00:42 +00:00
public void setParcelOtherCleanTime ( IClientAPI remoteClient , int localID , int otherCleanTime )
2008-10-18 05:51:36 +00:00
{
2008-11-08 17:00:42 +00:00
ILandObject land ;
lock ( m_landList )
{
m_landList . TryGetValue ( localID , out land ) ;
}
2008-10-18 05:51:36 +00:00
2008-11-09 01:31:38 +00:00
if ( land = = null ) return ;
2008-10-18 05:51:36 +00:00
2010-12-13 20:35:56 +00:00
if ( ! m_scene . Permissions . CanEditParcelProperties ( remoteClient . AgentId , land , GroupPowers . LandOptions ) )
2008-10-18 05:51:36 +00:00
return ;
2009-10-02 09:10:52 +00:00
land . LandData . OtherCleanTime = otherCleanTime ;
2008-10-18 05:51:36 +00:00
2009-10-02 09:10:52 +00:00
UpdateLandObject ( localID , land . LandData ) ;
2008-10-18 05:51:36 +00:00
}
2011-01-26 21:12:41 +00:00
protected void InstallInterfaces ( )
{
2011-01-27 19:37:20 +00:00
Command clearCommand
= new Command ( "clear" , CommandIntentions . COMMAND_HAZARDOUS , ClearCommand , "Clears all the parcels from the region." ) ;
Command showCommand
= new Command ( "show" , CommandIntentions . COMMAND_STATISTICAL , ShowParcelsCommand , "Shows all parcels on the region." ) ;
2011-01-26 21:12:41 +00:00
2011-01-27 19:37:20 +00:00
m_commander . RegisterCommand ( "clear" , clearCommand ) ;
2011-01-26 21:12:41 +00:00
m_commander . RegisterCommand ( "show" , showCommand ) ;
// Add this to our scene so scripts can call these functions
m_scene . RegisterModuleCommander ( m_commander ) ;
2011-01-27 19:37:20 +00:00
}
protected void ClearCommand ( Object [ ] args )
{
2011-01-27 20:57:59 +00:00
string response = MainConsole . Instance . CmdPrompt (
string . Format (
"Are you sure that you want to clear all land parcels from {0} (y or n)" ,
m_scene . RegionInfo . RegionName ) ,
"n" ) ;
2011-01-27 19:37:20 +00:00
2011-01-27 20:57:59 +00:00
if ( response . ToLower ( ) = = "y" )
{
Clear ( true ) ;
MainConsole . Instance . OutputFormat ( "Cleared all parcels from {0}" , m_scene . RegionInfo . RegionName ) ;
}
else
{
MainConsole . Instance . OutputFormat ( "Aborting clear of all parcels from {0}" , m_scene . RegionInfo . RegionName ) ;
}
2011-01-27 19:37:20 +00:00
}
2011-01-26 21:12:41 +00:00
protected void ShowParcelsCommand ( Object [ ] args )
{
StringBuilder report = new StringBuilder ( ) ;
report . AppendFormat ( "Land information for {0}\n" , m_scene . RegionInfo . RegionName ) ;
report . AppendFormat (
2011-01-27 20:11:30 +00:00
"{0,-20} {1,-10} {2,-9} {3,-18} {4,-18} {5,-20}\n" ,
2011-01-26 21:12:41 +00:00
"Parcel Name" ,
2011-01-27 20:11:30 +00:00
"Local ID" ,
2011-01-26 21:12:41 +00:00
"Area" ,
"Starts" ,
"Ends" ,
"Owner" ) ;
lock ( m_landList )
{
foreach ( ILandObject lo in m_landList . Values )
{
LandData ld = lo . LandData ;
report . AppendFormat (
2011-01-27 20:11:30 +00:00
"{0,-20} {1,-10} {2,-9} {3,-18} {4,-18} {5,-20}\n" ,
ld . Name , ld . LocalID , ld . Area , lo . StartPoint , lo . EndPoint , m_userManager . GetUserName ( ld . OwnerID ) ) ;
2011-01-26 21:12:41 +00:00
}
}
MainConsole . Instance . Output ( report . ToString ( ) ) ;
2011-01-27 20:11:30 +00:00
}
2008-05-01 14:31:30 +00:00
}
2012-02-02 23:40:56 +00:00
}