aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules
diff options
context:
space:
mode:
authorMaster ScienceSim2010-10-28 09:00:39 -0700
committerMaster ScienceSim2010-10-28 09:00:39 -0700
commit0f28fa400d1f853cc3c3ebd2707b08ed06d2f127 (patch)
tree7742c37af66e92492a8aedd20b7f39b99af86eee /OpenSim/Region/CoreModules
parentSmall cleanup and add more debugging information (diff)
downloadopensim-SC-0f28fa400d1f853cc3c3ebd2707b08ed06d2f127.zip
opensim-SC-0f28fa400d1f853cc3c3ebd2707b08ed06d2f127.tar.gz
opensim-SC-0f28fa400d1f853cc3c3ebd2707b08ed06d2f127.tar.bz2
opensim-SC-0f28fa400d1f853cc3c3ebd2707b08ed06d2f127.tar.xz
Added background thread to handle delayed send and save of appearance
to accommodate batching of the many updates that happen on login and teleport. Fixed handling of the serial property in appearance.
Diffstat (limited to 'OpenSim/Region/CoreModules')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs219
1 files changed, 164 insertions, 55 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
index 5444f80..903e94b 100644
--- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
@@ -32,6 +32,10 @@ using Nini.Config;
32using OpenMetaverse; 32using OpenMetaverse;
33using OpenSim.Framework; 33using OpenSim.Framework;
34 34
35using System.Threading;
36using System.Timers;
37using System.Collections.Generic;
38
35using OpenSim.Region.Framework.Interfaces; 39using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
37using OpenSim.Services.Interfaces; 41using OpenSim.Services.Interfaces;
@@ -44,7 +48,15 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
44 private static readonly byte[] BAKE_INDICES = new byte[] { 8, 9, 10, 11, 19, 20 }; 48 private static readonly byte[] BAKE_INDICES = new byte[] { 8, 9, 10, 11, 19, 20 };
45 private Scene m_scene = null; 49 private Scene m_scene = null;
46 50
47 private bool m_startAnimationSet = false; 51 private static readonly int m_savetime = 5; // seconds to wait before saving changed appearance
52 private static readonly int m_sendtime = 2; // seconds to wait before sending changed appearance
53
54 private static readonly int m_checkTime = 500; // milliseconds to wait between checks for appearance updates
55 private System.Timers.Timer m_updateTimer = new System.Timers.Timer();
56 private Dictionary<UUID,long> m_savequeue = new Dictionary<UUID,long>();
57 private Dictionary<UUID,long> m_sendqueue = new Dictionary<UUID,long>();
58
59 #region RegionModule Members
48 60
49 public void Initialise(Scene scene, IConfigSource source) 61 public void Initialise(Scene scene, IConfigSource source)
50 { 62 {
@@ -56,6 +68,10 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
56 68
57 public void PostInitialise() 69 public void PostInitialise()
58 { 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);
59 } 75 }
60 76
61 public void Close() 77 public void Close()
@@ -84,15 +100,8 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
84 // client.OnAvatarNowWearing -= AvatarIsWearing; 100 // client.OnAvatarNowWearing -= AvatarIsWearing;
85 } 101 }
86 102
87 public void CheckBakedTextureAssets(IClientAPI client, UUID textureID, int idx) 103 #endregion
88 { 104
89 if (m_scene.AssetService.Get(textureID.ToString()) == null)
90 {
91 m_log.WarnFormat("[AVFACTORY]: Missing baked texture {0} ({1}) for avatar {2}",textureID,idx,client.Name);
92 client.SendRebakeAvatarTextures(textureID);
93 }
94 }
95
96 /// <summary> 105 /// <summary>
97 /// Set appearance data (textureentry and slider settings) received from the client 106 /// Set appearance data (textureentry and slider settings) received from the client
98 /// </summary> 107 /// </summary>
@@ -100,6 +109,10 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
100 /// <param name="visualParam"></param> 109 /// <param name="visualParam"></param>
101 public void SetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams) 110 public void SetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams)
102 { 111 {
112// DEBUG ON
113 m_log.WarnFormat("[AVFACTORY] SetAppearance for {0}",client.AgentId);
114// DEBUG OFF
115
103 ScenePresence sp = m_scene.GetScenePresence(client.AgentId); 116 ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
104 if (sp == null) 117 if (sp == null)
105 { 118 {
@@ -107,79 +120,175 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
107 return; 120 return;
108 } 121 }
109 122
110// DEBUG ON
111 m_log.WarnFormat("[AVFACTORY] SetAppearance for {0}",client.AgentId);
112// DEBUG OFF
113
114/*
115 if (m_physicsActor != null)
116 {
117 if (!IsChildAgent)
118 {
119 // This may seem like it's redundant, remove the avatar from the physics scene
120 // just to add it back again, but it saves us from having to update
121 // 3 variables 10 times a second.
122 bool flyingTemp = m_physicsActor.Flying;
123 RemoveFromPhysicalScene();
124 //m_scene.PhysicsScene.RemoveAvatar(m_physicsActor);
125
126 //PhysicsActor = null;
127
128 AddToPhysicalScene(flyingTemp);
129 }
130 }
131*/
132 #region Bake Cache Check
133
134 bool changed = false; 123 bool changed = false;
135 124
136 // Process the texture entry 125 // Process the texture entry
137 if (textureEntry != null) 126 if (textureEntry != null)
138 { 127 {
128 changed = sp.Appearance.SetTextureEntries(textureEntry);
129
139 for (int i = 0; i < BAKE_INDICES.Length; i++) 130 for (int i = 0; i < BAKE_INDICES.Length; i++)
140 { 131 {
141 int j = BAKE_INDICES[i]; 132 int idx = BAKE_INDICES[i];
142 Primitive.TextureEntryFace face = textureEntry.FaceTextures[j]; 133 Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx];
143
144 if (face != null && face.TextureID != AppearanceManager.DEFAULT_AVATAR_TEXTURE) 134 if (face != null && face.TextureID != AppearanceManager.DEFAULT_AVATAR_TEXTURE)
145 Util.FireAndForget(delegate(object o) { CheckBakedTextureAssets(client,face.TextureID,j); }); 135 Util.FireAndForget(delegate(object o) { CheckBakedTextureAssets(client,face.TextureID,idx); });
146 } 136 }
147 changed = sp.Appearance.SetTextureEntries(textureEntry);
148
149 } 137 }
150 138
151 #endregion Bake Cache Check 139 // Process the visual params, this may change height as well
152 140 if (visualParams != null)
153 changed = sp.Appearance.SetVisualParams(visualParams) || changed; 141 {
154 142 if (sp.Appearance.SetVisualParams(visualParams))
155 // If nothing changed (this happens frequently) just return 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
156 if (changed) 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)
157 { 191 {
192 m_sendqueue[agentid] = timestamp;
193 m_updateTimer.Start();
194 }
195 }
196
197 public void QueueAppearanceSave(UUID agentid)
198 {
158// DEBUG ON 199// DEBUG ON
159 m_log.Warn("[AVFACTORY] Appearance changed"); 200 m_log.WarnFormat("[AVFACTORY] Queue appearance save for {0}",agentid);
160// DEBUG OFF 201// DEBUG OFF
161 sp.Appearance.SetAppearance(textureEntry, visualParams);
162 if (sp.Appearance.AvatarHeight > 0)
163 sp.SetHeight(sp.Appearance.AvatarHeight);
164 202
165 m_scene.AvatarService.SetAppearance(client.AgentId, sp.Appearance); 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;
166 } 219 }
220
167// DEBUG ON 221// DEBUG ON
168 else 222 m_log.WarnFormat("[AVFACTORY] Handle appearance send for {0}\n{1}",agentid,sp.Appearance.ToString());
169 m_log.Warn("[AVFACTORY] Appearance did not change"); 223// DEBUG OFF
170// DEBUG OFF
171 224
225 // Send the appearance to everyone in the scene
172 sp.SendAppearanceToAllOtherAgents(); 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
173 if (!m_startAnimationSet) 236 if (!m_startAnimationSet)
174 { 237 {
175 sp.Animator.UpdateMovementAnimations(); 238 sp.Animator.UpdateMovementAnimations();
176 m_startAnimationSet = true; 239 m_startAnimationSet = true;
177 } 240 }
241*/
242 }
178 243
179 client.SendAvatarDataImmediate(sp); 244 private void HandleAppearanceSave(UUID agentid)
180 client.SendAppearance(sp.Appearance.Owner,sp.Appearance.VisualParams,sp.Appearance.Texture.GetBytes()); 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);
181 } 254 }
182 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)
266 {
267 Util.FireAndForget(delegate(object o) { HandleAppearanceSend(kvp.Key); });
268 m_sendqueue.Remove(kvp.Key);
269 }
270 }
271 }
272
273 lock (m_savequeue)
274 {
275 Dictionary<UUID,long> saves = new Dictionary<UUID,long>(m_savequeue);
276 foreach (KeyValuePair<UUID,long> kvp in saves)
277 {
278 if (kvp.Value < now)
279 {
280 Util.FireAndForget(delegate(object o) { HandleAppearanceSave(kvp.Key); });
281 m_savequeue.Remove(kvp.Key);
282 }
283 }
284 }
285
286 if (m_savequeue.Count == 0 && m_sendqueue.Count == 0)
287 m_updateTimer.Stop();
288 }
289
290 #endregion
291
183 /// <summary> 292 /// <summary>
184 /// Tell the client for this scene presence what items it should be wearing now 293 /// Tell the client for this scene presence what items it should be wearing now
185 /// </summary> 294 /// </summary>