diff options
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar/AvatarFactory')
-rw-r--r-- | OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs | 347 |
1 files changed, 261 insertions, 86 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index 22c8937..903e94b 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs | |||
@@ -32,58 +32,46 @@ using Nini.Config; | |||
32 | using OpenMetaverse; | 32 | using OpenMetaverse; |
33 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
34 | 34 | ||
35 | using System.Threading; | ||
36 | using System.Timers; | ||
37 | using System.Collections.Generic; | ||
38 | |||
35 | using OpenSim.Region.Framework.Interfaces; | 39 | using OpenSim.Region.Framework.Interfaces; |
36 | using OpenSim.Region.Framework.Scenes; | 40 | using OpenSim.Region.Framework.Scenes; |
37 | using OpenSim.Services.Interfaces; | 41 | using OpenSim.Services.Interfaces; |
38 | 42 | ||
39 | namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | 43 | namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory |
40 | { | 44 | { |
41 | public class AvatarFactoryModule : IAvatarFactory, IRegionModule | 45 | public class AvatarFactoryModule : IRegionModule |
42 | { | 46 | { |
43 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 47 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
48 | private static readonly byte[] BAKE_INDICES = new byte[] { 8, 9, 10, 11, 19, 20 }; | ||
44 | private Scene m_scene = null; | 49 | private Scene m_scene = null; |
45 | private static readonly AvatarAppearance def = new AvatarAppearance(); | ||
46 | 50 | ||
47 | public bool TryGetAvatarAppearance(UUID avatarId, out AvatarAppearance appearance) | 51 | private static readonly int m_savetime = 5; // seconds to wait before saving changed appearance |
48 | { | 52 | private static readonly int m_sendtime = 2; // seconds to wait before sending changed appearance |
49 | AvatarData avatar = m_scene.AvatarService.GetAvatar(avatarId); | ||
50 | //if ((profile != null) && (profile.RootFolder != null)) | ||
51 | if (avatar != null) | ||
52 | { | ||
53 | appearance = avatar.ToAvatarAppearance(avatarId); | ||
54 | return true; | ||
55 | } | ||
56 | 53 | ||
57 | m_log.ErrorFormat("[APPEARANCE]: Appearance not found for {0}, creating default", avatarId); | 54 | private static readonly int m_checkTime = 500; // milliseconds to wait between checks for appearance updates |
58 | appearance = CreateDefault(avatarId); | 55 | private System.Timers.Timer m_updateTimer = new System.Timers.Timer(); |
59 | return false; | 56 | private Dictionary<UUID,long> m_savequeue = new Dictionary<UUID,long>(); |
60 | } | 57 | private Dictionary<UUID,long> m_sendqueue = new Dictionary<UUID,long>(); |
61 | 58 | ||
62 | private AvatarAppearance CreateDefault(UUID avatarId) | 59 | #region RegionModule Members |
63 | { | ||
64 | AvatarAppearance appearance = null; | ||
65 | AvatarWearable[] wearables; | ||
66 | byte[] visualParams; | ||
67 | GetDefaultAvatarAppearance(out wearables, out visualParams); | ||
68 | appearance = new AvatarAppearance(avatarId, wearables, visualParams); | ||
69 | |||
70 | return appearance; | ||
71 | } | ||
72 | 60 | ||
73 | public void Initialise(Scene scene, IConfigSource source) | 61 | public void Initialise(Scene scene, IConfigSource source) |
74 | { | 62 | { |
75 | scene.RegisterModuleInterface<IAvatarFactory>(this); | ||
76 | scene.EventManager.OnNewClient += NewClient; | 63 | scene.EventManager.OnNewClient += NewClient; |
77 | 64 | ||
78 | if (m_scene == null) | 65 | if (m_scene == null) |
79 | { | ||
80 | m_scene = scene; | 66 | m_scene = scene; |
81 | } | ||
82 | |||
83 | } | 67 | } |
84 | 68 | ||
85 | public void PostInitialise() | 69 | public void PostInitialise() |
86 | { | 70 | { |
71 | m_updateTimer.Enabled = false; | ||
72 | m_updateTimer.AutoReset = true; | ||
73 | m_updateTimer.Interval = m_checkTime; // 500 milliseconds wait to start async ops | ||
74 | m_updateTimer.Elapsed += new ElapsedEventHandler(HandleAppearanceUpdateTimer); | ||
87 | } | 75 | } |
88 | 76 | ||
89 | public void Close() | 77 | public void Close() |
@@ -102,6 +90,8 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
102 | 90 | ||
103 | public void NewClient(IClientAPI client) | 91 | public void NewClient(IClientAPI client) |
104 | { | 92 | { |
93 | client.OnRequestWearables += SendWearables; | ||
94 | client.OnSetAppearance += SetAppearance; | ||
105 | client.OnAvatarNowWearing += AvatarIsWearing; | 95 | client.OnAvatarNowWearing += AvatarIsWearing; |
106 | } | 96 | } |
107 | 97 | ||
@@ -110,42 +100,211 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
110 | // client.OnAvatarNowWearing -= AvatarIsWearing; | 100 | // client.OnAvatarNowWearing -= AvatarIsWearing; |
111 | } | 101 | } |
112 | 102 | ||
113 | public void SetAppearanceAssets(UUID userID, ref AvatarAppearance appearance) | 103 | #endregion |
104 | |||
105 | /// <summary> | ||
106 | /// Set appearance data (textureentry and slider settings) received from the client | ||
107 | /// </summary> | ||
108 | /// <param name="texture"></param> | ||
109 | /// <param name="visualParam"></param> | ||
110 | public void SetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams) | ||
114 | { | 111 | { |
115 | IInventoryService invService = m_scene.InventoryService; | 112 | // DEBUG ON |
113 | m_log.WarnFormat("[AVFACTORY] SetAppearance for {0}",client.AgentId); | ||
114 | // DEBUG OFF | ||
116 | 115 | ||
117 | if (invService.GetRootFolder(userID) != null) | 116 | ScenePresence sp = m_scene.GetScenePresence(client.AgentId); |
117 | if (sp == null) | ||
118 | { | 118 | { |
119 | for (int i = 0; i < 13; i++) | 119 | m_log.WarnFormat("[AVFACTORY] SetAppearance unable to find presence for {0}",client.AgentId); |
120 | return; | ||
121 | } | ||
122 | |||
123 | bool changed = false; | ||
124 | |||
125 | // Process the texture entry | ||
126 | if (textureEntry != null) | ||
127 | { | ||
128 | changed = sp.Appearance.SetTextureEntries(textureEntry); | ||
129 | |||
130 | for (int i = 0; i < BAKE_INDICES.Length; i++) | ||
120 | { | 131 | { |
121 | if (appearance.Wearables[i].ItemID == UUID.Zero) | 132 | int idx = BAKE_INDICES[i]; |
133 | Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx]; | ||
134 | if (face != null && face.TextureID != AppearanceManager.DEFAULT_AVATAR_TEXTURE) | ||
135 | Util.FireAndForget(delegate(object o) { CheckBakedTextureAssets(client,face.TextureID,idx); }); | ||
136 | } | ||
137 | } | ||
138 | |||
139 | // Process the visual params, this may change height as well | ||
140 | if (visualParams != null) | ||
141 | { | ||
142 | if (sp.Appearance.SetVisualParams(visualParams)) | ||
143 | { | ||
144 | changed = true; | ||
145 | if (sp.Appearance.AvatarHeight > 0) | ||
146 | sp.SetHeight(sp.Appearance.AvatarHeight); | ||
147 | } | ||
148 | } | ||
149 | |||
150 | // If something changed in the appearance then queue an appearance save | ||
151 | if (changed) | ||
152 | QueueAppearanceSave(client.AgentId); | ||
153 | |||
154 | // And always queue up an appearance update to send out | ||
155 | QueueAppearanceSend(client.AgentId); | ||
156 | |||
157 | // Send the appearance back to the avatar | ||
158 | AvatarAppearance avp = sp.Appearance; | ||
159 | sp.ControllingClient.SendAvatarDataImmediate(sp); | ||
160 | sp.ControllingClient.SendAppearance(avp.Owner,avp.VisualParams,avp.Texture.GetBytes()); | ||
161 | } | ||
162 | |||
163 | /// <summary> | ||
164 | /// Checks for the existance of a baked texture asset and | ||
165 | /// requests the viewer rebake if the asset is not found | ||
166 | /// </summary> | ||
167 | /// <param name="client"></param> | ||
168 | /// <param name="textureID"></param> | ||
169 | /// <param name="idx"></param> | ||
170 | private void CheckBakedTextureAssets(IClientAPI client, UUID textureID, int idx) | ||
171 | { | ||
172 | if (m_scene.AssetService.Get(textureID.ToString()) == null) | ||
173 | { | ||
174 | m_log.WarnFormat("[AVFACTORY]: Missing baked texture {0} ({1}) for avatar {2}", | ||
175 | textureID,idx,client.Name); | ||
176 | client.SendRebakeAvatarTextures(textureID); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | #region UpdateAppearanceTimer | ||
181 | |||
182 | public void QueueAppearanceSend(UUID agentid) | ||
183 | { | ||
184 | // DEBUG ON | ||
185 | m_log.WarnFormat("[AVFACTORY] Queue appearance send for {0}",agentid); | ||
186 | // DEBUG OFF | ||
187 | |||
188 | // 100 nanoseconds (ticks) we should wait | ||
189 | long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_sendtime * 10000000); | ||
190 | lock (m_sendqueue) | ||
191 | { | ||
192 | m_sendqueue[agentid] = timestamp; | ||
193 | m_updateTimer.Start(); | ||
194 | } | ||
195 | } | ||
196 | |||
197 | public void QueueAppearanceSave(UUID agentid) | ||
198 | { | ||
199 | // DEBUG ON | ||
200 | m_log.WarnFormat("[AVFACTORY] Queue appearance save for {0}",agentid); | ||
201 | // DEBUG OFF | ||
202 | |||
203 | // 100 nanoseconds (ticks) we should wait | ||
204 | long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 10000000); | ||
205 | lock (m_savequeue) | ||
206 | { | ||
207 | m_savequeue[agentid] = timestamp; | ||
208 | m_updateTimer.Start(); | ||
209 | } | ||
210 | } | ||
211 | |||
212 | private void HandleAppearanceSend(UUID agentid) | ||
213 | { | ||
214 | ScenePresence sp = m_scene.GetScenePresence(agentid); | ||
215 | if (sp == null) | ||
216 | { | ||
217 | m_log.WarnFormat("[AVFACTORY] Agent {0} no longer in the scene",agentid); | ||
218 | return; | ||
219 | } | ||
220 | |||
221 | // DEBUG ON | ||
222 | m_log.WarnFormat("[AVFACTORY] Handle appearance send for {0}\n{1}",agentid,sp.Appearance.ToString()); | ||
223 | // DEBUG OFF | ||
224 | |||
225 | // Send the appearance to everyone in the scene | ||
226 | sp.SendAppearanceToAllOtherAgents(); | ||
227 | |||
228 | // Send the appearance back to the avatar | ||
229 | AvatarAppearance avp = sp.Appearance; | ||
230 | sp.ControllingClient.SendAvatarDataImmediate(sp); | ||
231 | sp.ControllingClient.SendAppearance(avp.Owner,avp.VisualParams,avp.Texture.GetBytes()); | ||
232 | |||
233 | /* | ||
234 | // this needs to be fixed, the flag should be on scene presence not the region module | ||
235 | // Start the animations if necessary | ||
236 | if (!m_startAnimationSet) | ||
237 | { | ||
238 | sp.Animator.UpdateMovementAnimations(); | ||
239 | m_startAnimationSet = true; | ||
240 | } | ||
241 | */ | ||
242 | } | ||
243 | |||
244 | private void HandleAppearanceSave(UUID agentid) | ||
245 | { | ||
246 | ScenePresence sp = m_scene.GetScenePresence(agentid); | ||
247 | if (sp == null) | ||
248 | { | ||
249 | m_log.WarnFormat("[AVFACTORY] Agent {0} no longer in the scene",agentid); | ||
250 | return; | ||
251 | } | ||
252 | |||
253 | m_scene.AvatarService.SetAppearance(agentid, sp.Appearance); | ||
254 | } | ||
255 | |||
256 | private void HandleAppearanceUpdateTimer(object sender, EventArgs ea) | ||
257 | { | ||
258 | long now = DateTime.Now.Ticks; | ||
259 | |||
260 | lock (m_sendqueue) | ||
261 | { | ||
262 | Dictionary<UUID,long> sends = new Dictionary<UUID,long>(m_sendqueue); | ||
263 | foreach (KeyValuePair<UUID,long> kvp in sends) | ||
264 | { | ||
265 | if (kvp.Value < now) | ||
122 | { | 266 | { |
123 | appearance.Wearables[i].AssetID = UUID.Zero; | 267 | Util.FireAndForget(delegate(object o) { HandleAppearanceSend(kvp.Key); }); |
268 | m_sendqueue.Remove(kvp.Key); | ||
124 | } | 269 | } |
125 | else | 270 | } |
126 | { | 271 | } |
127 | InventoryItemBase baseItem = new InventoryItemBase(appearance.Wearables[i].ItemID, userID); | ||
128 | baseItem = invService.GetItem(baseItem); | ||
129 | 272 | ||
130 | if (baseItem != null) | 273 | lock (m_savequeue) |
131 | { | 274 | { |
132 | appearance.Wearables[i].AssetID = baseItem.AssetID; | 275 | Dictionary<UUID,long> saves = new Dictionary<UUID,long>(m_savequeue); |
133 | } | 276 | foreach (KeyValuePair<UUID,long> kvp in saves) |
134 | else | 277 | { |
135 | { | 278 | if (kvp.Value < now) |
136 | m_log.ErrorFormat( | 279 | { |
137 | "[APPEARANCE]: Can't find inventory item {0} for {1}, setting to default", | 280 | Util.FireAndForget(delegate(object o) { HandleAppearanceSave(kvp.Key); }); |
138 | appearance.Wearables[i].ItemID, (WearableType)i); | 281 | m_savequeue.Remove(kvp.Key); |
139 | |||
140 | appearance.Wearables[i].AssetID = def.Wearables[i].AssetID; | ||
141 | } | ||
142 | } | 282 | } |
143 | } | 283 | } |
144 | } | 284 | } |
145 | else | 285 | |
286 | if (m_savequeue.Count == 0 && m_sendqueue.Count == 0) | ||
287 | m_updateTimer.Stop(); | ||
288 | } | ||
289 | |||
290 | #endregion | ||
291 | |||
292 | /// <summary> | ||
293 | /// Tell the client for this scene presence what items it should be wearing now | ||
294 | /// </summary> | ||
295 | public void SendWearables(IClientAPI client) | ||
296 | { | ||
297 | ScenePresence sp = m_scene.GetScenePresence(client.AgentId); | ||
298 | if (sp == null) | ||
146 | { | 299 | { |
147 | m_log.WarnFormat("[APPEARANCE]: user {0} has no inventory, appearance isn't going to work", userID); | 300 | m_log.WarnFormat("[AVFACTORY] SendWearables unable to find presence for {0}",client.AgentId); |
301 | return; | ||
148 | } | 302 | } |
303 | |||
304 | // DEBUG ON | ||
305 | m_log.WarnFormat("[AVFACTORY]: Received request for wearables of {0}", client.AgentId); | ||
306 | // DEBUG OFF | ||
307 | client.SendWearables(sp.Appearance.Wearables,sp.Appearance.Serial++); | ||
149 | } | 308 | } |
150 | 309 | ||
151 | /// <summary> | 310 | /// <summary> |
@@ -153,65 +312,81 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
153 | /// </summary> | 312 | /// </summary> |
154 | /// <param name="sender"></param> | 313 | /// <param name="sender"></param> |
155 | /// <param name="e"></param> | 314 | /// <param name="e"></param> |
156 | public void AvatarIsWearing(Object sender, AvatarWearingArgs e) | 315 | public void AvatarIsWearing(IClientAPI client, AvatarWearingArgs e) |
157 | { | 316 | { |
158 | m_log.DebugFormat("[APPEARANCE]: AvatarIsWearing"); | 317 | ScenePresence sp = m_scene.GetScenePresence(client.AgentId); |
159 | 318 | if (sp == null) | |
160 | IClientAPI clientView = (IClientAPI)sender; | ||
161 | ScenePresence sp = m_scene.GetScenePresence(clientView.AgentId); | ||
162 | |||
163 | if (sp == null) | ||
164 | { | 319 | { |
165 | m_log.Error("[APPEARANCE]: Avatar is child agent, ignoring AvatarIsWearing event"); | 320 | m_log.WarnFormat("[AVFACTORY] AvatarIsWearing unable to find presence for {0}",client.AgentId); |
166 | return; | 321 | return; |
167 | } | 322 | } |
323 | |||
324 | // DEBUG ON | ||
325 | m_log.WarnFormat("[AVFACTORY]: AvatarIsWearing called for {0}",client.AgentId); | ||
326 | // DEBUG OFF | ||
168 | 327 | ||
169 | AvatarAppearance avatAppearance = sp.Appearance; | 328 | AvatarAppearance avatAppearance = new AvatarAppearance(sp.Appearance); |
170 | //if (!TryGetAvatarAppearance(clientView.AgentId, out avatAppearance)) | 329 | |
330 | //if (!TryGetAvatarAppearance(client.AgentId, out avatAppearance)) | ||
171 | //{ | 331 | //{ |
172 | // m_log.Warn("[APPEARANCE]: We didn't seem to find the appearance, falling back to ScenePresence"); | 332 | // m_log.Warn("[AVFACTORY]: We didn't seem to find the appearance, falling back to ScenePresence"); |
173 | // avatAppearance = sp.Appearance; | 333 | // avatAppearance = sp.Appearance; |
174 | //} | 334 | //} |
175 | 335 | ||
176 | //m_log.DebugFormat("[APPEARANCE]: Received wearables for {0}", clientView.Name); | 336 | //m_log.DebugFormat("[AVFACTORY]: Received wearables for {0}", client.Name); |
177 | 337 | ||
178 | foreach (AvatarWearingArgs.Wearable wear in e.NowWearing) | 338 | foreach (AvatarWearingArgs.Wearable wear in e.NowWearing) |
179 | { | 339 | { |
180 | if (wear.Type < 13) | 340 | if (wear.Type < AvatarWearable.MAX_WEARABLES) |
181 | { | 341 | { |
182 | avatAppearance.Wearables[wear.Type].ItemID = wear.ItemID; | 342 | AvatarWearable newWearable = new AvatarWearable(wear.ItemID,UUID.Zero); |
343 | avatAppearance.SetWearable(wear.Type, newWearable); | ||
183 | } | 344 | } |
184 | } | 345 | } |
185 | 346 | ||
186 | SetAppearanceAssets(sp.UUID, ref avatAppearance); | 347 | SetAppearanceAssets(sp.UUID, ref avatAppearance); |
187 | AvatarData adata = new AvatarData(avatAppearance); | ||
188 | m_scene.AvatarService.SetAvatar(clientView.AgentId, adata); | ||
189 | 348 | ||
349 | m_scene.AvatarService.SetAppearance(client.AgentId, avatAppearance); | ||
190 | sp.Appearance = avatAppearance; | 350 | sp.Appearance = avatAppearance; |
191 | } | 351 | } |
192 | 352 | ||
193 | public static void GetDefaultAvatarAppearance(out AvatarWearable[] wearables, out byte[] visualParams) | 353 | private void SetAppearanceAssets(UUID userID, ref AvatarAppearance appearance) |
194 | { | 354 | { |
195 | visualParams = GetDefaultVisualParams(); | 355 | IInventoryService invService = m_scene.InventoryService; |
196 | wearables = AvatarWearable.DefaultWearables; | ||
197 | } | ||
198 | 356 | ||
199 | public void UpdateDatabase(UUID user, AvatarAppearance appearance) | 357 | if (invService.GetRootFolder(userID) != null) |
200 | { | 358 | { |
201 | //m_log.DebugFormat("[APPEARANCE]: UpdateDatabase"); | 359 | for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++) |
202 | AvatarData adata = new AvatarData(appearance); | 360 | { |
203 | m_scene.AvatarService.SetAvatar(user, adata); | 361 | if (appearance.Wearables[i].ItemID == UUID.Zero) |
204 | } | 362 | { |
363 | appearance.Wearables[i].AssetID = UUID.Zero; | ||
364 | } | ||
365 | else | ||
366 | { | ||
367 | InventoryItemBase baseItem = new InventoryItemBase(appearance.Wearables[i].ItemID, userID); | ||
368 | baseItem = invService.GetItem(baseItem); | ||
205 | 369 | ||
206 | private static byte[] GetDefaultVisualParams() | 370 | if (baseItem != null) |
207 | { | 371 | { |
208 | byte[] visualParams; | 372 | appearance.Wearables[i].AssetID = baseItem.AssetID; |
209 | visualParams = new byte[218]; | 373 | } |
210 | for (int i = 0; i < 218; i++) | 374 | else |
375 | { | ||
376 | m_log.ErrorFormat( | ||
377 | "[AVFACTORY]: Can't find inventory item {0} for {1}, setting to default", | ||
378 | appearance.Wearables[i].ItemID, (WearableType)i); | ||
379 | |||
380 | appearance.Wearables[i].ItemID = UUID.Zero; | ||
381 | appearance.Wearables[i].AssetID = UUID.Zero; | ||
382 | } | ||
383 | } | ||
384 | } | ||
385 | } | ||
386 | else | ||
211 | { | 387 | { |
212 | visualParams[i] = 100; | 388 | m_log.WarnFormat("[AVFACTORY]: user {0} has no inventory, appearance isn't going to work", userID); |
213 | } | 389 | } |
214 | return visualParams; | ||
215 | } | 390 | } |
216 | } | 391 | } |
217 | } | 392 | } |