/* * 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. * * Neither the name of the OpenSim 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 System; using System.Threading; using System.Collections.Generic; using System.Reflection; using libsecondlife; using log4net; using Nini.Config; using OpenSim.Framework; using OpenSim.Region.Environment.Interfaces; using OpenSim.Region.Environment.Scenes; namespace OpenSim.Region.Environment.Modules.World.Estate { public class EstateManagementModule : IRegionModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private delegate void LookupUUIDS(List uuidLst); private Scene m_scene; #region Packet Data Responders private void sendDetailedEstateData(IClientAPI remote_client, LLUUID invoice) { remote_client.sendDetailedEstateData(invoice,m_scene.RegionInfo.EstateSettings.estateName,m_scene.RegionInfo.EstateSettings.estateID); remote_client.sendEstateManagersList(invoice,m_scene.RegionInfo.EstateSettings.estateManagers,m_scene.RegionInfo.EstateSettings.estateID); remote_client.sendBannedUserList(invoice, m_scene.RegionInfo.regionBanlist, m_scene.RegionInfo.EstateSettings.estateID); } private void estateSetRegionInfoHandler(bool blockTerraform, bool noFly, bool allowDamage, bool blockLandResell, int maxAgents, float objectBonusFactor, int matureLevel, bool restrictPushObject, bool allowParcelChanges) { m_scene.RegionInfo.EstateSettings.regionFlags = Simulator.RegionFlags.None; if (blockTerraform) { m_scene.RegionInfo.EstateSettings.regionFlags = m_scene.RegionInfo.EstateSettings.regionFlags | Simulator.RegionFlags.BlockTerraform; } if (noFly) { m_scene.RegionInfo.EstateSettings.regionFlags = m_scene.RegionInfo.EstateSettings.regionFlags | Simulator.RegionFlags.NoFly; } if (allowDamage) { m_scene.RegionInfo.EstateSettings.regionFlags = m_scene.RegionInfo.EstateSettings.regionFlags | Simulator.RegionFlags.AllowDamage; } if (blockLandResell) { m_scene.RegionInfo.EstateSettings.regionFlags = m_scene.RegionInfo.EstateSettings.regionFlags | Simulator.RegionFlags.BlockLandResell; } m_scene.RegionInfo.EstateSettings.maxAgents = (byte) maxAgents; m_scene.RegionInfo.EstateSettings.objectBonusFactor = objectBonusFactor; m_scene.RegionInfo.EstateSettings.simAccess = (Simulator.SimAccess) matureLevel; if (restrictPushObject) { m_scene.RegionInfo.EstateSettings.regionFlags = m_scene.RegionInfo.EstateSettings.regionFlags | Simulator.RegionFlags.RestrictPushObject; } if (allowParcelChanges) { m_scene.RegionInfo.EstateSettings.regionFlags = m_scene.RegionInfo.EstateSettings.regionFlags | Simulator.RegionFlags.AllowParcelChanges; } sendRegionInfoPacketToAll(); } public void setEstateTerrainBaseTexture(IClientAPI remoteClient, int corner, LLUUID texture) { switch (corner) { case 0: m_scene.RegionInfo.EstateSettings.terrainBase0 = texture; break; case 1: m_scene.RegionInfo.EstateSettings.terrainBase1 = texture; break; case 2: m_scene.RegionInfo.EstateSettings.terrainBase2 = texture; break; case 3: m_scene.RegionInfo.EstateSettings.terrainBase3 = texture; break; } } public void setEstateTerrainDetailTexture(IClientAPI client, int corner, LLUUID textureUUID) { switch (corner) { case 0: m_scene.RegionInfo.EstateSettings.terrainDetail0 = textureUUID; break; case 1: m_scene.RegionInfo.EstateSettings.terrainDetail1 = textureUUID; break; case 2: m_scene.RegionInfo.EstateSettings.terrainDetail2 = textureUUID; break; case 3: m_scene.RegionInfo.EstateSettings.terrainDetail3 = textureUUID; break; } } public void setEstateTerrainTextureHeights(IClientAPI client, int corner, float lowValue, float highValue) { switch (corner) { case 0: m_scene.RegionInfo.EstateSettings.terrainStartHeight0 = lowValue; m_scene.RegionInfo.EstateSettings.terrainHeightRange0 = highValue; break; case 1: m_scene.RegionInfo.EstateSettings.terrainStartHeight1 = lowValue; m_scene.RegionInfo.EstateSettings.terrainHeightRange1 = highValue; break; case 2: m_scene.RegionInfo.EstateSettings.terrainStartHeight2 = lowValue; m_scene.RegionInfo.EstateSettings.terrainHeightRange2 = highValue; break; case 3: m_scene.RegionInfo.EstateSettings.terrainStartHeight3 = lowValue; m_scene.RegionInfo.EstateSettings.terrainHeightRange3 = highValue; break; } } private void handleCommitEstateTerrainTextureRequest(IClientAPI remoteClient) { sendRegionHandshakeToAll(); } public void setRegionTerrainSettings(float WaterHeight, float TerrainRaiseLimit, float TerrainLowerLimit, bool UseFixedSun, float SunHour) { // Water Height m_scene.RegionInfo.EstateSettings.waterHeight = WaterHeight; // Terraforming limits m_scene.RegionInfo.EstateSettings.terrainRaiseLimit = TerrainRaiseLimit; m_scene.RegionInfo.EstateSettings.terrainLowerLimit = TerrainLowerLimit; // Time of day / fixed sun m_scene.RegionInfo.EstateSettings.useFixedSun = UseFixedSun; m_scene.RegionInfo.EstateSettings.sunHour = SunHour; m_scene.EventManager.TriggerEstateToolsTimeUpdate(m_scene.RegionInfo.RegionHandle, UseFixedSun, UseFixedSun, SunHour); //m_log.Debug("[ESTATE]: UFS: " + UseFixedSun.ToString()); //m_log.Debug("[ESTATE]: SunHour: " + SunHour.ToString()); sendRegionInfoPacketToAll(); } private void handleEstateRestartSimRequest(IClientAPI remoteClient, int timeInSeconds) { m_scene.Restart(timeInSeconds); } private void handleChangeEstateCovenantRequest(IClientAPI remoteClient, LLUUID estateCovenantID) { m_scene.RegionInfo.CovenantID = estateCovenantID; m_scene.RegionInfo.SaveEstatecovenantUUID(estateCovenantID); } private void handleEstateAccessDeltaRequest(IClientAPI remote_client, LLUUID invoice, int estateAccessType, LLUUID user) { // EstateAccessDelta handles Estate Managers, Sim Access, Sim Banlist, allowed Groups.. etc. switch (estateAccessType) { case 64: if (m_scene.ExternalChecks.ExternalChecksCanIssueEstateCommand(remote_client.AgentId) || m_scene.ExternalChecks.ExternalChecksBypassPermissions()) { RegionBanListItem[] banlistcheck = m_scene.RegionInfo.regionBanlist.ToArray(); bool alreadyInList = false; for (int i = 0; i < banlistcheck.Length; i++) { if (user == banlistcheck[i].bannedUUID) { alreadyInList = true; break; } } if (!alreadyInList) { RegionBanListItem item = new RegionBanListItem(); item.bannedUUID = user; item.regionUUID = m_scene.RegionInfo.RegionID; item.bannedIP = "0.0.0.0"; item.bannedIPHostMask = "0.0.0.0"; m_scene.RegionInfo.regionBanlist.Add(item); m_scene.AddToRegionBanlist(item); ScenePresence s = m_scene.GetScenePresence(user); if (s != null) { m_scene.TeleportClientHome(user, s.ControllingClient); } } else { remote_client.SendAlertMessage("User is already on the region ban list"); } //m_scene.RegionInfo.regionBanlist.Add(Manager(user); remote_client.sendBannedUserList(invoice, m_scene.RegionInfo.regionBanlist, m_scene.RegionInfo.EstateSettings.estateID); } else { remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions"); } break; case 128: if (m_scene.ExternalChecks.ExternalChecksCanIssueEstateCommand(remote_client.AgentId) || m_scene.ExternalChecks.ExternalChecksBypassPermissions()) { RegionBanListItem[] banlistcheck = m_scene.RegionInfo.regionBanlist.ToArray(); bool alreadyInList = false; RegionBanListItem listitem = null; for (int i = 0; i < banlistcheck.Length; i++) { if (user == banlistcheck[i].bannedUUID) { alreadyInList = true; listitem = banlistcheck[i]; break; } } if (alreadyInList && listitem != null) { m_scene.RegionInfo.regionBanlist.Remove(listitem); m_scene.RemoveFromRegionBanlist(listitem); } else { remote_client.SendAlertMessage("User is not on the region ban list"); } //m_scene.RegionInfo.regionBanlist.Add(Manager(user); remote_client.sendBannedUserList(invoice, m_scene.RegionInfo.regionBanlist, m_scene.RegionInfo.EstateSettings.estateID); } else { remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions"); } break; case 256: // This needs to be updated for SuperEstateOwnerUser.. a non existing user in the estatesettings.xml // So make sure you really trust your region owners. because they can add other estate manaagers to your other estates if (remote_client.AgentId == m_scene.RegionInfo.MasterAvatarAssignedUUID || m_scene.ExternalChecks.ExternalChecksBypassPermissions()) { m_scene.RegionInfo.EstateSettings.AddEstateManager(user); remote_client.sendEstateManagersList(invoice, m_scene.RegionInfo.EstateSettings.estateManagers, m_scene.RegionInfo.EstateSettings.estateID); } else { remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions"); } break; case 512: // This needs to be updated for SuperEstateOwnerUser.. a non existing user in the estatesettings.xml // So make sure you really trust your region owners. because they can add other estate manaagers to your other estates if (remote_client.AgentId == m_scene.RegionInfo.MasterAvatarAssignedUUID || m_scene.ExternalChecks.ExternalChecksBypassPermissions()) { m_scene.RegionInfo.EstateSettings.RemoveEstateManager(user); remote_client.sendEstateManagersList(invoice, m_scene.RegionInfo.EstateSettings.estateManagers, m_scene.RegionInfo.EstateSettings.estateID); } else { remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions"); } break; default: m_log.ErrorFormat("EstateOwnerMessage: Unknown EstateAccessType requested in estateAccessDelta: {0}", estateAccessType.ToString()); break; } } private void SendSimulatorBlueBoxMessage(IClientAPI remote_client, LLUUID invoice, LLUUID senderID, LLUUID sessionID, string senderName, string message) { m_scene.SendRegionMessageFromEstateTools(senderID, sessionID, senderName, message); } private void SendEstateBlueBoxMessage(IClientAPI remote_client, LLUUID invoice, LLUUID senderID, LLUUID sessionID, string senderName, string message) { m_scene.SendEstateMessageFromEstateTools(senderID, sessionID, senderName, message); } private void handleEstateDebugRegionRequest(IClientAPI remote_client, LLUUID invoice, LLUUID senderID, bool scripted, bool collisionEvents, bool physics) { if (physics) { m_scene.RegionInfo.EstateSettings.regionFlags |= Simulator.RegionFlags.SkipPhysics; } else { m_scene.RegionInfo.EstateSettings.regionFlags &= ~Simulator.RegionFlags.SkipPhysics; } if (scripted) { m_scene.RegionInfo.EstateSettings.regionFlags |= Simulator.RegionFlags.SkipScripts; } else { m_scene.RegionInfo.EstateSettings.regionFlags &= ~Simulator.RegionFlags.SkipScripts; } m_scene.SetSceneCoreDebug(scripted, collisionEvents, physics); } private void handleEstateTeleportOneUserHomeRequest(IClientAPI remover_client, LLUUID invoice, LLUUID senderID, LLUUID prey) { if (prey != LLUUID.Zero) { ScenePresence s = m_scene.GetScenePresence(prey); if (s != null) { m_scene.TeleportClientHome(prey, s.ControllingClient); } } } private void HandleRegionInfoRequest(IClientAPI remote_client) { RegionInfoForEstateMenuArgs args = new RegionInfoForEstateMenuArgs(); args.billableFactor = m_scene.RegionInfo.EstateSettings.billableFactor; args.estateID = m_scene.RegionInfo.EstateSettings.estateID; args.maxAgents = m_scene.RegionInfo.EstateSettings.maxAgents; args.objectBonusFactor = m_scene.RegionInfo.EstateSettings.objectBonusFactor; args.parentEstateID = m_scene.RegionInfo.EstateSettings.parentEstateID; args.pricePerMeter = m_scene.RegionInfo.EstateSettings.pricePerMeter; args.redirectGridX = m_scene.RegionInfo.EstateSettings.redirectGridX; args.redirectGridY = m_scene.RegionInfo.EstateSettings.redirectGridY; args.regionFlags = (uint)(m_scene.RegionInfo.EstateSettings.regionFlags); args.simAccess = (byte)m_scene.RegionInfo.EstateSettings.simAccess; if (m_scene.RegionInfo.EstateSettings.useFixedSun) args.sunHour = m_scene.RegionInfo.EstateSettings.sunHour; else args.sunHour = m_scene.EventManager.GetSunLindenHour(); args.terrainLowerLimit = m_scene.RegionInfo.EstateSettings.terrainLowerLimit; args.terrainRaiseLimit = m_scene.RegionInfo.EstateSettings.terrainRaiseLimit; args.useEstateSun = !m_scene.RegionInfo.EstateSettings.useFixedSun; args.waterHeight = m_scene.RegionInfo.EstateSettings.waterHeight; args.simName = m_scene.RegionInfo.RegionName; remote_client.sendRegionInfoToEstateMenu(args); } private static void HandleEstateCovenantRequest(IClientAPI remote_client) { remote_client.sendEstateCovenantInformation(); } private void HandleLandStatRequest(int parcelID, uint reportType, uint requestFlags, string filter, IClientAPI remoteClient) { Dictionary SceneData = new Dictionary(); List uuidNameLookupList = new List(); if (reportType == 1) { SceneData = m_scene.PhysicsScene.GetTopColliders(); } else if (reportType == 0) { SceneData = m_scene.m_innerScene.GetTopScripts(); } List SceneReport = new List(); lock (SceneData) { foreach (uint obj in SceneData.Keys) { SceneObjectPart prt = m_scene.GetSceneObjectPart(obj); if (prt != null) { if (prt.ParentGroup != null) { SceneObjectGroup sog = prt.ParentGroup; if (sog != null) { LandStatReportItem lsri = new LandStatReportItem(); lsri.LocationX = sog.AbsolutePosition.X; lsri.LocationY = sog.AbsolutePosition.Y; lsri.LocationZ = sog.AbsolutePosition.Z; lsri.Score = SceneData[obj]; lsri.TaskID = sog.UUID; lsri.TaskLocalID = sog.LocalId; lsri.TaskName = sog.GetPartName(obj); if (m_scene.CommsManager.UUIDNameCachedTest(sog.OwnerID)) { lsri.OwnerName = m_scene.CommsManager.UUIDNameRequestString(sog.OwnerID); } else { lsri.OwnerName = "waiting"; lock (uuidNameLookupList) uuidNameLookupList.Add(sog.OwnerID); } if (filter.Length != 0) { if ((lsri.OwnerName.Contains(filter) || lsri.TaskName.Contains(filter))) { } else { continue; } } SceneReport.Add(lsri); } } } } } remoteClient.SendLandStatReply(reportType, requestFlags, (uint)SceneReport.Count,SceneReport.ToArray()); if (uuidNameLookupList.Count > 0) LookupUUID(uuidNameLookupList); } private void LookupUUIDSCompleted(IAsyncResult iar) { LookupUUIDS icon = (LookupUUIDS)iar.AsyncState; icon.EndInvoke(iar); } private void LookupUUID(List uuidLst) { LookupUUIDS d = LookupUUIDsAsync; d.BeginInvoke(uuidLst, LookupUUIDSCompleted, d); } private void LookupUUIDsAsync(List uuidLst) { LLUUID[] uuidarr = new LLUUID[0]; lock (uuidLst) { uuidarr = uuidLst.ToArray(); } for (int i = 0; i < uuidarr.Length; i++) { // string lookupname = m_scene.CommsManager.UUIDNameRequestString(uuidarr[i]); m_scene.CommsManager.UUIDNameRequestString(uuidarr[i]); // we drop it. It gets cached though... so we're ready for the next request. } } #endregion #region Outgoing Packets public void sendRegionInfoPacketToAll() { List avatars = m_scene.GetAvatars(); for (int i = 0; i < avatars.Count; i++) { HandleRegionInfoRequest(avatars[i].ControllingClient); ; } } public void sendRegionHandshake(IClientAPI remoteClient) { RegionHandshakeArgs args = new RegionHandshakeArgs(); bool estatemanager = false; LLUUID[] EstateManagers = m_scene.RegionInfo.EstateSettings.estateManagers; for (int i = 0; i < EstateManagers.Length; i++) { if (EstateManagers[i] == remoteClient.AgentId) estatemanager = true; } args.isEstateManager = estatemanager; args.billableFactor = m_scene.RegionInfo.EstateSettings.billableFactor; args.terrainHeightRange0 = m_scene.RegionInfo.EstateSettings.terrainHeightRange0; args.terrainHeightRange1 = m_scene.RegionInfo.EstateSettings.terrainHeightRange1; args.terrainHeightRange2 = m_scene.RegionInfo.EstateSettings.terrainHeightRange2; args.terrainHeightRange3 = m_scene.RegionInfo.EstateSettings.terrainHeightRange3; args.terrainStartHeight0 = m_scene.RegionInfo.EstateSettings.terrainStartHeight0; args.terrainStartHeight1 = m_scene.RegionInfo.EstateSettings.terrainStartHeight1; args.terrainStartHeight2 = m_scene.RegionInfo.EstateSettings.terrainStartHeight2; args.terrainStartHeight3 = m_scene.RegionInfo.EstateSettings.terrainStartHeight3; args.simAccess = (byte)m_scene.RegionInfo.EstateSettings.simAccess; args.waterHeight = m_scene.RegionInfo.EstateSettings.waterHeight; args.regionFlags = (uint)m_scene.RegionInfo.EstateSettings.regionFlags; args.regionName = m_scene.RegionInfo.RegionName; args.SimOwner = m_scene.RegionInfo.MasterAvatarAssignedUUID; args.terrainBase0 = m_scene.RegionInfo.EstateSettings.terrainBase0; args.terrainBase1 = m_scene.RegionInfo.EstateSettings.terrainBase1; args.terrainBase2 = m_scene.RegionInfo.EstateSettings.terrainBase2; args.terrainBase3 = m_scene.RegionInfo.EstateSettings.terrainBase3; args.terrainDetail0 = m_scene.RegionInfo.EstateSettings.terrainDetail0; args.terrainDetail1 = m_scene.RegionInfo.EstateSettings.terrainDetail1; args.terrainDetail2 = m_scene.RegionInfo.EstateSettings.terrainDetail2; args.terrainDetail3 = m_scene.RegionInfo.EstateSettings.terrainDetail3; remoteClient.SendRegionHandshake(m_scene.RegionInfo,args); } public void sendRegionHandshakeToAll() { m_scene.Broadcast( sendRegionHandshake ); } #endregion #region IRegionModule Members public void Initialise(Scene scene, IConfigSource source) { m_scene = scene; m_scene.EventManager.OnNewClient += EventManager_OnNewClient; m_scene.EventManager.OnRequestChangeWaterHeight += changeWaterHeight; } public void PostInitialise() { } public void Close() { } public string Name { get { return "EstateManagementModule"; } } public bool IsSharedModule { get { return false; } } #endregion #region Other Functions public void changeWaterHeight(float height) { setRegionTerrainSettings(height, m_scene.RegionInfo.EstateSettings.terrainRaiseLimit, m_scene.RegionInfo.EstateSettings.terrainLowerLimit, m_scene.RegionInfo.EstateSettings.useFixedSun, m_scene.RegionInfo.EstateSettings.sunHour); sendRegionInfoPacketToAll(); } #endregion private void EventManager_OnNewClient(IClientAPI client) { client.OnDetailedEstateDataRequest += sendDetailedEstateData; client.OnSetEstateFlagsRequest += estateSetRegionInfoHandler; client.OnSetEstateTerrainBaseTexture += setEstateTerrainBaseTexture; client.OnSetEstateTerrainDetailTexture += setEstateTerrainDetailTexture; client.OnSetEstateTerrainTextureHeights += setEstateTerrainTextureHeights; client.OnCommitEstateTerrainTextureRequest += handleCommitEstateTerrainTextureRequest; client.OnSetRegionTerrainSettings += setRegionTerrainSettings; client.OnEstateRestartSimRequest += handleEstateRestartSimRequest; client.OnEstateChangeCovenantRequest += handleChangeEstateCovenantRequest; client.OnUpdateEstateAccessDeltaRequest += handleEstateAccessDeltaRequest; client.OnSimulatorBlueBoxMessageRequest += SendSimulatorBlueBoxMessage; client.OnEstateBlueBoxMessageRequest += SendEstateBlueBoxMessage; client.OnEstateDebugRegionRequest += handleEstateDebugRegionRequest; client.OnEstateTeleportOneUserHomeRequest += handleEstateTeleportOneUserHomeRequest; client.OnRegionInfoRequest += HandleRegionInfoRequest; client.OnEstateCovenantRequest += HandleEstateCovenantRequest; client.OnLandStatRequest += HandleLandStatRequest; sendRegionHandshake(client); } } }