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
bulletsim^2
Justin Clark-Casey (justincc) 2011-08-30 01:58:32 +01:00
parent 18037d41c4
commit be357f8fee
8 changed files with 168 additions and 24 deletions

View File

@ -136,7 +136,6 @@ namespace OpenSim.Region.ClientStack.Linden
TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset; TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset;
CAPSFetchInventoryDescendents = m_Scene.HandleFetchInventoryDescendentsCAPS; CAPSFetchInventoryDescendents = m_Scene.HandleFetchInventoryDescendentsCAPS;
GetClient = m_Scene.SceneContents.GetControllingClient; GetClient = m_Scene.SceneContents.GetControllingClient;
} }
/// <summary> /// <summary>

View File

@ -257,20 +257,27 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
return true; return true;
} }
public bool SaveBakedTextures(UUID agentId) public Dictionary<BakeType, Primitive.TextureEntryFace> GetBakedTextureFaces(UUID agentId)
{ {
ScenePresence sp = m_scene.GetScenePresence(agentId); ScenePresence sp = m_scene.GetScenePresence(agentId);
if (sp == null || sp.IsChildAgent) if (sp == null)
return false; return new Dictionary<BakeType, Primitive.TextureEntryFace>();
return GetBakedTextureFaces(sp);
}
private Dictionary<BakeType, Primitive.TextureEntryFace> GetBakedTextureFaces(ScenePresence sp)
{
if (sp.IsChildAgent)
return new Dictionary<BakeType, Primitive.TextureEntryFace>();
Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures
= new Dictionary<BakeType, Primitive.TextureEntryFace>();
AvatarAppearance appearance = sp.Appearance; AvatarAppearance appearance = sp.Appearance;
Primitive.TextureEntryFace[] faceTextures = appearance.Texture.FaceTextures; 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))) foreach (int i in Enum.GetValues(typeof(BakeType)))
{ {
BakeType bakeType = (BakeType)i; BakeType bakeType = (BakeType)i;
@ -283,7 +290,31 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
// acd.AgentID, i, acd.Appearance.Texture.FaceTextures[i]); // acd.AgentID, i, acd.Appearance.Texture.FaceTextures[i]);
int ftIndex = (int)AppearanceManager.BakeTypeToAgentTextureIndex(bakeType); 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<BakeType, Primitive.TextureEntryFace> bakedTextures = GetBakedTextureFaces(sp);
if (bakedTextures.Count == 0)
return false;
foreach (BakeType bakeType in bakedTextures.Keys)
{
Primitive.TextureEntryFace bakedTextureFace = bakedTextures[bakeType];
if (bakedTextureFace == null) if (bakedTextureFace == null)
{ {
@ -299,6 +330,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
if (asset != null) if (asset != null)
{ {
asset.Temporary = false; asset.Temporary = false;
asset.Local = false;
m_scene.AssetService.Store(asset); m_scene.AssetService.Store(asset);
} }
else else

View File

@ -26,9 +26,12 @@
*/ */
using System; using System;
using System.Collections.Generic;
using Nini.Config;
using NUnit.Framework; using NUnit.Framework;
using OpenMetaverse; using OpenMetaverse;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Region.CoreModules.Asset;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using OpenSim.Tests.Common; using OpenSim.Tests.Common;
using OpenSim.Tests.Common.Mock; using OpenSim.Tests.Common.Mock;
@ -65,5 +68,53 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
// TODO: Check baked texture // TODO: Check baked texture
Assert.AreEqual(visualParams, sp.Appearance.VisualParams); 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<BakeType, Primitive.TextureEntryFace> 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);
}
} }
} }

View File

