From c2ea7b99e1cdbc06035e12306a71712f763b0818 Mon Sep 17 00:00:00 2001 From: MW Date: Tue, 25 Mar 2008 18:48:07 +0000 Subject: Moved Avatar appearance Factory to its own project so that the reference to MySQLDatabaseMapper could be removed from Region.Environment. Added a using OpenSim.Framework.Data statement to MySQLDatabaseMapper , to try to fix the build problem that has been reported on the mailing list. --- .../Data.MySQLMapper/MySQLDatabaseMapper.cs | 1 + OpenSim/Region/Environment/ModuleLoader.cs | 18 +- .../Environment/Modules/AppearanceTableMapper.cs | 7 +- .../Environment/Modules/AvatarFactoryModule.cs | 4 +- OpenSim/Region/Environment/Scenes/Scene.cs | 22 +- .../Modules/AvatarFactory/AppearanceTableMapper.cs | 242 +++++++++++++++ .../Modules/AvatarFactory/AvatarFactoryModule.cs | 337 +++++++++++++++++++++ .../AvatarFactory/Properties/AssemblyInfo.cs | 36 +++ prebuild.xml | 30 +- 9 files changed, 682 insertions(+), 15 deletions(-) create mode 100644 OpenSim/Region/Modules/AvatarFactory/AppearanceTableMapper.cs create mode 100644 OpenSim/Region/Modules/AvatarFactory/AvatarFactoryModule.cs create mode 100644 OpenSim/Region/Modules/AvatarFactory/Properties/AssemblyInfo.cs diff --git a/OpenSim/Framework/Data.MySQLMapper/MySQLDatabaseMapper.cs b/OpenSim/Framework/Data.MySQLMapper/MySQLDatabaseMapper.cs index da3b6a5..ae58f00 100644 --- a/OpenSim/Framework/Data.MySQLMapper/MySQLDatabaseMapper.cs +++ b/OpenSim/Framework/Data.MySQLMapper/MySQLDatabaseMapper.cs @@ -27,6 +27,7 @@ using System.Data.Common; using MySql.Data.MySqlClient; +using OpenSim.Framework.Data; namespace OpenSim.Framework.Data.MySQLMapper { diff --git a/OpenSim/Region/Environment/ModuleLoader.cs b/OpenSim/Region/Environment/ModuleLoader.cs index 4a8bf7b..7fb8d8a 100644 --- a/OpenSim/Region/Environment/ModuleLoader.cs +++ b/OpenSim/Region/Environment/ModuleLoader.cs @@ -114,15 +114,15 @@ namespace OpenSim.Region.Environment m_loadedSharedModules.Add(loadMod.Name, loadMod); } - AvatarFactoryModule avatarFactory = new AvatarFactoryModule(); - if (m_loadedSharedModules.ContainsKey(avatarFactory.Name)) - { - m_log.ErrorFormat("[MODULES]: Module name \"{0}\" already exists in module list. Module type {1} not added!", avatarFactory.Name, "AvarFactoryModule"); - } - else - { - m_loadedSharedModules.Add(avatarFactory.Name, avatarFactory); - } + // AvatarFactoryModule avatarFactory = new AvatarFactoryModule(); + // if (m_loadedSharedModules.ContainsKey(avatarFactory.Name)) + // { + // m_log.ErrorFormat("[MODULES]: Module name \"{0}\" already exists in module list. Module type {1} not added!", avatarFactory.Name, "AvarFactoryModule"); + // } + // else + // { + // m_loadedSharedModules.Add(avatarFactory.Name, avatarFactory); + // } XMLRPCModule xmlRpcMod = new XMLRPCModule(); if (m_loadedSharedModules.ContainsKey(xmlRpcMod.Name)) diff --git a/OpenSim/Region/Environment/Modules/AppearanceTableMapper.cs b/OpenSim/Region/Environment/Modules/AppearanceTableMapper.cs index 0dc43a6..eab6528 100644 --- a/OpenSim/Region/Environment/Modules/AppearanceTableMapper.cs +++ b/OpenSim/Region/Environment/Modules/AppearanceTableMapper.cs @@ -24,8 +24,7 @@ * (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; using System.Collections.Generic; using System.Text; using OpenSim.Region.Environment.Scenes; @@ -34,6 +33,7 @@ using OpenSim.Framework.Data.Base; namespace OpenSim.Region.Environment.Modules { + /* public class AppearanceRowMapper : BaseRowMapper { public AppearanceRowMapper(BaseSchema schema, AvatarAppearance obj) @@ -239,4 +239,5 @@ namespace OpenSim.Region.Environment.Modules } } } -} + +}*/ diff --git a/OpenSim/Region/Environment/Modules/AvatarFactoryModule.cs b/OpenSim/Region/Environment/Modules/AvatarFactoryModule.cs index da33726..6758d41 100644 --- a/OpenSim/Region/Environment/Modules/AvatarFactoryModule.cs +++ b/OpenSim/Region/Environment/Modules/AvatarFactoryModule.cs @@ -25,6 +25,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* using System; using System.Collections.Generic; using System.Threading; @@ -39,6 +40,7 @@ using OpenSim.Framework.Data.Base; namespace OpenSim.Region.Environment.Modules { + /* public class AvatarFactoryModule : IAvatarFactory { private Scene m_scene = null; @@ -334,4 +336,4 @@ namespace OpenSim.Region.Environment.Modules return visualParams; } } -} +}*/ diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs index f02f038..6644299 100644 --- a/OpenSim/Region/Environment/Scenes/Scene.cs +++ b/OpenSim/Region/Environment/Scenes/Scene.cs @@ -1461,7 +1461,7 @@ namespace OpenSim.Region.Environment.Scenes m_log.Warn("[AVATAR DEBUGGING]: Couldn't fetch avatar appearance from factory, please report this to the opensim mantis"); byte[] visualParams; AvatarWearable[] wearables; - AvatarFactoryModule.GetDefaultAvatarAppearance(out wearables, out visualParams); + GetDefaultAvatarAppearance(out wearables, out visualParams); appearance = new AvatarAppearance(client.AgentId, wearables, visualParams); } } @@ -2723,5 +2723,25 @@ namespace OpenSim.Region.Environment.Scenes } #endregion + + #region Avatar Appearance Default + + public static void GetDefaultAvatarAppearance(out AvatarWearable[] wearables, out byte[] visualParams) + { + visualParams = GetDefaultVisualParams(); + wearables = AvatarWearable.DefaultWearables; + } + + private static byte[] GetDefaultVisualParams() + { + byte[] visualParams; + visualParams = new byte[218]; + for (int i = 0; i < 218; i++) + { + visualParams[i] = 100; + } + return visualParams; + } + #endregion } } diff --git a/OpenSim/Region/Modules/AvatarFactory/AppearanceTableMapper.cs b/OpenSim/Region/Modules/AvatarFactory/AppearanceTableMapper.cs new file mode 100644 index 0000000..579ee01 --- /dev/null +++ b/OpenSim/Region/Modules/AvatarFactory/AppearanceTableMapper.cs @@ -0,0 +1,242 @@ +/* + * 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 OpenSim 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.Text; +using OpenSim.Region.Environment.Scenes; +using OpenSim.Framework; +using OpenSim.Framework.Data.Base; + +namespace OpenSim.Region.Modules.AvatarFactory +{ + public class AppearanceRowMapper : BaseRowMapper + { + public AppearanceRowMapper(BaseSchema schema, AvatarAppearance obj) + : base(schema, obj) + { + } + } + + public class AppearanceTableMapper : BaseTableMapper + { + public AppearanceTableMapper(BaseDatabaseConnector database, string tableName) + : base(database, tableName) + { + BaseSchema rowMapperSchema = new BaseSchema(this); + m_schema = rowMapperSchema; + + m_keyFieldMapper = rowMapperSchema.AddMapping("UUID", + delegate(AppearanceRowMapper mapper) { return mapper.Object.ScenePresenceID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.ScenePresenceID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("Serial", + delegate(AppearanceRowMapper mapper) { return (uint)mapper.Object.WearablesSerial; }, + delegate(AppearanceRowMapper mapper, uint value) { mapper.Object.WearablesSerial = (int)value; }); + + rowMapperSchema.AddMapping("WearableItem0", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[0].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { + if (mapper.Object.Wearables == null) + { + mapper.Object.Wearables = new OpenSim.Framework.AvatarWearable[13]; + for (int i = 0; i < 13; i++) + { + mapper.Object.Wearables[i] = new AvatarWearable(); + } + } + mapper.Object.Wearables[0].ItemID = new libsecondlife.LLUUID(value.ToString()); + }); + + rowMapperSchema.AddMapping("WearableAsset0", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[0].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[0].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem1", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[1].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[1].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset1", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[1].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[1].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem2", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[2].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[2].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset2", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[2].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[2].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem3", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[3].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[3].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset3", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[3].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[3].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem4", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[4].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[4].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset4", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[4].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[4].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem5", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[5].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[5].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset5", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[5].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[5].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem6", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[6].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[6].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset6", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[6].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[6].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem7", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[7].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[7].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset7", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[7].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[7].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem8", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[8].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[8].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset8", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[8].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[8].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem9", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[9].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[9].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset9", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[9].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[9].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem10", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[10].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[10].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset10", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[10].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[10].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem11", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[11].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[11].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset11", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[11].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[11].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem12", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[12].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[12].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset12", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[12].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[12].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + } + + public bool Add(Guid userID, AvatarAppearance appearance) + { + AppearanceRowMapper mapper = CreateRowMapper(appearance); + return Add(mapper); + } + + public bool Update(Guid userID, AvatarAppearance appearance) + { + AppearanceRowMapper mapper = CreateRowMapper(appearance); + return Update(appearance.ScenePresenceID.UUID, mapper); + } + + protected AppearanceRowMapper CreateRowMapper(AvatarAppearance appearance) + { + return new AppearanceRowMapper(m_schema, appearance); + } + + protected AppearanceRowMapper CreateRowMapper() + { + return CreateRowMapper(new AvatarAppearance()); + } + + protected AppearanceRowMapper FromReader(BaseDataReader reader, AvatarAppearance appearance) + { + AppearanceRowMapper mapper = CreateRowMapper(appearance); + mapper.FillObject(reader); + return mapper; + } + + public override AppearanceRowMapper FromReader(BaseDataReader reader) + { + AppearanceRowMapper mapper = CreateRowMapper(); + mapper.FillObject(reader); + return mapper; + } + + public bool TryGetValue(Guid presenceID, out AvatarAppearance val) + { + AppearanceRowMapper mapper; + if (TryGetValue(presenceID, out mapper)) + { + val = mapper.Object; + return true; + } + else + { + val = null; + return false; + } + } + } +} diff --git a/OpenSim/Region/Modules/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/Modules/AvatarFactory/AvatarFactoryModule.cs new file mode 100644 index 0000000..1f99a72 --- /dev/null +++ b/OpenSim/Region/Modules/AvatarFactory/AvatarFactoryModule.cs @@ -0,0 +1,337 @@ +/* + * 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 OpenSim 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.Threading; +using libsecondlife; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Framework.Communications.Cache; +using OpenSim.Framework.Data.MySQLMapper; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; +using OpenSim.Framework.Data.Base; + +namespace OpenSim.Region.Modules.AvatarFactory +{ + public class AvatarFactoryModule : IAvatarFactory + { + private Scene m_scene = null; + private readonly Dictionary m_avatarsAppearance = new Dictionary(); + + private bool m_enablePersist = false; + private string m_connectionString; + private bool m_configured = false; + private BaseDatabaseConnector m_databaseMapper; + private AppearanceTableMapper m_appearanceMapper; + + private Dictionary m_fetchesInProgress = new Dictionary(); + private object m_syncLock = new object(); + + public bool TryGetAvatarAppearance(LLUUID avatarId, out AvatarAppearance appearance) + { + + //should only let one thread at a time do this part + EventWaitHandle waitHandle = null; + bool fetchInProgress = false; + lock (m_syncLock) + { + appearance = CheckCache(avatarId); + if (appearance != null) + { + return true; + } + + //not in cache so check to see if another thread is already fetching it + if (m_fetchesInProgress.TryGetValue(avatarId, out waitHandle)) + { + fetchInProgress = true; + } + else + { + fetchInProgress = false; + + //no thread already fetching this appearance, so add a wait handle to list + //for any following threads that want the same appearance + waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset); + m_fetchesInProgress.Add(avatarId, waitHandle); + } + } + + if (fetchInProgress) + { + waitHandle.WaitOne(); + appearance = CheckCache(avatarId); + if (appearance != null) + { + waitHandle = null; + return true; + } + else + { + waitHandle = null; + return false; + } + } + else + { + Thread.Sleep(5000); + + //this is the first thread to request this appearance + //so let it check the db and if not found then create a default appearance + //and add that to the cache + appearance = CheckDatabase(avatarId); + if (appearance != null) + { + //appearance has now been added to cache so lets pulse any waiting threads + lock (m_syncLock) + { + m_fetchesInProgress.Remove(avatarId); + waitHandle.Set(); + } + // waitHandle.Close(); + waitHandle = null; + return true; + } + + //not found a appearance for the user, so create a new default one + appearance = CreateDefault(avatarId); + if (appearance != null) + { + //update database + if (m_enablePersist) + { + m_appearanceMapper.Add(avatarId.UUID, appearance); + } + + //add appearance to dictionary cache + lock (m_avatarsAppearance) + { + m_avatarsAppearance[avatarId] = appearance; + } + + //appearance has now been added to cache so lets pulse any waiting threads + lock (m_syncLock) + { + m_fetchesInProgress.Remove(avatarId); + waitHandle.Set(); + } + // waitHandle.Close(); + waitHandle = null; + return true; + } + else + { + //something went wrong, so release the wait handle and remove it + //all waiting threads will fail to find cached appearance + //but its better for them to fail than wait for ever + lock (m_syncLock) + { + m_fetchesInProgress.Remove(avatarId); + waitHandle.Set(); + } + //waitHandle.Close(); + waitHandle = null; + return false; + } + } + } + + private AvatarAppearance CreateDefault(LLUUID avatarId) + { + AvatarAppearance appearance = null; + AvatarWearable[] wearables; + byte[] visualParams; + GetDefaultAvatarAppearance(out wearables, out visualParams); + appearance = new AvatarAppearance(avatarId, wearables, visualParams); + + return appearance; + } + + private AvatarAppearance CheckDatabase(LLUUID avatarId) + { + AvatarAppearance appearance = null; + if (m_enablePersist) + { + if (m_appearanceMapper.TryGetValue(avatarId.UUID, out appearance)) + { + appearance.VisualParams = GetDefaultVisualParams(); + appearance.TextureEntry = AvatarAppearance.GetDefaultTextureEntry(); + lock (m_avatarsAppearance) + { + m_avatarsAppearance[avatarId] = appearance; + } + } + } + return appearance; + } + + private AvatarAppearance CheckCache(LLUUID avatarId) + { + AvatarAppearance appearance = null; + lock (m_avatarsAppearance) + { + if (m_avatarsAppearance.ContainsKey(avatarId)) + { + appearance = m_avatarsAppearance[avatarId]; + } + } + return appearance; + } + + public void Initialise(Scene scene, IConfigSource source) + { + scene.RegisterModuleInterface(this); + scene.EventManager.OnNewClient += NewClient; + + if (m_scene == null) + { + m_scene = scene; + } + + if (!m_configured) + { + m_configured = true; + try + { + m_enablePersist = source.Configs["Startup"].GetBoolean("appearance_persist", false); + m_connectionString = source.Configs["Startup"].GetString("appearance_connection_string", ""); + } + catch (Exception) + { + } + if (m_enablePersist) + { + m_databaseMapper = new MySQLDatabaseMapper(m_connectionString); + m_appearanceMapper = new AppearanceTableMapper(m_databaseMapper, "AvatarAppearance"); + } + } + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return "Default Avatar Factory"; } + } + + public bool IsSharedModule + { + get { return true; } + } + + public void NewClient(IClientAPI client) + { + client.OnAvatarNowWearing += AvatarIsWearing; + } + + public void RemoveClient(IClientAPI client) + { + // client.OnAvatarNowWearing -= AvatarIsWearing; + } + + public void AvatarIsWearing(Object sender, AvatarWearingArgs e) + { + IClientAPI clientView = (IClientAPI)sender; + CachedUserInfo profile = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(clientView.AgentId); + if (profile != null) + { + if (profile.RootFolder != null) + { + if (m_avatarsAppearance.ContainsKey(clientView.AgentId)) + { + AvatarAppearance avatAppearance = null; + lock (m_avatarsAppearance) + { + avatAppearance = m_avatarsAppearance[clientView.AgentId]; + } + + foreach (AvatarWearingArgs.Wearable wear in e.NowWearing) + { + if (wear.Type < 13) + { + if (wear.ItemID == LLUUID.Zero) + { + avatAppearance.Wearables[wear.Type].ItemID = LLUUID.Zero; + avatAppearance.Wearables[wear.Type].AssetID = LLUUID.Zero; + + UpdateDatabase(clientView.AgentId, avatAppearance); + } + else + { + LLUUID assetId; + + InventoryItemBase baseItem = profile.RootFolder.HasItem(wear.ItemID); + if (baseItem != null) + { + assetId = baseItem.assetID; + avatAppearance.Wearables[wear.Type].AssetID = assetId; + avatAppearance.Wearables[wear.Type].ItemID = wear.ItemID; + + UpdateDatabase(clientView.AgentId, avatAppearance); + } + } + } + } + } + } + } + } + + public void UpdateDatabase(LLUUID userID, AvatarAppearance avatAppearance) + { + if (m_enablePersist) + { + m_appearanceMapper.Update(userID.UUID, avatAppearance); + } + } + + public static void GetDefaultAvatarAppearance(out AvatarWearable[] wearables, out byte[] visualParams) + { + visualParams = GetDefaultVisualParams(); + wearables = AvatarWearable.DefaultWearables; + } + + private static byte[] GetDefaultVisualParams() + { + byte[] visualParams; + visualParams = new byte[218]; + for (int i = 0; i < 218; i++) + { + visualParams[i] = 100; + } + return visualParams; + } + } +} diff --git a/OpenSim/Region/Modules/AvatarFactory/Properties/AssemblyInfo.cs b/OpenSim/Region/Modules/AvatarFactory/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..5707990 --- /dev/null +++ b/OpenSim/Region/Modules/AvatarFactory/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenSim.Region.Modules.AvatarFactory")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("OpenSim.Region.Modules.AvatarFactory")] +[assembly: AssemblyCopyright("Copyright © 2008")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("8e369713-faf5-4e55-a789-f8f1a087d3ed")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/prebuild.xml b/prebuild.xml index 68a9815..f84d3ca 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -232,6 +232,35 @@ + + + + + ../../../../bin/ + + + + + ../../../../bin/ + + + + ../../../../bin/ + + + + + + + + + + + + + + + @@ -750,7 +779,6 @@ - -- cgit v1.1