diff options
-rw-r--r-- | OpenSim/Framework/AvatarAppearance.cs | 11 | ||||
-rw-r--r-- | OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs | 219 |
2 files changed, 171 insertions, 59 deletions
diff --git a/OpenSim/Framework/AvatarAppearance.cs b/OpenSim/Framework/AvatarAppearance.cs index 05330c7..e66a1e7 100644 --- a/OpenSim/Framework/AvatarAppearance.cs +++ b/OpenSim/Framework/AvatarAppearance.cs | |||
@@ -233,7 +233,7 @@ namespace OpenSim.Framework | |||
233 | // DEBUG ON | 233 | // DEBUG ON |
234 | m_log.WarnFormat("[AVATAR APPEARANCE] create empty appearance for {0}",owner); | 234 | m_log.WarnFormat("[AVATAR APPEARANCE] create empty appearance for {0}",owner); |
235 | // DEBUG OFF | 235 | // DEBUG OFF |
236 | m_serial = 0; | 236 | m_serial = 1; |
237 | m_owner = owner; | 237 | m_owner = owner; |
238 | 238 | ||
239 | SetDefaultWearables(); | 239 | SetDefaultWearables(); |
@@ -289,7 +289,7 @@ namespace OpenSim.Framework | |||
289 | // DEBUG OFF | 289 | // DEBUG OFF |
290 | if (appearance == null) | 290 | if (appearance == null) |
291 | { | 291 | { |
292 | m_serial = 0; | 292 | m_serial = 1; |
293 | m_owner = UUID.Zero; | 293 | m_owner = UUID.Zero; |
294 | 294 | ||
295 | SetDefaultWearables(); | 295 | SetDefaultWearables(); |
@@ -467,6 +467,9 @@ namespace OpenSim.Framework | |||
467 | public override String ToString() | 467 | public override String ToString() |
468 | { | 468 | { |
469 | String s = ""; | 469 | String s = ""; |
470 | |||
471 | s += String.Format("Serial: {0}\n",m_serial); | ||
472 | |||
470 | for (uint i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++) | 473 | for (uint i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++) |
471 | if (m_texture.FaceTextures[i] != null) | 474 | if (m_texture.FaceTextures[i] != null) |
472 | s += String.Format("Texture: {0} --> {1}\n",i,m_texture.FaceTextures[i].TextureID); | 475 | s += String.Format("Texture: {0} --> {1}\n",i,m_texture.FaceTextures[i].TextureID); |
@@ -625,8 +628,8 @@ namespace OpenSim.Framework | |||
625 | /// </summary> | 628 | /// </summary> |
626 | public void Unpack(OSDMap data) | 629 | public void Unpack(OSDMap data) |
627 | { | 630 | { |
628 | if ((data != null) && (data["appearance_serial"] != null)) | 631 | if ((data != null) && (data["serial"] != null)) |
629 | m_serial = data["appearance_serial"].AsInteger(); | 632 | m_serial = data["serial"].AsInteger(); |
630 | if ((data != null) && (data["height"] != null)) | 633 | if ((data != null) && (data["height"] != null)) |
631 | m_avatarHeight = (float)data["height"].AsReal(); | 634 | m_avatarHeight = (float)data["height"].AsReal(); |
632 | if ((data != null) && (data["hipoffset"] != null)) | 635 | if ((data != null) && (data["hipoffset"] != null)) |
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; | |||
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; |
@@ -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> |