From 5e4d6cab00cb29cd088ab7b62ab13aff103b64cb Mon Sep 17 00:00:00 2001 From: onefang Date: Sun, 19 May 2019 21:24:15 +1000 Subject: Dump OpenSim 0.9.0.1 into it's own branch. --- .../Shared/Api/Implementation/OSSL_Api.cs | 2065 ++++++++++++++------ 1 file changed, 1487 insertions(+), 578 deletions(-) (limited to 'OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 83aa245..6e28fe0 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -45,6 +45,7 @@ using OpenSim.Framework; using OpenSim.Framework.Console; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Scripting; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; using OpenSim.Region.ScriptEngine.Shared.ScriptBase; @@ -138,8 +139,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api internal TaskInventoryItem m_item; internal bool m_OSFunctionsEnabled = false; internal ThreatLevel m_MaxThreatLevel = ThreatLevel.VeryLow; + internal float m_ScriptDelayFactor = 1.0f; + internal float m_ScriptDistanceFactor = 1.0f; + internal bool m_debuggerSafe = false; internal Dictionary m_FunctionPerms = new Dictionary(); - protected IUrlModule m_UrlModule = null; public void Initialize( @@ -148,6 +151,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_ScriptEngine = scriptEngine; m_host = host; m_item = item; + m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false); m_UrlModule = m_ScriptEngine.World.RequestModuleInterface(); @@ -157,6 +161,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // m_log.Warn("[OSSL] OSSL FUNCTIONS ENABLED"); } + m_ScriptDelayFactor = + m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f); + m_ScriptDistanceFactor = + m_ScriptEngine.Config.GetFloat("ScriptDistanceLimitFactor", 1.0f); + string risk = m_ScriptEngine.Config.GetString("OSFunctionThreatLevel", "VeryLow"); switch (risk) { @@ -187,7 +196,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api default: break; } - } + } public override Object InitializeLifetimeService() { @@ -209,7 +218,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api internal void OSSLError(string msg) { - OSSLShoutError("OSSL Runtime Error: " + msg); + if (m_debuggerSafe) + { + OSSLShoutError(msg); + } + else + { + throw new ScriptException("OSSL Runtime Error: " + msg); + } } /// @@ -244,22 +260,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api wComm.DeliverMessage(ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.Name, m_host.UUID, message); } - // Returns of the function is allowed. Throws a script exception if not allowed. - public bool CheckThreatLevel(ThreatLevel level, string function) + // Returns if OSSL is enabled. Throws a script exception if OSSL is not allowed.. + // for safe funtions always active + public void CheckThreatLevel() { + m_host.AddScriptLPS(1); if (!m_OSFunctionsEnabled) - { - OSSLError(String.Format("{0} permission denied. All OS functions are disabled.", function)); - return false; - } + OSSLError(String.Format("{0} permission denied. All OS functions are disabled.")); // throws + } + + // Returns if the function is allowed. Throws a script exception if not allowed. + public void CheckThreatLevel(ThreatLevel level, string function) + { + m_host.AddScriptLPS(1); + if (!m_OSFunctionsEnabled) + OSSLError(String.Format("{0} permission denied. All OS functions are disabled.", function)); // throws string reasonWhyNot = CheckThreatLevelTest(level, function); if (!String.IsNullOrEmpty(reasonWhyNot)) { OSSLError(reasonWhyNot); - return false; } - return true; } // Check to see if function is allowed. Returns an empty string if function permitted @@ -299,7 +320,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api foreach (string id in ids) { string current = id.Trim(); - if (current.ToUpper() == "PARCEL_GROUP_MEMBER" || current.ToUpper() == "PARCEL_OWNER" || current.ToUpper() == "ESTATE_MANAGER" || current.ToUpper() == "ESTATE_OWNER") + if (current.ToUpper() == "PARCEL_GROUP_MEMBER" || current.ToUpper() == "PARCEL_OWNER" || current.ToUpper() == "ESTATE_MANAGER" || current.ToUpper() == "ESTATE_OWNER" || current.ToUpper() == "ACTIVE_GOD" || current.ToUpper() == "GRID_GOD" || current.ToUpper() == "GOD") { if (!perms.AllowedOwnerClasses.Contains(current)) perms.AllowedOwnerClasses.Add(current.ToUpper()); @@ -404,6 +425,35 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + + //Only grid gods may use the function + if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("GRID_GOD")) + { + if (World.Permissions.IsGridGod(ownerID)) + { + return String.Empty; + } + } + + //Any god may use the function + if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("GOD")) + { + if (World.Permissions.IsAdministrator(ownerID)) + { + return String.Empty; + } + } + + //Only active gods may use the function + if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("ACTIVE_GOD")) + { + ScenePresence sp = World.GetScenePresence(ownerID); + if (sp != null && !sp.IsDeleted && sp.IsGod) + { + return String.Empty; + } + } + if (!m_FunctionPerms[function].AllowedCreators.Contains(m_item.CreatorID)) return( String.Format("{0} permission denied. Script creator is not in the list of users allowed to execute this function and prim owner also has no permission.", @@ -425,16 +475,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api OSSLShoutError(string.Format("Use of function {0} is deprecated. Use {1} instead.", function, replacement)); } + protected void ScriptSleep(int delay) + { + delay = (int)((float)delay * m_ScriptDelayFactor); + if (delay == 0) + return; + System.Threading.Thread.Sleep(delay); + } + public LSL_Integer osSetTerrainHeight(int x, int y, double val) { - if (!CheckThreatLevel(ThreatLevel.High, "osSetTerrainHeight")) return 0; + CheckThreatLevel(ThreatLevel.High, "osSetTerrainHeight"); return SetTerrainHeight(x, y, val); } public LSL_Integer osTerrainSetHeight(int x, int y, double val) { - if (!CheckThreatLevel(ThreatLevel.High, "osTerrainSetHeight")) return 0; + CheckThreatLevel(ThreatLevel.High, "osTerrainSetHeight"); OSSLDeprecated("osTerrainSetHeight", "osSetTerrainHeight"); return SetTerrainHeight(x, y, val); @@ -442,8 +500,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api private LSL_Integer SetTerrainHeight(int x, int y, double val) { - m_host.AddScriptLPS(1); - if (x > (World.RegionInfo.RegionSizeX - 1) || x < 0 || y > (World.RegionInfo.RegionSizeY - 1) || y < 0) OSSLError("osSetTerrainHeight: Coordinate out of bounds"); @@ -460,18 +516,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Float osGetTerrainHeight(int x, int y) { + CheckThreatLevel(); return GetTerrainHeight(x, y); } public LSL_Float osTerrainGetHeight(int x, int y) { + CheckThreatLevel(); OSSLDeprecated("osTerrainGetHeight", "osGetTerrainHeight"); return GetTerrainHeight(x, y); } private LSL_Float GetTerrainHeight(int x, int y) { - m_host.AddScriptLPS(1); if (x > (World.RegionInfo.RegionSizeX - 1) || x < 0 || y > (World.RegionInfo.RegionSizeY - 1) || y < 0) OSSLError("osGetTerrainHeight: Coordinate out of bounds"); @@ -480,8 +537,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osTerrainFlush() { - if (!CheckThreatLevel(ThreatLevel.VeryLow, "osTerrainFlush")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osTerrainFlush"); ITerrainModule terrainModule = World.RequestModuleInterface(); if (terrainModule != null) terrainModule.TaintTerrain(); @@ -495,31 +551,40 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // The underlying functionality is fixed, since the security // as such is sound // - if (!CheckThreatLevel(ThreatLevel.High, "osRegionRestart")) return 0; + CheckThreatLevel(ThreatLevel.High, "osRegionRestart"); IRestartModule restartModule = World.RequestModuleInterface(); - m_host.AddScriptLPS(1); if (World.Permissions.CanIssueEstateCommand(m_host.OwnerID, false) && (restartModule != null)) { if (seconds < 15) { - restartModule.AbortRestart("Restart aborted"); + restartModule.AbortRestart("Region restart has been aborted\n"); return 1; } - List times = new List(); - while (seconds > 0) + RegionRestart(seconds, String.Empty); + return 1; + } + else + { + return 0; + } + } + + public int osRegionRestart(double seconds, string msg) + { + CheckThreatLevel(ThreatLevel.High, "osRegionRestart"); + + IRestartModule restartModule = World.RequestModuleInterface(); + if (World.Permissions.CanIssueEstateCommand(m_host.OwnerID, false) && (restartModule != null)) + { + if (seconds < 15) { - times.Add((int)seconds); - if (seconds > 300) - seconds -= 120; - else if (seconds > 30) - seconds -= 30; - else - seconds -= 15; + restartModule.AbortRestart("Region restart has been aborted\n"); + return 1; } - restartModule.ScheduleRestart(UUID.Zero, "Region will restart in {0}", times.ToArray(), true); + RegionRestart(seconds, msg); return 1; } else @@ -528,15 +593,38 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + private void RegionRestart(double seconds, string msg) + { + IRestartModule restartModule = World.RequestModuleInterface(); + + List times = new List(); + while (seconds > 0) + { + times.Add((int)seconds); + if (seconds > 300) + seconds -= 120; + else if (seconds > 120) + seconds -= 60; + else if (seconds > 60) + seconds -= 30; + else + seconds -= 15; + } + + if (msg == String.Empty) + restartModule.ScheduleRestart(UUID.Zero, "Region: " + World.RegionInfo.RegionName + " is about to restart.\n\nIf you stay here you will be logged out.\n\n\nTime remaining: {0}.\n", times.ToArray(), true); + + else + restartModule.ScheduleRestart(UUID.Zero, msg + "\n\nTime remaining: {0}.\n", times.ToArray(), true); + } + public void osRegionNotice(string msg) { // This implementation provides absolutely no security // It's high griefing potential makes this classification // necessary // - if (!CheckThreatLevel(ThreatLevel.VeryHigh, "osRegionNotice")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryHigh, "osRegionNotice"); IDialogModule dm = World.RequestModuleInterface(); @@ -549,9 +637,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // This function has no security. It can be used to destroy // arbitrary builds the user would normally have no rights to // - if (!CheckThreatLevel(ThreatLevel.VeryHigh, "osSetRot")) return; + CheckThreatLevel(ThreatLevel.VeryHigh, "osSetRot"); - m_host.AddScriptLPS(1); if (World.Entities.ContainsKey(target)) { EntityBase entity; @@ -572,13 +659,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osSetDynamicTextureURL(string dynamicID, string contentType, string url, string extraParams, int timer) { - m_host.AddScriptLPS(1); + // This may be upgraded depending on the griefing or DOS + // potential, or guarded with a delay + // + CheckThreatLevel(ThreatLevel.VeryLow, "osSetDynamicTextureURL"); + if (dynamicID == String.Empty) { IDynamicTextureManager textureManager = World.RequestModuleInterface(); UUID createdTexture = textureManager.AddDynamicTextureURL(World.RegionInfo.RegionID, m_host.UUID, contentType, url, - extraParams, timer); + extraParams); return createdTexture.ToString(); } else @@ -592,13 +683,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osSetDynamicTextureURLBlend(string dynamicID, string contentType, string url, string extraParams, int timer, int alpha) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osSetDynamicTextureURLBlend"); + if (dynamicID == String.Empty) { IDynamicTextureManager textureManager = World.RequestModuleInterface(); UUID createdTexture = textureManager.AddDynamicTextureURL(World.RegionInfo.RegionID, m_host.UUID, contentType, url, - extraParams, timer, true, (byte) alpha); + extraParams, true, (byte) alpha); return createdTexture.ToString(); } else @@ -612,13 +704,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osSetDynamicTextureURLBlendFace(string dynamicID, string contentType, string url, string extraParams, bool blend, int disp, int timer, int alpha, int face) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osSetDynamicTextureURLBlendFace"); + if (dynamicID == String.Empty) { IDynamicTextureManager textureManager = World.RequestModuleInterface(); UUID createdTexture = textureManager.AddDynamicTextureURL(World.RegionInfo.RegionID, m_host.UUID, contentType, url, - extraParams, timer, blend, disp, (byte) alpha, face); + extraParams, blend, disp, (byte) alpha, face); return createdTexture.ToString(); } else @@ -632,7 +725,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osSetDynamicTextureData(string dynamicID, string contentType, string data, string extraParams, int timer) { - m_host.AddScriptLPS(1); + return osSetDynamicTextureDataFace(dynamicID, contentType, data, extraParams, timer, -1); + } + + public string osSetDynamicTextureDataFace(string dynamicID, string contentType, string data, string extraParams, + int timer, int face) + { + CheckThreatLevel(ThreatLevel.VeryLow, "osSetDynamicTextureData"); + if (dynamicID == String.Empty) { IDynamicTextureManager textureManager = World.RequestModuleInterface(); @@ -644,7 +744,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } UUID createdTexture = textureManager.AddDynamicTextureData(World.RegionInfo.RegionID, m_host.UUID, contentType, data, - extraParams, timer); + extraParams, false, 3, 255, face); + return createdTexture.ToString(); } } @@ -659,7 +760,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osSetDynamicTextureDataBlend(string dynamicID, string contentType, string data, string extraParams, int timer, int alpha) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osSetDynamicTextureDataBlend"); + if (dynamicID == String.Empty) { IDynamicTextureManager textureManager = World.RequestModuleInterface(); @@ -671,7 +773,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } UUID createdTexture = textureManager.AddDynamicTextureData(World.RegionInfo.RegionID, m_host.UUID, contentType, data, - extraParams, timer, true, (byte) alpha); + extraParams, true, (byte) alpha); return createdTexture.ToString(); } } @@ -686,7 +788,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osSetDynamicTextureDataBlendFace(string dynamicID, string contentType, string data, string extraParams, bool blend, int disp, int timer, int alpha, int face) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow , "osSetDynamicTextureDataBlendFace"); + if (dynamicID == String.Empty) { IDynamicTextureManager textureManager = World.RequestModuleInterface(); @@ -698,7 +801,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } UUID createdTexture = textureManager.AddDynamicTextureData(World.RegionInfo.RegionID, m_host.UUID, contentType, data, - extraParams, timer, blend, disp, (byte) alpha, face); + extraParams, blend, disp, (byte) alpha, face); return createdTexture.ToString(); } } @@ -712,9 +815,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public bool osConsoleCommand(string command) { - if (!CheckThreatLevel(ThreatLevel.Severe, "osConsoleCommand")) return false; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Severe, "osConsoleCommand"); // For safety, we add another permission check here, and don't rely only on the standard OSSL permissions if (World.Permissions.CanRunConsoleCommand(m_host.OwnerID)) @@ -728,123 +829,183 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osSetPrimFloatOnWater(int floatYN) { - if (!CheckThreatLevel(ThreatLevel.VeryLow, "osSetPrimFloatOnWater")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osSetPrimFloatOnWater"); m_host.ParentGroup.RootPart.SetFloatOnWater(floatYN); } + private bool checkAllowAgentTPbyLandOwner(UUID agentId, Vector3 pos) + { + UUID hostOwner = m_host.OwnerID; + + if(hostOwner == agentId) + return true; + + if (m_item.PermsGranter == agentId) + { + if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TELEPORT) != 0) + return true; + } + + ILandObject land = World.LandChannel.GetLandObject(pos); + if(land == null) + return true; + + LandData landdata = land.LandData; + if(landdata == null) + return true; + + if(landdata.OwnerID == hostOwner) + return true; + + EstateSettings es = World.RegionInfo.EstateSettings; + if(es != null && es.IsEstateManagerOrOwner(hostOwner)) + return true; + + if(!landdata.IsGroupOwned) + return false; + + UUID landGroup = landdata.GroupID; + if(landGroup == UUID.Zero) + return false; + + if(landGroup == m_host.GroupID) + return true; + + return false; + } + // Teleport functions public void osTeleportAgent(string agent, string regionName, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) { // High because there is no security check. High griefer potential // - if (!CheckThreatLevel(ThreatLevel.High, "osTeleportAgent")) return; + CheckThreatLevel(ThreatLevel.Severe, "osTeleportAgent"); - TeleportAgent(agent, regionName, position, lookat, false); + TeleportAgent(agent, regionName, position, lookat); } private void TeleportAgent(string agent, string regionName, - LSL_Types.Vector3 position, LSL_Types.Vector3 lookat, bool relaxRestrictions) + LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) { - m_host.AddScriptLPS(1); - UUID agentId = new UUID(); + if(String.IsNullOrEmpty(regionName)) + regionName = World.RegionInfo.RegionName; + + UUID agentId; if (UUID.TryParse(agent, out agentId)) { ScenePresence presence = World.GetScenePresence(agentId); - if (presence != null) + if (presence == null || presence.IsDeleted || presence.IsInTransit) + return; + + Vector3 pos = presence.AbsolutePosition; + if(!checkAllowAgentTPbyLandOwner(agentId, pos)) { - // For osTeleportAgent, agent must be over owners land to avoid abuse - // For osTeleportOwner, this restriction isn't necessary - - // commented out because its redundant and uneeded please remove eventually. - // if (relaxRestrictions || - // m_host.OwnerID - // == World.LandChannel.GetLandObject( - // presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID) - // { - - // We will launch the teleport on a new thread so that when the script threads are terminated - // before teleport in ScriptInstance.GetXMLState(), we don't end up aborting the one doing the teleporting. - Util.FireAndForget( - o => World.RequestTeleportLocation( - presence.ControllingClient, regionName, position, - lookat, (uint)TPFlags.ViaLocation), - null, "OSSL_Api.TeleportAgentByRegionCoords"); - // } + ScriptSleep(500); + return; + } + if(regionName == World.RegionInfo.RegionName) + { + // should be faster than going to threadpool + World.RequestTeleportLocation(presence.ControllingClient, regionName, position, + lookat, (uint)TPFlags.ViaLocation); + ScriptSleep(500); + } + else + { + // We will launch the teleport on a new thread so that when the script threads are terminated + // before teleport in ScriptInstance.GetXMLState(), we don't end up aborting the one doing the teleporting. + Util.FireAndForget( + o => World.RequestTeleportLocation( + presence.ControllingClient, regionName, position, + lookat, (uint)TPFlags.ViaLocation), + null, "OSSL_Api.TeleportAgentByRegionCoords"); + ScriptSleep(5000); } } } - public void osTeleportAgent(string agent, int regionX, int regionY, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) + public void osTeleportAgent(string agent, int regionGridX, int regionGridY, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) { // High because there is no security check. High griefer potential // - if (!CheckThreatLevel(ThreatLevel.High, "osTeleportAgent")) return; + CheckThreatLevel(ThreatLevel.Severe, "osTeleportAgent"); - TeleportAgent(agent, regionX, regionY, position, lookat, false); + TeleportAgent(agent, regionGridX, regionGridY, position, lookat); } - private void TeleportAgent(string agent, int regionX, int regionY, - LSL_Types.Vector3 position, LSL_Types.Vector3 lookat, bool relaxRestrictions) + private void TeleportAgent(string agent, int regionGridX, int regionGridY, + LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) { - // ulong regionHandle = Util.UIntsToLong(((uint)regionX * (uint)Constants.RegionSize), ((uint)regionY * (uint)Constants.RegionSize)); - ulong regionHandle = Util.RegionLocToHandle((uint)regionX, (uint)regionY); + ulong regionHandle = Util.RegionGridLocToHandle((uint)regionGridX, (uint)regionGridY); - m_host.AddScriptLPS(1); - UUID agentId = new UUID(); + UUID agentId; if (UUID.TryParse(agent, out agentId)) { ScenePresence presence = World.GetScenePresence(agentId); - if (presence != null) - { - // For osTeleportAgent, agent must be over owners land to avoid abuse - // For osTeleportOwner, this restriction isn't necessary - - // commented out because its redundant and uneeded please remove eventually. - // if (relaxRestrictions || - // m_host.OwnerID - // == World.LandChannel.GetLandObject( - // presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID) - // { - - // We will launch the teleport on a new thread so that when the script threads are terminated - // before teleport in ScriptInstance.GetXMLState(), we don't end up aborting the one doing the teleporting. - Util.FireAndForget( - o => World.RequestTeleportLocation( - presence.ControllingClient, regionHandle, - position, lookat, (uint)TPFlags.ViaLocation), - null, "OSSL_Api.TeleportAgentByRegionName"); - // } + if (presence == null || presence.IsDeleted || presence.IsInTransit) + return; + Vector3 pos = presence.AbsolutePosition; + if(!checkAllowAgentTPbyLandOwner(agentId, pos)) + { + ScriptSleep(500); + return; } + + Util.FireAndForget( + o => World.RequestTeleportLocation( + presence.ControllingClient, regionHandle, + position, lookat, (uint)TPFlags.ViaLocation), + null, "OSSL_Api.TeleportAgentByRegionName"); + + ScriptSleep(5000); } } public void osTeleportAgent(string agent, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) { - // High because there is no security check. High griefer potential - // - if (!CheckThreatLevel(ThreatLevel.High, "osTeleportAgent")) return; + UUID agentId; + if (UUID.TryParse(agent, out agentId)) + { + ScenePresence presence = World.GetScenePresence(agentId); + if (presence == null || presence.IsDeleted || presence.IsInTransit) + return; - osTeleportAgent(agent, World.RegionInfo.RegionName, position, lookat); + Vector3 pos = presence.AbsolutePosition; + if(!checkAllowAgentTPbyLandOwner(agentId, pos)) + { + ScriptSleep(500); + return; + } + + World.RequestTeleportLocation(presence.ControllingClient, World.RegionInfo.RegionName, position, + lookat, (uint)TPFlags.ViaLocation); + ScriptSleep(500); + } } public void osTeleportOwner(string regionName, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) { - TeleportAgent(m_host.OwnerID.ToString(), regionName, position, lookat, true); + // Threat level None because this is what can already be done with the World Map in the viewer + CheckThreatLevel(ThreatLevel.None, "osTeleportOwner"); + + TeleportAgent(m_host.OwnerID.ToString(), regionName, position, lookat); } - public void osTeleportOwner(LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) + public void osTeleportOwner(int regionGridX, int regionGridY, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) { - osTeleportOwner(World.RegionInfo.RegionName, position, lookat); + CheckThreatLevel(ThreatLevel.None, "osTeleportOwner"); + + TeleportAgent(m_host.OwnerID.ToString(), regionGridX, regionGridY, position, lookat); } - public void osTeleportOwner(int regionX, int regionY, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) + public void osTeleportOwner(LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) { - TeleportAgent(m_host.OwnerID.ToString(), regionX, regionY, position, lookat, true); + CheckThreatLevel(ThreatLevel.None, "osTeleportOwner"); + + osTeleportAgent(m_host.OwnerID.ToString(), position, lookat); } /// @@ -856,9 +1017,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public void osForceOtherSit(string avatar) { - if (!CheckThreatLevel(ThreatLevel.VeryHigh, "osForceOtherSit")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryHigh, "osForceOtherSit"); ForceSit(avatar, m_host.UUID); } @@ -871,9 +1030,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public void osForceOtherSit(string avatar, string target) { - if (!CheckThreatLevel(ThreatLevel.VeryHigh, "osForceOtherSit")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryHigh, "osForceOtherSit"); UUID targetID = new UUID(target); @@ -882,7 +1039,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void ForceSit(string avatar, UUID targetID) { - UUID agentID; + UUID agentID; if (!UUID.TryParse(avatar, out agentID)) return; @@ -900,21 +1057,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api part.SitTargetPosition); } - // Functions that get information from the agent itself. - // - // osGetAgentIP - this is used to determine the IP address of - //the client. This is needed to help configure other in world - //resources based on the IP address of the clients connected. - //I think High is a good risk level for this, as it is an - //information leak. - // Severe is even better coz privacy is important. + // Get a list of all the avatars/agents in the region + public LSL_List osGetAgents() + { + // threat level is None as we could get this information with an + // in-world script as well, just not as efficient + CheckThreatLevel(ThreatLevel.None, "osGetAgents"); + + LSL_List result = new LSL_List(); + World.ForEachRootScenePresence(delegate(ScenePresence sp) + { + result.Add(new LSL_String(sp.Name)); + }); + return result; + } + public string osGetAgentIP(string agent) { - if (!CheckThreatLevel(ThreatLevel.Severe, "osGetAgentIP")) return ""; + CheckThreatLevel(ThreatLevel.Severe, "osGetAgentIP"); + if(!(World.Permissions.IsGod(m_host.OwnerID))) // user god always needed + return ""; UUID avatarID = (UUID)agent; - m_host.AddScriptLPS(1); if (World.Entities.ContainsKey((UUID)agent) && World.Entities[avatarID] is ScenePresence) { ScenePresence target = (ScenePresence)World.Entities[avatarID]; @@ -925,61 +1090,48 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return ""; } - // Get a list of all the avatars/agents in the region - public LSL_List osGetAgents() - { - m_host.AddScriptLPS(1); - - LSL_List result = new LSL_List(); - World.ForEachRootScenePresence(delegate(ScenePresence sp) - { - result.Add(new LSL_String(sp.Name)); - }); - return result; - } - // Adam's super super custom animation functions public void osAvatarPlayAnimation(string avatar, string animation) { - if (!CheckThreatLevel(ThreatLevel.VeryHigh, "osAvatarPlayAnimation")) return; + CheckThreatLevel(ThreatLevel.VeryHigh, "osAvatarPlayAnimation"); AvatarPlayAnimation(avatar, animation); } private void AvatarPlayAnimation(string avatar, string animation) { - UUID avatarID = (UUID)avatar; + UUID avatarID; + if(!UUID.TryParse(avatar, out avatarID)) + return; - m_host.AddScriptLPS(1); - if (World.Entities.ContainsKey((UUID)avatar) && World.Entities[avatarID] is ScenePresence) + ScenePresence target = World.GetScenePresence(avatarID); + if (target == null) + return; + + UUID animID = UUID.Zero; + m_host.TaskInventory.LockItemsForRead(true); + foreach (KeyValuePair inv in m_host.TaskInventory) { - ScenePresence target = (ScenePresence)World.Entities[avatarID]; - if (target != null) + if (inv.Value.Type == (int)AssetType.Animation) { - UUID animID=UUID.Zero; - lock (m_host.TaskInventory) - { - foreach (KeyValuePair inv in m_host.TaskInventory) - { - if (inv.Value.Name == animation) - { - if (inv.Value.Type == (int)AssetType.Animation) - animID = inv.Value.AssetID; - continue; - } - } - } - if (animID == UUID.Zero) - target.Animator.AddAnimation(animation, m_host.UUID); - else - target.Animator.AddAnimation(animID, m_host.UUID); + if (inv.Value.Name == animation) + { + animID = inv.Value.AssetID; + break; + } } } + m_host.TaskInventory.LockItemsForRead(false); + + if (animID == UUID.Zero) + target.Animator.AddAnimation(animation, m_host.UUID); + else + target.Animator.AddAnimation(animID, m_host.UUID); } public void osAvatarStopAnimation(string avatar, string animation) { - if (!CheckThreatLevel(ThreatLevel.VeryHigh, "osAvatarStopAnimation")) return; + CheckThreatLevel(ThreatLevel.VeryHigh, "osAvatarStopAnimation"); AvatarStopAnimation(avatar, animation); } @@ -988,8 +1140,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { UUID avatarID = (UUID)avatar; - m_host.AddScriptLPS(1); - // FIXME: What we really want to do here is factor out the similar code in llStopAnimation() to a common // method (though see that doesn't do the is animation check, which is probably a bug) and have both // these functions call that common code. However, this does mean navigating the brain-dead requirement @@ -1010,6 +1160,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api animID = UUID.Zero; } + if (animID == UUID.Zero) target.Animator.RemoveAnimation(animation); else @@ -1019,58 +1170,106 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } //Texture draw functions + + public string osDrawResetTransform(string drawList) + { + CheckThreatLevel(); + + drawList += "ResetTransf;"; + return drawList; + } + + public string osDrawRotationTransform(string drawList, LSL_Float x) + { + CheckThreatLevel(); + + drawList += "RotTransf " + x + ";"; + return drawList; + } + + public string osDrawScaleTransform(string drawList, LSL_Float x, LSL_Float y) + { + CheckThreatLevel(); + + drawList += "ScaleTransf " + x + "," + y + ";"; + return drawList; + } + + public string osDrawTranslationTransform(string drawList, LSL_Float x, LSL_Float y) + { + CheckThreatLevel(); + + drawList += "TransTransf " + x + "," + y + ";"; + return drawList; + } + public string osMovePen(string drawList, int x, int y) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList += "MoveTo " + x + "," + y + ";"; return drawList; } public string osDrawLine(string drawList, int startX, int startY, int endX, int endY) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList += "MoveTo "+ startX+","+ startY +"; LineTo "+endX +","+endY +"; "; return drawList; } public string osDrawLine(string drawList, int endX, int endY) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList += "LineTo " + endX + "," + endY + "; "; return drawList; } public string osDrawText(string drawList, string text) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.None, "osDrawText"); + drawList += "Text " + text + "; "; return drawList; } public string osDrawEllipse(string drawList, int width, int height) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList += "Ellipse " + width + "," + height + "; "; return drawList; } + public string osDrawFilledEllipse(string drawList, int width, int height) + { + CheckThreatLevel(); + + drawList += "FillEllipse " + width + "," + height + "; "; + return drawList; + } + public string osDrawRectangle(string drawList, int width, int height) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList += "Rectangle " + width + "," + height + "; "; return drawList; } public string osDrawFilledRectangle(string drawList, int width, int height) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList += "FillRectangle " + width + "," + height + "; "; return drawList; } public string osDrawFilledPolygon(string drawList, LSL_List x, LSL_List y) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); if (x.Length != y.Length || x.Length < 3) { @@ -1087,7 +1286,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osDrawPolygon(string drawList, LSL_List x, LSL_List y) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); if (x.Length != y.Length || x.Length < 3) { @@ -1104,28 +1303,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osSetFontSize(string drawList, int fontSize) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList += "FontSize "+ fontSize +"; "; return drawList; } public string osSetFontName(string drawList, string fontName) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList += "FontName "+ fontName +"; "; return drawList; } public string osSetPenSize(string drawList, int penSize) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList += "PenSize " + penSize + "; "; return drawList; } public string osSetPenColor(string drawList, string color) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList += "PenColor " + color + "; "; return drawList; } @@ -1133,30 +1336,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // Deprecated public string osSetPenColour(string drawList, string colour) { + CheckThreatLevel(); OSSLDeprecated("osSetPenColour", "osSetPenColor"); - m_host.AddScriptLPS(1); drawList += "PenColour " + colour + "; "; return drawList; } public string osSetPenCap(string drawList, string direction, string type) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList += "PenCap " + direction + "," + type + "; "; return drawList; } public string osDrawImage(string drawList, int width, int height, string imageUrl) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList +="Image " +width + "," + height+ ","+ imageUrl +"; " ; return drawList; } public LSL_Vector osGetDrawStringSize(string contentType, string text, string fontName, int fontSize) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); LSL_Vector vec = new LSL_Vector(0,0,0); IDynamicTextureManager textureManager = World.RequestModuleInterface(); @@ -1178,17 +1383,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // It was probably added as a crutch or debugging aid, and // should be removed // - if (!CheckThreatLevel(ThreatLevel.High, "osSetStateEvents")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osSetStateEvents"); m_host.SetScriptEvents(m_item.ItemID, events); } public void osSetRegionWaterHeight(double height) { - if (!CheckThreatLevel(ThreatLevel.High, "osSetRegionWaterHeight")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osSetRegionWaterHeight"); World.EventManager.TriggerRequestChangeWaterHeight((float)height); } @@ -1201,9 +1403,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// The "Sun Hour" that is desired, 0...24, with 0 just after SunRise public void osSetRegionSunSettings(bool useEstateSun, bool sunFixed, double sunHour) { - if (!CheckThreatLevel(ThreatLevel.High, "osSetRegionSunSettings")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osSetRegionSunSettings"); while (sunHour > 24.0) sunHour -= 24.0; @@ -1226,9 +1426,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// The "Sun Hour" that is desired, 0...24, with 0 just after SunRise public void osSetEstateSunSettings(bool sunFixed, double sunHour) { - if (!CheckThreatLevel(ThreatLevel.High, "osSetEstateSunSettings")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osSetEstateSunSettings"); while (sunHour > 24.0) sunHour -= 24.0; @@ -1250,7 +1448,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public double osGetCurrentSunHour() { - m_host.AddScriptLPS(1); + CheckThreatLevel(); // Must adjust for the fact that Region Sun Settings are still LL offset double sunHour = World.RegionInfo.RegionSettings.SunPosition - 6; @@ -1267,19 +1465,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public double osSunGetParam(string param) { + CheckThreatLevel(ThreatLevel.None, "osSunGetParam"); OSSLDeprecated("osSunGetParam", "osGetSunParam"); return GetSunParam(param); } public double osGetSunParam(string param) { + CheckThreatLevel(); return GetSunParam(param); } private double GetSunParam(string param) { - m_host.AddScriptLPS(1); - double value = 0.0; ISunModule module = World.RequestModuleInterface(); @@ -1293,21 +1491,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osSunSetParam(string param, double value) { -//// if (!CheckThreatLevel(ThreatLevel.None, "osSunSetParam")) return; + CheckThreatLevel(ThreatLevel.None, "osSunSetParam"); OSSLDeprecated("osSunSetParam", "osSetSunParam"); SetSunParam(param, value); } public void osSetSunParam(string param, double value) { -//// if (!CheckThreatLevel(ThreatLevel.None, "osSetSunParam")) return; + CheckThreatLevel(ThreatLevel.None, "osSetSunParam"); SetSunParam(param, value); } private void SetSunParam(string param, double value) { - m_host.AddScriptLPS(1); - ISunModule module = World.RequestModuleInterface(); if (module != null) { @@ -1317,7 +1513,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osWindActiveModelPluginName() { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.None, "osWindActiveModelPluginName"); IWindModule module = World.RequestModuleInterface(); if (module != null) @@ -1330,8 +1526,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osSetWindParam(string plugin, string param, LSL_Float value) { - if (!CheckThreatLevel(ThreatLevel.VeryLow, "osSetWindParam")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osSetWindParam"); IWindModule module = World.RequestModuleInterface(); if (module != null) @@ -1346,7 +1541,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Float osGetWindParam(string plugin, string param) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osGetWindParam"); IWindModule module = World.RequestModuleInterface(); if (module != null) @@ -1360,8 +1555,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // Routines for creating and managing parcels programmatically public void osParcelJoin(LSL_Vector pos1, LSL_Vector pos2) { - if (!CheckThreatLevel(ThreatLevel.High, "osParcelJoin")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osParcelJoin"); int startx = (int)(pos1.x < pos2.x ? pos1.x : pos2.x); int starty = (int)(pos1.y < pos2.y ? pos1.y : pos2.y); @@ -1373,8 +1567,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osParcelSubdivide(LSL_Vector pos1, LSL_Vector pos2) { - if (!CheckThreatLevel(ThreatLevel.High, "osParcelSubdivide")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osParcelSubdivide"); int startx = (int)(pos1.x < pos2.x ? pos1.x : pos2.x); int starty = (int)(pos1.y < pos2.y ? pos1.y : pos2.y); @@ -1387,7 +1580,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osParcelSetDetails(LSL_Vector pos, LSL_List rules) { const string functionName = "osParcelSetDetails"; - if (!CheckThreatLevel(ThreatLevel.High, functionName)) return; + CheckThreatLevel(ThreatLevel.High, functionName); OSSLDeprecated(functionName, "osSetParcelDetails"); SetParcelDetails(pos, rules, functionName); } @@ -1395,14 +1588,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osSetParcelDetails(LSL_Vector pos, LSL_List rules) { const string functionName = "osSetParcelDetails"; - if (!CheckThreatLevel(ThreatLevel.High, functionName)) return; + CheckThreatLevel(ThreatLevel.High, functionName); SetParcelDetails(pos, rules, functionName); } private void SetParcelDetails(LSL_Vector pos, LSL_List rules, string functionName) { - m_host.AddScriptLPS(1); - // Get a reference to the land data and make sure the owner of the script // can modify it @@ -1413,15 +1604,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; } - if (!World.Permissions.CanEditParcelProperties(m_host.OwnerID, startLandObject, GroupPowers.LandOptions)) + if (!World.Permissions.CanEditParcelProperties(m_host.OwnerID, startLandObject, GroupPowers.LandOptions, false)) { - OSSLShoutError("You do not have permission to modify the parcel"); + OSSLShoutError("script owner does not have permission to modify the parcel"); return; } // Create a new land data object we can modify LandData newLand = startLandObject.LandData.Copy(); UUID uuid; + EstateSettings es = World.RegionInfo.EstateSettings; + + bool changed = false; + bool changedSeeAvs = false; + bool changedoverlay = false; + bool changedneedupdate = false; // Process the rules, not sure what the impact would be of changing owner or group for (int idx = 0; idx < rules.Length;) @@ -1431,35 +1628,151 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api switch (code) { case ScriptBaseClass.PARCEL_DETAILS_NAME: - newLand.Name = arg; + if(newLand.Name != arg) + { + newLand.Name = arg; + changed = true; + } break; case ScriptBaseClass.PARCEL_DETAILS_DESC: - newLand.Description = arg; + if(newLand.Description != arg) + { + newLand.Description = arg; + changed = true; + } break; case ScriptBaseClass.PARCEL_DETAILS_OWNER: - if (!CheckThreatLevel(ThreatLevel.VeryHigh, functionName)) return; - if (UUID.TryParse(arg, out uuid)) - newLand.OwnerID = uuid; + if(es != null && !es.IsEstateManagerOrOwner(m_host.OwnerID)) + { + OSSLError("script owner does not have permission to modify the parcel owner"); + } + else + { + if (UUID.TryParse(arg, out uuid)) + { + if(newLand.OwnerID != uuid) + { + changed = true; + newLand.OwnerID = uuid; + newLand.GroupID = UUID.Zero; + } + } + } break; case ScriptBaseClass.PARCEL_DETAILS_GROUP: - if (!CheckThreatLevel(ThreatLevel.VeryHigh, functionName)) return; - if (UUID.TryParse(arg, out uuid)) - newLand.GroupID = uuid; + if(m_host.OwnerID == newLand.OwnerID || es == null || es.IsEstateManagerOrOwner(m_host.OwnerID)) + { + if (UUID.TryParse(arg, out uuid)) + { + if(newLand.GroupID != uuid) + { + if(uuid == UUID.Zero) + { + changed = true; + newLand.GroupID = uuid; + } + else + { + IGroupsModule groupsModule = m_ScriptEngine.World.RequestModuleInterface(); + GroupMembershipData member = null; + if (groupsModule != null) + member = groupsModule.GetMembershipData(uuid, newLand.OwnerID); + if (member == null) + OSSLError(string.Format("land owner is not member of the new group for parcel")); + else + { + changed = true; + newLand.GroupID = uuid; + } + } + } + } + } + else + { + OSSLError("script owner does not have permission to modify the parcel group"); + } break; case ScriptBaseClass.PARCEL_DETAILS_CLAIMDATE: - if (!CheckThreatLevel(ThreatLevel.VeryHigh, functionName)) return; - newLand.ClaimDate = Convert.ToInt32(arg); - if (newLand.ClaimDate == 0) - newLand.ClaimDate = Util.UnixTimeSinceEpoch(); + if(es != null && !es.IsEstateManagerOrOwner(m_host.OwnerID)) + { + OSSLError("script owner does not have permission to modify the parcel CLAIM DATE"); + } + else + { + int date = Convert.ToInt32(arg); + if (date == 0) + date = Util.UnixTimeSinceEpoch(); + if(newLand.ClaimDate != date) + { + changed = true; + newLand.ClaimDate = date; + } + } + break; + + case ScriptBaseClass.PARCEL_DETAILS_SEE_AVATARS: + bool newavs = (Convert.ToInt32(arg) != 0); + if(newLand.SeeAVs != newavs) + { + changed = true; + changedSeeAvs = true; + changedoverlay = true; + changedneedupdate = true; + newLand.SeeAVs = newavs; + } + break; + + case ScriptBaseClass.PARCEL_DETAILS_ANY_AVATAR_SOUNDS: + bool newavsounds = (Convert.ToInt32(arg) != 0); + if(newLand.AnyAVSounds != newavsounds) + { + changed = true; + newLand.AnyAVSounds = newavsounds; + } + break; + + case ScriptBaseClass.PARCEL_DETAILS_GROUP_SOUNDS: + bool newgrpsounds = (Convert.ToInt32(arg) != 0); + if(newLand.GroupAVSounds != newgrpsounds) + { + changed = true; + newLand.GroupAVSounds = newgrpsounds; + } break; - } - } + } + } + if(changed) + { + World.LandChannel.UpdateLandObject(newLand.LocalID, newLand); + + if(changedneedupdate) + { + UUID parcelID= newLand.GlobalID; + World.ForEachRootScenePresence(delegate (ScenePresence avatar) + { + if (avatar == null || avatar.IsDeleted || avatar.IsInTransit) + return; + + if(changedSeeAvs && avatar.currentParcelUUID == parcelID ) + avatar.currentParcelUUID = parcelID; // force parcel flags review + + if(avatar.ControllingClient == null) + return; + + // this will be needed for some things like damage etc +// if(avatar.currentParcelUUID == parcelID) +// startLandObject.SendLandUpdateToClient(avatar.ControllingClient); - World.LandChannel.UpdateLandObject(newLand.LocalID,newLand); + if(changedoverlay && !avatar.IsNPC) + World.LandChannel.SendParcelsOverlay(avatar.ControllingClient); + }); + } + } } public double osList2Double(LSL_Types.list src, int index) @@ -1469,7 +1782,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // is not allowed to contain any. // This really should be removed. // - m_host.AddScriptLPS(1); + CheckThreatLevel(); + if (index < 0) { index = src.Length + index; @@ -1485,9 +1799,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { // What actually is the difference to the LL function? // - if (!CheckThreatLevel(ThreatLevel.VeryLow, "osSetParcelMediaURL")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osSetParcelMediaURL"); ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); @@ -1501,9 +1813,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { // What actually is the difference to the LL function? // - if (!CheckThreatLevel(ThreatLevel.VeryLow, "osSetParcelSIPAddress")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osSetParcelSIPAddress"); ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); @@ -1529,9 +1839,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // that trigger engine-specific failures. // Besides, public grid users aren't supposed to know. // - // On the other hand, what other script engines are there? - // - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osGetScriptEngineName"); int scriptEngineNameIndex = 0; @@ -1557,7 +1865,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer osCheckODE() { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + LSL_Integer ret = 0; // false if (m_ScriptEngine.World.PhysicsScene != null) { @@ -1580,22 +1889,46 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // about the physics engine, this function returns an empty string if // the user does not have permission to see it. This as opposed to // throwing an exception. + m_host.AddScriptLPS(1); string ret = String.Empty; + if (String.IsNullOrEmpty(CheckThreatLevelTest(ThreatLevel.High, "osGetPhysicsEngineType"))) + { + if (m_ScriptEngine.World.PhysicsScene != null) + { + ret = m_ScriptEngine.World.PhysicsScene.EngineType; + // An old physics engine might have an uninitialized engine type + if (ret == null) + ret = "unknown"; + } + } + + return ret; + } + + public string osGetPhysicsEngineName() + { + CheckThreatLevel(); + + string ret = "NoEngine"; if (m_ScriptEngine.World.PhysicsScene != null) { - ret = m_ScriptEngine.World.PhysicsScene.EngineType; + ret = m_ScriptEngine.World.PhysicsScene.EngineName; // An old physics engine might have an uninitialized engine type if (ret == null) - ret = "unknown"; - } - + ret = "UnknownEngine"; + } return ret; } public string osGetSimulatorVersion() { - m_host.AddScriptLPS(1); + // High because it can be used to target attacks to known weaknesses + // This would allow a new class of griefer scripts that don't even + // require their user to know what they are doing (see script + // kiddie) + // + CheckThreatLevel(ThreatLevel.High,"osGetSimulatorVersion"); return m_ScriptEngine.World.GetSimulatorVersion(); } @@ -1639,7 +1972,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public Object osParseJSONNew(string JSON) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.None, "osParseJSONNew"); try { @@ -1648,14 +1981,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } catch(Exception e) { - OSSLError("osParseJSONNew: Problems decoding JSON string " + JSON + " : " + e.Message); + OSSLError("osParseJSONNew: Problems decoding JSON string " + JSON + " : " + e.Message) ; return null; } } public Hashtable osParseJSON(string JSON) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.None, "osParseJSON"); Object decoded = osParseJSONNew(JSON); @@ -1686,7 +2019,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public void osMessageObject(LSL_Key objectUUID, string message) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Low, "osMessageObject"); UUID objUUID; if (!UUID.TryParse(objectUUID, out objUUID)) // prior to patching, a thrown exception regarding invalid GUID format would be shouted instead. @@ -1715,6 +2048,54 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api "dataserver", resobj, new DetectParams[0])); } + + /// + /// Similar to llDie but given an object UUID + /// + /// + + public void osDie(LSL_Key objectUUID) + { +// CheckThreatLevel(ThreatLevel.VeryHigh, "osDie"); + // if this is restricted to objects rezzed by this host level can be reduced + + CheckThreatLevel(ThreatLevel.Low, "osDie"); + + UUID objUUID; + if (!UUID.TryParse(objectUUID, out objUUID)) + { + OSSLShoutError("osDie() cannot delete objects with invalid UUIDs"); + return; + } + + // harakiri check + if(objUUID == UUID.Zero) + { + if (!m_host.ParentGroup.IsAttachment) + throw new SelfDeleteException(); + return; + } + + SceneObjectGroup sceneOG = World.GetSceneObjectGroup(objUUID); + + if (sceneOG == null || sceneOG.IsDeleted) + return; + + if(sceneOG.IsAttachment) + return; + + if (sceneOG.OwnerID != m_host.OwnerID) + return; + + // harakiri check + if(sceneOG.UUID == m_host.ParentGroup.UUID) + throw new SelfDeleteException(); + + // restrict to objects rezzed by host + if(sceneOG.RezzerID == m_host.ParentGroup.UUID) + World.DeleteSceneObject(sceneOG, false); + } + /// /// Write a notecard directly to the prim's inventory. /// @@ -1727,7 +2108,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// The contents of the notecard. public void osMakeNotecard(string notecardName, LSL_Types.list contents) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osMakeNotecard"); StringBuilder notecardData = new StringBuilder(); @@ -1778,8 +2159,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api taskItem.ResetIDs(m_host.UUID); taskItem.ParentID = m_host.UUID; taskItem.CreationDate = (uint)Util.UnixTimeSinceEpoch(); - taskItem.Name = asset.Name; - taskItem.Description = asset.Description; + taskItem.Name = name; + taskItem.Description = description; taskItem.Type = (int)AssetType.Notecard; taskItem.InvType = (int)InventoryType.Notecard; taskItem.OwnerID = m_host.OwnerID; @@ -1799,6 +2180,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.Inventory.AddInventoryItemExclusive(taskItem, false); else m_host.Inventory.AddInventoryItem(taskItem, false); + m_host.ParentGroup.InvalidateDeepEffectivePerms(); return taskItem; } @@ -1843,15 +2225,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { UUID assetID = UUID.Zero; - if (!UUID.TryParse(notecardNameOrUuid, out assetID)) + bool notecardNameIsUUID = UUID.TryParse(notecardNameOrUuid, out assetID); + + if (!notecardNameIsUUID) { - foreach (TaskInventoryItem item in m_host.TaskInventory.Values) - { - if (item.Type == 7 && item.Name == notecardNameOrUuid) - { - assetID = item.AssetID; - } - } + assetID = SearchTaskInventoryForAssetId(notecardNameOrUuid); } if (assetID == UUID.Zero) @@ -1862,13 +2240,43 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api AssetBase a = World.AssetService.Get(assetID.ToString()); if (a == null) - return UUID.Zero; + { + // Whoops, it's still possible here that the notecard name was properly + // formatted like a UUID but isn't an asset UUID so lets look it up by name after all + assetID = SearchTaskInventoryForAssetId(notecardNameOrUuid); + if (assetID == UUID.Zero) + return UUID.Zero; + + if (!NotecardCache.IsCached(assetID)) + { + a = World.AssetService.Get(assetID.ToString()); + + if (a == null) + { + return UUID.Zero; + } + } + } NotecardCache.Cache(assetID, a.Data); }; return assetID; } + protected UUID SearchTaskInventoryForAssetId(string name) + { + UUID assetId = UUID.Zero; + m_host.TaskInventory.LockItemsForRead(true); + foreach (TaskInventoryItem item in m_host.TaskInventory.Values) + { + if (item.Type == 7 && item.Name == name) + { + assetId = item.AssetID; + } + } + m_host.TaskInventory.LockItemsForRead(false); + return assetId; + } /// /// Directly get an entire notecard at once. @@ -1885,7 +2293,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// Notecard line public string osGetNotecardLine(string name, int line) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryHigh, "osGetNotecardLine"); UUID assetID = CacheNotecard(name); @@ -1912,7 +2320,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// Notecard text public string osGetNotecard(string name) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryHigh, "osGetNotecard"); string text = LoadNotecard(name); @@ -1941,7 +2349,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public int osGetNumberOfNotecardLines(string name) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryHigh, "osGetNumberOfNotecardLines"); UUID assetID = CacheNotecard(name); @@ -1956,8 +2364,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osAvatarName2Key(string firstname, string lastname) { - if (!CheckThreatLevel(ThreatLevel.Low, "osAvatarName2Key")) return string.Empty; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Low, "osAvatarName2Key"); IUserManagement userManager = World.RequestModuleInterface(); if (userManager == null) @@ -2008,7 +2415,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osKey2Name(string id) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Low, "osKey2Name"); UUID key = new UUID(); @@ -2117,8 +2524,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public string osGetGridNick() { -//// if (!CheckThreatLevel(ThreatLevel.None, "osGetGridNick")) return ""; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osGetGridNick"); string nick = String.Empty; IConfigSource config = m_ScriptEngine.ConfigSource; @@ -2134,8 +2540,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osGetGridName() { -//// if (!CheckThreatLevel(ThreatLevel.None, "osGetGridName")) return ""; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osGetGridName"); string name = String.Empty; IConfigSource config = m_ScriptEngine.ConfigSource; @@ -2151,8 +2556,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osGetGridLoginURI() { - if (!CheckThreatLevel(ThreatLevel.Moderate, "osGetGridLoginURI")) return ""; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osGetGridLoginURI"); string loginURI = String.Empty; IConfigSource config = m_ScriptEngine.ConfigSource; @@ -2168,11 +2572,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osGetGridHomeURI() { - if (!CheckThreatLevel(ThreatLevel.Moderate, "osGetGridHomeURI")) return ""; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osGetGridHomeURI"); IConfigSource config = m_ScriptEngine.ConfigSource; - string HomeURI = Util.GetConfigVarFromSections(config, "HomeURI", + string HomeURI = Util.GetConfigVarFromSections(config, "HomeURI", new string[] { "Startup", "Hypergrid" }, String.Empty); if (!string.IsNullOrEmpty(HomeURI)) @@ -2190,8 +2593,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osGetGridGatekeeperURI() { - if (!CheckThreatLevel(ThreatLevel.Moderate, "osGetGridGatekeeperURI")) return ""; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osGetGridGatekeeperURI"); IConfigSource config = m_ScriptEngine.ConfigSource; string gatekeeperURI = Util.GetConfigVarFromSections(config, "GatekeeperURI", @@ -2209,8 +2611,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osGetGridCustom(string key) { - if (!CheckThreatLevel(ThreatLevel.Moderate, "osGetGridCustom")) return String.Empty; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osGetGridCustom"); string retval = String.Empty; IConfigSource config = m_ScriptEngine.ConfigSource; @@ -2226,8 +2627,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osGetAvatarHomeURI(string uuid) { - if (!CheckThreatLevel(ThreatLevel.Moderate, "osGetAvatarHomeURI")) return ""; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Low, "osGetAvatarHomeURI"); IUserManagement userManager = m_ScriptEngine.World.RequestModuleInterface(); string returnValue = ""; @@ -2259,14 +2659,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_String osFormatString(string str, LSL_List strings) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osFormatString"); return String.Format(str, strings.Data); } public LSL_List osMatchString(string src, string pattern, int start) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osMatchString"); LSL_List result = new LSL_List(); @@ -2307,7 +2707,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_String osReplaceString(string src, string pattern, string replace, int count, int start) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osReplaceString"); // Normalize indices (if negative). // After normlaization they may still be @@ -2331,24 +2731,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osLoadedCreationDate() { - if (!CheckThreatLevel(ThreatLevel.Low, "osLoadedCreationDate")) return ""; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Low, "osLoadedCreationDate"); return World.RegionInfo.RegionSettings.LoadedCreationDate; } public string osLoadedCreationTime() { - if (!CheckThreatLevel(ThreatLevel.Low, "osLoadedCreationTime")) return ""; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Low, "osLoadedCreationTime"); return World.RegionInfo.RegionSettings.LoadedCreationTime; } public string osLoadedCreationID() { - if (!CheckThreatLevel(ThreatLevel.Low, "osLoadedCreationID")) return ""; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Low, "osLoadedCreationID"); return World.RegionInfo.RegionSettings.LoadedCreationID; } @@ -2368,8 +2765,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public LSL_List osGetLinkPrimitiveParams(int linknumber, LSL_List rules) { - if (!CheckThreatLevel(ThreatLevel.High, "osGetLinkPrimitiveParams")) return new LSL_List(); - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osGetLinkPrimitiveParams"); + InitLSL(); // One needs to cast m_LSL_Api because we're using functions not // on the ILSL_Api interface. @@ -2396,9 +2793,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osForceCreateLink(string target, int parent) { - if (!CheckThreatLevel(ThreatLevel.VeryLow, "osForceCreateLink")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osForceCreateLink"); InitLSL(); ((LSL_Api)m_LSL_Api).CreateLink(target, parent); @@ -2406,9 +2801,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osForceBreakLink(int linknum) { - if (!CheckThreatLevel(ThreatLevel.VeryLow, "osForceBreakLink")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osForceBreakLink"); InitLSL(); ((LSL_Api)m_LSL_Api).BreakLink(linknum); @@ -2416,9 +2809,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osForceBreakAllLinks() { - if (!CheckThreatLevel(ThreatLevel.VeryLow, "osForceBreakAllLinks")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osForceBreakAllLinks"); InitLSL(); ((LSL_Api)m_LSL_Api).BreakAllLinks(); @@ -2426,7 +2817,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer osIsNpc(LSL_Key npc) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); INPCModule module = World.RequestModuleInterface(); if (module != null) @@ -2442,31 +2833,99 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Key osNpcCreate(string firstname, string lastname, LSL_Vector position, string notecard) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcCreate")) return new LSL_Key(ScriptBaseClass.NULL_KEY); - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcCreate"); + + // have to get the npc module also here to set the default Not Owned + INPCModule module = World.RequestModuleInterface(); + if(module == null) + return new LSL_Key(UUID.Zero.ToString()); + + bool owned = (module.NPCOptionFlags & NPCOptionsFlags.AllowNotOwned) == 0; - return NpcCreate(firstname, lastname, position, notecard, false, false); + return NpcCreate(firstname, lastname, position, notecard, owned, false, false); } public LSL_Key osNpcCreate(string firstname, string lastname, LSL_Vector position, string notecard, int options) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcCreate")) return new LSL_Key(ScriptBaseClass.NULL_KEY); - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcCreate"); return NpcCreate( firstname, lastname, position, notecard, (options & ScriptBaseClass.OS_NPC_NOT_OWNED) == 0, - (options & ScriptBaseClass.OS_NPC_SENSE_AS_AGENT) != 0); + (options & ScriptBaseClass.OS_NPC_SENSE_AS_AGENT) != 0, + (options & ScriptBaseClass.OS_NPC_OBJECT_GROUP) != 0); } private LSL_Key NpcCreate( - string firstname, string lastname, LSL_Vector position, string notecard, bool owned, bool senseAsAgent) + string firstname, string lastname, LSL_Vector position, string notecard, bool owned, bool senseAsAgent, bool hostGroupID) { + if (!World.Permissions.CanRezObject(1, m_host.OwnerID, new Vector3((float)position.x, (float)position.y, (float)position.z))) + { + OSSLError("no permission to rez NPC at requested location"); + return new LSL_Key(UUID.Zero.ToString()); + } + INPCModule module = World.RequestModuleInterface(); - if (module != null) + if(module == null) + { + OSSLError("NPC module not enabled"); + return new LSL_Key(UUID.Zero.ToString()); + } + + string groupTitle = String.Empty; + UUID groupID = UUID.Zero; + + AvatarAppearance appearance = null; + + // check creation options + NPCOptionsFlags createFlags = module.NPCOptionFlags; + + if((createFlags & NPCOptionsFlags.AllowNotOwned) == 0 && !owned) + { + OSSLError("Not owned NPCs disabled"); + owned = true; // we should get here... + } + + if((createFlags & NPCOptionsFlags.AllowSenseAsAvatar) == 0 && senseAsAgent) { - AvatarAppearance appearance = null; + OSSLError("NPC allow sense as Avatar disabled"); + senseAsAgent = false; + } + + if(hostGroupID && m_host.GroupID != UUID.Zero) + { + IGroupsModule groupsModule = m_ScriptEngine.World.RequestModuleInterface(); + if (groupsModule != null) + { + GroupMembershipData member = groupsModule.GetMembershipData(m_host.GroupID, m_host.OwnerID); + if (member == null) + { + OSSLError(string.Format("osNpcCreate: the object owner is not member of the object group")); + return new LSL_Key(UUID.Zero.ToString()); + } + + groupID = m_host.GroupID; + + if((createFlags & NPCOptionsFlags.NoNPCGroup) != 0) + { + GroupRecord grprec = groupsModule.GetGroupRecord(m_host.GroupID); + if(grprec != null && grprec.GroupName != "") + groupTitle = grprec.GroupName; + } + } + } + + if((createFlags & NPCOptionsFlags.NoNPCGroup) == 0) + { + if (firstname != String.Empty || lastname != String.Empty) + { + if (firstname != "Shown outfit:") + groupTitle = "- NPC -"; + } + } + if((createFlags & NPCOptionsFlags.AllowCloneOtherAvatars) != 0) + { UUID id; if (UUID.TryParse(notecard, out id)) { @@ -2474,38 +2933,52 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (clonePresence != null) appearance = clonePresence.Appearance; } + } - if (appearance == null) - { - string appearanceSerialized = LoadNotecard(notecard); + if (appearance == null) + { + string appearanceSerialized = LoadNotecard(notecard); - if (appearanceSerialized != null) + if (appearanceSerialized != null) + { + try { OSDMap appearanceOsd = (OSDMap)OSDParser.DeserializeLLSDXml(appearanceSerialized); appearance = new AvatarAppearance(); appearance.Unpack(appearanceOsd); } - else + catch { - OSSLError(string.Format("osNpcCreate: Notecard reference '{0}' not found.", notecard)); + OSSLError(string.Format("osNpcCreate: Error processing notcard '{0}'", notecard)); + return new LSL_Key(UUID.Zero.ToString()); } } + else + { + OSSLError(string.Format("osNpcCreate: Notecard reference '{0}' not found.", notecard)); + } + } - UUID ownerID = UUID.Zero; - if (owned) - ownerID = m_host.OwnerID; - UUID x = module.CreateNPC(firstname, - lastname, - position, - ownerID, - senseAsAgent, - World, - appearance); + UUID ownerID = UUID.Zero; + if (owned) + ownerID = m_host.OwnerID; + UUID x = module.CreateNPC(firstname, + lastname, + position, + UUID.Random(), + ownerID, + groupTitle, + groupID, + senseAsAgent, + World, + appearance); - return new LSL_Key(x.ToString()); + ScenePresence sp; + if (World.TryGetScenePresence(x, out sp)) + { + sp.SendAvatarDataToAllAgents(); } - - return new LSL_Key(UUID.Zero.ToString()); + return new LSL_Key(x.ToString()); } /// @@ -2516,8 +2989,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// The asset ID of the notecard saved. public LSL_Key osNpcSaveAppearance(LSL_Key npc, string notecard) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcSaveAppearance")) return new LSL_Key(ScriptBaseClass.NULL_KEY); - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcSaveAppearance"); INPCModule npcModule = World.RequestModuleInterface(); @@ -2538,8 +3010,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcLoadAppearance(LSL_Key npc, string notecard) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcLoadAppearance")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcLoadAppearance"); INPCModule npcModule = World.RequestModuleInterface(); @@ -2570,7 +3041,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Key osNpcGetOwner(LSL_Key npc) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.None, "osNpcGetOwner"); INPCModule npcModule = World.RequestModuleInterface(); if (npcModule != null) @@ -2591,7 +3062,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector osNpcGetPos(LSL_Key npc) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcGetPos"); INPCModule npcModule = World.RequestModuleInterface(); if (npcModule != null) @@ -2614,8 +3085,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcMoveTo(LSL_Key npc, LSL_Vector pos) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcMoveTo")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcMoveTo"); INPCModule module = World.RequestModuleInterface(); if (module != null) @@ -2633,8 +3103,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcMoveToTarget(LSL_Key npc, LSL_Vector target, int options) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcMoveToTarget")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcMoveToTarget"); INPCModule module = World.RequestModuleInterface(); if (module != null) @@ -2658,7 +3127,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Rotation osNpcGetRot(LSL_Key npc) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcGetRot"); INPCModule npcModule = World.RequestModuleInterface(); if (npcModule != null) @@ -2681,8 +3150,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcSetRot(LSL_Key npc, LSL_Rotation rotation) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcSetRot")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcSetRot"); INPCModule npcModule = World.RequestModuleInterface(); if (npcModule != null) @@ -2703,8 +3171,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcStopMoveToTarget(LSL_Key npc) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcStopMoveToTarget")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcStopMoveToTarget"); INPCModule module = World.RequestModuleInterface(); if (module != null) @@ -2718,15 +3185,60 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } - public void osNpcSay(LSL_Key npc, string message) - { - osNpcSay(npc, 0, message); - } - - public void osNpcSay(LSL_Key npc, int channel, string message) + public void osNpcSetProfileAbout(LSL_Key npc, string about) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcSay")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Low, "osNpcSetProfileAbout"); + + INPCModule module = World.RequestModuleInterface(); + if (module != null) + { + UUID npcId = new UUID(npc.m_string); + + if (!module.CheckPermissions(npcId, m_host.OwnerID)) + return; + + ScenePresence sp = World.GetScenePresence(npcId); + if (sp != null) + ((INPC)(sp.ControllingClient)).profileAbout = about; + } + } + + public void osNpcSetProfileImage(LSL_Key npc, string image) + { + CheckThreatLevel(ThreatLevel.Low, "osNpcSetProfileImage"); + + INPCModule module = World.RequestModuleInterface(); + if (module != null) + { + UUID npcId = new UUID(npc.m_string); + + if (!module.CheckPermissions(npcId, m_host.OwnerID)) + return; + + UUID ImageID = new UUID(); + + ImageID = ScriptUtils.GetAssetIdFromItemName(m_host, image, (int)AssetType.Texture); + + if (ImageID == null || ImageID == UUID.Zero) + { + if (!UUID.TryParse(image, out ImageID)) + return; + } + + ScenePresence sp = World.GetScenePresence(npcId); + if (sp != null) + ((INPC)(sp.ControllingClient)).profileImage = ImageID; + } + } + + public void osNpcSay(LSL_Key npc, string message) + { + osNpcSay(npc, 0, message); + } + + public void osNpcSay(LSL_Key npc, int channel, string message) + { + CheckThreatLevel(ThreatLevel.High, "osNpcSay"); INPCModule module = World.RequestModuleInterface(); if (module != null) @@ -2742,8 +3254,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcShout(LSL_Key npc, int channel, string message) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcShout")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcShout"); INPCModule module = World.RequestModuleInterface(); if (module != null) @@ -2759,8 +3270,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcSit(LSL_Key npc, LSL_Key target, int options) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcSit")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcSit"); INPCModule module = World.RequestModuleInterface(); if (module != null) @@ -2776,8 +3286,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcStand(LSL_Key npc) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcStand")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcStand"); INPCModule module = World.RequestModuleInterface(); if (module != null) @@ -2793,25 +3302,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcRemove(LSL_Key npc) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcRemove")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcRemove"); - INPCModule module = World.RequestModuleInterface(); - if (module != null) + try { - UUID npcId = new UUID(npc.m_string); + INPCModule module = World.RequestModuleInterface(); + if (module != null) + { + UUID npcId = new UUID(npc.m_string); - if (!module.CheckPermissions(npcId, m_host.OwnerID)) - return; + if (!module.CheckPermissions(npcId, m_host.OwnerID)) + return; - module.DeleteNPC(npcId, World); + module.DeleteNPC(npcId, World); + } } + catch { } } public void osNpcPlayAnimation(LSL_Key npc, string animation) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcPlayAnimation")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcPlayAnimation"); INPCModule module = World.RequestModuleInterface(); if (module != null) @@ -2825,8 +3336,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcStopAnimation(LSL_Key npc, string animation) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcStopAnimation")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcStopAnimation"); INPCModule module = World.RequestModuleInterface(); if (module != null) @@ -2840,8 +3350,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcWhisper(LSL_Key npc, int channel, string message) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcWhisper")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcWhisper"); INPCModule module = World.RequestModuleInterface(); if (module != null) @@ -2857,8 +3366,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcTouch(LSL_Key npcLSL_Key, LSL_Key object_key, LSL_Integer link_num) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcTouch")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcTouch"); INPCModule module = World.RequestModuleInterface(); int linkNum = link_num.value; @@ -2902,16 +3410,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// The asset ID of the notecard saved. public LSL_Key osOwnerSaveAppearance(string notecard) { - if (!CheckThreatLevel(ThreatLevel.Moderate, "osOwnerSaveAppearance")) return new LSL_Key(ScriptBaseClass.NULL_KEY); - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osOwnerSaveAppearance"); return SaveAppearanceToNotecard(m_host.OwnerID, notecard); } public LSL_Key osAgentSaveAppearance(LSL_Key avatarId, string notecard) { - if (!CheckThreatLevel(ThreatLevel.High, "osAgentSaveAppearance")) return new LSL_Key(ScriptBaseClass.NULL_KEY); - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryHigh, "osAgentSaveAppearance"); return SaveAppearanceToNotecard(avatarId, notecard); } @@ -2923,7 +3429,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (appearanceModule != null) { appearanceModule.SaveBakedTextures(sp.UUID); - OSDMap appearancePacked = sp.Appearance.Pack(); + EntityTransferContext ctx = new EntityTransferContext(); + OSDMap appearancePacked = sp.Appearance.Pack(ctx); TaskInventoryItem item = SaveNotecard(notecard, "Avatar Appearance", Util.GetFormattedXml(appearancePacked as OSD), true); @@ -2962,7 +3469,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// "male" or "female" or "unknown" public LSL_String osGetGender(LSL_Key rawAvatarId) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.None, "osGetGender"); UUID avatarId; if (!UUID.TryParse(rawAvatarId, out avatarId)) @@ -3005,7 +3512,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public LSL_Key osGetMapTexture() { - m_host.AddScriptLPS(1); + CheckThreatLevel(); return m_ScriptEngine.World.RegionInfo.RegionSettings.TerrainImageID.ToString(); } @@ -3017,7 +3524,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public LSL_Key osGetRegionMapTexture(string regionName) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osGetRegionMapTexture"); Scene scene = m_ScriptEngine.World; UUID key = UUID.Zero; @@ -3033,6 +3540,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (region != null) key = region.TerrainImage; + ScriptSleep(1000); + return key.ToString(); } @@ -3045,7 +3554,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// List of floats public LSL_List osGetRegionStats() { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osGetRegionStats"); + LSL_List ret = new LSL_List(); float[] stats = World.StatsReporter.LastReportedSimStats; @@ -3058,32 +3568,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector osGetRegionSize() { - m_host.AddScriptLPS(1); - - bool isMegaregion; - IRegionCombinerModule rcMod = World.RequestModuleInterface(); - if (rcMod != null) - isMegaregion = rcMod.IsRootForMegaregion(World.RegionInfo.RegionID); - else - isMegaregion = false; + CheckThreatLevel(); - if (isMegaregion) - { - Vector2 size = rcMod.GetSizeOfMegaregion(World.RegionInfo.RegionID); - return new LSL_Vector(size.X, size.Y, Constants.RegionHeight); - } - else - { - Scene scene = m_ScriptEngine.World; - GridRegion region = scene.GridService.GetRegionByUUID(UUID.Zero, World.RegionInfo.RegionID); - return new LSL_Vector((float)region.RegionSizeX, (float)region.RegionSizeX, Constants.RegionHeight); - } + Scene scene = m_ScriptEngine.World; + RegionInfo reg = World.RegionInfo; +// GridRegion region = scene.GridService.GetRegionByUUID(UUID.Zero, World.RegionInfo.RegionID); +// return new LSL_Vector((float)region.RegionSizeX, (float)region.RegionSizeY, (float)Constants.RegionHeight); + return new LSL_Vector((float)reg.RegionSizeX, (float)reg.RegionSizeY, 0.0f); } public int osGetSimulatorMemory() { - if (!CheckThreatLevel(ThreatLevel.Moderate, "osGetSimulatorMemory")) return 0; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osGetSimulatorMemory"); + long pws = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64; if (pws > Int32.MaxValue) @@ -3094,10 +3591,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return (int)pws; } + public int osGetSimulatorMemoryKB() + { + CheckThreatLevel(ThreatLevel.Moderate, "osGetSimulatorMemoryKB"); + + long pws = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64; + + if((pws & 0x3FFL) != 0) + pws += 0x400L; + pws >>= 10; + + if (pws > Int32.MaxValue) + return Int32.MaxValue; + + return (int)pws; + } + public void osSetSpeed(string UUID, LSL_Float SpeedModifier) { - if (!CheckThreatLevel(ThreatLevel.Moderate, "osSetSpeed")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osSetSpeed"); + ScenePresence avatar = World.GetScenePresence(new UUID(UUID)); if (avatar != null) @@ -3106,8 +3619,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osKickAvatar(string FirstName, string SurName, string alert) { - if (!CheckThreatLevel(ThreatLevel.Severe, "osKickAvatar")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Severe, "osKickAvatar"); World.ForEachRootScenePresence(delegate(ScenePresence sp) { @@ -3125,23 +3637,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Float osGetHealth(string avatar) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.None, "osGetHealth"); LSL_Float health = new LSL_Float(-1); ScenePresence presence = World.GetScenePresence(new UUID(avatar)); - if (presence != null) health = presence.Health; + if (presence != null) + health = presence.Health; return health; } public void osCauseDamage(string avatar, double damage) { - if (!CheckThreatLevel(ThreatLevel.High, "osCauseDamage")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osCauseDamage"); UUID avatarId = new UUID(avatar); Vector3 pos = m_host.GetWorldPosition(); - ScenePresence presence = World.GetScenePresence(avatarId); + ScenePresence presence = World.GetScenePresence(avatarId); if (presence != null) { LandData land = World.GetLandData(pos); @@ -3163,13 +3675,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osCauseHealing(string avatar, double healing) { - if (!CheckThreatLevel(ThreatLevel.High, "osCauseHealing")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osCauseHealing"); UUID avatarId = new UUID(avatar); ScenePresence presence = World.GetScenePresence(avatarId); - if (presence != null && World.ScriptDanger(m_host.LocalId, m_host.GetWorldPosition())) + if (presence != null) { float health = presence.Health; health += (float)healing; @@ -3181,31 +3692,67 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + public void osSetHealth(string avatar, double health) + { + CheckThreatLevel(ThreatLevel.High, "osSetHealth"); + + UUID avatarId = new UUID(avatar); + ScenePresence presence = World.GetScenePresence(avatarId); + + if (presence != null) + { + if (health > 100.0) + health = 100.0; + else if (health < 1.0) + health = 1.0; + + presence.setHealthWithUpdate((float)health); + } + } + + public void osSetHealRate(string avatar, double healrate) + { + CheckThreatLevel(ThreatLevel.High, "osSetHealRate"); + + UUID avatarId = new UUID(avatar); + ScenePresence presence = World.GetScenePresence(avatarId); + + if (presence != null) + presence.HealRate = (float)healrate; + } + + public LSL_Float osGetHealRate(string avatar) + { + CheckThreatLevel(ThreatLevel.None, "osGetHealRate"); + + LSL_Float rate = new LSL_Float(0); + ScenePresence presence = World.GetScenePresence(new UUID(avatar)); + if (presence != null) + rate = presence.HealRate; + return rate; + } + public LSL_List osGetPrimitiveParams(LSL_Key prim, LSL_List rules) { - if (!CheckThreatLevel(ThreatLevel.High, "osGetPrimitiveParams")) return new LSL_List(); - m_host.AddScriptLPS(1); - InitLSL(); + CheckThreatLevel(ThreatLevel.High, "osGetPrimitiveParams"); + InitLSL(); return m_LSL_Api.GetPrimitiveParamsEx(prim, rules); } public void osSetPrimitiveParams(LSL_Key prim, LSL_List rules) { - if (!CheckThreatLevel(ThreatLevel.High, "osSetPrimitiveParams")) return; - m_host.AddScriptLPS(1); - InitLSL(); + CheckThreatLevel(ThreatLevel.High, "osSetPrimitiveParams"); + InitLSL(); m_LSL_Api.SetPrimitiveParamsEx(prim, rules, "osSetPrimitiveParams"); } /// - /// Set parameters for light projection in host prim + /// Set parameters for light projection in host prim /// public void osSetProjectionParams(bool projection, LSL_Key texture, double fov, double focus, double amb) { - if (!CheckThreatLevel(ThreatLevel.High, "osSetProjectionParams")) return; - osSetProjectionParams(UUID.Zero.ToString(), projection, texture, fov, focus, amb); } @@ -3214,8 +3761,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public void osSetProjectionParams(LSL_Key prim, bool projection, LSL_Key texture, double fov, double focus, double amb) { - if (!CheckThreatLevel(ThreatLevel.High, "osSetProjectionParams")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osSetProjectionParams"); SceneObjectPart obj = null; if (prim == UUID.Zero.ToString()) @@ -3245,12 +3791,31 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// Strided list of the UUID, position and name of each avatar in the region public LSL_List osGetAvatarList() { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.None, "osGetAvatarList"); LSL_List result = new LSL_List(); World.ForEachRootScenePresence(delegate (ScenePresence avatar) { - if (avatar != null && avatar.UUID != m_host.OwnerID) + if (avatar != null && !avatar.IsDeleted && avatar.UUID != m_host.OwnerID ) + { + result.Add(new LSL_String(avatar.UUID.ToString())); + result.Add(new LSL_Vector(avatar.AbsolutePosition)); + result.Add(new LSL_String(avatar.Name)); + } + }); + + return result; + } + + public LSL_List osGetNPCList() + { + CheckThreatLevel(ThreatLevel.None, "osGetNPCList"); + + LSL_List result = new LSL_List(); + World.ForEachRootScenePresence(delegate (ScenePresence avatar) + { + // npcs are not childagents but that is now. + if (avatar != null && avatar.IsNPC && !avatar.IsDeleted && !avatar.IsChildAgent && !avatar.IsInTransit) { result.Add(new LSL_String(avatar.UUID.ToString())); result.Add(new LSL_Vector(avatar.AbsolutePosition)); @@ -3268,7 +3833,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public LSL_String osUnixTimeToTimestamp(long time) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osUnixTimeToTimestamp"); long baseTicks = 621355968000000000; long tickResolution = 10000000; @@ -3282,10 +3847,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// Get the description from an inventory item /// /// - /// Item description + /// Item description public LSL_String osGetInventoryDesc(string item) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); lock (m_host.TaskInventory) { @@ -3308,8 +3873,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public LSL_Integer osInviteToGroup(LSL_Key agentId) { - if (!CheckThreatLevel(ThreatLevel.VeryLow, "osInviteToGroup")) return ScriptBaseClass.FALSE; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osInviteToGroup"); UUID agent = new UUID(agentId); @@ -3343,8 +3907,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public LSL_Integer osEjectFromGroup(LSL_Key agentId) { - if (!CheckThreatLevel(ThreatLevel.VeryLow, "osEjectFromGroup")) return ScriptBaseClass.FALSE; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osEjectFromGroup"); UUID agent = new UUID(agentId); @@ -3378,9 +3941,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public void osSetTerrainTexture(int level, LSL_Key texture) { - if (!CheckThreatLevel(ThreatLevel.High, "osSetTerrainTexture")) return; + CheckThreatLevel(ThreatLevel.High, "osSetTerrainTexture"); - m_host.AddScriptLPS(1); //Check to make sure that the script's owner is the estate manager/master //World.Permissions.GenericEstatePermission( if (World.Permissions.IsGod(m_host.OwnerID)) @@ -3408,9 +3970,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public void osSetTerrainTextureHeight(int corner, double low, double high) { - if (!CheckThreatLevel(ThreatLevel.High, "osSetTerrainTextureHeight")) return; + CheckThreatLevel(ThreatLevel.High, "osSetTerrainTextureHeight"); - m_host.AddScriptLPS(1); //Check to make sure that the script's owner is the estate manager/master //World.Permissions.GenericEstatePermission( if (World.Permissions.IsGod(m_host.OwnerID)) @@ -3429,9 +3990,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osForceAttachToAvatar(int attachmentPoint) { - if (!CheckThreatLevel(ThreatLevel.High, "osForceAttachToAvatar")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osForceAttachToAvatar"); InitLSL(); ((LSL_Api)m_LSL_Api).AttachToAvatar(attachmentPoint); @@ -3439,18 +3998,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osForceAttachToAvatarFromInventory(string itemName, int attachmentPoint) { - if (!CheckThreatLevel(ThreatLevel.High, "osForceAttachToAvatarFromInventory")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osForceAttachToAvatarFromInventory"); ForceAttachToAvatarFromInventory(m_host.OwnerID, itemName, attachmentPoint); } public void osForceAttachToOtherAvatarFromInventory(string rawAvatarId, string itemName, int attachmentPoint) { - if (!CheckThreatLevel(ThreatLevel.Severe, "osForceAttachToOtherAvatarFromInventory")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryHigh, "osForceAttachToOtherAvatarFromInventory"); UUID avatarId; @@ -3480,7 +4035,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (item.InvType != (int)InventoryType.Object) { // FIXME: Temporary null check for regression tests since they dont' have the infrastructure to set - // up the api reference. + // up the api reference. if (m_LSL_Api != null) ((LSL_Api)m_LSL_Api).llSay(0, string.Format("Unable to attach, item '{0}' is not an object.", itemName)); @@ -3509,9 +4064,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osForceDetachFromAvatar() { - if (!CheckThreatLevel(ThreatLevel.High, "osForceDetachFromAvatar")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osForceDetachFromAvatar"); InitLSL(); ((LSL_Api)m_LSL_Api).DetachFromAvatar(); @@ -3519,9 +4072,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_List osGetNumberOfAttachments(LSL_Key avatar, LSL_List attachmentPoints) { - if (!CheckThreatLevel(ThreatLevel.Moderate, "osGetNumberOfAttachments")) return new LSL_List(); - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osGetNumberOfAttachments"); UUID targetUUID; ScenePresence target; @@ -3555,15 +4106,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osMessageAttachments(LSL_Key avatar, string message, LSL_List attachmentPoints, int options) { - if (!CheckThreatLevel(ThreatLevel.Moderate, "osMessageAttachments")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osMessageAttachments"); UUID targetUUID; + if(!UUID.TryParse(avatar.ToString(), out targetUUID)) + return; + + if(targetUUID == UUID.Zero) + return; + ScenePresence target; + if(!World.TryGetScenePresence(targetUUID, out target)) + return; - if (attachmentPoints.Length >= 1 && UUID.TryParse(avatar.ToString(), out targetUUID) && World.TryGetScenePresence(targetUUID, out target)) + if(target.IsDeleted || target.IsInTransit) + return; + + List aps = new List(); + if(attachmentPoints.Length != 0) { - List aps = new List(); foreach (object point in attachmentPoints.Data) { int ipoint; @@ -3572,115 +4133,76 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api aps.Add(ipoint); } } + // parsing failed + if(aps.Count != attachmentPoints.Length) + return; + } - List attachments = new List(); - - bool msgAll = aps.Contains(ScriptBaseClass.OS_ATTACH_MSG_ALL); - bool invertPoints = (options & ScriptBaseClass.OS_ATTACH_MSG_INVERT_POINTS) != 0; + List attachments = new List(); - if (msgAll && invertPoints) - { - return; - } - else if (msgAll || invertPoints) - { - attachments = target.GetAttachments(); - } - else - { - foreach (int point in aps) - { - if (point > 0) - { - attachments.AddRange(target.GetAttachments((uint)point)); - } - } - } + bool msgAll; + bool invertPoints = (options & ScriptBaseClass.OS_ATTACH_MSG_INVERT_POINTS) != 0; - // if we have no attachments at this point, exit now - if (attachments.Count == 0) - { + if(aps.Count == 0) + { + if(!invertPoints) return; - } + msgAll = true; + invertPoints = false; + } + else + msgAll = aps.Contains(ScriptBaseClass.OS_ATTACH_MSG_ALL); - List ignoreThese = new List(); + if (msgAll && invertPoints) + return; - if (invertPoints) + if (msgAll || invertPoints) + { + attachments = target.GetAttachments(); + } + else + { + foreach (int point in aps) { - foreach (SceneObjectGroup attachment in attachments) + if (point > 0) { - if (aps.Contains((int)attachment.AttachmentPoint)) - { - ignoreThese.Add(attachment); - } + attachments.AddRange(target.GetAttachments((uint)point)); } } + } - foreach (SceneObjectGroup attachment in ignoreThese) - { - attachments.Remove(attachment); - } - ignoreThese.Clear(); - - // if inverting removed all attachments to check, exit now - if (attachments.Count < 1) - { - return; - } + // if we have no attachments at this point, exit now + if (attachments.Count == 0) + { + return; + } - if ((options & ScriptBaseClass.OS_ATTACH_MSG_OBJECT_CREATOR) != 0) - { - foreach (SceneObjectGroup attachment in attachments) - { - if (attachment.RootPart.CreatorID != m_host.CreatorID) - { - ignoreThese.Add(attachment); - } - } + bool optionObjCreator = (options & + ScriptBaseClass.OS_ATTACH_MSG_OBJECT_CREATOR) != 0; + bool optionScriptCreator = (options & + ScriptBaseClass.OS_ATTACH_MSG_SCRIPT_CREATOR) != 0; - foreach (SceneObjectGroup attachment in ignoreThese) - { - attachments.Remove(attachment); - } - ignoreThese.Clear(); + UUID hostCreatorID = m_host.CreatorID; + UUID itemCreatorID = m_item.CreatorID; - // if filtering by same object creator removed all - // attachments to check, exit now - if (attachments.Count == 0) - { - return; - } - } + foreach (SceneObjectGroup sog in attachments) + { + if(sog.IsDeleted || sog.inTransit) + continue; - if ((options & ScriptBaseClass.OS_ATTACH_MSG_SCRIPT_CREATOR) != 0) - { - foreach (SceneObjectGroup attachment in attachments) - { - if (attachment.RootPart.CreatorID != m_item.CreatorID) - { - ignoreThese.Add(attachment); - } - } + if (invertPoints && aps.Contains((int)sog.AttachmentPoint)) + continue; - foreach (SceneObjectGroup attachment in ignoreThese) - { - attachments.Remove(attachment); - } - ignoreThese.Clear(); + UUID CreatorID = sog.RootPart.CreatorID; + if (optionObjCreator && CreatorID != hostCreatorID) + continue; - // if filtering by object creator must match originating - // script creator removed all attachments to check, - // exit now - if (attachments.Count == 0) - { - return; - } - } + if (optionScriptCreator && CreatorID != itemCreatorID) + continue; - foreach (SceneObjectGroup attachment in attachments) - { - MessageObject(attachment.RootPart.UUID, message); - } + SceneObjectPart[] parts = sog.Parts; + foreach(SceneObjectPart p in parts) + MessageObject(p.UUID, message); } } @@ -3693,7 +4215,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// 1 if thing is a valid UUID, 0 otherwise public LSL_Integer osIsUUID(string thing) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); UUID test; return UUID.TryParse(thing, out test) ? 1 : 0; @@ -3707,7 +4229,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public LSL_Float osMin(double a, double b) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); return Math.Min(a, b); } @@ -3720,16 +4242,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public LSL_Float osMax(double a, double b) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); return Math.Max(a, b); } public LSL_Key osGetRezzingObject() { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.None, "osGetRezzingObject"); - return new LSL_Key(m_host.ParentGroup.FromPartID.ToString()); + UUID rezID = m_host.ParentGroup.RezzerID; + if(rezID == UUID.Zero || m_host.ParentGroup.Scene.GetScenePresence(rezID) != null) + return new LSL_Key(UUID.Zero.ToString()); + return new LSL_Key(rezID.ToString()); } /// @@ -3738,7 +4263,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public void osSetContentType(LSL_Key id, string type) { - if (!CheckThreatLevel(ThreatLevel.High, "osSetContentType")) return; + CheckThreatLevel(ThreatLevel.High, "osSetContentType"); if (m_UrlModule != null) m_UrlModule.HttpContentType(new UUID(id),type); @@ -3750,7 +4275,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// boolean indicating whether an error was shouted. protected bool ShoutErrorOnLackingOwnerPerms(int perms, string errorPrefix) { - m_host.AddScriptLPS(1); bool fail = false; if (m_item.PermsGranter != m_host.OwnerID) { @@ -3800,39 +4324,36 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osDropAttachment() { - if (!CheckThreatLevel(ThreatLevel.Low, "osDropAttachment")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osDropAttachment"); DropAttachment(true); } public void osForceDropAttachment() { - if (!CheckThreatLevel(ThreatLevel.High, "osForceDropAttachment")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osForceDropAttachment"); DropAttachment(false); } public void osDropAttachmentAt(LSL_Vector pos, LSL_Rotation rot) { - if (!CheckThreatLevel(ThreatLevel.Low, "osDropAttachmentAt")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osDropAttachmentAt"); DropAttachmentAt(true, pos, rot); } public void osForceDropAttachmentAt(LSL_Vector pos, LSL_Rotation rot) { - if (!CheckThreatLevel(ThreatLevel.High, "osForceDropAttachmentAt")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osForceDropAttachmentAt"); DropAttachmentAt(false, pos, rot); } public LSL_Integer osListenRegex(int channelID, string name, string ID, string msg, int regexBitfield) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Low, "osListenRegex"); + UUID keyID; UUID.TryParse(ID, out keyID); @@ -3879,7 +4400,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer osRegexIsMatch(string input, string pattern) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Low, "osRegexIsMatch"); + try { return Regex.IsMatch(input, pattern) ? 1 : 0; @@ -3890,5 +4412,392 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return 0; } } + + public LSL_String osRequestURL(LSL_List options) + { + CheckThreatLevel(ThreatLevel.Moderate, "osRequestSecureURL"); + + Hashtable opts = new Hashtable(); + for (int i = 0 ; i < options.Length ; i++) + { + object opt = options.Data[i]; + if (opt.ToString() == "allowXss") + opts["allowXss"] = true; + } + + if (m_UrlModule != null) + return m_UrlModule.RequestURL(m_ScriptEngine.ScriptModule, m_host, m_item.ItemID, opts).ToString(); + return UUID.Zero.ToString(); + } + + public LSL_String osRequestSecureURL(LSL_List options) + { + CheckThreatLevel(ThreatLevel.Moderate, "osRequestSecureURL"); + + Hashtable opts = new Hashtable(); + for (int i = 0 ; i < options.Length ; i++) + { + object opt = options.Data[i]; + if (opt.ToString() == "allowXss") + opts["allowXss"] = true; + } + + if (m_UrlModule != null) + return m_UrlModule.RequestSecureURL(m_ScriptEngine.ScriptModule, m_host, m_item.ItemID, opts).ToString(); + return UUID.Zero.ToString(); + } + + public void osCollisionSound(string impact_sound, double impact_volume) + { + CheckThreatLevel(); + + if(impact_sound == "") + { + m_host.CollisionSoundVolume = (float)impact_volume; + m_host.CollisionSound = m_host.invalidCollisionSoundUUID; + if(impact_volume == 0.0) + m_host.CollisionSoundType = -1; // disable all sounds + else if(impact_volume == 1.0f) + m_host.CollisionSoundType = 0; // full return to default sounds + else + m_host.CollisionSoundType = 2; // default sounds with volume + m_host.aggregateScriptEvents(); + return; + } + // TODO: Parameter check logic required. + UUID soundId = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, impact_sound, AssetType.Sound); + if(soundId != UUID.Zero) + { + m_host.CollisionSound = soundId; + m_host.CollisionSoundVolume = (float)impact_volume; + m_host.CollisionSoundType = 1; + } + else + m_host.CollisionSoundType = -1; + + m_host.aggregateScriptEvents(); + } + + // still not very usefull, detector is lost on rez, restarts, etc + public void osVolumeDetect(int detect) + { + CheckThreatLevel(); + + if (m_host.ParentGroup == null || m_host.ParentGroup.IsDeleted || m_host.ParentGroup.IsAttachment) + return; + + m_host.ScriptSetVolumeDetect(detect != 0); + } + + /// + /// Get inertial data + /// + /// + /// + /// + /// a LSL list with contents: + /// LSL_Float mass, the total mass of a linkset + /// LSL_Vector CenterOfMass, center mass relative to root prim + /// LSL_Vector Inertia, elements of diagonal of inertia Ixx,Iyy,Izz divided by total mass + /// LSL_Vector aux, elements of upper triagle of inertia Ixy (= Iyx), Ixz (= Izx), Iyz(= Izy) divided by total mass + /// + public LSL_List osGetInertiaData() + { + CheckThreatLevel(); + + LSL_List result = new LSL_List(); + float TotalMass; + Vector3 CenterOfMass; + Vector3 Inertia; + Vector4 aux; + + SceneObjectGroup sog = m_host.ParentGroup; + if(sog== null || sog.IsDeleted) + return result; + + sog.GetInertiaData(out TotalMass, out CenterOfMass, out Inertia, out aux ); + if(TotalMass > 0) + { + float t = 1.0f/TotalMass; + Inertia.X *= t; + Inertia.Y *= t; + Inertia.Z *= t; + + aux.X *= t; + aux.Y *= t; + aux.Z *= t; + } + + result.Add(new LSL_Float(TotalMass)); + result.Add(new LSL_Vector(CenterOfMass.X, CenterOfMass.Y, CenterOfMass.Z)); + result.Add(new LSL_Vector(Inertia.X, Inertia.Y, Inertia.Z)); + result.Add(new LSL_Vector(aux.X, aux.Y, aux.Z)); + return result; + } + + /// + /// set inertial data + /// replaces the automatic calculation of mass, center of mass and inertia + /// + /// + /// total mass of linkset + /// location of center of mass relative to root prim in local coords + /// moment of inertia relative to principal axis and center of mass,Ixx, Iyy, Izz divided by mass + /// rotation of the inertia, relative to local axis + /// + /// the inertia argument is is inertia divided by mass, so corresponds only to the geometric distribution of mass and both can be changed independently. + /// + + public void osSetInertia(LSL_Float mass, LSL_Vector centerOfMass, LSL_Vector principalInertiaScaled, LSL_Rotation lslrot) + { + CheckThreatLevel(); + + SceneObjectGroup sog = m_host.ParentGroup; + if(sog== null || sog.IsDeleted) + return; + + if(mass < 0 || principalInertiaScaled.x < 0 || principalInertiaScaled.y < 0 || principalInertiaScaled.z < 0) + return; + + // need more checks + + Vector3 CenterOfMass = new Vector3((float)centerOfMass.x,(float)centerOfMass.y,(float)centerOfMass.z); + Vector3 Inertia; + float m = (float)mass; + + Inertia.X = m * (float)principalInertiaScaled.x; + Inertia.Y = m * (float)principalInertiaScaled.y; + Inertia.Z = m * (float)principalInertiaScaled.z; + + Vector4 rot = new Vector4((float)lslrot.x, (float)lslrot.y, (float)lslrot.y, (float)lslrot.s); + rot.Normalize(); + + sog.SetInertiaData(m, CenterOfMass, Inertia, rot ); + } + + /// + /// set inertial data as a sphere + /// replaces the automatic calculation of mass, center of mass and inertia + /// + /// + /// total mass of linkset + /// size of the Box + /// location of center of mass relative to root prim in local coords + /// rotation of the box, and so inertia, relative to local axis + /// + /// + public void osSetInertiaAsBox(LSL_Float mass, LSL_Vector boxSize, LSL_Vector centerOfMass, LSL_Rotation lslrot) + { + CheckThreatLevel(); + + SceneObjectGroup sog = m_host.ParentGroup; + if(sog== null || sog.IsDeleted) + return; + + if(mass < 0) + return; + + // need more checks + + Vector3 CenterOfMass = new Vector3((float)centerOfMass.x,(float)centerOfMass.y,(float)centerOfMass.z); + Vector3 Inertia; + float lx = (float)boxSize.x; + float ly = (float)boxSize.y; + float lz = (float)boxSize.z; + float m = (float)mass; + float t = m / 12.0f; + + Inertia.X = t * (ly*ly + lz*lz); + Inertia.Y = t * (lx*lx + lz*lz); + Inertia.Z = t * (lx*lx + ly*ly); + + Vector4 rot = new Vector4((float)lslrot.x, (float)lslrot.y, (float)lslrot.z, (float)lslrot.s); + rot.Normalize(); + + sog.SetInertiaData(m, CenterOfMass, Inertia, rot ); + } + + /// + /// set inertial data as a sphere + /// replaces the automatic calculation of mass, center of mass and inertia + /// + /// + /// total mass of linkset + /// radius of the sphere + /// location of center of mass relative to root prim in local coords + /// + /// + public void osSetInertiaAsSphere(LSL_Float mass, LSL_Float radius, LSL_Vector centerOfMass) + { + CheckThreatLevel(); + + SceneObjectGroup sog = m_host.ParentGroup; + if(sog== null || sog.IsDeleted) + return; + + if(mass < 0) + return; + + // need more checks + + Vector3 CenterOfMass = new Vector3((float)centerOfMass.x,(float)centerOfMass.y,(float)centerOfMass.z); + Vector3 Inertia; + float r = (float)radius; + float m = (float)mass; + float t = 0.4f * m * r * r; + + Inertia.X = t; + Inertia.Y = t; + Inertia.Z = t; + + sog.SetInertiaData(m, CenterOfMass, Inertia, new Vector4(0f, 0f, 0f,1.0f)); + } + + /// + /// set inertial data as a cylinder + /// replaces the automatic calculation of mass, center of mass and inertia + /// + /// + /// total mass of linkset + /// radius of the cylinder + /// lenght of the cylinder + /// location of center of mass relative to root prim in local coords + /// rotation of the cylinder, and so inertia, relative to local axis + /// + /// cylinder axis aligned with Z axis. For other orientations provide the rotation. + /// + public void osSetInertiaAsCylinder(LSL_Float mass, LSL_Float radius, LSL_Float lenght, LSL_Vector centerOfMass, LSL_Rotation lslrot) + { + CheckThreatLevel(); + + SceneObjectGroup sog = m_host.ParentGroup; + if(sog== null || sog.IsDeleted) + return; + + if(mass < 0) + return; + + // need more checks + + Vector3 CenterOfMass = new Vector3((float)centerOfMass.x,(float)centerOfMass.y,(float)centerOfMass.z); + Vector3 Inertia; + float m = (float)mass; + float r = (float)radius; + r *= r; + Inertia.Z = 0.5f * m * r; + float t = (float)lenght; + t *= t; + t += 3.0f * r; + t *= 8.333333e-2f * m; + + Inertia.X = t; + Inertia.Y = t; + + Vector4 rot = new Vector4((float)lslrot.x, (float)lslrot.y, (float)lslrot.z, (float)lslrot.s); + rot.Normalize(); + + sog.SetInertiaData(m, CenterOfMass, Inertia, rot); + } + + /// + /// removes inertial data manual override + /// default automatic calculation is used again + /// + /// + public void osClearInertia() + { + CheckThreatLevel(); + + SceneObjectGroup sog = m_host.ParentGroup; + if(sog== null || sog.IsDeleted) + return; + + sog.SetInertiaData(-1, Vector3.Zero, Vector3.Zero, Vector4.Zero ); + } + + private bool checkAllowObjectTPbyLandOwner(Vector3 pos) + { + ILandObject land = World.LandChannel.GetLandObject(pos); + if(land == null) + return true; + + LandData landdata = land.LandData; + if(landdata == null) + return true; + + UUID hostOwner = m_host.OwnerID; + if(landdata.OwnerID == hostOwner) + return true; + + EstateSettings es = World.RegionInfo.EstateSettings; + if(es != null && es.IsEstateManagerOrOwner(hostOwner)) + return true; + + if(!landdata.IsGroupOwned) + return false; + + UUID landGroup = landdata.GroupID; + if(landGroup == UUID.Zero) + return false; + + if(landGroup == m_host.GroupID) + return true; + + return false; + } + + /// + /// teleports a object (full linkset) + /// + /// the id of the linkset to teleport + /// target position + /// a rotation to apply + /// several flags/param> + /// + /// only does teleport local to region + /// if object has scripts, owner must have rights to run scripts on target location + /// object owner must have rights to enter ojects on target location + /// target location parcel must have enought free prims capacity for the linkset prims + /// all avatars siting on the object must have access to target location + /// has a cool down time. retries before expire reset it + /// fail conditions are silent ignored + /// + public LSL_Integer osTeleportObject(LSL_Key objectUUID, LSL_Vector targetPos, LSL_Rotation rotation, LSL_Integer flags) + { + CheckThreatLevel(ThreatLevel.Severe, "osTeleportObject"); + + UUID objUUID; + if (!UUID.TryParse(objectUUID, out objUUID)) + { + OSSLShoutError("osTeleportObject() invalid object Key"); + return -1; + } + + SceneObjectGroup sog = World.GetSceneObjectGroup(objUUID); + if(sog== null || sog.IsDeleted || sog.inTransit) + return -1; + + if(sog.OwnerID != m_host.OwnerID) + { + Vector3 pos = sog.AbsolutePosition; + if(!checkAllowObjectTPbyLandOwner(pos)) + return -1; + } + + UUID myid = m_host.ParentGroup.UUID; + + return sog.TeleportObject(myid, targetPos, rotation, flags); + // a delay here may break vehicles + } + + public LSL_Integer osGetLinkNumber(LSL_String name) + { + CheckThreatLevel(); + + SceneObjectGroup sog = m_host.ParentGroup; + if(sog== null || sog.IsDeleted) + return -1; + return sog.GetLinkNumber(name); + } } } -- cgit v1.1