CharacterSerializer.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text.RegularExpressions;
  5. using Assets.HeroEditor4D.Common.Scripts.Common;
  6. using Assets.HeroEditor4D.Common.Scripts.Data;
  7. using Assets.HeroEditor4D.Common.Scripts.Enums;
  8. using Newtonsoft.Json;
  9. using UnityEngine;
  10. namespace Assets.HeroEditor4D.Common.Scripts.CharacterScripts
  11. {
  12. public partial class Character
  13. {
  14. public string ToJson()
  15. {
  16. if (SpriteCollection == null) throw new Exception("SpriteCollection is null!");
  17. var description = new Dictionary<string, string>
  18. {
  19. { "Body", SpriteToString(SpriteCollection.Body, BodyRenderers[0]) },
  20. { "Ears", SpriteToString(SpriteCollection.Ears, EarsRenderers[0]) },
  21. { "Hair", SpriteToString(SpriteCollection.Hair, HairRenderer) },
  22. { "Beard", SpriteToString(SpriteCollection.Beard, BeardRenderer) },
  23. { "Helmet", SpriteToString(SpriteCollection.Armor, HelmetRenderer) },
  24. { "Armor", SpritesToString(SpriteCollection.Armor, ArmorRenderers) },
  25. //{ "Cape", SpriteToString(SpriteCollection.Cape, CapeRenderer) },
  26. { "Backpack", SpriteToString(SpriteCollection.Backpack, BackpackRenderer) },
  27. { "Shield", SpriteToString(SpriteCollection.Shield, ShieldRenderers[0]) },
  28. { "WeaponType", WeaponType.ToString() },
  29. { "Expression", Expression },
  30. { "HideEars", HideEars.ToString() },
  31. { "CropHair", CropHair.ToString() },
  32. { "Makeup", SpriteToString(SpriteCollection.Makeup, MakeupRenderer) },
  33. { "Mask", SpriteToString(SpriteCollection.Mask, MaskRenderer) },
  34. { "Earrings", SpriteToString(SpriteCollection.Earrings, EarringsRenderers[0]) }
  35. };
  36. switch (WeaponType)
  37. {
  38. case WeaponType.Melee1H:
  39. case WeaponType.Melee2H:
  40. case WeaponType.Firearm1H:
  41. case WeaponType.Firearm2H:
  42. description.Add("PrimaryWeapon", SpriteToString(GetWeaponCollection(WeaponType), PrimaryWeaponRenderer));
  43. break;
  44. case WeaponType.Paired:
  45. description.Add("SecondaryWeapon", SpriteToString(SpriteCollection.Firearm1H, SecondaryWeaponRenderer)); // TODO:
  46. break;
  47. case WeaponType.Bow:
  48. description.Add("Bow", SpriteToString(SpriteCollection.Bow, BowRenderers[0]));
  49. break;
  50. case WeaponType.Crossbow:
  51. description.Add("Crossbow", SpriteToString(SpriteCollection.Crossbow, CrossbowRenderers[0]));
  52. break;
  53. default:
  54. throw new NotImplementedException();
  55. }
  56. foreach (var expression in Expressions)
  57. {
  58. description.Add($"Expression.{expression.Name}.Eyebrows", SpriteToString(SpriteCollection.Eyebrows, expression.Eyebrows, EyebrowsRenderer.color));
  59. description.Add($"Expression.{expression.Name}.Eyes", SpriteToString(SpriteCollection.Eyes, expression.Eyes, EyesRenderer.color));
  60. description.Add($"Expression.{expression.Name}.EyesColor", "#" + ColorUtility.ToHtmlStringRGBA(expression.EyesColor));
  61. description.Add($"Expression.{expression.Name}.Mouth", SpriteToString(SpriteCollection.Mouth, expression.Mouth, MouthRenderer.color));
  62. }
  63. return JsonConvert.SerializeObject(description);
  64. }
  65. public void LoadFromJson(string json, bool silent)
  66. {
  67. var description = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
  68. if (SpriteCollection == null) throw new Exception("SpriteCollection is null!");
  69. RestoreFromString(ref Body, BodyRenderers, SpriteCollection.Body, description["Body"], silent);
  70. RestoreFromString(ref Head, HeadRenderer, SpriteCollection.Body, description["Body"], silent);
  71. RestoreFromString(ref Ears, EarsRenderers, SpriteCollection.Ears, description["Ears"], silent);
  72. RestoreFromString(ref Hair, HairRenderer, SpriteCollection.Hair, description["Hair"], silent);
  73. RestoreFromString(ref Beard, BeardRenderer, SpriteCollection.Beard, description["Beard"], silent);
  74. RestoreFromString(ref Helmet, HelmetRenderer, SpriteCollection.Armor, description["Helmet"], silent);
  75. RestoreFromString(ref Armor, ArmorRenderers, SpriteCollection.Armor, description["Armor"], silent);
  76. //RestoreFromString(ref Cape, CapeRenderer, SpriteCollection.Cape, description["Cape"], silent);
  77. //RestoreFromString(ref Quiver, QuiverRenderer, SpriteCollection.Bow.Union(SpriteCollection.Crossbow), description["Quiver"], silent);
  78. RestoreFromString(ref Backpack, BackpackRenderer, SpriteCollection.Backpack, description["Backpack"], silent);
  79. RestoreFromString(ref Shield, ShieldRenderers, SpriteCollection.Shield, description["Shield"], silent);
  80. Expression = description["Expression"];
  81. Expressions = new List<Expression>();
  82. HideEars = description.ContainsKey("HideEars") && bool.Parse(description["HideEars"]);
  83. CropHair = description.ContainsKey("HideHair") && bool.Parse(description["CropHair"]);
  84. RestoreFromString(ref Makeup, MakeupRenderer, SpriteCollection.Makeup, description["Makeup"], silent);
  85. RestoreFromString(ref Mask, MaskRenderer, SpriteCollection.Mask, description["Mask"], silent);
  86. RestoreFromString(ref Earrings, EarringsRenderers, SpriteCollection.Earrings, description["Earrings"], silent);
  87. foreach (var key in description.Keys)
  88. {
  89. if (key.Contains("Expression."))
  90. {
  91. var parts = key.Split('.');
  92. var expressionName = parts[1];
  93. var expressionPart = parts[2];
  94. var expression = Expressions.SingleOrDefault(i => i.Name == expressionName);
  95. if (expression == null)
  96. {
  97. expression = new Expression { Name = expressionName };
  98. Expressions.Add(expression);
  99. }
  100. switch (expressionPart)
  101. {
  102. case "Eyebrows":
  103. RestoreFromString(ref expression.Eyebrows, EyebrowsRenderer, SpriteCollection.Eyebrows, description[key]);
  104. break;
  105. case "Eyes":
  106. RestoreFromString(ref expression.Eyes, EyesRenderer, SpriteCollection.Eyes, description[key]);
  107. break;
  108. case "EyesColor":
  109. ColorUtility.TryParseHtmlString(description[key], out var color);
  110. expression.EyesColor = color;
  111. break;
  112. case "Mouth":
  113. RestoreFromString(ref expression.Mouth, MouthRenderer, SpriteCollection.Mouth, description[key]);
  114. break;
  115. default:
  116. throw new NotSupportedException(expressionPart);
  117. }
  118. }
  119. }
  120. SetExpression("Default");
  121. WeaponType = (WeaponType) Enum.Parse(typeof(WeaponType), description["WeaponType"], silent);
  122. if (description.ContainsKey("PrimaryWeapon"))
  123. {
  124. var weapon = RestoreFromString(ref PrimaryWeapon, PrimaryWeaponRenderer, GetWeaponCollection(WeaponType), description["PrimaryWeapon"], silent);
  125. if (weapon != null && (WeaponType == WeaponType.Firearm1H || WeaponType == WeaponType.Firearm2H))
  126. {
  127. SetFirearmMuzzle(weapon);
  128. }
  129. }
  130. if (description.ContainsKey("SecondaryWeapon"))
  131. {
  132. RestoreFromString(ref SecondaryWeapon, SecondaryWeaponRenderer, SpriteCollection.Firearm1H, description["SecondaryWeapon"], silent);
  133. }
  134. if (description.ContainsKey("Bow"))
  135. {
  136. RestoreFromString(ref CompositeWeapon, BowRenderers, SpriteCollection.Bow, description["Bow"], silent);
  137. }
  138. else if (description.ContainsKey("Crossbow"))
  139. {
  140. RestoreFromString(ref CompositeWeapon, CrossbowRenderers, SpriteCollection.Crossbow, description["Crossbow"], silent);
  141. }
  142. Initialize();
  143. }
  144. private IEnumerable<ItemSprite> GetWeaponCollection(WeaponType weaponType)
  145. {
  146. switch (weaponType)
  147. {
  148. case WeaponType.Melee1H: return SpriteCollection.MeleeWeapon1H;
  149. case WeaponType.Paired: return SpriteCollection.MeleeWeapon1H;
  150. case WeaponType.Melee2H: return SpriteCollection.MeleeWeapon2H;
  151. case WeaponType.Bow: return SpriteCollection.Bow;
  152. case WeaponType.Crossbow: return SpriteCollection.Crossbow;
  153. case WeaponType.Firearm1H: return SpriteCollection.Firearm1H;
  154. case WeaponType.Firearm2H: return SpriteCollection.Firearm2H;
  155. case WeaponType.Throwable: return SpriteCollection.Throwable;
  156. default:
  157. throw new NotSupportedException(weaponType.ToString());
  158. }
  159. }
  160. private static string SpriteToString(IEnumerable<ItemSprite> collection, SpriteRenderer renderer)
  161. {
  162. if (renderer == null) return null;
  163. return SpriteToString(collection, renderer.sprite, renderer.color);
  164. }
  165. private static string SpritesToString(IEnumerable<ItemSprite> collection, List<SpriteRenderer> renderers)
  166. {
  167. var values = renderers.Select(i => SpriteToString(collection, i));
  168. return string.Join(",", values);
  169. }
  170. private static string SpriteToString(IEnumerable<ItemSprite> collection, Sprite sprite, Color color)
  171. {
  172. if (sprite == null) return null;
  173. var entry = collection.SingleOrDefault(i => i.Sprite == sprite || i.Sprites.Any(j => j == sprite));
  174. if (entry == null)
  175. {
  176. throw new Exception($"Can't find {sprite.name} in SpriteCollection.");
  177. }
  178. var result = color == Color.white ? entry.Id : entry.Id + "#" + ColorUtility.ToHtmlStringRGBA(color);
  179. return result;
  180. }
  181. private ItemSprite RestoreFromString(ref Sprite sprite, SpriteRenderer renderer, IEnumerable<ItemSprite> collection, string serialized, bool silent = false)
  182. {
  183. if (renderer == null) return null;
  184. if (string.IsNullOrEmpty(serialized))
  185. {
  186. sprite = renderer.sprite = null;
  187. return null;
  188. }
  189. var parts = serialized.Split('#');
  190. var id = parts[0];
  191. var color = Color.white;
  192. if (parts.Length > 1)
  193. {
  194. ColorUtility.TryParseHtmlString("#" + parts[1], out color);
  195. }
  196. var entries = collection.Where(i => i.Id == id).ToList();
  197. switch (entries.Count)
  198. {
  199. case 1:
  200. sprite = renderer.sprite = entries[0].Sprites.Count == 1 ? entries[0].Sprites[0] : renderer.GetComponent<SpriteMapping>().FindSprite(entries[0].Sprites);
  201. renderer.color = color;
  202. return entries[0];
  203. case 0:
  204. if (silent) Debug.LogWarning("entries.Count = " + entries.Count); else throw new Exception($"Entry with id {id} not found in SpriteCollection."); return null;
  205. default:
  206. if (silent) Debug.LogWarning("entries.Count = " + entries.Count); else throw new Exception($"Multiple entries with id {id} found in SpriteCollection."); return null;
  207. }
  208. }
  209. private static void RestoreFromString(ref List<Sprite> sprites, List<SpriteRenderer> renderers, List<ItemSprite> collection, string serialized, bool silent = false)
  210. {
  211. if (string.IsNullOrEmpty(serialized))
  212. {
  213. sprites = new List<Sprite>();
  214. foreach (var renderer in renderers)
  215. {
  216. renderer.sprite = null;
  217. }
  218. return;
  219. }
  220. sprites = new List<Sprite>();
  221. var values = serialized.Split(',');
  222. for (var i = 0; i < values.Length; i++)
  223. {
  224. if (values[i] == "") continue;
  225. var match = Regex.Match(values[i], @"(?<Id>[\w\. \[\]]+)(?<Color>#\w+)*");
  226. var id = match.Groups["Id"].Value;
  227. var color = Color.white;
  228. if (match.Groups["Color"].Success)
  229. {
  230. ColorUtility.TryParseHtmlString(match.Groups["Color"].Value, out color);
  231. }
  232. var entries = collection.Where(i => i.Id == id).ToList();
  233. switch (entries.Count)
  234. {
  235. case 1:
  236. if (values.Length == 1)
  237. {
  238. sprites = entries[0].Sprites.ToList();
  239. renderers.ForEach(j => j.color = color);
  240. }
  241. else
  242. {
  243. var sprite = renderers[i].GetComponent<SpriteMapping>().FindSprite(entries[0].Sprites);
  244. if (!sprites.Contains(sprite))
  245. {
  246. sprites.Add(sprite);
  247. }
  248. renderers[i].color = color;
  249. }
  250. break;
  251. case 0:
  252. if (silent) Debug.LogWarning("entries.Count = " + entries.Count); else throw new Exception($"Entry with id {id} not found in SpriteCollection."); break;
  253. default:
  254. if (silent) Debug.LogWarning("entries.Count = " + entries.Count); else throw new Exception($"Multiple entries with id {id} found in SpriteCollection."); break;
  255. }
  256. }
  257. }
  258. }
  259. }