| | 1 | | using DCL.Helpers; |
| | 2 | | using Decentraland.Sdk.Ecs6; |
| | 3 | | using MainScripts.DCL.Components; |
| | 4 | | using System; |
| | 5 | | using System.Collections.Generic; |
| | 6 | | using System.Linq; |
| | 7 | | using UnityEngine; |
| | 8 | |
|
| | 9 | | [Serializable] |
| | 10 | | public class AvatarModel : BaseModel |
| | 11 | | { |
| | 12 | | [Serializable] |
| | 13 | | public class AvatarEmoteEntry |
| | 14 | | { |
| | 15 | | public int slot; |
| | 16 | | public string urn; |
| | 17 | | } |
| | 18 | |
|
| | 19 | | public string id; |
| | 20 | | public string name; |
| | 21 | | public string bodyShape; |
| | 22 | |
|
| | 23 | | public Color skinColor; |
| | 24 | | public Color hairColor; |
| | 25 | | public Color eyeColor; |
| | 26 | |
|
| 3090 | 27 | | public List<string> wearables = new (); |
| 3090 | 28 | | public HashSet<string> forceRender = new (); |
| 3090 | 29 | | public List<AvatarEmoteEntry> emotes = new (); |
| | 30 | |
|
| | 31 | | public string expressionTriggerId = null; |
| 3090 | 32 | | public long expressionTriggerTimestamp = -1; |
| | 33 | | public bool talking = false; |
| | 34 | |
|
| | 35 | | public static AvatarModel FallbackModel(string name, int id) => |
| 587 | 36 | | new () |
| | 37 | | { |
| | 38 | | id = $"{name}_{id}", |
| | 39 | | name = name, |
| | 40 | | bodyShape = "urn:decentraland:off-chain:base-avatars:BaseMale", |
| | 41 | |
|
| | 42 | | skinColor = new Color(0.800f, 0.608f, 0.467f), |
| | 43 | | hairColor = new Color(0.596f, 0.373f, 0.216f), |
| | 44 | | eyeColor = new Color(0.373f, 0.224f, 0.196f), |
| | 45 | | }; |
| | 46 | |
|
| | 47 | | public override BaseModel GetDataFromPb(ComponentBodyPayload pbModel) |
| | 48 | | { |
| 0 | 49 | | if (pbModel.PayloadCase != ComponentBodyPayload.PayloadOneofCase.AvatarShape) |
| 0 | 50 | | return Utils.SafeUnimplemented<AvatarModel, AvatarModel>(expected: ComponentBodyPayload.PayloadOneofCase.Ava |
| | 51 | |
|
| 0 | 52 | | var model = new AvatarModel(); |
| 0 | 53 | | if (pbModel.AvatarShape.HasId) model.id = pbModel.AvatarShape.Id; |
| 0 | 54 | | if (pbModel.AvatarShape.HasName) model.name = pbModel.AvatarShape.Name; |
| 0 | 55 | | if (pbModel.AvatarShape.HasTalking) model.talking = pbModel.AvatarShape.Talking; |
| 0 | 56 | | if (pbModel.AvatarShape.HasBodyShape) model.bodyShape = pbModel.AvatarShape.BodyShape; |
| 0 | 57 | | if (pbModel.AvatarShape.EyeColor != null) model.eyeColor = pbModel.AvatarShape.EyeColor.AsUnityColor(); |
| 0 | 58 | | if (pbModel.AvatarShape.HairColor != null) model.hairColor = pbModel.AvatarShape.HairColor.AsUnityColor(); |
| 0 | 59 | | if (pbModel.AvatarShape.SkinColor != null) model.skinColor = pbModel.AvatarShape.SkinColor.AsUnityColor(); |
| 0 | 60 | | if (pbModel.AvatarShape.HasExpressionTriggerId) model.expressionTriggerId = pbModel.AvatarShape.ExpressionTrigge |
| 0 | 61 | | if (pbModel.AvatarShape.HasExpressionTriggerTimestamp) model.expressionTriggerTimestamp = pbModel.AvatarShape.Ex |
| 0 | 62 | | if (pbModel.AvatarShape.Wearables is { Count: > 0 }) model.wearables = pbModel.AvatarShape.Wearables.ToList(); |
| | 63 | |
|
| 0 | 64 | | if (pbModel.AvatarShape.Emotes is { Count: > 0 }) |
| | 65 | | { |
| 0 | 66 | | model.emotes = new List<AvatarEmoteEntry>(pbModel.AvatarShape.Emotes.Count); |
| | 67 | |
|
| 0 | 68 | | for (var i = 0; i < pbModel.AvatarShape.Emotes.Count; i++) |
| | 69 | | { |
| 0 | 70 | | if (pbModel.AvatarShape.Emotes[i] == null) continue; |
| 0 | 71 | | AvatarEmoteEntry emote = new AvatarEmoteEntry(); |
| | 72 | |
|
| 0 | 73 | | if (pbModel.AvatarShape.Emotes[i].HasSlot) emote.slot = pbModel.AvatarShape.Emotes[i].Slot; |
| 0 | 74 | | if (pbModel.AvatarShape.Emotes[i].HasUrn) emote.urn = pbModel.AvatarShape.Emotes[i].Urn; |
| 0 | 75 | | model.emotes.Add(emote); |
| | 76 | | } |
| | 77 | | } |
| | 78 | |
|
| 0 | 79 | | return model; |
| | 80 | | } |
| | 81 | |
|
| | 82 | | private bool IsListContainedIn(List<string> first, List<string> second) |
| | 83 | | { |
| 4 | 84 | | foreach (string item in first) |
| | 85 | |
|
| | 86 | | // This contains is slow |
| 0 | 87 | | if (!second.Contains(item)) |
| 0 | 88 | | return false; |
| | 89 | |
|
| 2 | 90 | | return true; |
| 0 | 91 | | } |
| | 92 | |
|
| | 93 | | private bool IsHashSetContainedIn(HashSet<string> first, HashSet<string> second) |
| | 94 | | { |
| 4 | 95 | | foreach (string item in first) |
| 0 | 96 | | if (!second.Contains(item)) |
| 0 | 97 | | return false; |
| | 98 | |
|
| 2 | 99 | | return true; |
| 0 | 100 | | } |
| | 101 | |
|
| | 102 | | public bool HaveSameWearablesAndColors(AvatarModel other) |
| | 103 | | { |
| 1 | 104 | | if (other == null) |
| 0 | 105 | | return false; |
| | 106 | |
|
| | 107 | | //wearables are the same |
| 1 | 108 | | if (!(wearables.Count == other.wearables.Count |
| | 109 | | && IsListContainedIn(wearables, other.wearables) |
| | 110 | | && IsListContainedIn(other.wearables, wearables))) |
| 0 | 111 | | return false; |
| | 112 | |
|
| 1 | 113 | | if (!(forceRender.Count == other.forceRender.Count |
| | 114 | | && IsHashSetContainedIn(forceRender, other.forceRender) |
| | 115 | | && IsHashSetContainedIn(other.forceRender, forceRender))) |
| 0 | 116 | | return false; |
| | 117 | |
|
| | 118 | | //emotes are the same |
| 1 | 119 | | if (emotes == null && other.emotes != null) |
| 0 | 120 | | return false; |
| | 121 | |
|
| 1 | 122 | | if (emotes != null && other.emotes == null) |
| 0 | 123 | | return false; |
| | 124 | |
|
| 1 | 125 | | if (emotes != null && other.emotes != null) |
| | 126 | | { |
| 1 | 127 | | if (emotes.Count != other.emotes.Count) |
| 0 | 128 | | return false; |
| | 129 | |
|
| 2 | 130 | | foreach (AvatarEmoteEntry emote in emotes) |
| | 131 | | { |
| 0 | 132 | | var found = false; |
| | 133 | |
|
| 0 | 134 | | foreach (AvatarEmoteEntry t in other.emotes) |
| 0 | 135 | | if (t.urn == emote.urn) |
| | 136 | | { |
| 0 | 137 | | found = true; |
| 0 | 138 | | break; |
| | 139 | | } |
| | 140 | |
|
| 0 | 141 | | if (!found) |
| 0 | 142 | | return false; |
| | 143 | | } |
| | 144 | | } |
| | 145 | |
|
| 1 | 146 | | return bodyShape == other.bodyShape && |
| | 147 | | skinColor == other.skinColor && |
| | 148 | | hairColor == other.hairColor && |
| | 149 | | eyeColor == other.eyeColor; |
| 0 | 150 | | } |
| | 151 | |
|
| | 152 | | public bool Equals(AvatarModel other) |
| | 153 | | { |
| 0 | 154 | | if (other == null) return false; |
| | 155 | |
|
| 0 | 156 | | bool wearablesAreEqual = wearables.All(other.wearables.Contains) |
| | 157 | | && other.wearables.All(wearables.Contains) |
| | 158 | | && wearables.Count == other.wearables.Count; |
| | 159 | |
|
| 0 | 160 | | bool forceRenderAreEqual = forceRender.All(other.forceRender.Contains) |
| | 161 | | && other.forceRender.All(forceRender.Contains) |
| | 162 | | && forceRender.Count == other.forceRender.Count; |
| | 163 | |
|
| 0 | 164 | | return id == other.id |
| | 165 | | && name == other.name |
| | 166 | | && bodyShape == other.bodyShape |
| | 167 | | && skinColor == other.skinColor |
| | 168 | | && hairColor == other.hairColor |
| | 169 | | && eyeColor == other.eyeColor |
| | 170 | | && expressionTriggerId == other.expressionTriggerId |
| | 171 | | && expressionTriggerTimestamp == other.expressionTriggerTimestamp |
| | 172 | | && wearablesAreEqual |
| | 173 | | && forceRenderAreEqual; |
| | 174 | | } |
| | 175 | |
|
| | 176 | | public void CopyFrom(AvatarModel other) |
| | 177 | | { |
| 727 | 178 | | if (other == null) |
| 0 | 179 | | return; |
| | 180 | |
|
| 727 | 181 | | id = other.id; |
| 727 | 182 | | name = other.name; |
| 727 | 183 | | bodyShape = other.bodyShape; |
| 727 | 184 | | skinColor = other.skinColor; |
| 727 | 185 | | hairColor = other.hairColor; |
| 727 | 186 | | eyeColor = other.eyeColor; |
| 727 | 187 | | expressionTriggerId = other.expressionTriggerId; |
| 727 | 188 | | expressionTriggerTimestamp = other.expressionTriggerTimestamp; |
| 727 | 189 | | wearables = new List<string>(other.wearables); |
| 727 | 190 | | emotes = other.emotes.Select(x => new AvatarEmoteEntry() { slot = x.slot, urn = x.urn }).ToList(); |
| 727 | 191 | | forceRender = new HashSet<string>(other.forceRender); |
| 727 | 192 | | } |
| | 193 | |
|
| | 194 | | public override BaseModel GetDataFromJSON(string json) => |
| 1 | 195 | | Utils.SafeFromJson<AvatarModel>(json); |
| | 196 | | } |