aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Modules/AvatarFactory/AvatarFactoryModule.cs
diff options
context:
space:
mode:
authorMW2008-03-25 18:48:07 +0000
committerMW2008-03-25 18:48:07 +0000
commitc2ea7b99e1cdbc06035e12306a71712f763b0818 (patch)
treee25876965e745f65917e7a740b2617961ee4b325 /OpenSim/Region/Modules/AvatarFactory/AvatarFactoryModule.cs
parent* Tear down CAPS and http handlers when an agent leaves a region (via crossin... (diff)
downloadopensim-SC_OLD-c2ea7b99e1cdbc06035e12306a71712f763b0818.zip
opensim-SC_OLD-c2ea7b99e1cdbc06035e12306a71712f763b0818.tar.gz
opensim-SC_OLD-c2ea7b99e1cdbc06035e12306a71712f763b0818.tar.bz2
opensim-SC_OLD-c2ea7b99e1cdbc06035e12306a71712f763b0818.tar.xz
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.
Diffstat (limited to 'OpenSim/Region/Modules/AvatarFactory/AvatarFactoryModule.cs')
-rw-r--r--OpenSim/Region/Modules/AvatarFactory/AvatarFactoryModule.cs337
1 files changed, 337 insertions, 0 deletions
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Threading;
31using libsecondlife;
32using Nini.Config;
33using OpenSim.Framework;
34using OpenSim.Framework.Communications.Cache;
35using OpenSim.Framework.Data.MySQLMapper;
36using OpenSim.Region.Environment.Interfaces;
37using OpenSim.Region.Environment.Scenes;
38using OpenSim.Framework.Data.Base;
39
40namespace OpenSim.Region.Modules.AvatarFactory
41{
42 public class AvatarFactoryModule : IAvatarFactory
43 {
44 private Scene m_scene = null;
45 private readonly Dictionary<LLUUID, AvatarAppearance> m_avatarsAppearance = new Dictionary<LLUUID, AvatarAppearance>();
46
47 private bool m_enablePersist = false;
48 private string m_connectionString;
49 private bool m_configured = false;
50 private BaseDatabaseConnector m_databaseMapper;
51 private AppearanceTableMapper m_appearanceMapper;
52
53 private Dictionary<LLUUID, EventWaitHandle> m_fetchesInProgress = new Dictionary<LLUUID, EventWaitHandle>();
54 private object m_syncLock = new object();
55
56 public bool TryGetAvatarAppearance(LLUUID avatarId, out AvatarAppearance appearance)
57 {
58
59 //should only let one thread at a time do this part
60 EventWaitHandle waitHandle = null;
61 bool fetchInProgress = false;
62 lock (m_syncLock)
63 {
64 appearance = CheckCache(avatarId);
65 if (appearance != null)
66 {
67 return true;
68 }
69
70 //not in cache so check to see if another thread is already fetching it
71 if (m_fetchesInProgress.TryGetValue(avatarId, out waitHandle))
72 {
73 fetchInProgress = true;
74 }
75 else
76 {
77 fetchInProgress = false;
78
79 //no thread already fetching this appearance, so add a wait handle to list
80 //for any following threads that want the same appearance
81 waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
82 m_fetchesInProgress.Add(avatarId, waitHandle);
83 }
84 }
85
86 if (fetchInProgress)
87 {
88 waitHandle.WaitOne();
89 appearance = CheckCache(avatarId);
90 if (appearance != null)
91 {
92 waitHandle = null;
93 return true;
94 }
95 else
96 {
97 waitHandle = null;
98 return false;
99 }
100 }
101 else
102 {
103 Thread.Sleep(5000);
104
105 //this is the first thread to request this appearance
106 //so let it check the db and if not found then create a default appearance
107 //and add that to the cache
108 appearance = CheckDatabase(avatarId);
109 if (appearance != null)
110 {
111 //appearance has now been added to cache so lets pulse any waiting threads
112 lock (m_syncLock)
113 {
114 m_fetchesInProgress.Remove(avatarId);
115 waitHandle.Set();
116 }
117 // waitHandle.Close();
118 waitHandle = null;
119 return true;
120 }
121
122 //not found a appearance for the user, so create a new default one
123 appearance = CreateDefault(avatarId);
124 if (appearance != null)
125 {
126 //update database
127 if (m_enablePersist)
128 {
129 m_appearanceMapper.Add(avatarId.UUID, appearance);
130 }
131
132 //add appearance to dictionary cache
133 lock (m_avatarsAppearance)
134 {
135 m_avatarsAppearance[avatarId] = appearance;
136 }
137
138 //appearance has now been added to cache so lets pulse any waiting threads
139 lock (m_syncLock)
140 {
141 m_fetchesInProgress.Remove(avatarId);
142 waitHandle.Set();
143 }
144 // waitHandle.Close();
145 waitHandle = null;
146 return true;
147 }
148 else
149 {
150 //something went wrong, so release the wait handle and remove it
151 //all waiting threads will fail to find cached appearance
152 //but its better for them to fail than wait for ever
153 lock (m_syncLock)
154 {
155 m_fetchesInProgress.Remove(avatarId);
156 waitHandle.Set();
157 }
158 //waitHandle.Close();
159 waitHandle = null;
160 return false;
161 }
162 }
163 }
164
165 private AvatarAppearance CreateDefault(LLUUID avatarId)
166 {
167 AvatarAppearance appearance = null;
168 AvatarWearable[] wearables;
169 byte[] visualParams;
170 GetDefaultAvatarAppearance(out wearables, out visualParams);
171 appearance = new AvatarAppearance(avatarId, wearables, visualParams);
172
173 return appearance;
174 }
175
176 private AvatarAppearance CheckDatabase(LLUUID avatarId)
177 {
178 AvatarAppearance appearance = null;
179 if (m_enablePersist)
180 {
181 if (m_appearanceMapper.TryGetValue(avatarId.UUID, out appearance))
182 {
183 appearance.VisualParams = GetDefaultVisualParams();
184 appearance.TextureEntry = AvatarAppearance.GetDefaultTextureEntry();
185 lock (m_avatarsAppearance)
186 {
187 m_avatarsAppearance[avatarId] = appearance;
188 }
189 }
190 }
191 return appearance;
192 }
193
194 private AvatarAppearance CheckCache(LLUUID avatarId)
195 {
196 AvatarAppearance appearance = null;
197 lock (m_avatarsAppearance)
198 {
199 if (m_avatarsAppearance.ContainsKey(avatarId))
200 {
201 appearance = m_avatarsAppearance[avatarId];
202 }
203 }
204 return appearance;
205 }
206
207 public void Initialise(Scene scene, IConfigSource source)
208 {
209 scene.RegisterModuleInterface<IAvatarFactory>(this);
210 scene.EventManager.OnNewClient += NewClient;
211
212 if (m_scene == null)
213 {
214 m_scene = scene;
215 }
216
217 if (!m_configured)
218 {
219 m_configured = true;
220 try
221 {
222 m_enablePersist = source.Configs["Startup"].GetBoolean("appearance_persist", false);
223 m_connectionString = source.Configs["Startup"].GetString("appearance_connection_string", "");
224 }
225 catch (Exception)
226 {
227 }
228 if (m_enablePersist)
229 {
230 m_databaseMapper = new MySQLDatabaseMapper(m_connectionString);
231 m_appearanceMapper = new AppearanceTableMapper(m_databaseMapper, "AvatarAppearance");
232 }
233 }
234 }
235
236 public void PostInitialise()
237 {
238 }
239
240 public void Close()
241 {
242 }
243
244 public string Name
245 {
246 get { return "Default Avatar Factory"; }
247 }
248
249 public bool IsSharedModule
250 {
251 get { return true; }
252 }
253
254 public void NewClient(IClientAPI client)
255 {
256 client.OnAvatarNowWearing += AvatarIsWearing;
257 }
258
259 public void RemoveClient(IClientAPI client)
260 {
261 // client.OnAvatarNowWearing -= AvatarIsWearing;
262 }
263
264 public void AvatarIsWearing(Object sender, AvatarWearingArgs e)
265 {
266 IClientAPI clientView = (IClientAPI)sender;
267 CachedUserInfo profile = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(clientView.AgentId);
268 if (profile != null)
269 {
270 if (profile.RootFolder != null)
271 {
272 if (m_avatarsAppearance.ContainsKey(clientView.AgentId))
273 {
274 AvatarAppearance avatAppearance = null;
275 lock (m_avatarsAppearance)
276 {
277 avatAppearance = m_avatarsAppearance[clientView.AgentId];
278 }
279
280 foreach (AvatarWearingArgs.Wearable wear in e.NowWearing)
281 {
282 if (wear.Type < 13)
283 {
284 if (wear.ItemID == LLUUID.Zero)
285 {
286 avatAppearance.Wearables[wear.Type].ItemID = LLUUID.Zero;
287 avatAppearance.Wearables[wear.Type].AssetID = LLUUID.Zero;
288
289 UpdateDatabase(clientView.AgentId, avatAppearance);
290 }
291 else
292 {
293 LLUUID assetId;
294
295 InventoryItemBase baseItem = profile.RootFolder.HasItem(wear.ItemID);
296 if (baseItem != null)
297 {
298 assetId = baseItem.assetID;
299 avatAppearance.Wearables[wear.Type].AssetID = assetId;
300 avatAppearance.Wearables[wear.Type].ItemID = wear.ItemID;
301
302 UpdateDatabase(clientView.AgentId, avatAppearance);
303 }
304 }
305 }
306 }
307 }
308 }
309 }
310 }
311
312 public void UpdateDatabase(LLUUID userID, AvatarAppearance avatAppearance)
313 {
314 if (m_enablePersist)
315 {
316 m_appearanceMapper.Update(userID.UUID, avatAppearance);
317 }
318 }
319
320 public static void GetDefaultAvatarAppearance(out AvatarWearable[] wearables, out byte[] visualParams)
321 {
322 visualParams = GetDefaultVisualParams();
323 wearables = AvatarWearable.DefaultWearables;
324 }
325
326 private static byte[] GetDefaultVisualParams()
327 {
328 byte[] visualParams;
329 visualParams = new byte[218];
330 for (int i = 0; i < 218; i++)
331 {
332 visualParams[i] = 100;
333 }
334 return visualParams;
335 }
336 }
337}