diff --git a/OpenSim/Framework/ILandObject.cs b/OpenSim/Framework/ILandObject.cs index e11efe273c..877e4b5425 100644 --- a/OpenSim/Framework/ILandObject.cs +++ b/OpenSim/Framework/ILandObject.cs @@ -194,5 +194,6 @@ namespace OpenSim.Framework string GetMusicUrl(); void Clear(); + ISceneObject[] GetSceneObjectGroups(); } } diff --git a/OpenSim/Framework/SLUtil.cs b/OpenSim/Framework/SLUtil.cs index cc30494d60..3bbb34f465 100644 --- a/OpenSim/Framework/SLUtil.cs +++ b/OpenSim/Framework/SLUtil.cs @@ -692,5 +692,73 @@ namespace OpenSim.Framework return new string[0]; return lines.ToArray(); } + + // libomv has old names on ATTACH_LEFT_PEC and ATTACH_RIGHT_PEC + public static readonly string[] AttachmentPointNames = new string[] + { + string.Empty, + "ATTACH_CHEST", // 1 + "ATTACH_HEAD", // 2 + "ATTACH_LSHOULDER", // 3 + "ATTACH_RSHOULDER", // 4 + "ATTACH_LHAND", // 5 + "ATTACH_RHAND", // 6 + "ATTACH_LFOOT", // 7 + "ATTACH_RFOOT", // 8 + "ATTACH_BACK", // 9 + "ATTACH_PELVIS", // 10 + "ATTACH_MOUTH", // 11 + "ATTACH_CHIN", // 12 + "ATTACH_LEAR", // 13 + "ATTACH_REAR", // 14 + "ATTACH_LEYE", // 15 + "ATTACH_REYE", // 16 + "ATTACH_NOSE", // 17 + "ATTACH_RUARM", // 18 + "ATTACH_RLARM", // 19 + "ATTACH_LUARM", // 20 + "ATTACH_LLARM", // 21 + "ATTACH_RHIP", // 22 + "ATTACH_RULEG", // 23 + "ATTACH_RLLEG", // 24 + "ATTACH_LHIP", // 25 + "ATTACH_LULEG", // 26 + "ATTACH_LLLEG", // 27 + "ATTACH_BELLY", // 28 + "ATTACH_LEFT_PEC", // 29 + "ATTACH_RIGHT_PEC", // 30 + "ATTACH_HUD_CENTER_2", // 31 + "ATTACH_HUD_TOP_RIGHT", // 32 + "ATTACH_HUD_TOP_CENTER", // 33 + "ATTACH_HUD_TOP_LEFT", // 34 + "ATTACH_HUD_CENTER_1", // 35 + "ATTACH_HUD_BOTTOM_LEFT", // 36 + "ATTACH_HUD_BOTTOM", // 37 + "ATTACH_HUD_BOTTOM_RIGHT", // 38 + "ATTACH_NECK", // 39 + "ATTACH_AVATAR_CENTER", // 40 + "ATTACH_LHAND_RING1", // 41 + "ATTACH_RHAND_RING1", // 42 + "ATTACH_TAIL_BASE", // 43 + "ATTACH_TAIL_TIP", // 44 + "ATTACH_LWING", // 45 + "ATTACH_RWING", // 46 + "ATTACH_FACE_JAW", // 47 + "ATTACH_FACE_LEAR", // 48 + "ATTACH_FACE_REAR", // 49 + "ATTACH_FACE_LEYE", // 50 + "ATTACH_FACE_REYE", // 51 + "ATTACH_FACE_TONGUE", // 52 + "ATTACH_GROIN", // 53 + "ATTACH_HIND_LFOOT", // 54 + "ATTACH_HIND_RFOOT" // 55 + }; + + public static string GetAttachmentName(int point) + { + if(point < AttachmentPointNames.Length) + return AttachmentPointNames[point]; + return "Unknown"; + } } } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index 84bba46765..12cbe1c386 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs @@ -122,7 +122,10 @@ namespace OpenSim.Region.ClientStack.Linden private bool m_AllowCapHomeLocation = true; private bool m_AllowCapGroupMemberData = true; - private IUserManagement m_UserManager; + private bool m_AllowCapLandResources = true; + private bool m_AllowCapAttachmentResources = true; + + private IUserManagement m_UserManager; private IUserAccountService m_userAccountService; private IMoneyModule m_moneyModule; @@ -199,6 +202,14 @@ namespace OpenSim.Region.ClientStack.Linden string GroupMemberDataUrl = CapsConfig.GetString("Cap_GroupMemberData", "localhost"); if(GroupMemberDataUrl == String.Empty) m_AllowCapGroupMemberData = false; + + string LandResourcesUrl = CapsConfig.GetString("Cap_LandResources", "localhost"); + if (LandResourcesUrl == String.Empty) + m_AllowCapLandResources = false; + + string AttachmentResourcesUrl = CapsConfig.GetString("Cap_AttachmentResources", "localhost"); + if (AttachmentResourcesUrl == String.Empty) + m_AllowCapAttachmentResources = false; } } @@ -273,6 +284,17 @@ namespace OpenSim.Region.ClientStack.Linden new SimpleStreamHandler(GetNewCapPath(), GroupMemberData)); } + if (m_AllowCapLandResources) + { + m_HostCapsObj.RegisterSimpleHandler("LandResources", + new SimpleOSDMapHandler("POST", GetNewCapPath(), LandResources)); + } + + if (m_AllowCapAttachmentResources) + { + m_HostCapsObj.RegisterSimpleHandler("AttachmentResources", + new SimpleStreamHandler(GetNewCapPath(), AttachmentResources)); + } } catch (Exception e) { @@ -1567,7 +1589,149 @@ namespace OpenSim.Region.ClientStack.Linden httpResponse.StatusCode = (int)HttpStatusCode.OK; } - public void ResourceCostSelected(IOSHttpRequest httpRequest,IOSHttpResponse httpResponse, OSDMap req) + public struct AttachmentScriptInfo + { + public byte attpoint; + public UUID id; + public string name; + public Vector3 pos; + public int memory; + }; + + public void AttachmentResources(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + if(m_Scene.TryGetScenePresence(m_AgentID, out ScenePresence sp) && !sp.IsChildAgent && !sp.IsDeleted && !sp.IsInTransit) + { + int totalmem = 0; + List atts = sp.GetAttachments(); + Dictionary> perAttPoints = new Dictionary>(); + foreach(SceneObjectGroup so in atts) + { + byte attp = so.GetAttachmentPoint(); + int mem = so.ScriptsMemory(); + totalmem += mem; + AttachmentScriptInfo info = new AttachmentScriptInfo() + { + attpoint = attp, + id = so.UUID, + name = so.Name, + memory = mem, + pos = so.AbsolutePosition + }; + if(perAttPoints.TryGetValue(attp, out List la)) + la.Add(info); + else + perAttPoints[attp] = new List(){ info }; + } + StringBuilder sb = LLSDxmlEncode.Start(); + LLSDxmlEncode.AddMap(sb); + LLSDxmlEncode.AddArray("attachments", sb); + + foreach (KeyValuePair> kvp in perAttPoints) + { + LLSDxmlEncode.AddMap(sb); + LLSDxmlEncode.AddElem("location", SLUtil.GetAttachmentName(kvp.Key), sb); + LLSDxmlEncode.AddArray("objects", sb); + foreach(AttachmentScriptInfo asi in kvp.Value) + { + LLSDxmlEncode.AddMap(sb); + LLSDxmlEncode.AddElem("id", asi.id, sb); + LLSDxmlEncode.AddElem("is_group_owned", (int)0, sb); + LLSDxmlEncode.AddElem("location", asi.pos, sb); + LLSDxmlEncode.AddElem("name", asi.name, sb); + LLSDxmlEncode.AddElem("owner_id", m_AgentID, sb); + LLSDxmlEncode.AddMap("resources", sb); + LLSDxmlEncode.AddElem("memory", asi.memory, sb); + LLSDxmlEncode.AddEndMap(sb); + LLSDxmlEncode.AddEndMap(sb); + } + LLSDxmlEncode.AddEndArray(sb); + LLSDxmlEncode.AddEndMap(sb); + } + LLSDxmlEncode.AddEndArray(sb); + + LLSDxmlEncode.AddMap("summary", sb); + LLSDxmlEncode.AddArray("available", sb); + + LLSDxmlEncode.AddMap(sb); + LLSDxmlEncode.AddElem("amount", (int)38, sb); + LLSDxmlEncode.AddElem("type", "urls", sb); + LLSDxmlEncode.AddEndMap(sb); + + LLSDxmlEncode.AddMap(sb); + LLSDxmlEncode.AddElem("amount", (int)-1, sb); + LLSDxmlEncode.AddElem("type", "memory", sb); + LLSDxmlEncode.AddEndMap(sb); + LLSDxmlEncode.AddEndArray(sb); + + LLSDxmlEncode.AddArray("used", sb); + + LLSDxmlEncode.AddMap(sb); + LLSDxmlEncode.AddElem("amount",(int) 0, sb); + LLSDxmlEncode.AddElem("type", "urls", sb); + LLSDxmlEncode.AddEndMap(sb); + + LLSDxmlEncode.AddMap(sb); + LLSDxmlEncode.AddElem("amount", totalmem, sb); + LLSDxmlEncode.AddElem("type", "memory", sb); + LLSDxmlEncode.AddEndMap(sb); + LLSDxmlEncode.AddEndArray(sb); + + LLSDxmlEncode.AddEndMap(sb); + + + LLSDxmlEncode.AddEndMap(sb); + + string tst = sb.ToString(); + + httpResponse.RawBuffer = LLSDxmlEncode.EndToNBBytes(sb); + httpResponse.StatusCode = (int)HttpStatusCode.OK; + return; + } + httpResponse.StatusCode = (int)HttpStatusCode.NotFound; + } + + public void LandResources(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, OSDMap req) + { + if(req.TryGetValue("parcel_id", out OSD tmp) && tmp is OSDUUID) + { + UUID parcelID = tmp.AsUUID(); + if(!Util.ParseFakeParcelID(parcelID, out ulong regionHandle, out uint x, out uint y) || regionHandle != m_Scene.RegionInfo.RegionHandle) + { + httpResponse.StatusCode = (int)HttpStatusCode.NotFound; + return; + } + + ILandObject land = m_Scene.LandChannel.GetLandObject(x, y); + if(land == null || land.LandData == null) + { + httpResponse.StatusCode = (int)HttpStatusCode.NotFound; + return; + } + + string uploaderPath = GetNewCapPath(); + ScriptResourceSummary uploader = + new ScriptResourceSummary(land.LandData.LocalID, m_Scene, m_HostCapsObj.HttpListener, uploaderPath, httpRequest.RemoteIPEndPoint.Address); + + m_HostCapsObj.RegisterSimpleHandler("LandResources", + new SimpleOSDMapHandler("POST", GetNewCapPath(), LandResources)); + + string protocol = m_HostCapsObj.SSLCaps ? "https://" : "http://"; + string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + uploaderPath; + + StringBuilder lsl = LLSDxmlEncode.Start(); + LLSDxmlEncode.AddMap(lsl); + LLSDxmlEncode.AddElem("ScriptResourceSummary", uploaderURL,lsl); + LLSDxmlEncode.AddEndMap(lsl); + + httpResponse.RawBuffer = LLSDxmlEncode.EndToNBBytes(lsl); + httpResponse.StatusCode = (int)HttpStatusCode.OK; + return; + } + httpResponse.StatusCode = (int)HttpStatusCode.BadRequest; + } + + public void ResourceCostSelected(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, OSDMap req) { float phys=0; float stream=0; @@ -2192,4 +2356,59 @@ namespace OpenSim.Region.ClientStack.Linden fs.Close(); } } -} + + public class ScriptResourceSummary + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private IHttpServer m_httpListener; + private string m_mypath; + private int m_parcelID; + private Scene m_scene; + private Timer m_timeoutTimer; + + private IPAddress m_address; + + public ScriptResourceSummary(int parcelID, Scene scene, IHttpServer httpServer, string path, IPAddress address) + { + m_httpListener = httpServer; + m_address = address; + m_mypath = path; + m_scene = scene; + m_parcelID = parcelID; + + m_timeoutTimer = new Timer(); + m_timeoutTimer.Elapsed += TimedOut; + m_timeoutTimer.Interval = 10000; + m_timeoutTimer.AutoReset = false; + m_timeoutTimer.Start(); + } + + /// + /// Handle raw asset upload data via the capability. + /// + /// + /// + /// + /// + public void ScriptResourceSummaryCap(IOSHttpRequest request, IOSHttpResponse response) + { + m_timeoutTimer.Stop(); + m_httpListener.RemoveSimpleStreamHandler(m_mypath); + m_timeoutTimer.Dispose(); + + if (request.RemoteIPEndPoint.Address != m_address) + { + response.StatusCode = (int)HttpStatusCode.Unauthorized; + return; + } + } + + private void TimedOut(object sender, ElapsedEventArgs args) + { + m_httpListener.RemoveSimpleStreamHandler(m_mypath); + m_log.InfoFormat("[CAPS]: Removing URL and handler for timed out ScriptResourceSummary"); + m_timeoutTimer.Dispose(); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs index 8e72ac2a3c..1e46b81cfa 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs @@ -124,6 +124,11 @@ namespace OpenSim.Region.CoreModules.World.Land } } + public ISceneObject[] GetSceneObjectGroups() + { + return primsOverMe.ToArray(); + } + public Vector2? GetNearestPoint(Vector3 pos) { Vector3 direction = new Vector3(m_centerPoint.X - pos.X, m_centerPoint.Y - pos.Y, 0f ); diff --git a/OpenSim/Region/Framework/Interfaces/IScriptModule.cs b/OpenSim/Region/Framework/Interfaces/IScriptModule.cs index 1993529275..b7fddf639d 100644 --- a/OpenSim/Region/Framework/Interfaces/IScriptModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IScriptModule.cs @@ -109,6 +109,7 @@ namespace OpenSim.Region.Framework.Interfaces /// A float the value is a representative execution time in milliseconds of all scripts in that Array. /// float GetScriptExecutionTime(List itemIDs); + int GetScriptsMemory(List itemIDs); /// /// Get the execution times of all scripts in each object. diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index bc00a50d70..3849afdbe0 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -5228,6 +5228,42 @@ namespace OpenSim.Region.Framework.Scenes return time; } + public int ScriptsMemory() + { + IScriptModule[] engines = Scene.RequestModuleInterfaces(); + + if (engines.Length == 0) // No engine at all + return 0; + + int memory = 0; + + // get all the scripts in all parts + SceneObjectPart[] parts = m_parts.GetArray(); + List scripts = new List(); + for (int i = 0; i < parts.Length; i++) + { + scripts.AddRange(parts[i].Inventory.GetInventoryItems(InventoryType.LSL)); + } + // extract the UUIDs + List ids = new List(scripts.Count); + foreach (TaskInventoryItem script in scripts) + { + if (!ids.Contains(script.ItemID)) + { + ids.Add(script.ItemID); + } + } + // Offer the list of script UUIDs to each engine found and accumulate the memory + foreach (IScriptModule e in engines) + { + if (e != null) + { + memory += e.GetScriptsMemory(ids); + } + } + return memory; + } + /// /// Returns a count of the number of running scripts in this groups parts. /// diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 7c74fd654c..a51c8b45a4 100755 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -2442,6 +2442,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine return time; } + public int GetScriptsMemory(List itemIDs) + { + return 0; + } + private float GetExectionTime(IScriptInstance si) { return (float)si.ExecutionTime.GetSumTime().TotalMilliseconds; diff --git a/OpenSim/Region/ScriptEngine/YEngine/XMREngine.cs b/OpenSim/Region/ScriptEngine/YEngine/XMREngine.cs index a33188b903..daf3ed11e3 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/XMREngine.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/XMREngine.cs @@ -1915,11 +1915,11 @@ namespace OpenSim.Region.ScriptEngine.Yengine } /** - * @brief A float the value is a representative execution time in - * milliseconds of all scripts in the link set. - * @param itemIDs = list of scripts in the link set - * @returns milliseconds for all those scripts - */ + * @brief A float the value is a representative execution time in + * milliseconds of all scripts in the link set. + * @param itemIDs = list of scripts in the link set + * @returns milliseconds for all those scripts + */ public float GetScriptExecutionTime(List itemIDs) { if((itemIDs == null) || (itemIDs.Count == 0)) @@ -1935,6 +1935,21 @@ namespace OpenSim.Region.ScriptEngine.Yengine return time; } + public int GetScriptsMemory(List itemIDs) + { + if ((itemIDs == null) || (itemIDs.Count == 0)) + return 0; + + int memory = 0; + foreach (UUID itemID in itemIDs) + { + XMRInstance instance = GetInstance(itemID); + if ((instance != null) && instance.Running) + memory += instance.xmrHeapUsed(); + } + return memory; + } + /** * @brief Block script from dequeuing events. */ diff --git a/OpenSim/Tests/Common/Mock/MockScriptEngine.cs b/OpenSim/Tests/Common/Mock/MockScriptEngine.cs index 63c8f94774..e82456e5ac 100644 --- a/OpenSim/Tests/Common/Mock/MockScriptEngine.cs +++ b/OpenSim/Tests/Common/Mock/MockScriptEngine.cs @@ -198,7 +198,12 @@ namespace OpenSim.Tests.Common public float GetScriptExecutionTime(List itemIDs) { - throw new System.NotImplementedException (); + return 0; + } + + public int GetScriptsMemory(List itemIDs) + { + return 0; } public Dictionary GetObjectScriptsExecutionTimes() diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 1efcad70a1..79dc1fc5db 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -765,7 +765,7 @@ ;; set to localhost. These defaults can be overwritten ;; in OpenSim.ini ;; - Cap_AttachmentResources = "" + Cap_AttachmentResources = "localhost" Cap_ChatSessionRequest = "" Cap_CopyInventoryFromNotecard = "localhost" Cap_DispatchRegionInfo = ""