CubismModel3Json.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925
  1. /**
  2. * Copyright(c) Live2D Inc. All rights reserved.
  3. *
  4. * Use of this source code is governed by the Live2D Open Software license
  5. * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
  6. */
  7. using Live2D.Cubism.Core;
  8. using System;
  9. using System.IO;
  10. using Live2D.Cubism.Framework.MouthMovement;
  11. using Live2D.Cubism.Framework.Physics;
  12. using Live2D.Cubism.Framework.UserData;
  13. using Live2D.Cubism.Framework.Pose;
  14. using Live2D.Cubism.Framework.Expression;
  15. using Live2D.Cubism.Framework.MotionFade;
  16. using Live2D.Cubism.Framework.Raycasting;
  17. using Live2D.Cubism.Rendering;
  18. using Live2D.Cubism.Rendering.Masking;
  19. #if UNITY_EDITOR
  20. using UnityEditor;
  21. #endif
  22. using UnityEngine;
  23. namespace Live2D.Cubism.Framework.Json
  24. {
  25. /// <summary>
  26. /// Exposes moc3.json asset data.
  27. /// </summary>
  28. [Serializable]
  29. // ReSharper disable once ClassCannotBeInstantiated
  30. public sealed class CubismModel3Json
  31. {
  32. #region Delegates
  33. /// <summary>
  34. /// Handles the loading of assets.
  35. /// </summary>
  36. /// <param name="assetType">The asset type to load.</param>
  37. /// <param name="assetPath">The path to the asset.</param>
  38. /// <returns></returns>
  39. public delegate object LoadAssetAtPathHandler(Type assetType, string assetPath);
  40. /// <summary>
  41. /// Picks a <see cref="Material"/> for a <see cref="CubismDrawable"/>.
  42. /// </summary>
  43. /// <param name="sender">Event source.</param>
  44. /// <param name="drawable">Drawable to pick for.</param>
  45. /// <returns>Picked material.</returns>
  46. public delegate Material MaterialPicker(CubismModel3Json sender, CubismDrawable drawable);
  47. /// <summary>
  48. /// Picks a <see cref="Texture2D"/> for a <see cref="CubismDrawable"/>.
  49. /// </summary>
  50. /// <param name="sender">Event source.</param>
  51. /// <param name="drawable">Drawable to pick for.</param>
  52. /// <returns>Picked texture.</returns>
  53. public delegate Texture2D TexturePicker(CubismModel3Json sender, CubismDrawable drawable);
  54. #endregion
  55. #region Load Methods
  56. /// <summary>
  57. /// Loads a model.json asset.
  58. /// </summary>
  59. /// <param name="assetPath">The path to the asset.</param>
  60. /// <returns>The <see cref="CubismModel3Json"/> on success; <see langword="null"/> otherwise.</returns>
  61. public static CubismModel3Json LoadAtPath(string assetPath)
  62. {
  63. // Use default asset load handler.
  64. return LoadAtPath(assetPath, BuiltinLoadAssetAtPath);
  65. }
  66. /// <summary>
  67. /// Loads a model.json asset.
  68. /// </summary>
  69. /// <param name="assetPath">The path to the asset.</param>
  70. /// <param name="loadAssetAtPath">Handler for loading assets.</param>
  71. /// <returns>The <see cref="CubismModel3Json"/> on success; <see langword="null"/> otherwise.</returns>
  72. public static CubismModel3Json LoadAtPath(string assetPath, LoadAssetAtPathHandler loadAssetAtPath)
  73. {
  74. // Load Json asset.
  75. var modelJsonAsset = loadAssetAtPath(typeof(string), assetPath) as string;
  76. // Return early in case Json asset wasn't loaded.
  77. if (modelJsonAsset == null)
  78. {
  79. return null;
  80. }
  81. // Deserialize Json.
  82. var modelJson = JsonUtility.FromJson<CubismModel3Json>(modelJsonAsset);
  83. // Finalize deserialization.
  84. modelJson.AssetPath = assetPath;
  85. modelJson.LoadAssetAtPath = loadAssetAtPath;
  86. // Set motion references.
  87. var value = CubismJsonParser.ParseFromString(modelJsonAsset);
  88. // Return early if there is no references.
  89. if (!value.Get("FileReferences").GetMap(null).ContainsKey("Motions"))
  90. {
  91. return modelJson;
  92. }
  93. var motionGroupNames = value.Get("FileReferences").Get("Motions").KeySet().ToArray();
  94. modelJson.FileReferences.Motions.GroupNames = motionGroupNames;
  95. var motionGroupNamesCount = motionGroupNames.Length;
  96. modelJson.FileReferences.Motions.Motions = new SerializableMotion[motionGroupNamesCount][];
  97. for (var i = 0; i < motionGroupNamesCount; i++)
  98. {
  99. var motionGroup = value.Get("FileReferences").Get("Motions").Get(motionGroupNames[i]);
  100. var motionCount = motionGroup.GetVector(null).ToArray().Length;
  101. modelJson.FileReferences.Motions.Motions[i] = new SerializableMotion[motionCount];
  102. for (var j = 0; j < motionCount; j++)
  103. {
  104. if (motionGroup.Get(j).GetMap(null).ContainsKey("File"))
  105. {
  106. modelJson.FileReferences.Motions.Motions[i][j].File = motionGroup.Get(j).Get("File").toString();
  107. }
  108. if (motionGroup.Get(j).GetMap(null).ContainsKey("Sound"))
  109. {
  110. modelJson.FileReferences.Motions.Motions[i][j].Sound = motionGroup.Get(j).Get("Sound").toString();
  111. }
  112. if (motionGroup.Get(j).GetMap(null).ContainsKey("FadeInTime"))
  113. {
  114. modelJson.FileReferences.Motions.Motions[i][j].FadeInTime = motionGroup.Get(j).Get("FadeInTime").ToFloat();
  115. }
  116. if (motionGroup.Get(j).GetMap(null).ContainsKey("FadeOutTime"))
  117. {
  118. modelJson.FileReferences.Motions.Motions[i][j].FadeOutTime = motionGroup.Get(j).Get("FadeOutTime").ToFloat();
  119. }
  120. }
  121. }
  122. return modelJson;
  123. }
  124. #endregion
  125. /// <summary>
  126. /// Path to <see langword="this"/>.
  127. /// </summary>
  128. public string AssetPath { get; private set; }
  129. /// <summary>
  130. /// Method for loading assets.
  131. /// </summary>
  132. private LoadAssetAtPathHandler LoadAssetAtPath { get; set; }
  133. #region Json Data
  134. /// <summary>
  135. /// The motion3.json format version.
  136. /// </summary>
  137. [SerializeField]
  138. public int Version;
  139. /// <summary>
  140. /// The file references.
  141. /// </summary>
  142. [SerializeField]
  143. public SerializableFileReferences FileReferences;
  144. /// <summary>
  145. /// Groups.
  146. /// </summary>
  147. [SerializeField]
  148. public SerializableGroup[] Groups;
  149. /// <summary>
  150. /// Hit areas.
  151. /// </summary>
  152. [SerializeField]
  153. public SerializableHitArea[] HitAreas;
  154. #endregion
  155. /// <summary>
  156. /// The contents of the referenced moc3 asset.
  157. /// </summary>
  158. /// <remarks>
  159. /// The contents isn't cached internally.
  160. /// </remarks>
  161. public byte[] Moc3
  162. {
  163. get
  164. {
  165. return LoadReferencedAsset<byte[]>(FileReferences.Moc);
  166. }
  167. }
  168. /// <summary>
  169. /// <see cref="CubismPose3Json"/> backing field.
  170. /// </summary>
  171. [NonSerialized]
  172. private CubismPose3Json _pose3Json;
  173. /// <summary>
  174. /// The contents of pose3.json asset.
  175. /// </summary>
  176. public CubismPose3Json Pose3Json
  177. {
  178. get
  179. {
  180. if(_pose3Json != null)
  181. {
  182. return _pose3Json;
  183. }
  184. var jsonString = string.IsNullOrEmpty(FileReferences.Pose) ? null : LoadReferencedAsset<String>(FileReferences.Pose);
  185. _pose3Json = CubismPose3Json.LoadFrom(jsonString);
  186. return _pose3Json;
  187. }
  188. }
  189. /// <summary>
  190. /// <see cref="Expression3Jsons"/> backing field.
  191. /// </summary>
  192. [NonSerialized]
  193. private CubismExp3Json[] _expression3Jsons;
  194. /// <summary>
  195. /// The referenced expression assets.
  196. /// </summary>
  197. /// <remarks>
  198. /// The references aren't cached internally.
  199. /// </remarks>
  200. public CubismExp3Json[] Expression3Jsons
  201. {
  202. get
  203. {
  204. // Fail silently...
  205. if(FileReferences.Expressions == null)
  206. {
  207. return null;
  208. }
  209. // Load expression only if necessary.
  210. if (_expression3Jsons == null)
  211. {
  212. _expression3Jsons = new CubismExp3Json[FileReferences.Expressions.Length];
  213. for (var i = 0; i < _expression3Jsons.Length; ++i)
  214. {
  215. var expressionJson = (string.IsNullOrEmpty(FileReferences.Expressions[i].File))
  216. ? null
  217. : LoadReferencedAsset<string>(FileReferences.Expressions[i].File);
  218. _expression3Jsons[i] = CubismExp3Json.LoadFrom(expressionJson);
  219. }
  220. }
  221. return _expression3Jsons;
  222. }
  223. }
  224. /// <summary>
  225. /// The contents of physics3.json asset.
  226. /// </summary>
  227. public string Physics3Json
  228. {
  229. get
  230. {
  231. return string.IsNullOrEmpty(FileReferences.Physics) ? null : LoadReferencedAsset<string>(FileReferences.Physics);
  232. }
  233. }
  234. public string UserData3Json
  235. {
  236. get
  237. {
  238. return string.IsNullOrEmpty(FileReferences.UserData) ? null : LoadReferencedAsset<string>(FileReferences.UserData);
  239. }
  240. }
  241. /// <summary>
  242. /// The contents of cdi3.json asset.
  243. /// </summary>
  244. public string DisplayInfo3Json
  245. {
  246. get
  247. {
  248. return string.IsNullOrEmpty(FileReferences.DisplayInfo) ? null : LoadReferencedAsset<string>(FileReferences.DisplayInfo);
  249. }
  250. }
  251. /// <summary>
  252. /// <see cref="Textures"/> backing field.
  253. /// </summary>
  254. [NonSerialized]
  255. private Texture2D[] _textures;
  256. /// <summary>
  257. /// The referenced texture assets.
  258. /// </summary>
  259. /// <remarks>
  260. /// The references aren't cached internally.
  261. /// </remarks>
  262. public Texture2D[] Textures
  263. {
  264. get
  265. {
  266. // Load textures only if necessary.
  267. if (_textures == null)
  268. {
  269. _textures = new Texture2D[FileReferences.Textures.Length];
  270. for (var i = 0; i < _textures.Length; ++i)
  271. {
  272. _textures[i] = LoadReferencedAsset<Texture2D>(FileReferences.Textures[i]);
  273. }
  274. }
  275. return _textures;
  276. }
  277. }
  278. #region Constructors
  279. /// <summary>
  280. /// Makes construction only possible through factories.
  281. /// </summary>
  282. private CubismModel3Json()
  283. {
  284. }
  285. #endregion
  286. /// <summary>
  287. /// Instantiates a <see cref="CubismMoc">model source</see> and a <see cref="CubismModel">model</see> with the default texture set.
  288. /// </summary>
  289. /// <param name="shouldImportAsOriginalWorkflow">Should import as original workflow.</param>
  290. /// <returns>The instantiated <see cref="CubismModel">model</see> on success; <see langword="null"/> otherwise.</returns>
  291. public CubismModel ToModel(bool shouldImportAsOriginalWorkflow = false)
  292. {
  293. return ToModel(CubismBuiltinPickers.MaterialPicker, CubismBuiltinPickers.TexturePicker, shouldImportAsOriginalWorkflow);
  294. }
  295. /// <summary>
  296. /// Instantiates a <see cref="CubismMoc">model source</see> and a <see cref="CubismModel">model</see>.
  297. /// </summary>
  298. /// <param name="pickMaterial">The material mapper to use.</param>
  299. /// <param name="pickTexture">The texture mapper to use.</param>
  300. /// <param name="shouldImportAsOriginalWorkflow">Should import as original workflow.</param>
  301. /// <returns>The instantiated <see cref="CubismModel">model</see> on success; <see langword="null"/> otherwise.</returns>
  302. public CubismModel ToModel(MaterialPicker pickMaterial, TexturePicker pickTexture, bool shouldImportAsOriginalWorkflow = false)
  303. {
  304. // Initialize model source and instantiate it.
  305. var mocAsBytes = Moc3;
  306. if (mocAsBytes == null)
  307. {
  308. return null;
  309. }
  310. var moc = CubismMoc.CreateFrom(mocAsBytes);
  311. var model = CubismModel.InstantiateFrom(moc);
  312. model.name = Path.GetFileNameWithoutExtension(FileReferences.Moc);
  313. #if UNITY_EDITOR
  314. // Add parameters and parts inspectors.
  315. model.gameObject.AddComponent<CubismParametersInspector>();
  316. model.gameObject.AddComponent<CubismPartsInspector>();
  317. #endif
  318. // Create renderers.
  319. var rendererController = model.gameObject.AddComponent<CubismRenderController>();
  320. var renderers = rendererController.Renderers;
  321. var drawables = model.Drawables;
  322. // Initialize materials.
  323. for (var i = 0; i < renderers.Length; ++i)
  324. {
  325. renderers[i].Material = pickMaterial(this, drawables[i]);
  326. }
  327. // Initialize textures.
  328. for (var i = 0; i < renderers.Length; ++i)
  329. {
  330. renderers[i].MainTexture = pickTexture(this, drawables[i]);
  331. }
  332. // Initialize drawables.
  333. if(HitAreas != null)
  334. {
  335. for (var i = 0; i < HitAreas.Length; i++)
  336. {
  337. for (var j = 0; j < drawables.Length; j++)
  338. {
  339. if (drawables[j].Id == HitAreas[i].Id)
  340. {
  341. // Add components for hit judgement to HitArea target Drawables.
  342. var hitDrawable = drawables[j].gameObject.AddComponent<CubismHitDrawable>();
  343. hitDrawable.Name = HitAreas[i].Name;
  344. drawables[j].gameObject.AddComponent<CubismRaycastable>();
  345. break;
  346. }
  347. }
  348. }
  349. }
  350. //Load from cdi3.json
  351. var DisplayInfo3JsonAsString = DisplayInfo3Json;
  352. var cdi3Json = CubismDisplayInfo3Json.LoadFrom(DisplayInfo3JsonAsString);
  353. // Initialize groups.
  354. var parameters = model.Parameters;
  355. for (var i = 0; i < parameters.Length; ++i)
  356. {
  357. if (IsParameterInGroup(parameters[i], "EyeBlink"))
  358. {
  359. if (model.gameObject.GetComponent<CubismEyeBlinkController>() == null)
  360. {
  361. model.gameObject.AddComponent<CubismEyeBlinkController>();
  362. }
  363. parameters[i].gameObject.AddComponent<CubismEyeBlinkParameter>();
  364. }
  365. // Set up mouth parameters.
  366. if (IsParameterInGroup(parameters[i], "LipSync"))
  367. {
  368. if (model.gameObject.GetComponent<CubismMouthController>() == null)
  369. {
  370. model.gameObject.AddComponent<CubismMouthController>();
  371. }
  372. parameters[i].gameObject.AddComponent<CubismMouthParameter>();
  373. }
  374. // Setting up the parameter name for display.
  375. if (cdi3Json != null)
  376. {
  377. var cubismDisplayInfoParameterName = parameters[i].gameObject.AddComponent<CubismDisplayInfoParameterName>();
  378. cubismDisplayInfoParameterName.Name = cdi3Json.Parameters[i].Name;
  379. cubismDisplayInfoParameterName.DisplayName = string.Empty;
  380. }
  381. }
  382. // Setting up the part name for display.
  383. if (cdi3Json != null)
  384. {
  385. // Initialize groups.
  386. var parts = model.Parts;
  387. for (var i = 0; i < parts.Length; i++)
  388. {
  389. var cubismDisplayInfoPartNames = parts[i].gameObject.AddComponent<CubismDisplayInfoPartName>();
  390. cubismDisplayInfoPartNames.Name = cdi3Json.Parts[i].Name;
  391. cubismDisplayInfoPartNames.DisplayName = string.Empty;
  392. }
  393. }
  394. // Add mask controller if required.
  395. for (var i = 0; i < drawables.Length; ++i)
  396. {
  397. if (!drawables[i].IsMasked)
  398. {
  399. continue;
  400. }
  401. // Add controller exactly once...
  402. model.gameObject.AddComponent<CubismMaskController>();
  403. break;
  404. }
  405. // Add original workflow component if is original workflow.
  406. if(shouldImportAsOriginalWorkflow)
  407. {
  408. // Add cubism update manager.
  409. var updateManager = model.gameObject.GetComponent<CubismUpdateController>();
  410. if(updateManager == null)
  411. {
  412. model.gameObject.AddComponent<CubismUpdateController>();
  413. }
  414. // Add parameter store.
  415. var parameterStore = model.gameObject.GetComponent<CubismParameterStore>();
  416. if(parameterStore == null)
  417. {
  418. parameterStore = model.gameObject.AddComponent<CubismParameterStore>();
  419. }
  420. // Add pose controller.
  421. var poseController = model.gameObject.GetComponent<CubismPoseController>();
  422. if(poseController == null)
  423. {
  424. poseController = model.gameObject.AddComponent<CubismPoseController>();
  425. }
  426. // Add expression controller.
  427. var expressionController = model.gameObject.GetComponent<CubismExpressionController>();
  428. if(expressionController == null)
  429. {
  430. expressionController = model.gameObject.AddComponent<CubismExpressionController>();
  431. }
  432. // Add fade controller.
  433. var motionFadeController = model.gameObject.GetComponent<CubismFadeController>();
  434. if(motionFadeController == null)
  435. {
  436. motionFadeController = model.gameObject.AddComponent<CubismFadeController>();
  437. }
  438. }
  439. // Initialize physics if JSON exists.
  440. var physics3JsonAsString = Physics3Json;
  441. if (!string.IsNullOrEmpty(physics3JsonAsString))
  442. {
  443. var physics3Json = CubismPhysics3Json.LoadFrom(physics3JsonAsString);
  444. var physicsController = model.gameObject.GetComponent<CubismPhysicsController>();
  445. if (physicsController == null)
  446. {
  447. physicsController = model.gameObject.AddComponent<CubismPhysicsController>();
  448. }
  449. physicsController.Initialize(physics3Json.ToRig());
  450. }
  451. var userData3JsonAsString = UserData3Json;
  452. if (!string.IsNullOrEmpty(userData3JsonAsString))
  453. {
  454. var userData3Json = CubismUserData3Json.LoadFrom(userData3JsonAsString);
  455. var drawableBodies = userData3Json.ToBodyArray(CubismUserDataTargetType.ArtMesh);
  456. for (var i = 0; i < drawables.Length; ++i)
  457. {
  458. var index = GetBodyIndexById(drawableBodies, drawables[i].Id);
  459. if (index >= 0)
  460. {
  461. var tag = drawables[i].gameObject.GetComponent<CubismUserDataTag>();
  462. if (tag == null)
  463. {
  464. tag = drawables[i].gameObject.AddComponent<CubismUserDataTag>();
  465. }
  466. tag.Initialize(drawableBodies[index]);
  467. }
  468. }
  469. }
  470. if (model.gameObject.GetComponent<Animator>() == null)
  471. {
  472. model.gameObject.AddComponent<Animator>();
  473. }
  474. // Make sure model is 'fresh'
  475. model.ForceUpdateNow();
  476. return model;
  477. }
  478. #region Helper Methods
  479. /// <summary>
  480. /// Type-safely loads an asset.
  481. /// </summary>
  482. /// <typeparam name="T">Asset type.</typeparam>
  483. /// <param name="referencedFile">Path to asset.</param>
  484. /// <returns>The asset on success; <see langword="null"/> otherwise.</returns>
  485. private T LoadReferencedAsset<T>(string referencedFile) where T : class
  486. {
  487. var assetPath = Path.GetDirectoryName(AssetPath) + "/" + referencedFile;
  488. return LoadAssetAtPath(typeof(T), assetPath) as T;
  489. }
  490. /// <summary>
  491. /// Builtin method for loading assets.
  492. /// </summary>
  493. /// <param name="assetType">Asset type.</param>
  494. /// <param name="assetPath">Path to asset.</param>
  495. /// <returns>The asset on success; <see langword="null"/> otherwise.</returns>
  496. private static object BuiltinLoadAssetAtPath(Type assetType, string assetPath)
  497. {
  498. // Explicitly deal with byte arrays.
  499. if (assetType == typeof(byte[]))
  500. {
  501. #if UNITY_EDITOR
  502. return File.ReadAllBytes(assetPath);
  503. #else
  504. var textAsset = Resources.Load(assetPath, typeof(TextAsset)) as TextAsset;
  505. return (textAsset != null)
  506. ? textAsset.bytes
  507. : null;
  508. #endif
  509. }
  510. else if (assetType == typeof(string))
  511. {
  512. #if UNITY_EDITOR
  513. return File.ReadAllText(assetPath);
  514. #else
  515. var textAsset = Resources.Load(assetPath, typeof(TextAsset)) as TextAsset;
  516. return (textAsset != null)
  517. ? textAsset.text
  518. : null;
  519. #endif
  520. }
  521. #if UNITY_EDITOR
  522. return AssetDatabase.LoadAssetAtPath(assetPath, assetType);
  523. #else
  524. return Resources.Load(assetPath, assetType);
  525. #endif
  526. }
  527. /// <summary>
  528. /// Checks whether the parameter is an eye blink parameter.
  529. /// </summary>
  530. /// <param name="parameter">Parameter to check.</param>
  531. /// <param name="groupName">Name of group to query for.</param>
  532. /// <returns><see langword="true"/> if parameter is an eye blink parameter; <see langword="false"/> otherwise.</returns>
  533. private bool IsParameterInGroup(CubismParameter parameter, string groupName)
  534. {
  535. // Return early if groups aren't available...
  536. if (Groups == null || Groups.Length == 0)
  537. {
  538. return false;
  539. }
  540. for (var i = 0; i < Groups.Length; ++i)
  541. {
  542. if (Groups[i].Name != groupName)
  543. {
  544. continue;
  545. }
  546. if(Groups[i].Ids != null)
  547. {
  548. for (var j = 0; j < Groups[i].Ids.Length; ++j)
  549. {
  550. if (Groups[i].Ids[j] == parameter.name)
  551. {
  552. return true;
  553. }
  554. }
  555. }
  556. }
  557. return false;
  558. }
  559. /// <summary>
  560. /// Get body index from body array by Id.
  561. /// </summary>
  562. /// <param name="bodies">Target body array.</param>
  563. /// <param name="id">Id for find.</param>
  564. /// <returns>Array index if Id found; -1 otherwise.</returns>
  565. private int GetBodyIndexById(CubismUserDataBody[] bodies, string id)
  566. {
  567. for (var i = 0; i < bodies.Length; ++i)
  568. {
  569. if (bodies[i].Id == id)
  570. {
  571. return i;
  572. }
  573. }
  574. return -1;
  575. }
  576. #endregion
  577. #region Json Helpers
  578. /// <summary>
  579. /// File references data.
  580. /// </summary>
  581. [Serializable]
  582. public struct SerializableFileReferences
  583. {
  584. /// <summary>
  585. /// Relative path to the moc3 asset.
  586. /// </summary>
  587. [SerializeField]
  588. public string Moc;
  589. /// <summary>
  590. /// Relative paths to texture assets.
  591. /// </summary>
  592. [SerializeField]
  593. public string[] Textures;
  594. /// <summary>
  595. /// Relative path to the pose3.json.
  596. /// </summary>
  597. [SerializeField]
  598. public string Pose;
  599. /// <summary>
  600. /// Relative path to the expression asset.
  601. /// </summary>
  602. [SerializeField]
  603. public SerializableExpression[] Expressions;
  604. /// <summary>
  605. /// Relative path to the pose motion3.json.
  606. /// </summary>
  607. [SerializeField]
  608. public SerializableMotions Motions;
  609. /// <summary>
  610. /// Relative path to the physics asset.
  611. /// </summary>
  612. [SerializeField]
  613. public string Physics;
  614. /// <summary>
  615. /// Relative path to the user data asset.
  616. /// </summary>
  617. [SerializeField]
  618. public string UserData;
  619. /// <summary>
  620. /// Relative path to the cdi3.json.
  621. /// </summary>
  622. [SerializeField]
  623. public string DisplayInfo;
  624. }
  625. /// <summary>
  626. /// Group data.
  627. /// </summary>
  628. [Serializable]
  629. public struct SerializableGroup
  630. {
  631. /// <summary>
  632. /// Target type.
  633. /// </summary>
  634. [SerializeField]
  635. public string Target;
  636. /// <summary>
  637. /// Group name.
  638. /// </summary>
  639. [SerializeField]
  640. public string Name;
  641. /// <summary>
  642. /// Referenced IDs.
  643. /// </summary>
  644. [SerializeField]
  645. public string[] Ids;
  646. }
  647. /// <summary>
  648. /// Expression data.
  649. /// </summary>
  650. [Serializable]
  651. public struct SerializableExpression
  652. {
  653. /// <summary>
  654. /// Expression Name.
  655. /// </summary>
  656. [SerializeField]
  657. public string Name;
  658. /// <summary>
  659. /// Expression File.
  660. /// </summary>
  661. [SerializeField]
  662. public string File;
  663. /// <summary>
  664. /// Expression FadeInTime.
  665. /// </summary>
  666. [SerializeField]
  667. public float FadeInTime;
  668. /// <summary>
  669. /// Expression FadeOutTime.
  670. /// </summary>
  671. [SerializeField]
  672. public float FadeOutTime;
  673. }
  674. /// <summary>
  675. /// Motion data.
  676. /// </summary>
  677. [Serializable]
  678. public struct SerializableMotions
  679. {
  680. /// <summary>
  681. /// Motion group names.
  682. /// </summary>
  683. [SerializeField]
  684. public string[] GroupNames;
  685. /// <summary>
  686. /// Motion groups.
  687. /// </summary>
  688. [SerializeField]
  689. public SerializableMotion[][] Motions;
  690. }
  691. /// <summary>
  692. /// Motion data.
  693. /// </summary>
  694. [Serializable]
  695. public struct SerializableMotion
  696. {
  697. /// <summary>
  698. /// File path.
  699. /// </summary>
  700. [SerializeField]
  701. public string File;
  702. /// <summary>
  703. /// Sound path.
  704. /// </summary>
  705. [SerializeField]
  706. public string Sound;
  707. /// <summary>
  708. /// Fade in time.
  709. /// </summary>
  710. [SerializeField]
  711. public float FadeInTime;
  712. /// <summary>
  713. /// Fade out time.
  714. /// </summary>
  715. [SerializeField]
  716. public float FadeOutTime;
  717. }
  718. /// <summary>
  719. /// Hit Area.
  720. /// </summary>
  721. [Serializable]
  722. public struct SerializableHitArea
  723. {
  724. /// <summary>
  725. /// Hit area name.
  726. /// </summary>
  727. [SerializeField]
  728. public string Name;
  729. /// <summary>
  730. /// Hit area id.
  731. /// </summary>
  732. [SerializeField]
  733. public string Id;
  734. }
  735. #endregion
  736. }
  737. }