/* * Copyright (c) 2006-2008, openmetaverse.org * All rights reserved. * * - 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. * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 OpenMetaverse.Packets; using System.Collections.Generic; namespace OpenMetaverse { /// /// Estate level administration and utilities /// public class EstateTools { private GridClient Client; public GroundTextureSettings GroundTextures; /// /// Triggered on LandStatReply when the report type is for "top colliders" /// /// /// public delegate void GetTopCollidersReply(int objectCount, List Tasks); /// /// Triggered on LandStatReply when the report type is for "top scripts" /// /// /// public delegate void GetTopScriptsReply(int objectCount, List Tasks); /// /// Triggered when the list of estate managers is received for the current estate /// /// /// /// public delegate void EstateManagersReply(uint estateID, int count, List managers); /// /// FIXME - Enumerate all params from EstateOwnerMessage packet /// /// /// /// /// public delegate void EstateUpdateInfoReply(string estateName, UUID estateOwner, uint estateID, bool denyNoPaymentInfo); public delegate void EstateManagersListReply(uint estateID, List managers); public delegate void EstateBansReply(uint estateID, int count, List banned); public delegate void EstateUsersReply(uint estateID, int count, List allowedUsers); public delegate void EstateGroupsReply(uint estateID, int count, List allowedGroups); public delegate void EstateCovenantReply(UUID covenantID, long timestamp, string estateName, UUID estateOwnerID); // Callback for LandStatReply packets //public event LandStatReply OnLandStatReply; /// Triggered upon a successful .GetTopColliders() public event GetTopCollidersReply OnGetTopColliders; /// Triggered upon a successful .GetTopScripts() public event GetTopScriptsReply OnGetTopScripts; /// Returned, along with other info, upon a successful .GetInfo() public event EstateUpdateInfoReply OnGetEstateUpdateInfo; /// Returned, along with other info, upon a successful .GetInfo() public event EstateManagersReply OnGetEstateManagers; /// Returned, along with other info, upon a successful .GetInfo() public event EstateBansReply OnGetEstateBans; /// Returned, along with other info, upon a successful .GetInfo() public event EstateGroupsReply OnGetAllowedGroups; /// Returned, along with other info, upon a successful .GetInfo() public event EstateUsersReply OnGetAllowedUsers; /// Triggered upon a successful .RequestCovenant() public event EstateCovenantReply OnGetCovenant; /// /// Constructor for EstateTools class /// /// public EstateTools(GridClient client) { Client = client; Client.Network.RegisterCallback(PacketType.LandStatReply, new NetworkManager.PacketCallback(LandStatReplyHandler)); Client.Network.RegisterCallback(PacketType.EstateOwnerMessage, new NetworkManager.PacketCallback(EstateOwnerMessageHandler)); Client.Network.RegisterCallback(PacketType.EstateCovenantReply, new NetworkManager.PacketCallback(EstateCovenantReplyHandler)); } /// Describes tasks returned in LandStatReply public class EstateTask { public Vector3 Position; public float Score; public UUID TaskID; public uint TaskLocalID; public string TaskName; public string OwnerName; } /// Used in the ReportType field of a LandStatRequest public enum LandStatReportType { TopScripts = 0, TopColliders = 1 } /// Used by EstateOwnerMessage packets public enum EstateAccessDelta { BanUser = 64, BanUserAllEstates = 66, UnbanUser = 128, UnbanUserAllEstates = 130 } public enum EstateAccessReplyDelta : uint { AllowedUsers = 17, AllowedGroups = 18, EstateBans = 20, EstateManagers = 24 } /// Used by GroundTextureSettings public class GroundTextureRegion { public UUID TextureID; public float Low; public float High; } /// Ground texture settings for each corner of the region public class GroundTextureSettings { public GroundTextureRegion Southwest; public GroundTextureRegion Northwest; public GroundTextureRegion Southeast; public GroundTextureRegion Northeast; } /// /// Requests estate information such as top scripts and colliders /// /// /// /// /// public void LandStatRequest(int parcelLocalID, LandStatReportType reportType, uint requestFlags, string filter) { LandStatRequestPacket p = new LandStatRequestPacket(); p.AgentData.AgentID = Client.Self.AgentID; p.AgentData.SessionID = Client.Self.SessionID; p.RequestData.Filter = Utils.StringToBytes(filter); p.RequestData.ParcelLocalID = parcelLocalID; p.RequestData.ReportType = (uint)reportType; p.RequestData.RequestFlags = requestFlags; Client.Network.SendPacket(p); } /// Requests estate settings, including estate manager and access/ban lists public void GetInfo() { EstateOwnerMessage("getinfo", ""); } /// Requests the "Top Scripts" list for the current region public void GetTopScripts() { //EstateOwnerMessage("scripts", ""); LandStatRequest(0, LandStatReportType.TopScripts, 0, ""); } /// Requests the "Top Colliders" list for the current region public void GetTopColliders() { //EstateOwnerMessage("colliders", ""); LandStatRequest(0, LandStatReportType.TopColliders, 0, ""); } private void EstateCovenantReplyHandler(Packet packet, Simulator simulator) { EstateCovenantReplyPacket reply = (EstateCovenantReplyPacket)packet; if (OnGetCovenant != null) { try { OnGetCovenant( reply.Data.CovenantID, reply.Data.CovenantTimestamp, Utils.BytesToString(reply.Data.EstateName), reply.Data.EstateOwnerID); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } } /// /// /// private void EstateOwnerMessageHandler(Packet packet, Simulator simulator) { EstateOwnerMessagePacket message = (EstateOwnerMessagePacket)packet; uint estateID; string method = Utils.BytesToString(message.MethodData.Method); //List parameters = new List(); if (method == "estateupdateinfo") { string estateName = Utils.BytesToString(message.ParamList[0].Parameter); UUID estateOwner = new UUID(Utils.BytesToString(message.ParamList[1].Parameter)); estateID = Utils.BytesToUInt(message.ParamList[2].Parameter); /* foreach (EstateOwnerMessagePacket.ParamListBlock param in message.ParamList) { parameters.Add(Utils.BytesToString(param.Parameter)); } */ bool denyNoPaymentInfo; if (Utils.BytesToUInt(message.ParamList[8].Parameter) == 0) denyNoPaymentInfo = true; else denyNoPaymentInfo = false; if (OnGetEstateUpdateInfo != null) { try { OnGetEstateUpdateInfo(estateName, estateOwner, estateID, denyNoPaymentInfo); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } } else if (method == "setaccess") { int count; estateID = Utils.BytesToUInt(message.ParamList[0].Parameter); if (message.ParamList.Length > 1) { //param comes in as a string for some reason uint param; if (!uint.TryParse(Utils.BytesToString(message.ParamList[1].Parameter), out param)) return; EstateAccessReplyDelta accessType = (EstateAccessReplyDelta)param; switch (accessType) { case EstateAccessReplyDelta.EstateManagers: if (OnGetEstateManagers != null) { if (message.ParamList.Length > 5) { if (!int.TryParse(Utils.BytesToString(message.ParamList[5].Parameter), out count)) return; List managers = new List(); for (int i = 6; i < message.ParamList.Length; i++) { try { UUID managerID = new UUID(message.ParamList[i].Parameter, 0); managers.Add(managerID); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } try { OnGetEstateManagers(estateID, count, managers); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } } break; case EstateAccessReplyDelta.EstateBans: if (OnGetEstateBans != null) { if (message.ParamList.Length > 6) { if (!int.TryParse(Utils.BytesToString(message.ParamList[4].Parameter), out count)) return; List bannedUsers = new List(); for (int i = 7; i < message.ParamList.Length; i++) { try { UUID bannedID = new UUID(message.ParamList[i].Parameter, 0); bannedUsers.Add(bannedID); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } try { OnGetEstateBans(estateID, count, bannedUsers); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } } break; case EstateAccessReplyDelta.AllowedUsers: if (OnGetAllowedUsers != null) { if (message.ParamList.Length > 5) { if (!int.TryParse(Utils.BytesToString(message.ParamList[2].Parameter), out count)) return; List allowedUsers = new List(); for (int i = 6; i < message.ParamList.Length; i++) { try { UUID allowedID = new UUID(message.ParamList[i].Parameter, 0); allowedUsers.Add(allowedID); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } try { OnGetAllowedUsers(estateID, count, allowedUsers); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } } break; case EstateAccessReplyDelta.AllowedGroups: if (OnGetAllowedGroups != null) { if (message.ParamList.Length > 5) { if (!int.TryParse(Utils.BytesToString(message.ParamList[3].Parameter), out count)) return; List allowedGroups = new List(); for (int i = 5; i < message.ParamList.Length; i++) { try { UUID groupID = new UUID(message.ParamList[i].Parameter, 0); allowedGroups.Add(groupID); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } try { OnGetAllowedGroups(estateID, count, allowedGroups); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } } break; } } } /* Console.WriteLine("--- " + method + " ---"); foreach (EstateOwnerMessagePacket.ParamListBlock block in message.ParamList) { Console.WriteLine(Utils.BytesToString(block.Parameter)); } Console.WriteLine("------"); */ } /// /// /// private void LandStatReplyHandler(Packet packet, Simulator simulator) { //if (OnLandStatReply != null || OnGetTopScripts != null || OnGetTopColliders != null) if (OnGetTopScripts != null || OnGetTopColliders != null) { LandStatReplyPacket p = (LandStatReplyPacket)packet; List Tasks = new List(); foreach (LandStatReplyPacket.ReportDataBlock rep in p.ReportData) { EstateTask task = new EstateTask(); task.Position = new Vector3(rep.LocationX, rep.LocationY, rep.LocationZ); task.Score = rep.Score; task.TaskID = rep.TaskID; task.TaskLocalID = rep.TaskLocalID; task.TaskName = Utils.BytesToString(rep.TaskName); task.OwnerName = Utils.BytesToString(rep.OwnerName); Tasks.Add(task); } LandStatReportType type = (LandStatReportType)p.RequestData.ReportType; if (OnGetTopScripts != null && type == LandStatReportType.TopScripts) { try { OnGetTopScripts((int)p.RequestData.TotalObjectCount, Tasks); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } else if (OnGetTopColliders != null && type == LandStatReportType.TopColliders) { try { OnGetTopColliders((int)p.RequestData.TotalObjectCount, Tasks); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } /* if (OnGetTopColliders != null) { //FIXME - System.UnhandledExceptionEventArgs OnLandStatReply( type, p.RequestData.RequestFlags, (int)p.RequestData.TotalObjectCount, Tasks ); } */ } } public void EstateOwnerMessage(string method, string param) { List listParams = new List(); listParams.Add(param); EstateOwnerMessage(method, listParams); } /// /// Used for setting and retrieving various estate panel settings /// /// EstateOwnerMessage Method field /// List of parameters to include public void EstateOwnerMessage(string method, ListlistParams) { EstateOwnerMessagePacket estate = new EstateOwnerMessagePacket(); estate.AgentData.AgentID = Client.Self.AgentID; estate.AgentData.SessionID = Client.Self.SessionID; estate.AgentData.TransactionID = UUID.Zero; estate.MethodData.Invoice = UUID.Random(); estate.MethodData.Method = Utils.StringToBytes(method); estate.ParamList = new EstateOwnerMessagePacket.ParamListBlock[listParams.Count]; for (int i = 0; i < listParams.Count; i++) { estate.ParamList[i] = new EstateOwnerMessagePacket.ParamListBlock(); estate.ParamList[i].Parameter = Utils.StringToBytes(listParams[i]); } Client.Network.SendPacket((Packet)estate); } /// /// Kick an avatar from an estate /// /// Key of Agent to remove public void KickUser(UUID userID) { EstateOwnerMessage("kickestate", userID.ToString()); } /// /// Ban an avatar from an estate /// Key of Agent to remove /// Ban user from this estate and all others owned by the estate owner public void BanUser(UUID userID, bool allEstates) { List listParams = new List(); uint flag = allEstates ? (uint)EstateAccessDelta.BanUserAllEstates : (uint)EstateAccessDelta.BanUser; listParams.Add(Client.Self.AgentID.ToString()); listParams.Add(flag.ToString()); listParams.Add(userID.ToString()); EstateOwnerMessage("estateaccessdelta", listParams); } /// Unban an avatar from an estate /// Key of Agent to remove /// /// Unban user from this estate and all others owned by the estate owner public void UnbanUser(UUID userID, bool allEstates) { List listParams = new List(); uint flag = allEstates ? (uint)EstateAccessDelta.UnbanUserAllEstates : (uint)EstateAccessDelta.UnbanUser; listParams.Add(Client.Self.AgentID.ToString()); listParams.Add(flag.ToString()); listParams.Add(userID.ToString()); EstateOwnerMessage("estateaccessdelta", listParams); } /// /// Send a message dialog to everyone in an entire estate /// /// Message to send all users in the estate public void EstateMessage(string message) { List listParams = new List(); listParams.Add(Client.Self.FirstName + " " + Client.Self.LastName); listParams.Add(message); EstateOwnerMessage("instantmessage", listParams); } /// /// Send a message dialog to everyone in a simulator /// /// Message to send all users in the simulator public void SimulatorMessage(string message) { List listParams = new List(); listParams.Add("-1"); listParams.Add("-1"); listParams.Add(Client.Self.AgentID.ToString()); listParams.Add(Client.Self.FirstName + " " + Client.Self.LastName); listParams.Add(message); EstateOwnerMessage("simulatormessage", listParams); } /// /// Send an avatar back to their home location /// /// Key of avatar to send home public void TeleportHomeUser(UUID pest) { List listParams = new List(); listParams.Add(Client.Self.AgentID.ToString()); listParams.Add(pest.ToString()); EstateOwnerMessage("teleporthomeuser", listParams); } /// /// Begin the region restart process /// public void RestartRegion() { EstateOwnerMessage("restart", "120"); } /// /// Cancels a region restart /// public void CancelRestart() { EstateOwnerMessage("restart", "-1"); } /// Estate panel "Region" tab settings public void SetRegionInfo(bool blockTerraform, bool blockFly, bool allowDamage, bool allowLandResell, bool restrictPushing, bool allowParcelJoinDivide, float agentLimit, float objectBonus, bool mature) { List listParams = new List(); if (blockTerraform) listParams.Add("Y"); else listParams.Add("N"); if (blockFly) listParams.Add("Y"); else listParams.Add("N"); if (allowDamage) listParams.Add("Y"); else listParams.Add("N"); if (allowLandResell) listParams.Add("Y"); else listParams.Add("N"); listParams.Add(agentLimit.ToString()); listParams.Add(objectBonus.ToString()); if (mature) listParams.Add("21"); else listParams.Add("13"); //FIXME - enumerate these settings if (restrictPushing) listParams.Add("Y"); else listParams.Add("N"); if (allowParcelJoinDivide) listParams.Add("Y"); else listParams.Add("N"); EstateOwnerMessage("setregioninfo", listParams); } /// Estate panel "Debug" tab settings public void SetRegionDebug(bool disableScripts, bool disableCollisions, bool disablePhysics) { List listParams = new List(); if (disableScripts) listParams.Add("Y"); else listParams.Add("N"); if (disableCollisions) listParams.Add("Y"); else listParams.Add("N"); if (disablePhysics) listParams.Add("Y"); else listParams.Add("N"); EstateOwnerMessage("setregiondebug", listParams); } public void RequestCovenant() { EstateCovenantRequestPacket req = new EstateCovenantRequestPacket(); req.AgentData.AgentID = Client.Self.AgentID; req.AgentData.SessionID = Client.Self.SessionID; Client.Network.SendPacket(req); } /// /// Upload a terrain RAW file /// /// A byte array containing the encoded terrain data /// The name of the file being uploaded /// The Id of the transfer request public UUID UploadTerrain(byte[] fileData, string fileName) { AssetUpload upload = new AssetUpload(); upload.AssetData = fileData; upload.AssetType = AssetType.Unknown; upload.Size = fileData.Length; upload.ID = UUID.Random(); // Tell the library we have a pending file to upload Client.Assets.SetPendingAssetUploadData(upload); // Create and populate a list with commands specific to uploading a raw terrain file List paramList = new List(); paramList.Add("upload filename"); paramList.Add(fileName); // Tell the simulator we have a new raw file to upload Client.Network.CurrentSim.Estate.EstateOwnerMessage("terrain", paramList); return upload.ID; } } }