From be357f8feeb438e3292292d163918a307d69c69a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 30 Aug 2011 01:58:32 +0100 Subject: Fix bug in persisting saved appearances for npcs Assets have to be marked non-local as well as non-temporary to persist. This is now done. Hopefully addresses http://opensimulator.org/mantis/view.php?id=5660 --- .../Linden/Caps/BunchOfCaps/BunchOfCaps.cs | 1 - .../Avatar/AvatarFactory/AvatarFactoryModule.cs | 48 ++++++++++++++++---- .../Tests/AvatarFactoryModuleTests.cs | 51 ++++++++++++++++++++++ .../Asset/LocalAssetServiceConnector.cs | 25 ++++++++--- .../Region/Framework/Interfaces/IAvatarFactory.cs | 17 ++++++++ OpenSim/Region/Framework/Scenes/ScenePresence.cs | 6 +-- OpenSim/Services/AssetService/AssetService.cs | 9 +++- OpenSim/Tests/Common/Helpers/SceneHelpers.cs | 35 ++++++++++++--- 8 files changed, 168 insertions(+), 24 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index ff889ea..d1ce5df 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs @@ -136,7 +136,6 @@ namespace OpenSim.Region.ClientStack.Linden TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset; CAPSFetchInventoryDescendents = m_Scene.HandleFetchInventoryDescendentsCAPS; GetClient = m_Scene.SceneContents.GetControllingClient; - } /// diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index 4627701..f34b6d2 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs @@ -257,20 +257,27 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory return true; } - public bool SaveBakedTextures(UUID agentId) + public Dictionary GetBakedTextureFaces(UUID agentId) { ScenePresence sp = m_scene.GetScenePresence(agentId); - if (sp == null || sp.IsChildAgent) - return false; + if (sp == null) + return new Dictionary(); + + return GetBakedTextureFaces(sp); + } + + private Dictionary GetBakedTextureFaces(ScenePresence sp) + { + if (sp.IsChildAgent) + return new Dictionary(); + + Dictionary bakedTextures + = new Dictionary(); AvatarAppearance appearance = sp.Appearance; Primitive.TextureEntryFace[] faceTextures = appearance.Texture.FaceTextures; - m_log.DebugFormat( - "[AV FACTORY]: Permanently saving baked textures for {0} in {1}", - sp.Name, m_scene.RegionInfo.RegionName); - foreach (int i in Enum.GetValues(typeof(BakeType))) { BakeType bakeType = (BakeType)i; @@ -283,7 +290,31 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // acd.AgentID, i, acd.Appearance.Texture.FaceTextures[i]); int ftIndex = (int)AppearanceManager.BakeTypeToAgentTextureIndex(bakeType); - Primitive.TextureEntryFace bakedTextureFace = faceTextures[ftIndex]; + bakedTextures[bakeType] = faceTextures[ftIndex]; + } + + return bakedTextures; + } + + public bool SaveBakedTextures(UUID agentId) + { + ScenePresence sp = m_scene.GetScenePresence(agentId); + + if (sp == null) + return false; + + m_log.DebugFormat( + "[AV FACTORY]: Permanently saving baked textures for {0} in {1}", + sp.Name, m_scene.RegionInfo.RegionName); + + Dictionary bakedTextures = GetBakedTextureFaces(sp); + + if (bakedTextures.Count == 0) + return false; + + foreach (BakeType bakeType in bakedTextures.Keys) + { + Primitive.TextureEntryFace bakedTextureFace = bakedTextures[bakeType]; if (bakedTextureFace == null) { @@ -299,6 +330,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory if (asset != null) { asset.Temporary = false; + asset.Local = false; m_scene.AssetService.Store(asset); } else diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs index b831b31..7b2f14e 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs @@ -26,9 +26,12 @@ */ using System; +using System.Collections.Generic; +using Nini.Config; using NUnit.Framework; using OpenMetaverse; using OpenSim.Framework; +using OpenSim.Region.CoreModules.Asset; using OpenSim.Region.Framework.Scenes; using OpenSim.Tests.Common; using OpenSim.Tests.Common.Mock; @@ -65,5 +68,53 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // TODO: Check baked texture Assert.AreEqual(visualParams, sp.Appearance.VisualParams); } + + [Test] + public void TestSaveBakedTextures() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + UUID userId = TestHelpers.ParseTail(0x1); + UUID eyesTextureId = TestHelpers.ParseTail(0x2); + + // We need an asset cache because otherwise the LocalAssetServiceConnector will short-circuit directly + // to the AssetService, which will then store temporary and local assets permanently + CoreAssetCache assetCache = new CoreAssetCache(); + + AvatarFactoryModule afm = new AvatarFactoryModule(); + TestScene scene = SceneHelpers.SetupScene(assetCache); + SceneHelpers.SetupSceneModules(scene, afm); + IClientAPI tc = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; + + // TODO: Use the actual BunchOfCaps functionality once we slot in the CapabilitiesModules + AssetBase uploadedAsset; + uploadedAsset = new AssetBase(eyesTextureId, "Baked Texture", (sbyte)AssetType.Texture, userId.ToString()); + uploadedAsset.Data = new byte[] { 2 }; + uploadedAsset.Temporary = true; + uploadedAsset.Local = true; // Local assets aren't persisted, non-local are + scene.AssetService.Store(uploadedAsset); + + byte[] visualParams = new byte[AvatarAppearance.VISUALPARAM_COUNT]; + for (byte i = 0; i < visualParams.Length; i++) + visualParams[i] = i; + + Primitive.TextureEntry bakedTextureEntry = new Primitive.TextureEntry(TestHelpers.ParseTail(0x10)); + uint eyesFaceIndex = (uint)AppearanceManager.BakeTypeToAgentTextureIndex(BakeType.Eyes); + Primitive.TextureEntryFace eyesFace = bakedTextureEntry.CreateFace(eyesFaceIndex); + eyesFace.TextureID = eyesTextureId; + + afm.SetAppearanceFromClient(tc, bakedTextureEntry, visualParams); + afm.SaveBakedTextures(userId); +// Dictionary bakedTextures = afm.GetBakedTextureFaces(userId); + + // We should also inpsect the asset data store layer directly, but this is difficult to get at right now. + assetCache.Clear(); + + AssetBase eyesBake = scene.AssetService.Get(eyesTextureId.ToString()); + Assert.That(eyesBake, Is.Not.Null); + Assert.That(eyesBake.Temporary, Is.False); + Assert.That(eyesBake.Local, Is.False); + } } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs index 51d1d59..cc5d061 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs @@ -129,15 +129,18 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset m_Cache = null; } - m_log.InfoFormat("[LOCAL ASSET SERVICES CONNECTOR]: Enabled local assets for region {0}", scene.RegionInfo.RegionName); + m_log.DebugFormat( + "[LOCAL ASSET SERVICES CONNECTOR]: Enabled connector for region {0}", scene.RegionInfo.RegionName); if (m_Cache != null) { - m_log.InfoFormat("[LOCAL ASSET SERVICES CONNECTOR]: Enabled asset caching for region {0}", scene.RegionInfo.RegionName); + m_log.DebugFormat( + "[LOCAL ASSET SERVICES CONNECTOR]: Enabled asset caching for region {0}", + scene.RegionInfo.RegionName); } else { - // Short-circuit directly to storage layer + // Short-circuit directly to storage layer. This ends up storing temporary and local assets. // scene.UnregisterModuleInterface(this); scene.RegisterModuleInterface(m_AssetService); @@ -246,9 +249,21 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset m_Cache.Cache(asset); if (asset.Temporary || asset.Local) + { +// m_log.DebugFormat( +// "[LOCAL ASSET SERVICE CONNECTOR]: Returning asset {0} {1} without querying database since status Temporary = {2}, Local = {3}", +// asset.Name, asset.ID, asset.Temporary, asset.Local); + return asset.ID; - - return m_AssetService.Store(asset); + } + else + { +// m_log.DebugFormat( +// "[LOCAL ASSET SERVICE CONNECTOR]: Passing {0} {1} on to asset service for storage, status Temporary = {2}, Local = {3}", +// asset.Name, asset.ID, asset.Temporary, asset.Local); + + return m_AssetService.Store(asset); + } } public bool UpdateContent(string id, byte[] data) diff --git a/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs b/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs index 6817725..4dbddf4 100644 --- a/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs +++ b/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs @@ -25,6 +25,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +using System.Collections.Generic; using OpenMetaverse; using OpenSim.Framework; @@ -39,7 +40,23 @@ namespace OpenSim.Region.Framework.Interfaces /// bool SendAppearance(UUID agentId); + /// + /// Return the baked texture ids of the given agent. + /// + /// + /// An empty list if this agent has no baked textures (e.g. because it's a child agent) + Dictionary GetBakedTextureFaces(UUID agentId); + + /// + /// Save the baked textures for the given agent permanently in the asset database. + /// + /// + /// This is used to preserve apperance textures for NPCs + /// + /// + /// true if a valid agent was found, false otherwise bool SaveBakedTextures(UUID agentId); + bool ValidateBakedTextureCache(IClientAPI client); void QueueAppearanceSend(UUID agentid); void QueueAppearanceSave(UUID agentid); diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 4148d4b..4143d44 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1695,9 +1695,9 @@ namespace OpenSim.Region.Framework.Scenes /// public void MoveToTarget(Vector3 pos, bool noFly) { -// m_log.DebugFormat( -// "[SCENE PRESENCE]: Avatar {0} received request to move to position {1} in {2}", -// Name, pos, m_scene.RegionInfo.RegionName); + m_log.DebugFormat( + "[SCENE PRESENCE]: Avatar {0} received request to move to position {1} in {2}", + Name, pos, m_scene.RegionInfo.RegionName); if (pos.X < 0 || pos.X >= Constants.RegionSize || pos.Y < 0 || pos.Y >= Constants.RegionSize diff --git a/OpenSim/Services/AssetService/AssetService.cs b/OpenSim/Services/AssetService/AssetService.cs index d40aa4b..2ea513b 100644 --- a/OpenSim/Services/AssetService/AssetService.cs +++ b/OpenSim/Services/AssetService/AssetService.cs @@ -83,7 +83,7 @@ namespace OpenSim.Services.AssetService if (assetLoaderEnabled) { - m_log.InfoFormat("[ASSET]: Loading default asset set from {0}", loaderArgs); + m_log.DebugFormat("[ASSET]: Loading default asset set from {0}", loaderArgs); m_AssetLoader.ForEachDefaultXmlAsset( loaderArgs, @@ -100,7 +100,7 @@ namespace OpenSim.Services.AssetService }); } - m_log.Info("[ASSET SERVICE]: Local asset service enabled"); + m_log.Debug("[ASSET SERVICE]: Local asset service enabled"); } } } @@ -180,6 +180,11 @@ namespace OpenSim.Services.AssetService // "[ASSET SERVICE]: Storing asset {0} {1}, bytes {2}", asset.Name, asset.FullID, asset.Data.Length); m_Database.StoreAsset(asset); } +// else +// { +// m_log.DebugFormat( +// "[ASSET SERVICE]: Not storing asset {0} {1}, bytes {2} as it already exists", asset.Name, asset.FullID, asset.Data.Length); +// } return asset.ID; } diff --git a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs index 086a725..2cf40d7 100644 --- a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs @@ -40,6 +40,7 @@ using OpenSim.Region.Framework; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.CoreModules.Avatar.Gods; +using OpenSim.Region.CoreModules.Asset; using OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset; using OpenSim.Region.CoreModules.ServiceConnectorsOut.Authentication; using OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory; @@ -56,6 +57,11 @@ namespace OpenSim.Tests.Common /// public class SceneHelpers { + public static TestScene SetupScene() + { + return SetupScene(null); + } + /// /// Set up a test scene /// @@ -63,9 +69,14 @@ namespace OpenSim.Tests.Common /// Automatically starts service threads, as would the normal runtime. /// /// - public static TestScene SetupScene() + public static TestScene SetupScene(CoreAssetCache cache) + { + return SetupScene("Unit test region", UUID.Random(), 1000, 1000, cache); + } + + public static TestScene SetupScene(string name, UUID id, uint x, uint y) { - return SetupScene("Unit test region", UUID.Random(), 1000, 1000); + return SetupScene(name, id, x, y, null); } /// @@ -78,7 +89,7 @@ namespace OpenSim.Tests.Common /// Y co-ordinate of the region /// This should be the same if simulating two scenes within a standalone /// - public static TestScene SetupScene(string name, UUID id, uint x, uint y) + public static TestScene SetupScene(string name, UUID id, uint x, uint y, CoreAssetCache cache) { Console.WriteLine("Setting up test scene {0}", name); @@ -103,7 +114,7 @@ namespace OpenSim.Tests.Common godsModule.Initialise(testScene, new IniConfigSource()); testScene.AddModule(godsModule.Name, godsModule); - LocalAssetServicesConnector assetService = StartAssetService(testScene); + LocalAssetServicesConnector assetService = StartAssetService(testScene, cache); StartAuthenticationService(testScene); LocalInventoryServicesConnector inventoryService = StartInventoryService(testScene); StartGridService(testScene); @@ -132,7 +143,7 @@ namespace OpenSim.Tests.Common return testScene; } - private static LocalAssetServicesConnector StartAssetService(Scene testScene) + private static LocalAssetServicesConnector StartAssetService(Scene testScene, CoreAssetCache cache) { LocalAssetServicesConnector assetService = new LocalAssetServicesConnector(); IConfigSource config = new IniConfigSource(); @@ -145,6 +156,20 @@ namespace OpenSim.Tests.Common assetService.Initialise(config); assetService.AddRegion(testScene); + + if (cache != null) + { + IConfigSource cacheConfig = new IniConfigSource(); + cacheConfig.AddConfig("Modules"); + cacheConfig.Configs["Modules"].Set("AssetCaching", "CoreAssetCache"); + cacheConfig.AddConfig("AssetCache"); + + cache.Initialise(cacheConfig); + cache.AddRegion(testScene); + cache.RegionLoaded(testScene); + testScene.AddRegionModule(cache.Name, cache); + } + assetService.RegionLoaded(testScene); testScene.AddRegionModule(assetService.Name, assetService); -- cgit v1.1