@ -129,15 +129,18 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
m_Cache = null; 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) 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 else
{ {
// Short-circuit directly to storage layer // Short-circuit directly to storage layer. This ends up storing temporary and local assets.
// //
scene.UnregisterModuleInterface<IAssetService>(this); scene.UnregisterModuleInterface<IAssetService>(this);
scene.RegisterModuleInterface<IAssetService>(m_AssetService); scene.RegisterModuleInterface<IAssetService>(m_AssetService);
@ -246,9 +249,21 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
m_Cache.Cache(asset); m_Cache.Cache(asset);
if (asset.Temporary || asset.Local) 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 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) public bool UpdateContent(string id, byte[] data)

View File

@ -25,6 +25,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
using System.Collections.Generic;
using OpenMetaverse; using OpenMetaverse;
using OpenSim.Framework; using OpenSim.Framework;
@ -39,7 +40,23 @@ namespace OpenSim.Region.Framework.Interfaces
/// <returns></returns> /// <returns></returns>
bool SendAppearance(UUID agentId); bool SendAppearance(UUID agentId);
/// <summary>
/// Return the baked texture ids of the given agent.
/// </summary>
/// <param name="agentId"></param>
/// <returns>An empty list if this agent has no baked textures (e.g. because it's a child agent)</returns>
Dictionary<BakeType, Primitive.TextureEntryFace> GetBakedTextureFaces(UUID agentId);
/// <summary>
/// Save the baked textures for the given agent permanently in the asset database.
/// </summary>
/// <remarks>
/// This is used to preserve apperance textures for NPCs
/// </remarks>
/// <param name="agentId"></param>
/// <returns>true if a valid agent was found, false otherwise</returns>
bool SaveBakedTextures(UUID agentId); bool SaveBakedTextures(UUID agentId);
bool ValidateBakedTextureCache(IClientAPI client); bool ValidateBakedTextureCache(IClientAPI client);
void QueueAppearanceSend(UUID agentid); void QueueAppearanceSend(UUID agentid);
void QueueAppearanceSave(UUID agentid); void QueueAppearanceSave(UUID agentid);

View File

@ -1695,9 +1695,9 @@ namespace OpenSim.Region.Framework.Scenes
/// </param> /// </param>
public void MoveToTarget(Vector3 pos, bool noFly) public void MoveToTarget(Vector3 pos, bool noFly)
{ {
// m_log.DebugFormat( m_log.DebugFormat(
// "[SCENE PRESENCE]: Avatar {0} received request to move to position {1} in {2}", "[SCENE PRESENCE]: Avatar {0} received request to move to position {1} in {2}",
// Name, pos, m_scene.RegionInfo.RegionName); Name, pos, m_scene.RegionInfo.RegionName);
if (pos.X < 0 || pos.X >= Constants.RegionSize if (pos.X < 0 || pos.X >= Constants.RegionSize
|| pos.Y < 0 || pos.Y >= Constants.RegionSize || pos.Y < 0 || pos.Y >= Constants.RegionSize

View File

@ -83,7 +83,7 @@ namespace OpenSim.Services.AssetService
if (assetLoaderEnabled) 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( m_AssetLoader.ForEachDefaultXmlAsset(
loaderArgs, 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); // "[ASSET SERVICE]: Storing asset {0} {1}, bytes {2}", asset.Name, asset.FullID, asset.Data.Length);
m_Database.StoreAsset(asset); 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; return asset.ID;
} }

View File

@ -40,6 +40,7 @@ using OpenSim.Region.Framework;
using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.CoreModules.Avatar.Gods; using OpenSim.Region.CoreModules.Avatar.Gods;
using OpenSim.Region.CoreModules.Asset;
using OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset; using OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset;
using OpenSim.Region.CoreModules.ServiceConnectorsOut.Authentication; using OpenSim.Region.CoreModules.ServiceConnectorsOut.Authentication;
using OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory; using OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory;
@ -56,6 +57,11 @@ namespace OpenSim.Tests.Common
/// </summary> /// </summary>
public class SceneHelpers public class SceneHelpers
{ {
public static TestScene SetupScene()
{
return SetupScene(null);
}
/// <summary> /// <summary>
/// Set up a test scene /// Set up a test scene
/// </summary> /// </summary>
@ -63,9 +69,14 @@ namespace OpenSim.Tests.Common
/// Automatically starts service threads, as would the normal runtime. /// Automatically starts service threads, as would the normal runtime.
/// </remarks> /// </remarks>
/// <returns></returns> /// <returns></returns>
public static TestScene SetupScene() public static TestScene SetupScene(CoreAssetCache cache)
{ {
return SetupScene("Unit test region", UUID.Random(), 1000, 1000); return SetupScene("Unit test region", UUID.Random(), 1000, 1000, cache);
}
public static TestScene SetupScene(string name, UUID id, uint x, uint y)
{
return SetupScene(name, id, x, y, null);
} }
/// <summary> /// <summary>
@ -78,7 +89,7 @@ namespace OpenSim.Tests.Common
/// <param name="y">Y co-ordinate of the region</param> /// <param name="y">Y co-ordinate of the region</param>
/// <param name="cm">This should be the same if simulating two scenes within a standalone</param> /// <param name="cm">This should be the same if simulating two scenes within a standalone</param>
/// <returns></returns> /// <returns></returns>
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); Console.WriteLine("Setting up test scene {0}", name);
@ -103,7 +114,7 @@ namespace OpenSim.Tests.Common
godsModule.Initialise(testScene, new IniConfigSource()); godsModule.Initialise(testScene, new IniConfigSource());
testScene.AddModule(godsModule.Name, godsModule); testScene.AddModule(godsModule.Name, godsModule);
LocalAssetServicesConnector assetService = StartAssetService(testScene); LocalAssetServicesConnector assetService = StartAssetService(testScene, cache);
StartAuthenticationService(testScene); StartAuthenticationService(testScene);
LocalInventoryServicesConnector inventoryService = StartInventoryService(testScene); LocalInventoryServicesConnector inventoryService = StartInventoryService(testScene);
StartGridService(testScene); StartGridService(testScene);
@ -132,7 +143,7 @@ namespace OpenSim.Tests.Common
return testScene; return testScene;
} }
private static LocalAssetServicesConnector StartAssetService(Scene testScene) private static LocalAssetServicesConnector StartAssetService(Scene testScene, CoreAssetCache cache)
{ {
LocalAssetServicesConnector assetService = new LocalAssetServicesConnector(); LocalAssetServicesConnector assetService = new LocalAssetServicesConnector();
IConfigSource config = new IniConfigSource(); IConfigSource config = new IniConfigSource();
@ -145,6 +156,20 @@ namespace OpenSim.Tests.Common
assetService.Initialise(config); assetService.Initialise(config);
assetService.AddRegion(testScene); 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); assetService.RegionLoaded(testScene);
testScene.AddRegionModule(assetService.Name, assetService); testScene.AddRegionModule(assetService.Name, assetService);