diff --git a/.gitignore b/.gitignore index bf3ac37e0c..1e412437cd 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,10 @@ bin/*.db-journal bin/addin-db-* bin/*.dll bin/OpenSim.vshost.exe.config +bin/OpenSim.32BitLaunch.vshost.exe.config +bin/OpenSim.32BitLaunch.log +UpgradeLog.XML +_UpgradeReport_Files/ bin/ScriptEngines/*-*-*-*-* bin/ScriptEngines/*.dll bin/ScriptEngines/*/*.dll diff --git a/.nant/local.include b/.nant/local.include index 6d3e97228f..35f00589e8 100644 --- a/.nant/local.include +++ b/.nant/local.include @@ -135,14 +135,25 @@ - + - - + + - + + + + + + + + + + + + diff --git a/OpenSim/Data/IXInventoryData.cs b/OpenSim/Data/IXInventoryData.cs index 85a5c08d37..e64a82820d 100644 --- a/OpenSim/Data/IXInventoryData.cs +++ b/OpenSim/Data/IXInventoryData.cs @@ -40,6 +40,11 @@ namespace OpenSim.Data public UUID folderID; public UUID agentID; public UUID parentFolderID; + + public XInventoryFolder Clone() + { + return (XInventoryFolder)MemberwiseClone(); + } } public class XInventoryItem @@ -64,6 +69,11 @@ namespace OpenSim.Data public UUID avatarID; public UUID parentFolderID; public int inventoryGroupPermissions; + + public XInventoryItem Clone() + { + return (XInventoryItem)MemberwiseClone(); + } } public interface IXInventoryData diff --git a/OpenSim/Framework/InventoryFolderBase.cs b/OpenSim/Framework/InventoryFolderBase.cs index a12183c535..b3457a65b9 100644 --- a/OpenSim/Framework/InventoryFolderBase.cs +++ b/OpenSim/Framework/InventoryFolderBase.cs @@ -73,33 +73,27 @@ namespace OpenSim.Framework { } - public InventoryFolderBase(UUID id) + public InventoryFolderBase(UUID id) : this() { ID = id; } - public InventoryFolderBase(UUID id, UUID owner) + public InventoryFolderBase(UUID id, UUID owner) : this(id) { - ID = id; Owner = owner; } - public InventoryFolderBase(UUID id, string name, UUID owner, UUID parent) + public InventoryFolderBase(UUID id, string name, UUID owner, UUID parent) : this(id, owner) { - ID = id; Name = name; - Owner = owner; ParentID = parent; } - public InventoryFolderBase(UUID id, string name, UUID owner, short type, UUID parent, ushort version) + public InventoryFolderBase( + UUID id, string name, UUID owner, short type, UUID parent, ushort version) : this(id, name, owner, parent) { - ID = id; - Name = name; - Owner = owner; Type = type; - ParentID = parent; Version = version; } } -} +} \ No newline at end of file diff --git a/OpenSim/Framework/Serialization/External/OspResolver.cs b/OpenSim/Framework/Serialization/External/OspResolver.cs index d31d27c4a6..fa7160f874 100644 --- a/OpenSim/Framework/Serialization/External/OspResolver.cs +++ b/OpenSim/Framework/Serialization/External/OspResolver.cs @@ -65,9 +65,14 @@ namespace OpenSim.Framework.Serialization UserAccount account = userService.GetUserAccount(UUID.Zero, userId); if (account != null) + { return MakeOspa(account.FirstName, account.LastName); + } // else +// { // m_log.WarnFormat("[OSP RESOLVER]: No user account for {0}", userId); +// System.Console.WriteLine("[OSP RESOLVER]: No user account for {0}", userId); +// } return null; } @@ -79,10 +84,13 @@ namespace OpenSim.Framework.Serialization /// public static string MakeOspa(string firstName, string lastName) { -// m_log.DebugFormat("[OSP RESOLVER]: Making OSPA for {0} {1}", firstName, lastName); + string ospa + = OSPA_PREFIX + OSPA_NAME_KEY + OSPA_PAIR_SEPARATOR + firstName + OSPA_NAME_VALUE_SEPARATOR + lastName; + +// m_log.DebugFormat("[OSP RESOLVER]: Made OSPA {0} for {1} {2}", ospa, firstName, lastName); +// System.Console.WriteLine("[OSP RESOLVER]: Made OSPA {0} for {1} {2}", ospa, firstName, lastName); - return - OSPA_PREFIX + OSPA_NAME_KEY + OSPA_PAIR_SEPARATOR + firstName + OSPA_NAME_VALUE_SEPARATOR + lastName; + return ospa; } /// diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs index b112b6db52..12a05b3df5 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs @@ -350,38 +350,38 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL1.PrincipalID)); } - /// - /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where - /// an account exists with the same name as the creator, though not the same id. - /// - [Test] - public void TestLoadIarV0_1SameNameCreator() - { - TestHelpers.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); - - UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "meowfood"); - UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL2, "hampshire"); - - m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream); - InventoryItemBase foundItem1 - = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name); - - Assert.That( - foundItem1.CreatorId, Is.EqualTo(m_uaLL2.PrincipalID.ToString()), - "Loaded item non-uuid creator doesn't match original"); - Assert.That( - foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL2.PrincipalID), - "Loaded item uuid creator doesn't match original"); - Assert.That(foundItem1.Owner, Is.EqualTo(m_uaMT.PrincipalID), - "Loaded item owner doesn't match inventory reciever"); - - AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString()); - string xmlData = Utils.BytesToString(asset1.Data); - SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); - - Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL2.PrincipalID)); - } +// /// +// /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where +// /// an account exists with the same name as the creator, though not the same id. +// /// +// [Test] +// public void TestLoadIarV0_1SameNameCreator() +// { +// TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); +// +// UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "meowfood"); +// UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL2, "hampshire"); +// +// m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream); +// InventoryItemBase foundItem1 +// = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name); +// +// Assert.That( +// foundItem1.CreatorId, Is.EqualTo(m_uaLL2.PrincipalID.ToString()), +// "Loaded item non-uuid creator doesn't match original"); +// Assert.That( +// foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL2.PrincipalID), +// "Loaded item uuid creator doesn't match original"); +// Assert.That(foundItem1.Owner, Is.EqualTo(m_uaMT.PrincipalID), +// "Loaded item owner doesn't match inventory reciever"); +// +// AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString()); +// string xmlData = Utils.BytesToString(asset1.Data); +// SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); +// +// Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL2.PrincipalID)); +// } /// /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where diff --git a/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs b/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs index 18bd0186b8..13b74983b1 100644 --- a/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs @@ -49,6 +49,11 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture public const int DISP_EXPIRE = 1; public const int DISP_TEMP = 2; + /// + /// If true then where possible dynamic textures are reused. + /// + public bool ReuseTextures { get; set; } + private Dictionary RegisteredScenes = new Dictionary(); private Dictionary RenderPlugins = @@ -56,6 +61,15 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture private Dictionary Updaters = new Dictionary(); + /// + /// Record dynamic textures that we can reuse for a given data and parameter combination rather than + /// regenerate. + /// + /// + /// Key is string.Format("{0}{1}", data + /// + private Cache m_reuseableDynamicTextures; + #region IDynamicTextureManager Members public void RegisterRender(string handleType, IDynamicTextureRender render) @@ -71,7 +85,8 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture /// /// /// - public void ReturnData(UUID id, byte[] data) + /// True if the data generated can be reused for subsequent identical requests + public void ReturnData(UUID id, byte[] data, bool isReuseable) { DynamicTextureUpdater updater = null; @@ -88,7 +103,11 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture if (RegisteredScenes.ContainsKey(updater.SimUUID)) { Scene scene = RegisteredScenes[updater.SimUUID]; - updater.DataReceived(data, scene); + UUID newTextureID = updater.DataReceived(data, scene); + + if (ReuseTextures && isReuseable && !updater.BlendWithOldTexture) + m_reuseableDynamicTextures.Store( + GenerateReusableTextureKey(updater.BodyData, updater.Params), newTextureID); } } @@ -169,6 +188,11 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture { if (RenderPlugins.ContainsKey(contentType)) { + // If we want to reuse dynamic textures then we have to ignore any request from the caller to expire + // them. + if (ReuseTextures) + disp = disp & ~DISP_EXPIRE; + DynamicTextureUpdater updater = new DynamicTextureUpdater(); updater.SimUUID = simID; updater.PrimID = primID; @@ -183,21 +207,49 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture updater.Url = "Local image"; updater.Disp = disp; - lock (Updaters) + object reusableTextureUUID = null; + + if (ReuseTextures) + reusableTextureUUID + = m_reuseableDynamicTextures.Get(GenerateReusableTextureKey(data, extraParams)); + + // We cannot reuse a dynamic texture if the data is going to be blended with something already there. + if (reusableTextureUUID == null || updater.BlendWithOldTexture) { - if (!Updaters.ContainsKey(updater.UpdaterID)) + lock (Updaters) { - Updaters.Add(updater.UpdaterID, updater); + if (!Updaters.ContainsKey(updater.UpdaterID)) + { + Updaters.Add(updater.UpdaterID, updater); + } + } + + RenderPlugins[contentType].AsyncConvertData(updater.UpdaterID, data, extraParams); + } + else + { + // No need to add to updaters as the texture is always the same. Not that this functionality + // apppears to be implemented anyway. + if (RegisteredScenes.ContainsKey(updater.SimUUID)) + { + SceneObjectPart part = RegisteredScenes[updater.SimUUID].GetSceneObjectPart(updater.PrimID); + + if (part != null) + updater.UpdatePart(part, (UUID)reusableTextureUUID); } } - RenderPlugins[contentType].AsyncConvertData(updater.UpdaterID, data, extraParams); return updater.UpdaterID; } return UUID.Zero; } + private string GenerateReusableTextureKey(string data, string extraParams) + { + return string.Format("{0}{1}", data, extraParams); + } + public void GetDrawStringSize(string contentType, string text, string fontName, int fontSize, out double xSize, out double ySize) { @@ -224,6 +276,12 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture public void PostInitialise() { +// ReuseTextures = true; + if (ReuseTextures) + { + m_reuseableDynamicTextures = new Cache(CacheMedium.Memory, CacheStrategy.Conservative); + m_reuseableDynamicTextures.DefaultTTL = new TimeSpan(24, 0, 0); + } } public void Close() @@ -268,10 +326,61 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture BodyData = null; } + /// + /// Update the given part with the new texture. + /// + /// + /// The old texture UUID. + /// + public UUID UpdatePart(SceneObjectPart part, UUID textureID) + { + UUID oldID; + + lock (part) + { + // mostly keep the values from before + Primitive.TextureEntry tmptex = part.Shape.Textures; + + // FIXME: Need to return the appropriate ID if only a single face is replaced. + oldID = tmptex.DefaultTexture.TextureID; + + if (Face == ALL_SIDES) + { + oldID = tmptex.DefaultTexture.TextureID; + tmptex.DefaultTexture.TextureID = textureID; + } + else + { + try + { + Primitive.TextureEntryFace texface = tmptex.CreateFace((uint)Face); + texface.TextureID = textureID; + tmptex.FaceTextures[Face] = texface; + } + catch (Exception) + { + tmptex.DefaultTexture.TextureID = textureID; + } + } + + // I'm pretty sure we always want to force this to true + // I'm pretty sure noone whats to set fullbright true if it wasn't true before. + // tmptex.DefaultTexture.Fullbright = true; + + part.UpdateTextureEntry(tmptex.GetBytes()); + } + + return oldID; + } + /// /// Called once new texture data has been received for this updater. /// - public void DataReceived(byte[] data, Scene scene) + /// + /// + /// True if the data given is reuseable. + /// The asset UUID given to the incoming data. + public UUID DataReceived(byte[] data, Scene scene) { SceneObjectPart part = scene.GetSceneObjectPart(PrimID); @@ -281,7 +390,8 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture String.Format("DynamicTextureModule: Error preparing image using URL {0}", Url); scene.SimChat(Utils.StringToBytes(msg), ChatTypeEnum.Say, 0, part.ParentGroup.RootPart.AbsolutePosition, part.Name, part.UUID, false); - return; + + return UUID.Zero; } byte[] assetData = null; @@ -323,52 +433,23 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture cacheLayerDecode = null; } - UUID oldID = UUID.Zero; - - lock (part) - { - // mostly keep the values from before - Primitive.TextureEntry tmptex = part.Shape.Textures; - - // remove the old asset from the cache - oldID = tmptex.DefaultTexture.TextureID; - - if (Face == ALL_SIDES) - { - tmptex.DefaultTexture.TextureID = asset.FullID; - } - else - { - try - { - Primitive.TextureEntryFace texface = tmptex.CreateFace((uint)Face); - texface.TextureID = asset.FullID; - tmptex.FaceTextures[Face] = texface; - } - catch (Exception) - { - tmptex.DefaultTexture.TextureID = asset.FullID; - } - } - - // I'm pretty sure we always want to force this to true - // I'm pretty sure noone whats to set fullbright true if it wasn't true before. - // tmptex.DefaultTexture.Fullbright = true; - - part.UpdateTextureEntry(tmptex.GetBytes()); - } + UUID oldID = UpdatePart(part, asset.FullID); if (oldID != UUID.Zero && ((Disp & DISP_EXPIRE) != 0)) { - if (oldAsset == null) oldAsset = scene.AssetService.Get(oldID.ToString()); + if (oldAsset == null) + oldAsset = scene.AssetService.Get(oldID.ToString()); + if (oldAsset != null) { - if (oldAsset.Temporary == true) + if (oldAsset.Temporary) { scene.AssetService.Delete(oldID.ToString()); } } } + + return asset.FullID; } private byte[] BlendTextures(byte[] frontImage, byte[] backImage, bool setNewAlpha, byte newAlpha) diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs index 05d54f03a2..53a9679580 100644 --- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs @@ -84,6 +84,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp public string body; public int responseCode; public string responseBody; + public string responseType = "text/plain"; //public ManualResetEvent ev; public bool requestDone; public int startTime; @@ -302,6 +303,22 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp } } + public void HttpContentType(UUID request, string type) + { + lock (m_UrlMap) + { + if (m_RequestMap.ContainsKey(request)) + { + UrlData urlData = m_RequestMap[request]; + urlData.requests[request].responseType = type; + } + else + { + m_log.Info("[HttpRequestHandler] There is no http-in request with id " + request.ToString()); + } + } + } + public void HttpResponse(UUID request, int status, string body) { lock (m_UrlMap) @@ -504,7 +521,8 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp //put response response["int_response_code"] = requestData.responseCode; response["str_response_string"] = requestData.responseBody; - response["content_type"] = "text/plain"; + response["content_type"] = requestData.responseType; + // response["content_type"] = "text/plain"; response["keepalive"] = false; response["reusecontext"] = false; diff --git a/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs b/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs index 6f839485ec..2b3a0f29ff 100644 --- a/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs @@ -67,12 +67,18 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL return true; } +// public bool AlwaysIdenticalConversion(string bodyData, string extraParams) +// { +// // We don't support conversion of body data. +// return false; +// } + public byte[] ConvertUrl(string url, string extraParams) { return null; } - public byte[] ConvertStream(Stream data, string extraParams) + public byte[] ConvertData(string bodyData, string extraParams) { return null; } @@ -236,9 +242,11 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL stream.Close(); } } + m_log.DebugFormat("[LOADIMAGEURLMODULE] Returning {0} bytes of image data for request {1}", imageJ2000.Length, state.RequestID); - m_textureManager.ReturnData(state.RequestID, imageJ2000); + + m_textureManager.ReturnData(state.RequestID, imageJ2000, false); } #region Nested type: RequestState diff --git a/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs b/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs index 9787c8c173..b50c0bd7cd 100644 --- a/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs +++ b/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs @@ -45,31 +45,250 @@ using OpenSim.Tests.Common.Mock; namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests { [TestFixture] - public class VectorRenderModuleTests + public class VectorRenderModuleTests : OpenSimTestCase { + Scene m_scene; + DynamicTextureModule m_dtm; + VectorRenderModule m_vrm; + + private void SetupScene(bool reuseTextures) + { + m_scene = new SceneHelpers().SetupScene(); + + m_dtm = new DynamicTextureModule(); + m_dtm.ReuseTextures = reuseTextures; + + m_vrm = new VectorRenderModule(); + + SceneHelpers.SetupSceneModules(m_scene, m_dtm, m_vrm); + } + [Test] public void TestDraw() { TestHelpers.InMethod(); - Scene scene = new SceneHelpers().SetupScene(); - DynamicTextureModule dtm = new DynamicTextureModule(); - VectorRenderModule vrm = new VectorRenderModule(); - SceneHelpers.SetupSceneModules(scene, dtm, vrm); - - SceneObjectGroup so = SceneHelpers.AddSceneObject(scene); + SetupScene(false); + SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); UUID originalTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; - dtm.AddDynamicTextureData( - scene.RegionInfo.RegionID, + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, so.UUID, - vrm.GetContentType(), + m_vrm.GetContentType(), "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;", "", 0); + Assert.That(originalTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); + } + + [Test] + public void TestRepeatSameDraw() + { + TestHelpers.InMethod(); + + string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;"; + + SetupScene(false); + SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + "", + 0); + + UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + "", + 0); + + Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); + } + + [Test] + public void TestRepeatSameDrawDifferentExtraParams() + { + TestHelpers.InMethod(); + + string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;"; + + SetupScene(false); + SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + "", + 0); + + UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + "alpha:250", + 0); + + Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); + } + + [Test] + public void TestRepeatSameDrawContainingImage() + { + TestHelpers.InMethod(); + + string dtText + = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://localhost/shouldnotexist.png"; + + SetupScene(false); + SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + "", + 0); + + UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + "", + 0); + + Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); + } + + [Test] + public void TestDrawReusingTexture() + { + TestHelpers.InMethod(); + + SetupScene(true); + SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); + UUID originalTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;", + "", + 0); Assert.That(originalTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); } + + [Test] + public void TestRepeatSameDrawReusingTexture() + { + TestHelpers.InMethod(); + + string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;"; + + SetupScene(true); + SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + "", + 0); + + UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + "", + 0); + + Assert.That(firstDynamicTextureID, Is.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); + } + + [Test] + public void TestRepeatSameDrawDifferentExtraParamsReusingTexture() + { + TestHelpers.InMethod(); + + string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;"; + + SetupScene(true); + SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + "", + 0); + + UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + "alpha:250", + 0); + + Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); + } + + [Test] + public void TestRepeatSameDrawContainingImageReusingTexture() + { + TestHelpers.InMethod(); + + string dtText + = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://localhost/shouldnotexist.png"; + + SetupScene(true); + SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + "", + 0); + + UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + "", + 0); + + Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); + } } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs index 018c190133..7c9c2446ab 100644 --- a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs @@ -30,6 +30,7 @@ using System.Drawing; using System.Drawing.Imaging; using System.Globalization; using System.IO; +using System.Linq; using System.Net; using Nini.Config; using OpenMetaverse; @@ -47,7 +48,6 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private string m_name = "VectorRenderModule"; private Scene m_scene; private IDynamicTextureManager m_textureManager; private Graphics m_graph; @@ -61,12 +61,12 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender public string GetContentType() { - return ("vector"); + return "vector"; } public string GetName() { - return m_name; + return Name; } public bool SupportsAsynchronous() @@ -74,14 +74,26 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender return true; } +// public bool AlwaysIdenticalConversion(string bodyData, string extraParams) +// { +// string[] lines = GetLines(bodyData); +// return lines.Any((str, r) => str.StartsWith("Image")); +// } + public byte[] ConvertUrl(string url, string extraParams) { return null; } - public byte[] ConvertStream(Stream data, string extraParams) + public byte[] ConvertData(string bodyData, string extraParams) { - return null; + bool reuseable; + return Draw(bodyData, extraParams, out reuseable); + } + + private byte[] ConvertData(string bodyData, string extraParams, out bool reuseable) + { + return Draw(bodyData, extraParams, out reuseable); } public bool AsyncConvertUrl(UUID id, string url, string extraParams) @@ -91,7 +103,12 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender public bool AsyncConvertData(UUID id, string bodyData, string extraParams) { - Draw(bodyData, id, extraParams); + // XXX: This isn't actually being done asynchronously! + bool reuseable; + byte[] data = ConvertData(bodyData, extraParams, out reuseable); + + m_textureManager.ReturnData(id, data, reuseable); + return true; } @@ -152,7 +169,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender public string Name { - get { return m_name; } + get { return "VectorRenderModule"; } } public bool IsSharedModule @@ -162,7 +179,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender #endregion - private void Draw(string data, UUID id, string extraParams) + private byte[] Draw(string data, string extraParams, out bool reuseable) { // We need to cater for old scripts that didnt use extraParams neatly, they use either an integer size which represents both width and height, or setalpha // we will now support multiple comma seperated params in the form width:256,height:512,alpha:255 @@ -343,7 +360,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender } } - GDIDraw(data, graph, altDataDelim); + GDIDraw(data, graph, altDataDelim, out reuseable); } byte[] imageJ2000 = new byte[0]; @@ -359,7 +376,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender e.Message, e.StackTrace); } - m_textureManager.ReturnData(id, imageJ2000); + return imageJ2000; } finally { @@ -434,8 +451,21 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender } */ - private void GDIDraw(string data, Graphics graph, char dataDelim) + /// + /// Split input data into discrete command lines. + /// + /// + /// + /// + private string[] GetLines(string data, char dataDelim) { + char[] lineDelimiter = { dataDelim }; + return data.Split(lineDelimiter); + } + + private void GDIDraw(string data, Graphics graph, char dataDelim, out bool reuseable) + { + reuseable = true; Point startPoint = new Point(0, 0); Point endPoint = new Point(0, 0); Pen drawPen = null; @@ -450,11 +480,9 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender myFont = new Font(fontName, fontSize); myBrush = new SolidBrush(Color.Black); - char[] lineDelimiter = {dataDelim}; char[] partsDelimiter = {','}; - string[] lines = data.Split(lineDelimiter); - foreach (string line in lines) + foreach (string line in GetLines(data, dataDelim)) { string nextLine = line.Trim(); //replace with switch, or even better, do some proper parsing @@ -485,6 +513,10 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender } else if (nextLine.StartsWith("Image")) { + // We cannot reuse any generated texture involving fetching an image via HTTP since that image + // can change. + reuseable = false; + float x = 0; float y = 0; GetParams(partsDelimiter, ref nextLine, 5, ref x, ref y); diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index 3f848ed1f7..4694b148b4 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs @@ -414,6 +414,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void LoadPlugins() { m_plugineffects = new Dictionary(); + LoadPlugins(Assembly.GetCallingAssembly()); string plugineffectsPath = "Terrain"; // Load the files in the Terrain/ dir @@ -427,32 +428,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain try { Assembly library = Assembly.LoadFrom(file); - foreach (Type pluginType in library.GetTypes()) - { - try - { - if (pluginType.IsAbstract || pluginType.IsNotPublic) - continue; - - string typeName = pluginType.Name; - - if (pluginType.GetInterface("ITerrainEffect", false) != null) - { - ITerrainEffect terEffect = (ITerrainEffect) Activator.CreateInstance(library.GetType(pluginType.ToString())); - - InstallPlugin(typeName, terEffect); - } - else if (pluginType.GetInterface("ITerrainLoader", false) != null) - { - ITerrainLoader terLoader = (ITerrainLoader) Activator.CreateInstance(library.GetType(pluginType.ToString())); - m_loaders[terLoader.FileExtension] = terLoader; - m_log.Info("L ... " + typeName); - } - } - catch (AmbiguousMatchException) - { - } - } + LoadPlugins(library); } catch (BadImageFormatException) { @@ -460,6 +436,36 @@ namespace OpenSim.Region.CoreModules.World.Terrain } } + private void LoadPlugins(Assembly library) + { + foreach (Type pluginType in library.GetTypes()) + { + try + { + if (pluginType.IsAbstract || pluginType.IsNotPublic) + continue; + + string typeName = pluginType.Name; + + if (pluginType.GetInterface("ITerrainEffect", false) != null) + { + ITerrainEffect terEffect = (ITerrainEffect)Activator.CreateInstance(library.GetType(pluginType.ToString())); + + InstallPlugin(typeName, terEffect); + } + else if (pluginType.GetInterface("ITerrainLoader", false) != null) + { + ITerrainLoader terLoader = (ITerrainLoader)Activator.CreateInstance(library.GetType(pluginType.ToString())); + m_loaders[terLoader.FileExtension] = terLoader; + m_log.Info("L ... " + typeName); + } + } + catch (AmbiguousMatchException) + { + } + } + } + public void InstallPlugin(string pluginName, ITerrainEffect effect) { lock (m_plugineffects) @@ -1176,7 +1182,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void InterfaceRunPluginEffect(Object[] args) { - if ((string) args[0] == "list") + string firstArg = (string)args[0]; + if (firstArg == "list") { m_log.Info("List of loaded plugins"); foreach (KeyValuePair kvp in m_plugineffects) @@ -1185,14 +1192,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain } return; } - if ((string) args[0] == "reload") + if (firstArg == "reload") { LoadPlugins(); return; } - if (m_plugineffects.ContainsKey((string) args[0])) + if (m_plugineffects.ContainsKey(firstArg)) { - m_plugineffects[(string) args[0]].RunEffect(m_channel); + m_plugineffects[firstArg].RunEffect(m_channel); CheckForTerrainUpdates(); } else diff --git a/OpenSim/Region/Framework/Interfaces/IDynamicTextureManager.cs b/OpenSim/Region/Framework/Interfaces/IDynamicTextureManager.cs index 8954513c06..1a3bcbbc71 100644 --- a/OpenSim/Region/Framework/Interfaces/IDynamicTextureManager.cs +++ b/OpenSim/Region/Framework/Interfaces/IDynamicTextureManager.cs @@ -33,7 +33,7 @@ namespace OpenSim.Region.Framework.Interfaces public interface IDynamicTextureManager { void RegisterRender(string handleType, IDynamicTextureRender render); - void ReturnData(UUID id, byte[] data); + void ReturnData(UUID id, byte[] data, bool isReuseable); UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url, string extraParams, int updateTimer); @@ -113,8 +113,20 @@ namespace OpenSim.Region.Framework.Interfaces string GetName(); string GetContentType(); bool SupportsAsynchronous(); + +// /// +// /// Return true if converting the input body and extra params data will always result in the same byte[] array +// /// +// /// +// /// This method allows the caller to use a previously generated asset if it has one. +// /// +// /// +// /// +// /// +// bool AlwaysIdenticalConversion(string bodyData, string extraParams); + byte[] ConvertUrl(string url, string extraParams); - byte[] ConvertStream(Stream data, string extraParams); + byte[] ConvertData(string bodyData, string extraParams); bool AsyncConvertUrl(UUID id, string url, string extraParams); bool AsyncConvertData(UUID id, string bodyData, string extraParams); void GetDrawStringSize(string text, string fontName, int fontSize, diff --git a/OpenSim/Region/Framework/Interfaces/IUrlModule.cs b/OpenSim/Region/Framework/Interfaces/IUrlModule.cs index 457444cd83..79e9f9d51e 100644 --- a/OpenSim/Region/Framework/Interfaces/IUrlModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IUrlModule.cs @@ -39,6 +39,8 @@ namespace OpenSim.Region.Framework.Interfaces UUID RequestSecureURL(IScriptModule engine, SceneObjectPart host, UUID itemID); void ReleaseURL(string url); void HttpResponse(UUID request, int status, string body); + void HttpContentType(UUID request, string type); + string GetHttpHeader(UUID request, string header); int GetFreeUrls(); diff --git a/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs b/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs index 44d2d452d5..9457ebb374 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs @@ -50,8 +50,40 @@ using OpenSim.Tests.Common.Mock; namespace OpenSim.Region.Framework.Tests { [TestFixture] - public class UserInventoryTests + public class UserInventoryTests : OpenSimTestCase { + [Test] + public void TestCreateInventoryFolders() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + // For this test both folders will have the same name which is legal in SL user inventories. + string foldersName = "f1"; + + Scene scene = new SceneHelpers().SetupScene(); + UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001)); + + UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, foldersName); + + List oneFolder + = UserInventoryHelpers.GetInventoryFolders(scene.InventoryService, user1.PrincipalID, foldersName); + + Assert.That(oneFolder.Count, Is.EqualTo(1)); + InventoryFolderBase firstRetrievedFolder = oneFolder[0]; + Assert.That(firstRetrievedFolder.Name, Is.EqualTo(foldersName)); + + UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, foldersName); + + List twoFolders + = UserInventoryHelpers.GetInventoryFolders(scene.InventoryService, user1.PrincipalID, foldersName); + + Assert.That(twoFolders.Count, Is.EqualTo(2)); + Assert.That(twoFolders[0].Name, Is.EqualTo(foldersName)); + Assert.That(twoFolders[1].Name, Is.EqualTo(foldersName)); + Assert.That(twoFolders[0].ID, Is.Not.EqualTo(twoFolders[1].ID)); + } + [Test] public void TestGiveInventoryItem() { @@ -83,7 +115,7 @@ namespace OpenSim.Region.Framework.Tests public void TestGiveInventoryFolder() { TestHelpers.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); +// TestHelpers.EnableLogging(); Scene scene = new SceneHelpers().SetupScene(); UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001)); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index b001c51606..45286c0135 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -7208,7 +7208,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - setLinkPrimParams(ScriptBaseClass.LINK_THIS, rules); + setLinkPrimParams(ScriptBaseClass.LINK_THIS, rules, "llSetPrimitiveParams"); ScriptSleep(200); } @@ -7217,7 +7217,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - setLinkPrimParams(linknumber, rules); + setLinkPrimParams(linknumber, rules, "llSetLinkPrimitiveParams"); ScriptSleep(200); } @@ -7226,17 +7226,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - setLinkPrimParams(linknumber, rules); + setLinkPrimParams(linknumber, rules, "llSetLinkPrimitiveParamsFast"); } - protected void setLinkPrimParams(int linknumber, LSL_List rules) + protected void setLinkPrimParams(int linknumber, LSL_List rules, string originFunc) { List parts = GetLinkParts(linknumber); LSL_List remaining = null; + uint rulesParsed = 0; foreach (SceneObjectPart part in parts) - remaining = SetPrimParams(part, rules); + remaining = SetPrimParams(part, rules, originFunc, ref rulesParsed); while (remaining != null && remaining.Length > 2) { @@ -7245,13 +7246,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api parts = GetLinkParts(linknumber); foreach (SceneObjectPart part in parts) - remaining = SetPrimParams(part, rules); + remaining = SetPrimParams(part, rules, originFunc, ref rulesParsed); } } - protected LSL_List SetPrimParams(SceneObjectPart part, LSL_List rules) + protected LSL_List SetPrimParams(SceneObjectPart part, LSL_List rules, string originFunc, ref uint rulesParsed) { int idx = 0; + int idxStart = 0; bool positionChanged = false; LSL_Vector currentPosition = GetPartLocalPos(part); @@ -7260,9 +7262,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { while (idx < rules.Length) { + ++rulesParsed; int code = rules.GetLSLIntegerItem(idx++); int remain = rules.Length - idx; + idxStart = idx; int face; LSL_Vector v; @@ -7639,7 +7643,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } catch (InvalidCastException e) { - ShoutError(e.Message); + ShoutError(string.Format( + "{0} error running rule #{1}: arg #{2} ", + originFunc, rulesParsed, idx - idxStart) + e.Message); } finally { @@ -10113,31 +10119,30 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Float llListStatistics(int operation, LSL_List src) { m_host.AddScriptLPS(1); - LSL_List nums = LSL_List.ToDoubleList(src); switch (operation) { case ScriptBaseClass.LIST_STAT_RANGE: - return nums.Range(); + return src.Range(); case ScriptBaseClass.LIST_STAT_MIN: - return nums.Min(); + return src.Min(); case ScriptBaseClass.LIST_STAT_MAX: - return nums.Max(); + return src.Max(); case ScriptBaseClass.LIST_STAT_MEAN: - return nums.Mean(); + return src.Mean(); case ScriptBaseClass.LIST_STAT_MEDIAN: - return nums.Median(); + return LSL_List.ToDoubleList(src).Median(); case ScriptBaseClass.LIST_STAT_NUM_COUNT: - return nums.NumericLength(); + return src.NumericLength(); case ScriptBaseClass.LIST_STAT_STD_DEV: - return nums.StdDev(); + return src.StdDev(); case ScriptBaseClass.LIST_STAT_SUM: - return nums.Sum(); + return src.Sum(); case ScriptBaseClass.LIST_STAT_SUM_SQUARES: - return nums.SumSqrs(); + return src.SumSqrs(); case ScriptBaseClass.LIST_STAT_GEOMETRIC_MEAN: - return nums.GeometricMean(); + return src.GeometricMean(); case ScriptBaseClass.LIST_STAT_HARMONIC_MEAN: - return nums.HarmonicMean(); + return src.HarmonicMean(); default: return 0.0; } @@ -10761,7 +10766,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return tid.ToString(); } - public void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules) + public void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules, string originFunc) { SceneObjectPart obj = World.GetSceneObjectPart(new UUID(prim)); if (obj == null) @@ -10770,14 +10775,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (obj.OwnerID != m_host.OwnerID) return; - LSL_List remaining = SetPrimParams(obj, rules); + uint rulesParsed = 0; + LSL_List remaining = SetPrimParams(obj, rules, originFunc, ref rulesParsed); while ((object)remaining != null && remaining.Length > 2) { LSL_Integer newLink = remaining.GetLSLIntegerItem(0); LSL_List newrules = remaining.GetSublist(1, -1); foreach(SceneObjectPart part in GetLinkParts(obj, newLink)){ - remaining = SetPrimParams(part, newrules); + remaining = SetPrimParams(part, newrules, originFunc, ref rulesParsed); } } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 1afa4fbc20..e245684a43 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -140,12 +140,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api internal float m_ScriptDistanceFactor = 1.0f; internal Dictionary m_FunctionPerms = new Dictionary(); + protected IUrlModule m_UrlModule = null; + public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) { m_ScriptEngine = ScriptEngine; m_host = host; m_item = item; + m_UrlModule = m_ScriptEngine.World.RequestModuleInterface(); + if (m_ScriptEngine.Config.GetBoolean("AllowOSFunctions", false)) m_OSFunctionsEnabled = true; @@ -2988,7 +2992,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); InitLSL(); - m_LSL_Api.SetPrimitiveParamsEx(prim, rules); + m_LSL_Api.SetPrimitiveParamsEx(prim, rules, "osSetPrimitiveParams"); } /// @@ -3358,5 +3362,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return new LSL_Key(m_host.ParentGroup.FromPartID.ToString()); } - } + + /// + /// Sets the response type for an HTTP request/response + /// + /// + public void osSetContentType(LSL_Key id, string type) + { + CheckThreatLevel(ThreatLevel.High,"osSetResponseType"); + if (m_UrlModule != null) + m_UrlModule.HttpContentType(new UUID(id),type); + } + + } } \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs index cd58614b58..e97ff9d1ba 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs @@ -424,7 +424,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_String llXorBase64StringsCorrect(string str1, string str2); void print(string str); - void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules); + void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules, string originFunc); LSL_List GetPrimitiveParamsEx(LSL_Key prim, LSL_List rules); } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs index 9ad1c22bd1..06729abe36 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs @@ -40,16 +40,75 @@ using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces { + /// + /// To permit region owners to enable the extended scripting functionality + /// of OSSL, without allowing malicious scripts to access potentially + /// troublesome functions, each OSSL function is assigned a threat level, + /// and access to the functions is granted or denied based on a default + /// threshold set in OpenSim.ini (which can be overridden for individual + /// functions on a case-by-case basis) + /// public enum ThreatLevel { + // Not documented, presumably means permanently disabled ? NoAccess = -1, + + /// + /// Function is no threat at all. It doesn't constitute a threat to + /// either users or the system and has no known side effects. + /// None = 0, + + /// + /// Abuse of this command can cause a nuisance to the region operator, + /// such as log message spew. + /// Nuisance = 1, + + /// + /// Extreme levels of abuse of this function can cause impaired + /// functioning of the region, or very gullible users can be tricked + /// into experiencing harmless effects. + /// VeryLow = 2, + + /// + /// Intentional abuse can cause crashes or malfunction under certain + /// circumstances, which can be easily rectified; or certain users can + /// be tricked into certain situations in an avoidable manner. + /// Low = 3, + + /// + /// Intentional abuse can cause denial of service and crashes with + /// potential of data or state loss; or trusting users can be tricked + /// into embarrassing or uncomfortable situations. + /// Moderate = 4, + + /// + /// Casual abuse can cause impaired functionality or temporary denial + /// of service conditions. Intentional abuse can easily cause crashes + /// with potential data loss, or can be used to trick experienced and + /// cautious users into unwanted situations, or changes global data + /// permanently and without undo ability. + /// High = 5, + + /// + /// Even normal use may, depending on the number of instances, or + /// frequency of use, result in severe service impairment or crash + /// with loss of data, or can be used to cause unwanted or harmful + /// effects on users without giving the user a means to avoid it. + /// VeryHigh = 6, + + /// + /// Even casual use is a danger to region stability, or function allows + /// console or OS command execution, or function allows taking money + /// without consent, or allows deletion or modification of user data, + /// or allows the compromise of sensitive data by design. + /// Severe = 7 }; @@ -306,5 +365,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces /// /// Rezzing object key or NULL_KEY if rezzed by agent or otherwise unknown. LSL_Key osGetRezzingObject(); + + /// + /// Sets the response type for an HTTP request/response + /// + /// + void osSetContentType(LSL_Key id, string type); } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs index e9131e4655..ba1ade2285 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs @@ -955,5 +955,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase { return m_OSSL_Functions.osGetRezzingObject(); } + + public void osSetContentType(LSL_Key id, string type) + { + m_OSSL_Functions.osSetContentType(id,type); + } } } diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs index 9d9df9c4e6..fcb98a5152 100644 --- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs +++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs @@ -1137,7 +1137,7 @@ namespace OpenSim.Region.ScriptEngine.Shared { list ret = new list(); double entry; - for (int i = 0; i < src.Data.Length - 1; i++) + for (int i = 0; i < src.Data.Length; i++) { if (double.TryParse(src.Data[i].ToString(), NumberStyles.Float, Culture.NumberFormatInfo, out entry)) { diff --git a/OpenSim/Services/InventoryService/XInventoryService.cs b/OpenSim/Services/InventoryService/XInventoryService.cs index deacd5a4b4..309dab4501 100644 --- a/OpenSim/Services/InventoryService/XInventoryService.cs +++ b/OpenSim/Services/InventoryService/XInventoryService.cs @@ -94,6 +94,7 @@ namespace OpenSim.Services.InventoryService m_Database = LoadPlugin(dllName, new Object[] {connString, String.Empty}); + if (m_Database == null) throw new Exception("Could not find a storage interface in the given module"); } @@ -326,7 +327,7 @@ namespace OpenSim.Services.InventoryService if (check != null) return false; - if (folder.Type != (short)AssetType.Folder || folder.Type != (short)AssetType.Unknown) + if (folder.Type != (short)AssetType.Folder && folder.Type != (short)AssetType.Unknown) { InventoryFolderBase rootFolder = GetRootFolder(folder.Owner); diff --git a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs index 7598cc360e..fc49169c97 100644 --- a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs @@ -245,7 +245,7 @@ namespace OpenSim.Tests.Common config.AddConfig("Modules"); config.AddConfig("InventoryService"); config.Configs["Modules"].Set("InventoryServices", "LocalInventoryServicesConnector"); - config.Configs["InventoryService"].Set("LocalServiceModule", "OpenSim.Services.InventoryService.dll:InventoryService"); + config.Configs["InventoryService"].Set("LocalServiceModule", "OpenSim.Services.InventoryService.dll:XInventoryService"); config.Configs["InventoryService"].Set("StorageProvider", "OpenSim.Tests.Common.dll"); LocalInventoryServicesConnector inventoryService = new LocalInventoryServicesConnector(); diff --git a/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs b/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs index b3a7c9eec3..87d9410f22 100644 --- a/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs @@ -199,7 +199,9 @@ namespace OpenSim.Tests.Common string[] components = path.Split(new string[] { PATH_DELIMITER }, 2, StringSplitOptions.None); InventoryFolderBase newFolder - = new InventoryFolderBase(UUID.Random(), components[0], parentFolder.Owner, parentFolder.ID); + = new InventoryFolderBase( + UUID.Random(), components[0], parentFolder.Owner, (short)AssetType.Unknown, parentFolder.ID, 0); + inventoryService.AddFolder(newFolder); if (components.Length > 1) diff --git a/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs b/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs new file mode 100644 index 0000000000..bca5979e50 --- /dev/null +++ b/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs @@ -0,0 +1,131 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Data; + +namespace OpenSim.Tests.Common.Mock +{ + public class TestXInventoryDataPlugin : IXInventoryData + { + private Dictionary m_allFolders = new Dictionary(); + private Dictionary m_allItems = new Dictionary(); + + public TestXInventoryDataPlugin(string conn, string realm) {} + + public XInventoryItem[] GetItems(string[] fields, string[] vals) + { + List origItems = Get(fields, vals, m_allItems.Values.ToList()); + + return origItems.Select(i => i.Clone()).ToArray(); + } + + public XInventoryFolder[] GetFolders(string[] fields, string[] vals) + { + List origFolders + = Get(fields, vals, m_allFolders.Values.ToList()); + + return origFolders.Select(f => f.Clone()).ToArray(); + } + + private List Get(string[] fields, string[] vals, List inputEntities) + { + List entities = inputEntities; + + for (int i = 0; i < fields.Length; i++) + { + entities + = entities.Where( + e => + { + FieldInfo fi = typeof(T).GetField(fields[i]); + if (fi == null) + throw new NotImplementedException(string.Format("No field {0} for val {1}", fields[i], vals[i])); + + return fi.GetValue(e).ToString() == vals[i]; + } + ).ToList(); + } + + return entities; + } + + public bool StoreFolder(XInventoryFolder folder) + { + m_allFolders[folder.folderID] = folder.Clone(); + +// Console.WriteLine("Added folder {0} {1}", folder.folderName, folder.folderID); + + return true; + } + + public bool StoreItem(XInventoryItem item) + { + m_allItems[item.inventoryID] = item.Clone(); + +// Console.WriteLine("Added item {0} {1}, creator {2}, owner {3}", item.inventoryName, item.inventoryID, item.creatorID, item.avatarID); + + return true; + } + + public bool DeleteFolders(string field, string val) + { + return DeleteFolders(new string[] { field }, new string[] { val }); + } + + public bool DeleteFolders(string[] fields, string[] vals) + { + XInventoryFolder[] foldersToDelete = GetFolders(fields, vals); + Array.ForEach(foldersToDelete, f => m_allFolders.Remove(f.folderID)); + + return true; + } + + public bool DeleteItems(string field, string val) + { + return DeleteItems(new string[] { field }, new string[] { val }); + } + + public bool DeleteItems(string[] fields, string[] vals) + { + XInventoryItem[] itemsToDelete = GetItems(fields, vals); + Array.ForEach(itemsToDelete, i => m_allItems.Remove(i.inventoryID)); + + return true; + } + + public bool MoveItem(string id, string newParent) { throw new NotImplementedException(); } + public XInventoryItem[] GetActiveGestures(UUID principalID) { throw new NotImplementedException(); } + public int GetAssetPermissions(UUID principalID, UUID assetID) { throw new NotImplementedException(); } + } +} \ No newline at end of file diff --git a/OpenSim/Tests/Common/TestHelpers.cs b/OpenSim/Tests/Common/TestHelpers.cs index 30121fef6a..57da802e6b 100644 --- a/OpenSim/Tests/Common/TestHelpers.cs +++ b/OpenSim/Tests/Common/TestHelpers.cs @@ -95,6 +95,7 @@ namespace OpenSim.Tests.Common public static void EnableLogging() { log4net.Config.XmlConfigurator.Configure(EnableLoggingConfigStream); + EnableLoggingConfigStream.Position = 0; } /// diff --git a/OpenSim/Tests/Torture/NPCTortureTests.cs b/OpenSim/Tests/Performance/NPCPerformanceTests.cs similarity index 98% rename from OpenSim/Tests/Torture/NPCTortureTests.cs rename to OpenSim/Tests/Performance/NPCPerformanceTests.cs index 731df6808c..627765b325 100644 --- a/OpenSim/Tests/Torture/NPCTortureTests.cs +++ b/OpenSim/Tests/Performance/NPCPerformanceTests.cs @@ -47,10 +47,10 @@ using OpenSim.Services.AvatarService; using OpenSim.Tests.Common; using OpenSim.Tests.Common.Mock; -namespace OpenSim.Tests.Torture +namespace OpenSim.Tests.Performance { /// - /// NPC torture tests + /// NPC performance tests /// /// /// Don't rely on the numbers given by these tests - they will vary a lot depending on what is already cached, @@ -58,7 +58,7 @@ namespace OpenSim.Tests.Torture /// earlier tests. /// [TestFixture] - public class NPCTortureTests + public class NPCPerformanceTests { private TestScene scene; private AvatarFactoryModule afm; diff --git a/OpenSim/Tests/Torture/ObjectTortureTests.cs b/OpenSim/Tests/Performance/ObjectPerformanceTests.cs similarity index 98% rename from OpenSim/Tests/Torture/ObjectTortureTests.cs rename to OpenSim/Tests/Performance/ObjectPerformanceTests.cs index 195d47bd52..2264d86246 100644 --- a/OpenSim/Tests/Torture/ObjectTortureTests.cs +++ b/OpenSim/Tests/Performance/ObjectPerformanceTests.cs @@ -36,10 +36,10 @@ using OpenSim.Region.Framework.Scenes; using OpenSim.Tests.Common; using OpenSim.Tests.Common.Mock; -namespace OpenSim.Tests.Torture +namespace OpenSim.Tests.Performance { /// - /// Object torture tests + /// Object performance tests /// /// /// Don't rely on the numbers given by these tests - they will vary a lot depending on what is already cached, @@ -47,7 +47,7 @@ namespace OpenSim.Tests.Torture /// earlier tests. /// [TestFixture] - public class ObjectTortureTests + public class ObjectPerformanceTests { [TearDown] public void TearDown() diff --git a/OpenSim/Tests/Torture/ScriptTortureTests.cs b/OpenSim/Tests/Performance/ScriptPerformanceTests.cs similarity index 98% rename from OpenSim/Tests/Torture/ScriptTortureTests.cs rename to OpenSim/Tests/Performance/ScriptPerformanceTests.cs index 24f278f3f8..d708abd1f4 100644 --- a/OpenSim/Tests/Torture/ScriptTortureTests.cs +++ b/OpenSim/Tests/Performance/ScriptPerformanceTests.cs @@ -42,10 +42,10 @@ using OpenSim.Region.ScriptEngine.XEngine; using OpenSim.Tests.Common; using OpenSim.Tests.Common.Mock; -namespace OpenSim.Tests.Torture +namespace OpenSim.Tests.Performance { /// - /// Script torture tests + /// Script performance tests /// /// /// Don't rely on the numbers given by these tests - they will vary a lot depending on what is already cached, @@ -53,7 +53,7 @@ namespace OpenSim.Tests.Torture /// earlier tests. /// [TestFixture] - public class ScriptTortureTests + public class ScriptPerformanceTests { private TestScene m_scene; private XEngine m_xEngine; diff --git a/OpenSim/Tests/Stress/VectorRenderModuleStressTests.cs b/OpenSim/Tests/Stress/VectorRenderModuleStressTests.cs new file mode 100644 index 0000000000..1f220c01ee --- /dev/null +++ b/OpenSim/Tests/Stress/VectorRenderModuleStressTests.cs @@ -0,0 +1,132 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading; +using log4net.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Scripting.DynamicTexture; +using OpenSim.Region.CoreModules.Scripting.VectorRender; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Serialization; +using OpenSim.Tests.Common; +using OpenSim.Tests.Common.Mock; + +namespace OpenSim.Tests.Stress +{ + [TestFixture] + public class VectorRenderModuleStressTests : OpenSimTestCase + { + public Scene Scene { get; private set; } + public DynamicTextureModule Dtm { get; private set; } + public VectorRenderModule Vrm { get; private set; } + + private void SetupScene(bool reuseTextures) + { + Scene = new SceneHelpers().SetupScene(); + + Dtm = new DynamicTextureModule(); + Dtm.ReuseTextures = reuseTextures; + + Vrm = new VectorRenderModule(); + + SceneHelpers.SetupSceneModules(Scene, Dtm, Vrm); + } + + [Test] + public void TestConcurrentRepeatedDraw() + { + int threads = 4; + TestHelpers.InMethod(); + + SetupScene(false); + + List drawers = new List(); + + for (int i = 0; i < threads; i++) + { + Drawer d = new Drawer(this, i); + drawers.Add(d); + Console.WriteLine("Starting drawer {0}", i); + Util.FireAndForget(o => d.Draw()); + } + + Thread.Sleep(10 * 60 * 1000); + + drawers.ForEach(d => d.Ready = false); + drawers.ForEach(d => Console.WriteLine("Drawer {0} drew {1} textures", d.Number, d.Pass + 1)); + } + + class Drawer + { + public int Number { get; private set; } + public int Pass { get; private set; } + public bool Ready { get; set; } + + private VectorRenderModuleStressTests m_tests; + + public Drawer(VectorRenderModuleStressTests tests, int number) + { + m_tests = tests; + Number = number; + Ready = true; + } + + public void Draw() + { + SceneObjectGroup so = SceneHelpers.AddSceneObject(m_tests.Scene); + + while (Ready) + { + UUID originalTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; + + // Ensure unique text + string text = string.Format("{0:D2}{1}", Number, Pass); + + m_tests.Dtm.AddDynamicTextureData( + m_tests.Scene.RegionInfo.RegionID, + so.UUID, + m_tests.Vrm.GetContentType(), + string.Format("PenColour BLACK; MoveTo 40,220; FontSize 32; Text {0};", text), + "", + 0); + + Assert.That(originalTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); + + Pass++; + } + } + } + } +} \ No newline at end of file diff --git a/prebuild.xml b/prebuild.xml index c626ae7493..ac03d2d383 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -3289,7 +3289,47 @@ - + + + + ../../../bin/ + + + + + ../../../bin/ + + + + ../../../bin/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + ../../../bin/