OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
AvatarAppearance.cs
Go to the documentation of this file.
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 OpenSimulator 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 
28 using System;
29 using System.Reflection;
30 using System.Collections;
31 using System.Collections.Generic;
32 using OpenMetaverse;
33 using OpenMetaverse.StructuredData;
34 using log4net;
35 
36 namespace OpenSim.Framework
37 {
41  public class AvatarAppearance
42  {
43  // SL box diferent to size
44  const float AVBOXAJUST = 0.2f;
45  // constrains for ubitode physics
46  const float AVBOXMINX = 0.2f;
47  const float AVBOXMINY = 0.3f;
48  const float AVBOXMINZ = 1.2f;
49 
50  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51 
52  // this is viewer capabilities and weared things dependent
53  // should be only used as initial default value ( V1 viewers )
54  public readonly static int VISUALPARAM_COUNT = 218;
55 
56 // public readonly static int TEXTURE_COUNT = 21
57  // 21 bad, make it be updated as libovm gets update
58  // also keeping in sync with it
59  public readonly static int TEXTURE_COUNT = Primitive.TextureEntry.MAX_FACES;
60 
61  public readonly static byte[] BAKE_INDICES = new byte[] { 8, 9, 10, 11, 19, 20 };
62 
63  protected int m_serial = 0;
64  protected byte[] m_visualparams;
65  protected Primitive.TextureEntry m_texture;
67  protected Dictionary<int, List<AvatarAttachment>> m_attachments;
68  protected float m_avatarHeight = 0;
69  protected Vector3 m_avatarSize = new Vector3(0.45f, 0.6f, 1.9f); // sl Z cloud value
70  protected Vector3 m_avatarBoxSize = new Vector3(0.45f, 0.6f, 1.9f);
71  protected float m_avatarFeetOffset = 0;
72  protected float m_avatarAnimOffset = 0;
74  protected bool m_cacheItemsDirty = true;
75 
76  public virtual int Serial
77  {
78  get { return m_serial; }
79  set { m_serial = value; }
80  }
81 
82  public virtual byte[] VisualParams
83  {
84  get { return m_visualparams; }
85  set { m_visualparams = value; }
86  }
87 
88  public virtual Vector3 AvatarSize
89  {
90  get { return m_avatarSize; }
91  }
92 
93  public virtual Vector3 AvatarBoxSize
94  {
95  get { return m_avatarBoxSize; }
96  }
97 
98  public virtual float AvatarFeetOffset
99  {
100  get { return m_avatarFeetOffset + m_avatarAnimOffset; }
101  }
102 
103  public virtual Primitive.TextureEntry Texture
104  {
105  get { return m_texture; }
106  set
107  {
108 // m_log.DebugFormat("[AVATAR APPEARANCE]: Set TextureEntry to {0}", value);
109  m_texture = value;
110  }
111  }
112 
113  public virtual AvatarWearable[] Wearables
114  {
115  get { return m_wearables; }
116  set { m_wearables = value; }
117  }
118 
119  public virtual float AvatarHeight
120  {
121  get { return m_avatarHeight; }
122  set { m_avatarHeight = value; }
123  }
124 
125  public virtual WearableCacheItem[] WearableCacheItems
126  {
127  get { return m_cacheitems; }
128  set { m_cacheitems = value; }
129  }
130 
131  public virtual bool WearableCacheItemsDirty
132  {
133  get { return m_cacheItemsDirty; }
134  set { m_cacheItemsDirty = value; }
135  }
136 
138  {
139 // m_log.WarnFormat("[AVATAR APPEARANCE]: create empty appearance");
140 
141  m_serial = 0;
142  SetDefaultWearables();
143  SetDefaultTexture();
144  SetDefaultParams();
145 // SetHeight();
146  SetSize(new Vector3(0.45f,0.6f,1.9f));
147  m_attachments = new Dictionary<int, List<AvatarAttachment>>();
148  }
149 
151  {
152 // m_log.WarnFormat("[AVATAR APPEARANCE]: create appearance from OSDMap");
153 
154  Unpack(map);
155 // SetHeight(); done in Unpack
156  }
157 
158  public AvatarAppearance(AvatarWearable[] wearables, Primitive.TextureEntry textureEntry, byte[] visualParams)
159  {
160 // m_log.WarnFormat("[AVATAR APPEARANCE] create initialized appearance");
161 
162  m_serial = 0;
163 
164  if (wearables != null)
165  m_wearables = wearables;
166  else
167  SetDefaultWearables();
168 
169  if (textureEntry != null)
170  m_texture = textureEntry;
171  else
172  SetDefaultTexture();
173 
174  if (visualParams != null)
175  m_visualparams = visualParams;
176  else
177  SetDefaultParams();
178 
179 // SetHeight();
180  if(m_avatarHeight == 0)
181  SetSize(new Vector3(0.45f,0.6f,1.9f));
182 
183  m_attachments = new Dictionary<int, List<AvatarAttachment>>();
184  }
185 
186  public AvatarAppearance(AvatarAppearance appearance): this(appearance, true,true)
187  {
188  }
189 
190  public AvatarAppearance(AvatarAppearance appearance, bool copyWearables)
191  : this(appearance, copyWearables, true)
192  {
193  }
194 
195  public AvatarAppearance(AvatarAppearance appearance, bool copyWearables, bool copyBaked)
196  {
197 // m_log.WarnFormat("[AVATAR APPEARANCE] create from an existing appearance");
198 
199  if (appearance == null)
200  {
201  m_serial = 0;
202  SetDefaultWearables();
203  SetDefaultTexture();
204  SetDefaultParams();
205 // SetHeight();
206  SetSize(new Vector3(0.45f, 0.6f, 1.9f));
207  m_attachments = new Dictionary<int, List<AvatarAttachment>>();
208 
209  return;
210  }
211 
212  m_serial = appearance.Serial;
213 
214  if (copyWearables && (appearance.Wearables != null))
215  {
216  m_wearables = new AvatarWearable[appearance.Wearables.Length];
217  for (int i = 0; i < appearance.Wearables.Length; i++)
218  {
219  m_wearables[i] = new AvatarWearable();
220  AvatarWearable wearable = appearance.Wearables[i];
221  for (int j = 0; j < wearable.Count; j++)
222  m_wearables[i].Add(wearable[j].ItemID, wearable[j].AssetID);
223  }
224  }
225  else
226  ClearWearables();
227 
228  m_texture = null;
229  if (appearance.Texture != null)
230  {
231  byte[] tbytes = appearance.Texture.GetBytes();
232  m_texture = new Primitive.TextureEntry(tbytes,0,tbytes.Length);
233  if (copyBaked && appearance.m_cacheitems != null)
234  m_cacheitems = (WearableCacheItem[])appearance.m_cacheitems.Clone();
235  else
236  m_cacheitems = null;
237  }
238 
239  m_visualparams = null;
240  if (appearance.VisualParams != null)
241  m_visualparams = (byte[])appearance.VisualParams.Clone();
242 
243 // m_avatarHeight = appearance.m_avatarHeight;
244  SetSize(appearance.AvatarSize);
245 
246  // Copy the attachment, force append mode since that ensures consistency
247  m_attachments = new Dictionary<int, List<AvatarAttachment>>();
248  foreach (AvatarAttachment attachment in appearance.GetAttachments())
249  AppendAttachment(new AvatarAttachment(attachment));
250  }
251 
253  {
254  int len = m_wearables.Length;
255  if(len > app.m_wearables.Length)
256  len = app.m_wearables.Length;
257 
258  for (int i = 0; i < len; i++)
259  {
260  int count = m_wearables[i].Count;
261  if(count > app.m_wearables[i].Count)
262  count = app.m_wearables[i].Count;
263 
264  for (int j = 0; j < count; j++)
265  {
266  UUID itemID = m_wearables[i][j].ItemID;
267  UUID assetID = app.Wearables[i].GetAsset(itemID);
268 
269  if (assetID != UUID.Zero)
270  m_wearables[i].Add(itemID, assetID);
271  }
272  }
273  }
274 
275  public void ClearWearables()
276  {
277  m_wearables = new AvatarWearable[AvatarWearable.LEGACY_VERSION_MAX_WEARABLES];
278  for (int i = 0; i < AvatarWearable.LEGACY_VERSION_MAX_WEARABLES; i++)
279  m_wearables[i] = new AvatarWearable();
280  }
281 
282  protected virtual void SetDefaultWearables()
283  {
284  m_wearables = AvatarWearable.DefaultWearables;
285  }
286 
291  public virtual void ResetAppearance()
292  {
293 // m_log.WarnFormat("[AVATAR APPEARANCE]: Reset appearance");
294 
295  m_serial = 0;
296 
297  SetDefaultTexture();
298 
299  //for (int i = 0; i < BAKE_INDICES.Length; i++)
300  // {
301  // int idx = BAKE_INDICES[i];
302  // m_texture.FaceTextures[idx].TextureID = UUID.Zero;
303  // }
304  }
305 
306  protected virtual void SetDefaultParams()
307  {
308  m_visualparams = new byte[] { 33,61,85,23,58,127,63,85,63,42,0,85,63,36,85,95,153,63,34,0,63,109,88,132,63,136,81,85,103,136,127,0,150,150,150,127,0,0,0,0,0,127,0,0,255,127,114,127,99,63,127,140,127,127,0,0,0,191,0,104,0,0,0,0,0,0,0,0,0,145,216,133,0,127,0,127,170,0,0,127,127,109,85,127,127,63,85,42,150,150,150,150,150,150,150,25,150,150,150,0,127,0,0,144,85,127,132,127,85,0,127,127,127,127,127,127,59,127,85,127,127,106,47,79,127,127,204,2,141,66,0,0,127,127,0,0,0,0,127,0,159,0,0,178,127,36,85,131,127,127,127,153,95,0,140,75,27,127,127,0,150,150,198,0,0,63,30,127,165,209,198,127,127,153,204,51,51,255,255,255,204,0,255,150,150,150,150,150,150,150,150,150,150,0,150,150,150,150,150,0,127,127,150,150,150,150,150,150,150,150,0,0,150,51,132,150,150,150 };
309 // for (int i = 0; i < VISUALPARAM_COUNT; i++)
310 // {
311 // m_visualparams[i] = 150;
312 // }
313  }
314 
319  public virtual void ResetBakedTextures()
320  {
321  SetDefaultTexture();
322 
323  //for (int i = 0; i < BAKE_INDICES.Length; i++)
324  // {
325  // int idx = BAKE_INDICES[i];
326  // m_texture.FaceTextures[idx].TextureID = UUID.Zero;
327  // }
328  }
329 
330  protected virtual void SetDefaultTexture()
331  {
332  m_texture = new Primitive.TextureEntry(new UUID(AppearanceManager.DEFAULT_AVATAR_TEXTURE));
333 
334  // for (uint i = 0; i < TEXTURE_COUNT; i++)
335  // m_texture.CreateFace(i).TextureID = new UUID(AppearanceManager.DEFAULT_AVATAR_TEXTURE);
336  }
337 
345  public virtual bool SetTextureEntries(Primitive.TextureEntry textureEntry)
346  {
347  if (textureEntry == null)
348  return false;
349 
350  // There are much simpler versions of this copy that could be
351  // made. We determine if any of the textures actually
352  // changed to know if the appearance should be saved later
353  bool changed = false;
354  for (uint i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++)
355  {
356  Primitive.TextureEntryFace newface = textureEntry.FaceTextures[i];
357  Primitive.TextureEntryFace oldface = m_texture.FaceTextures[i];
358 
359  if (newface == null)
360  {
361  if (oldface == null)
362  continue;
363  }
364  else
365  {
366  if (oldface != null && oldface.TextureID == newface.TextureID)
367  continue;
368  }
369 
370  changed = true;
371  }
372 
373  m_texture = textureEntry;
374 
375  return changed;
376  }
377 
385  public virtual bool SetVisualParams(byte[] visualParams)
386  {
387  if (visualParams == null)
388  return false;
389 
390  // There are much simpler versions of this copy that could be
391  // made. We determine if any of the visual parameters actually
392  // changed to know if the appearance should be saved later
393  bool changed = false;
394 
395  int newsize = visualParams.Length;
396 
397  if (newsize != m_visualparams.Length)
398  {
399  changed = true;
400  m_visualparams = (byte[])visualParams.Clone();
401  }
402  else
403  {
404 
405  for (int i = 0; i < newsize; i++)
406  {
407  if (visualParams[i] != m_visualparams[i])
408  {
409  // DEBUG ON
410  // m_log.WarnFormat("[AVATARAPPEARANCE] vparams changed [{0}] {1} ==> {2}",
411  // i,m_visualparams[i],visualParams[i]);
412  // DEBUG OFF
413  m_visualparams[i] = visualParams[i];
414  changed = true;
415  }
416  }
417  }
418  // Reset the height if the visual parameters actually changed
419 // if (changed)
420 // SetHeight();
421 
422  return changed;
423  }
424 
425  public virtual void SetAppearance(Primitive.TextureEntry textureEntry, byte[] visualParams)
426  {
427  SetTextureEntries(textureEntry);
428  SetVisualParams(visualParams);
429  }
430 
434  public virtual void SetHeight()
435  {
436 /*
437  // Start with shortest possible female avatar height
438  m_avatarHeight = 1.14597f;
439  // Add offset for male avatars
440  if (m_visualparams[(int)VPElement.SHAPE_MALE] != 0)
441  m_avatarHeight += 0.0848f;
442  // Add offsets for visual params
443  m_avatarHeight += 0.516945f * (float)m_visualparams[(int)VPElement.SHAPE_HEIGHT] / 255.0f
444  + 0.08117f * (float)m_visualparams[(int)VPElement.SHAPE_HEAD_SIZE] / 255.0f
445  + 0.3836f * (float)m_visualparams[(int)VPElement.SHAPE_LEG_LENGTH] / 255.0f
446  + 0.07f * (float)m_visualparams[(int)VPElement.SHOES_PLATFORM_HEIGHT] / 255.0f
447  + 0.08f * (float)m_visualparams[(int)VPElement.SHOES_HEEL_HEIGHT] / 255.0f
448  + 0.076f * (float)m_visualparams[(int)VPElement.SHAPE_NECK_LENGTH] / 255.0f;
449 */
450  }
451 
452  public void SetSize(Vector3 avSize)
453  {
454  if (avSize.X > 32f)
455  avSize.X = 32f;
456  else if (avSize.X < 0.1f)
457  avSize.X = 0.1f;
458 
459  if (avSize.Y > 32f)
460  avSize.Y = 32f;
461  else if (avSize.Y < 0.1f)
462  avSize.Y = 0.1f;
463  if (avSize.Z > 32f)
464  avSize.Z = 32f;
465  else if (avSize.Z < 0.1f)
466  avSize.Z = 0.1f;
467 
468  m_avatarSize = avSize;
469  m_avatarBoxSize = avSize;
470  m_avatarBoxSize.Z += AVBOXAJUST;
471  if (m_avatarBoxSize.X < AVBOXMINX)
472  m_avatarBoxSize.X = AVBOXMINX;
473  if (m_avatarBoxSize.Y < AVBOXMINY)
474  m_avatarBoxSize.Y = AVBOXMINY;
475  if (m_avatarBoxSize.Z < AVBOXMINZ)
476  m_avatarBoxSize.Z = AVBOXMINZ;
477  m_avatarHeight = m_avatarSize.Z;
478  }
479 
480  public virtual void SetWearable(int wearableId, AvatarWearable wearable)
481  {
482 // DEBUG ON
483 // m_log.WarnFormat("[AVATARAPPEARANCE] set wearable {0} --> {1}:{2}",wearableId,wearable.ItemID,wearable.AssetID);
484 // DEBUG OFF
485  if (wearableId >= m_wearables.Length)
486  {
487  int currentLength = m_wearables.Length;
488  Array.Resize(ref m_wearables, wearableId + 1);
489  for (int i = currentLength ; i < m_wearables.Length ; i++)
490  m_wearables[i] = new AvatarWearable();
491  }
492  m_wearables[wearableId].Clear();
493  for (int i = 0; i < wearable.Count; i++)
494  m_wearables[wearableId].Add(wearable[i].ItemID, wearable[i].AssetID);
495  }
496 
497 // DEBUG ON
498  public override String ToString()
499  {
500  String s = "";
501 
502  s += String.Format("Serial: {0}\n",m_serial);
503 
504  for (uint i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++)
505  if (m_texture.FaceTextures[i] != null)
506  s += String.Format("Texture: {0} --> {1}\n",i,m_texture.FaceTextures[i].TextureID);
507 
508  foreach (AvatarWearable awear in m_wearables)
509  {
510  for (int i = 0; i < awear.Count; i++)
511  s += String.Format("Wearable: item={0}, asset={1}\n",awear[i].ItemID,awear[i].AssetID);
512  }
513 
514  s += "Visual Params: ";
515  // for (uint j = 0; j < AvatarAppearance.VISUALPARAM_COUNT; j++)
516  for (uint j = 0; j < m_visualparams.Length; j++)
517  s += String.Format("{0},",m_visualparams[j]);
518  s += "\n";
519 
520  return s;
521  }
522 // DEBUG OFF
523 
530  public List<AvatarAttachment> GetAttachments()
531  {
532  lock (m_attachments)
533  {
534  List<AvatarAttachment> alist = new List<AvatarAttachment>();
535  foreach (KeyValuePair<int, List<AvatarAttachment>> kvp in m_attachments)
536  {
537  foreach (AvatarAttachment attach in kvp.Value)
538  alist.Add(new AvatarAttachment(attach));
539  }
540  return alist;
541  }
542  }
543 
544  internal void AppendAttachment(AvatarAttachment attach)
545  {
546 // m_log.DebugFormat(
547 // "[AVATAR APPEARNCE]: Appending itemID={0}, assetID={1} at {2}",
548 // attach.ItemID, attach.AssetID, attach.AttachPoint);
549 
550  lock (m_attachments)
551  {
552  if (!m_attachments.ContainsKey(attach.AttachPoint))
553  m_attachments[attach.AttachPoint] = new List<AvatarAttachment>();
554 
555  foreach (AvatarAttachment prev in m_attachments[attach.AttachPoint])
556  {
557  if (prev.ItemID == attach.ItemID)
558  return;
559  }
560 
561  m_attachments[attach.AttachPoint].Add(attach);
562  }
563  }
564 
565  internal void ReplaceAttachment(AvatarAttachment attach)
566  {
567 // m_log.DebugFormat(
568 // "[AVATAR APPEARANCE]: Replacing itemID={0}, assetID={1} at {2}",
569 // attach.ItemID, attach.AssetID, attach.AttachPoint);
570 
571  lock (m_attachments)
572  {
573  m_attachments[attach.AttachPoint] = new List<AvatarAttachment>();
574  m_attachments[attach.AttachPoint].Add(attach);
575  }
576  }
577 
593  public bool SetAttachment(int attachpoint, UUID item, UUID asset)
594  {
595 // m_log.DebugFormat(
596 // "[AVATAR APPEARANCE]: Setting attachment at {0} with item ID {1}, asset ID {2}",
597 // attachpoint, item, asset);
598 
599  if (attachpoint == 0)
600  return false;
601 
602  lock (m_attachments)
603  {
604  if (item == UUID.Zero)
605  {
606  if (m_attachments.ContainsKey(attachpoint))
607  {
608  m_attachments.Remove(attachpoint);
609  return true;
610  }
611 
612  return false;
613  }
614 
615  // When a user logs in, the attachment item ids are pulled from persistence in the Avatars table. However,
616  // the asset ids are not saved. When the avatar enters a simulator the attachments are set again. If
617  // we simply perform an item check here then the asset ids (which are now present) are never set, and NPC attachments
618  // later fail unless the attachment is detached and reattached.
619  //
620  // Therefore, we will carry on with the set if the existing attachment has no asset id.
621  AvatarAttachment existingAttachment = GetAttachmentForItem(item);
622  if (existingAttachment != null)
623  {
624 // m_log.DebugFormat(
625 // "[AVATAR APPEARANCE]: Found existing attachment for {0}, asset {1} at point {2}",
626 // existingAttachment.ItemID, existingAttachment.AssetID, existingAttachment.AttachPoint);
627 
628  if (existingAttachment.AssetID != UUID.Zero && existingAttachment.AttachPoint == (attachpoint & 0x7F))
629  {
630  m_log.DebugFormat(
631  "[AVATAR APPEARANCE]: Ignoring attempt to attach an already attached item {0} at point {1}",
632  item, attachpoint);
633 
634  return false;
635  }
636  else
637  {
638  // Remove it here so that the later append does not add a second attachment but we still update
639  // the assetID
640  DetachAttachment(existingAttachment.ItemID);
641  }
642  }
643 
644  // check if this is an append or a replace, 0x80 marks it as an append
645  if ((attachpoint & 0x80) > 0)
646  {
647  // strip the append bit
648  int point = attachpoint & 0x7F;
649  AppendAttachment(new AvatarAttachment(point, item, asset));
650  }
651  else
652  {
653  ReplaceAttachment(new AvatarAttachment(attachpoint,item, asset));
654  }
655  }
656 
657  return true;
658  }
659 
666  {
667  lock (m_attachments)
668  {
669  foreach (KeyValuePair<int, List<AvatarAttachment>> kvp in m_attachments)
670  {
671  int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; });
672  if (index >= 0)
673  return kvp.Value[index];
674  }
675  }
676 
677  return null;
678  }
679 
680  public int GetAttachpoint(UUID itemID)
681  {
682  lock (m_attachments)
683  {
684  foreach (KeyValuePair<int, List<AvatarAttachment>> kvp in m_attachments)
685  {
686  int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; });
687  if (index >= 0)
688  return kvp.Key;
689  }
690  }
691  return 0;
692  }
693 
694  public bool DetachAttachment(UUID itemID)
695  {
696  lock (m_attachments)
697  {
698  foreach (KeyValuePair<int, List<AvatarAttachment>> kvp in m_attachments)
699  {
700  int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; });
701  if (index >= 0)
702  {
703 // m_log.DebugFormat(
704 // "[AVATAR APPEARANCE]: Detaching attachment {0}, index {1}, point {2}",
705 // m_attachments[kvp.Key][index].ItemID, index, m_attachments[kvp.Key][index].AttachPoint);
706 
707  // Remove it from the list of attachments at that attach point
708  m_attachments[kvp.Key].RemoveAt(index);
709 
710  // And remove the list if there are no more attachments here
711  if (m_attachments[kvp.Key].Count == 0)
712  m_attachments.Remove(kvp.Key);
713 
714  return true;
715  }
716  }
717  }
718 
719  return false;
720  }
721 
722  public void ClearAttachments()
723  {
724  lock (m_attachments)
725  m_attachments.Clear();
726  }
727 
728  #region Packing Functions
729 
734  {
735  OSDMap data = new OSDMap();
736 
737  data["serial"] = OSD.FromInteger(m_serial);
738  data["height"] = OSD.FromReal(m_avatarHeight);
739 
740  // Wearables
741  //
742  // This will send as many or as few wearables as we have, unless a count
743  // is given. Used for legacy (pre 0.4) versions.
744  int count = ctx.WearablesCount;
745  if (ctx.WearablesCount == -1)
746  count = m_wearables.Length;
747  OSDArray wears = new OSDArray(count);
748  for (int i = 0; i < count; i++)
749  {
750  AvatarWearable dummyWearable = new AvatarWearable();
751 
752  if (i < m_wearables.Length)
753  wears.Add(m_wearables[i].Pack());
754  else
755  wears.Add(dummyWearable.Pack());
756  }
757  data["wearables"] = wears;
758 
759  // Avatar Textures
761  for (uint i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++)
762  {
763  if (m_texture.FaceTextures[i] != null)
764  textures.Add(OSD.FromUUID(m_texture.FaceTextures[i].TextureID));
765  else
766  textures.Add(OSD.FromUUID(AppearanceManager.DEFAULT_AVATAR_TEXTURE));
767  }
768  data["textures"] = textures;
769 
770  if (m_cacheitems != null)
771  {
772  OSDArray baked = WearableCacheItem.BakedToOSD(m_cacheitems);
773  if (baked != null)
774  data["bakedcache"] = baked;
775  }
776 
777  // Visual Parameters
778  OSDBinary visualparams = new OSDBinary(m_visualparams);
779  data["visualparams"] = visualparams;
780 
781  lock (m_attachments)
782  {
783  // Attachments
784  OSDArray attachs = new OSDArray(m_attachments.Count);
785  foreach (AvatarAttachment attach in GetAttachments())
786  attachs.Add(attach.Pack());
787  data["attachments"] = attachs;
788  }
789 
790  return data;
791  }
792 
797  public void Unpack(OSDMap data)
798  {
799  if ((data != null) && (data["serial"] != null))
800  m_serial = data["serial"].AsInteger();
801  if ((data != null) && (data["height"] != null))
802 // m_avatarHeight = (float)data["height"].AsReal();
803  SetSize(new Vector3(0.45f,0.6f, (float)data["height"].AsReal()));
804 
805  try
806  {
807  // Wearables
808  SetDefaultWearables();
809  if ((data != null) && (data["wearables"] != null) && (data["wearables"]).Type == OSDType.Array)
810  {
811  OSDArray wears = (OSDArray)(data["wearables"]);
812 
813  int count = wears.Count;
814 
815  m_wearables = new AvatarWearable[count];
816 
817  for (int i = 0; i < count; i++)
818  m_wearables[i] = new AvatarWearable((OSDArray)wears[i]);
819  }
820  else
821  {
822  m_log.Warn("[AVATAR APPEARANCE]: failed to unpack wearables");
823  }
824 
825  // Avatar Textures
826  SetDefaultTexture();
827  if ((data != null) && (data["textures"] != null) && (data["textures"]).Type == OSDType.Array)
828  {
829  OSDArray textures = (OSDArray)(data["textures"]);
830  for (int i = 0; i < AvatarAppearance.TEXTURE_COUNT && i < textures.Count; i++)
831  {
832  UUID textureID = AppearanceManager.DEFAULT_AVATAR_TEXTURE;
833  if (textures[i] != null)
834  textureID = textures[i].AsUUID();
835  m_texture.CreateFace((uint)i).TextureID = new UUID(textureID);
836  }
837  }
838  else
839  {
840  m_log.Warn("[AVATAR APPEARANCE]: failed to unpack textures");
841  }
842 
843  if ((data != null) && (data["bakedcache"] != null) && (data["bakedcache"]).Type == OSDType.Array)
844  {
845  OSDArray bakedOSDArray = (OSDArray)(data["bakedcache"]);
846  m_cacheitems = WearableCacheItem.BakedFromOSD(bakedOSDArray);
847  }
848 
849  // Visual Parameters
850  SetDefaultParams();
851  if ((data != null) && (data["visualparams"] != null))
852  {
853  if ((data["visualparams"].Type == OSDType.Binary) || (data["visualparams"].Type == OSDType.Array))
854  m_visualparams = data["visualparams"].AsBinary();
855  }
856  else
857  {
858  m_log.Warn("[AVATAR APPEARANCE]: failed to unpack visual parameters");
859  }
860 
861  // Attachments
862  m_attachments = new Dictionary<int, List<AvatarAttachment>>();
863  if ((data != null) && (data["attachments"] != null) && (data["attachments"]).Type == OSDType.Array)
864  {
865  OSDArray attachs = (OSDArray)(data["attachments"]);
866  for (int i = 0; i < attachs.Count; i++)
867  {
868  AvatarAttachment att = new AvatarAttachment((OSDMap)attachs[i]);
869  AppendAttachment(att);
870 
871 // m_log.DebugFormat(
872 // "[AVATAR APPEARANCE]: Unpacked attachment itemID {0}, assetID {1}, point {2}",
873 // att.ItemID, att.AssetID, att.AttachPoint);
874  }
875  }
876  }
877  catch (Exception e)
878  {
879  m_log.ErrorFormat("[AVATAR APPEARANCE]: unpack failed badly: {0}{1}", e.Message, e.StackTrace);
880  }
881  }
882 
883  #endregion
884 
885  #region VPElement
886 
891  public enum VPElement : int
892  {
896  SHAPE_BIG_BROW = 0,
900  SHAPE_NOSE_BIG_OUT = 1,
904  SHAPE_BROAD_NOSTRILS = 2,
908  SHAPE_CLEFT_CHIN = 3,
912  SHAPE_BULBOUS_NOSE_TIP = 4,
916  SHAPE_WEAK_CHIN = 5,
920  SHAPE_DOUBLE_CHIN = 6,
924  SHAPE_SUNKEN_CHEEKS = 7,
928  SHAPE_NOBLE_NOSE_BRIDGE = 8,
932  SHAPE_JOWLS = 9,
936  SHAPE_CLEFT_CHIN_UPPER = 10,
940  SHAPE_HIGH_CHEEK_BONES = 11,
944  SHAPE_EARS_OUT = 12,
948  HAIR_POINTY_EYEBROWS = 13,
952  SHAPE_SQUARE_JAW = 14,
956  SHAPE_PUFFY_UPPER_CHEEKS = 15,
960  SHAPE_UPTURNED_NOSE_TIP = 16,
964  SHAPE_BULBOUS_NOSE = 17,
968  SHAPE_UPPER_EYELID_FOLD = 18,
972  SHAPE_ATTACHED_EARLOBES = 19,
976  SHAPE_BAGGY_EYES = 20,
980  SHAPE_WIDE_EYES = 21,
984  SHAPE_WIDE_LIP_CLEFT = 22,
988  SHAPE_WIDE_NOSE_BRIDGE = 23,
992  HAIR_ARCED_EYEBROWS = 24,
996  SHAPE_HEIGHT = 25,
1000  SHAPE_THICKNESS = 26,
1004  SHAPE_BIG_EARS = 27,
1008  SHAPE_SHOULDERS = 28,
1012  SHAPE_HIP_WIDTH = 29,
1016  SHAPE_TORSO_LENGTH = 30,
1017  SHAPE_MALE = 31,
1021  GLOVES_GLOVE_LENGTH = 32,
1025  EYES_EYE_LIGHTNESS = 33,
1029  EYES_EYE_COLOR = 34,
1033  SHAPE_BREAST_SIZE = 35,
1037  SKIN_RAINBOW_COLOR = 36,
1041  SKIN_RED_SKIN = 37,
1045  SKIN_PIGMENT = 38,
1046  HAIR_RAINBOW_COLOR_39 = 39,
1050  HAIR_RED_HAIR = 40,
1054  HAIR_BLONDE_HAIR = 41,
1058  HAIR_WHITE_HAIR = 42,
1062  SKIN_ROSY_COMPLEXION = 43,
1066  SKIN_LIP_PINKNESS = 44,
1070  HAIR_EYEBROW_SIZE = 45,
1074  HAIR_FRONT_FRINGE = 46,
1078  HAIR_SIDE_FRINGE = 47,
1082  HAIR_BACK_FRINGE = 48,
1086  HAIR_HAIR_FRONT = 49,
1090  HAIR_HAIR_SIDES = 50,
1094  HAIR_HAIR_BACK = 51,
1098  HAIR_HAIR_SWEEP = 52,
1102  HAIR_HAIR_TILT = 53,
1106  HAIR_HAIR_PART_MIDDLE = 54,
1110  HAIR_HAIR_PART_RIGHT = 55,
1114  HAIR_HAIR_PART_LEFT = 56,
1118  HAIR_HAIR_SIDES_FULL = 57,
1122  SKIN_BODY_DEFINITION = 58,
1126  SHAPE_LIP_WIDTH = 59,
1130  SHAPE_BELLY_SIZE = 60,
1134  SKIN_FACIAL_DEFINITION = 61,
1138  SKIN_WRINKLES = 62,
1142  SKIN_FRECKLES = 63,
1146  HAIR_SIDEBURNS = 64,
1150  HAIR_MOUSTACHE = 65,
1154  HAIR_SOULPATCH = 66,
1158  HAIR_CHIN_CURTAINS = 67,
1162  HAIR_HAIR_RUMPLED = 68,
1166  HAIR_HAIR_BIG_FRONT = 69,
1170  HAIR_HAIR_BIG_TOP = 70,
1174  HAIR_HAIR_BIG_BACK = 71,
1178  HAIR_HAIR_SPIKED = 72,
1182  SHAPE_DEEP_CHIN = 73,
1186  HAIR_BANGS_PART_MIDDLE = 74,
1190  SHAPE_HEAD_SHAPE = 75,
1194  SHAPE_EYE_SPACING = 76,
1198  SHOES_HEEL_HEIGHT = 77,
1202  SHOES_PLATFORM_HEIGHT = 78,
1206  SHAPE_LIP_THICKNESS = 79,
1210  SHAPE_MOUTH_HEIGHT = 80,
1214  SHAPE_BREAST_GRAVITY = 81,
1218  SHOES_SHOE_PLATFORM_WIDTH = 82,
1222  SHOES_HEEL_SHAPE = 83,
1226  SHOES_TOE_SHAPE = 84,
1230  SHAPE_FOOT_SIZE = 85,
1234  SHAPE_WIDE_NOSE = 86,
1238  SHAPE_EYELASHES_LONG = 87,
1242  UNDERSHIRT_SLEEVE_LENGTH = 88,
1246  UNDERSHIRT_BOTTOM = 89,
1250  UNDERSHIRT_COLLAR_FRONT = 90,
1251  JACKET_SLEEVE_LENGTH_91 = 91,
1252  JACKET_COLLAR_FRONT_92 = 92,
1256  JACKET_BOTTOM_LENGTH_LOWER = 93,
1260  JACKET_OPEN_JACKET = 94,
1264  SHOES_SHOE_HEIGHT = 95,
1268  SOCKS_SOCKS_LENGTH = 96,
1272  UNDERPANTS_PANTS_LENGTH = 97,
1276  UNDERPANTS_PANTS_WAIST = 98,
1280  PANTS_LEG_PANTFLAIR = 99,
1284  SHAPE_FOREHEAD_ANGLE = 100,
1288  SHAPE_BODY_FAT = 101,
1292  PANTS_LOW_CROTCH = 102,
1296  SHAPE_EGG_HEAD = 103,
1300  SHAPE_SQUASH_STRETCH_HEAD = 104,
1304  SHAPE_TORSO_MUSCLES = 105,
1308  SHAPE_EYELID_CORNER_UP = 106,
1312  SHAPE_LEG_MUSCLES = 107,
1316  SHAPE_TALL_LIPS = 108,
1320  SHOES_SHOE_TOE_THICK = 109,
1324  SHAPE_CROOKED_NOSE = 110,
1328  SHAPE_MOUTH_CORNER = 111,
1332  SHAPE_FACE_SHEAR = 112,
1336  SHAPE_SHIFT_MOUTH = 113,
1340  SHAPE_POP_EYE = 114,
1344  SHAPE_JAW_JUT = 115,
1348  HAIR_HAIR_SHEAR_BACK = 116,
1352  SHAPE_HAND_SIZE = 117,
1356  SHAPE_LOVE_HANDLES = 118,
1357  SHAPE_TORSO_MUSCLES_119 = 119,
1361  SHAPE_HEAD_SIZE = 120,
1365  SHAPE_NECK_THICKNESS = 121,
1369  SHAPE_BREAST_FEMALE_CLEAVAGE = 122,
1373  SHAPE_CHEST_MALE_NO_PECS = 123,
1377  SHAPE_EYE_SIZE = 124,
1381  SHAPE_LEG_LENGTH = 125,
1385  SHAPE_ARM_LENGTH = 126,
1389  SKIN_LIPSTICK_COLOR = 127,
1393  SKIN_LIPSTICK = 128,
1397  SKIN_LIPGLOSS = 129,
1401  SKIN_EYELINER = 130,
1405  SKIN_BLUSH = 131,
1409  SKIN_BLUSH_COLOR = 132,
1413  SKIN_OUT_SHDW_OPACITY = 133,
1417  SKIN_OUTER_SHADOW = 134,
1421  SKIN_OUT_SHDW_COLOR = 135,
1425  SKIN_INNER_SHADOW = 136,
1429  SKIN_NAIL_POLISH = 137,
1433  SKIN_BLUSH_OPACITY = 138,
1437  SKIN_IN_SHDW_COLOR = 139,
1441  SKIN_IN_SHDW_OPACITY = 140,
1445  SKIN_EYELINER_COLOR = 141,
1449  SKIN_NAIL_POLISH_COLOR = 142,
1453  HAIR_EYEBROW_DENSITY = 143,
1457  HAIR_HAIR_THICKNESS = 144,
1461  SHAPE_SADDLEBAGS = 145,
1465  HAIR_HAIR_TAPER_BACK = 146,
1469  HAIR_HAIR_TAPER_FRONT = 147,
1473  SHAPE_NECK_LENGTH = 148,
1477  HAIR_LOWER_EYEBROWS = 149,
1481  SHAPE_LOWER_BRIDGE_NOSE = 150,
1485  SHAPE_LOW_SEPTUM_NOSE = 151,
1489  SHAPE_JAW_ANGLE = 152,
1493  HAIR_HAIR_SHEAR_FRONT = 153,
1497  HAIR_HAIR_VOLUME = 154,
1501  SHAPE_LIP_CLEFT_DEEP = 155,
1505  SHAPE_PUFFY_LOWER_LIDS = 156,
1509  SHAPE_EYE_DEPTH = 157,
1513  SHAPE_HEAD_LENGTH = 158,
1517  SKIN_BODY_FRECKLES = 159,
1521  UNDERSHIRT_COLLAR_BACK = 160,
1522  JACKET_COLLAR_BACK_161 = 161,
1523  SHIRT_COLLAR_BACK_162 = 162,
1527  HAIR_PIGTAILS = 163,
1531  HAIR_PONYTAIL = 164,
1535  SHAPE_BUTT_SIZE = 165,
1539  SHAPE_POINTY_EARS = 166,
1543  SHAPE_LIP_RATIO = 167,
1544  SHIRT_SLEEVE_LENGTH_168 = 168,
1548  SHIRT_SHIRT_BOTTOM = 169,
1549  SHIRT_COLLAR_FRONT_170 = 170,
1550  SHIRT_SHIRT_RED = 171,
1551  SHIRT_SHIRT_GREEN = 172,
1552  SHIRT_SHIRT_BLUE = 173,
1553  PANTS_PANTS_RED = 174,
1554  PANTS_PANTS_GREEN = 175,
1555  PANTS_PANTS_BLUE = 176,
1556  SHOES_SHOES_RED = 177,
1557  SHOES_SHOES_GREEN = 178,
1561  PANTS_WAIST_HEIGHT = 179,
1562  PANTS_PANTS_LENGTH_180 = 180,
1566  PANTS_LOOSE_LOWER_CLOTHING = 181,
1567  SHOES_SHOES_BLUE = 182,
1568  SOCKS_SOCKS_RED = 183,
1569  SOCKS_SOCKS_GREEN = 184,
1570  SOCKS_SOCKS_BLUE = 185,
1571  UNDERSHIRT_UNDERSHIRT_RED = 186,
1572  UNDERSHIRT_UNDERSHIRT_GREEN = 187,
1573  UNDERSHIRT_UNDERSHIRT_BLUE = 188,
1574  UNDERPANTS_UNDERPANTS_RED = 189,
1575  UNDERPANTS_UNDERPANTS_GREEN = 190,
1576  UNDERPANTS_UNDERPANTS_BLUE = 191,
1577  GLOVES_GLOVES_RED = 192,
1581  SHIRT_LOOSE_UPPER_CLOTHING = 193,
1582  GLOVES_GLOVES_GREEN = 194,
1583  GLOVES_GLOVES_BLUE = 195,
1584  JACKET_JACKET_RED = 196,
1585  JACKET_JACKET_GREEN = 197,
1586  JACKET_JACKET_BLUE = 198,
1590  SHIRT_SHIRTSLEEVE_FLAIR = 199,
1594  SHAPE_BOWED_LEGS = 200,
1598  SHAPE_HIP_LENGTH = 201,
1602  GLOVES_GLOVE_FINGERS = 202,
1606  SKIRT_SKIRT_BUSTLE = 203,
1610  SKIRT_SKIRT_LENGTH = 204,
1614  SKIRT_SLIT_FRONT = 205,
1618  SKIRT_SLIT_BACK = 206,
1622  SKIRT_SLIT_LEFT = 207,
1626  SKIRT_SLIT_RIGHT = 208,
1630  SKIRT_SKIRT_LOOSENESS = 209,
1631  SHIRT_SHIRT_WRINKLES = 210,
1632  PANTS_PANTS_WRINKLES = 211,
1636  JACKET_JACKET_WRINKLES = 212,
1640  SHAPE_MALE_PACKAGE = 213,
1644  SHAPE_EYELID_INNER_CORNER_UP = 214,
1645  SKIRT_SKIRT_RED = 215,
1646  SKIRT_SKIRT_GREEN = 216,
1647  SKIRT_SKIRT_BLUE = 217,
1648 
1652 
1656  BREAST_PHYSICS_MASS = 218,
1657  BREAST_PHYSICS_GRAVITY = 219,
1658  BREAST_PHYSICS_DRAG = 220,
1659  BREAST_PHYSICS_UPDOWN_MAX_EFFECT = 221,
1660  BREAST_PHYSICS_UPDOWN_SPRING = 222,
1661  BREAST_PHYSICS_UPDOWN_GAIN = 223,
1662  BREAST_PHYSICS_UPDOWN_DAMPING = 224,
1663  BREAST_PHYSICS_INOUT_MAX_EFFECT = 225,
1664  BREAST_PHYSICS_INOUT_SPRING = 226,
1665  BREAST_PHYSICS_INOUT_GAIN = 227,
1666  BREAST_PHYSICS_INOUT_DAMPING = 228,
1670  BELLY_PHYISCS_MASS = 229,
1671  BELLY_PHYSICS_GRAVITY = 230,
1672  BELLY_PHYSICS_DRAG = 231,
1673  BELLY_PHYISCS_UPDOWN_MAX_EFFECT = 232,
1674  BELLY_PHYSICS_UPDOWN_SPRING = 233,
1675  BELLY_PHYSICS_UPDOWN_GAIN = 234,
1676  BELLY_PHYSICS_UPDOWN_DAMPING = 235,
1677 
1681  BUTT_PHYSICS_MASS = 236,
1682  BUTT_PHYSICS_GRAVITY = 237,
1683  BUTT_PHYSICS_DRAG = 238,
1684  BUTT_PHYSICS_UPDOWN_MAX_EFFECT = 239,
1685  BUTT_PHYSICS_UPDOWN_SPRING = 240,
1686  BUTT_PHYSICS_UPDOWN_GAIN = 241,
1687  BUTT_PHYSICS_UPDOWN_DAMPING = 242,
1688  BUTT_PHYSICS_LEFTRIGHT_MAX_EFFECT = 243,
1689  BUTT_PHYSICS_LEFTRIGHT_SPRING = 244,
1690  BUTT_PHYSICS_LEFTRIGHT_GAIN = 245,
1691  BUTT_PHYSICS_LEFTRIGHT_DAMPING = 246,
1695  BREAST_PHYSICS_LEFTRIGHT_MAX_EFFECT = 247,
1696  BREAST_PHYSICS_LEFTRIGHT_SPRING= 248,
1697  BREAST_PHYSICS_LEFTRIGHT_GAIN = 249,
1698  BREAST_PHYSICS_LEFTRIGHT_DAMPING = 250,
1699 
1700  // Ubit: 07/96/2013 new parameters
1701  _APPEARANCEMESSAGE_VERSION = 251, //ID 11000
1702 
1703  SHAPE_HOVER = 252, //ID 11001
1704  }
1705  #endregion
1706  }
1707 }
virtual Primitive.TextureEntry Texture
void Unpack(OSDMap data)
Unpack and OSDMap and initialize the appearance from it
OpenMetaverse.StructuredData.OSDArray OSDArray
virtual void SetAppearance(Primitive.TextureEntry textureEntry, byte[] visualParams)
Contains the Avatar's Appearance and methods to manipulate the appearance.
virtual void ResetBakedTextures()
Invalidate all of the baked textures in the appearance, useful if you know that none are valid ...
AvatarAppearance(AvatarAppearance appearance, bool copyWearables)
OpenMetaverse.StructuredData.OSDMap OSDMap
AvatarAppearance(AvatarAppearance appearance, bool copyWearables, bool copyBaked)
AvatarAttachment GetAttachmentForItem(UUID itemID)
If the item is already attached, return it.
Dictionary< int, List< AvatarAttachment > > m_attachments
void GetAssetsFrom(AvatarAppearance app)
AvatarAppearance(AvatarWearable[] wearables, Primitive.TextureEntry textureEntry, byte[] visualParams)
virtual AvatarWearable[] Wearables
virtual bool SetTextureEntries(Primitive.TextureEntry textureEntry)
Set up appearance texture ids.
OSDMap Pack(EntityTransferContext ctx)
Create an OSDMap from the appearance data
List< AvatarAttachment > GetAttachments()
Get a list of the attachments.
virtual void SetWearable(int wearableId, AvatarWearable wearable)
virtual void ResetAppearance()
Invalidate all of the baked textures in the appearance, useful if you know that none are valid ...
virtual bool SetVisualParams(byte[] visualParams)
Set up visual parameters for the avatar and refresh the avatar height
Primitive.TextureEntry m_texture
AvatarAppearance(AvatarAppearance appearance)
bool SetAttachment(int attachpoint, UUID item, UUID asset)
Set an attachment
VPElement
Viewer Params Array Element for AgentSetAppearance Generated from LibOMV's Visual Params list ...
virtual void SetHeight()
Set avatar height by a calculation based on their visual parameters.