Anime.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. /**
  2. * 魔力宝贝图档解析脚本 - CGTool
  3. *
  4. * @Author HonorLee (dev@honorlee.me)
  5. * @Version 1.0 (2023-04-15)
  6. * @License GPL-3.0
  7. *
  8. * Anime.cs 动画基础类
  9. */
  10. using System;
  11. using System.Collections.Generic;
  12. using System.IO;
  13. using System.Text.RegularExpressions;
  14. using UnityEngine;
  15. namespace CGTool
  16. {
  17. //动画信息
  18. public class AnimeInfo
  19. {
  20. public int Version;
  21. //4 bytes 动画索引
  22. public uint Index;
  23. //4 bytes 动画文件地址
  24. public uint Addr;
  25. //2 bytes 动作数量
  26. public int ActionCount;
  27. //2 bytes 未知字节
  28. public byte[] Unknow;
  29. //动画数据 Direction -> ActionType -> AnimeData
  30. public Dictionary<int, Dictionary<int, AnimeDetail>> AnimeDatas = new Dictionary<int, Dictionary<int, AnimeDetail>>();
  31. }
  32. //动画帧数据
  33. public class AnimeFrameInfo
  34. {
  35. //图档编号
  36. public uint GraphicIndex;
  37. //宽度
  38. public int Width;
  39. //高度
  40. public int Height;
  41. //偏移X
  42. public int OffsetX;
  43. //偏移Y
  44. public int OffsetY;
  45. //音效编号
  46. public int AudioIndex;
  47. //动效编号
  48. public Anime.EffectType Effect;
  49. //动画Sprite
  50. public Sprite AnimeSprite;
  51. }
  52. //动画数据
  53. public class AnimeDetail
  54. {
  55. public uint Index;
  56. public int Version;
  57. public int Direction;
  58. public int ActionType;
  59. public uint CycleTime;
  60. public uint FrameCount;
  61. public Texture2D AnimeTexture;
  62. public AnimeFrameInfo[] AnimeFrameInfos;
  63. // public byte[] unknown;
  64. }
  65. //动画相关Enum类型
  66. public class Anime : MonoBehaviour
  67. {
  68. //方向
  69. public enum DirectionType
  70. {
  71. NULL=-1,
  72. North=0,
  73. NorthEast=1,
  74. East=2,
  75. SouthEast=3,
  76. South=4,
  77. SouthWest=5,
  78. West=6,
  79. NorthWest=7
  80. }
  81. //方向九宫映射表
  82. public static DirectionType[,] DirectionTypeMap = new DirectionType[3,3]
  83. {
  84. {DirectionType.North,DirectionType.NorthEast,DirectionType.East},
  85. {DirectionType.NorthWest,DirectionType.NULL,DirectionType.SouthEast},
  86. {DirectionType.West,DirectionType.SouthWest,DirectionType.South}
  87. };
  88. //动作(未补全)
  89. public enum ActionType
  90. {
  91. Stand=0,
  92. Walk=1,
  93. BeforeRun=2,
  94. Run=3,
  95. AfterRun=4,
  96. Attack=5,
  97. Magic=6,
  98. Throw=7,
  99. Hurt=8,
  100. Defence=9,
  101. Dead=10,
  102. Sit=11,
  103. Hi=12,
  104. Happy=13,
  105. Angry=14,
  106. Sad=15,
  107. Shock=16,
  108. }
  109. //动效
  110. public enum EffectType
  111. {
  112. Hit=1,
  113. HitOver=2
  114. }
  115. public enum PlayType
  116. {
  117. Loop,
  118. Once,
  119. OnceAndDestroy
  120. }
  121. //动画列表缓存 Index -> AnimeInfo
  122. private static Dictionary<uint, AnimeInfo> _animeInfoCache = new Dictionary<uint, AnimeInfo>();
  123. //动画序列文件前缀 Direction -> Action -> AnimeData
  124. private static Dictionary<int,string> _animeInfoVersionPrefex = new Dictionary<int, string>()
  125. {
  126. //龙之沙漏 之前版本前Info数据
  127. {0,@"AnimeInfo_\d+"},
  128. //龙之沙漏 版本Info数据
  129. {1,@"AnimeInfoEx_\d+"}
  130. };
  131. private static List<string> _animeInfoFilePaths = new List<string>();
  132. //动画数据文件前缀
  133. private static Dictionary<int,string> _animeDataVersionPrefex = new Dictionary<int, string>()
  134. {
  135. //龙之沙漏 之前版本前Data数据
  136. {0,@"Anime_\d+"},
  137. //龙之沙漏 版本Data数据
  138. {1,@"AnimeEx_\d+"}
  139. };
  140. private static List<string> _animeDataFilePaths = new List<string>();
  141. //初始化并缓存动画信息
  142. public static void Init()
  143. {
  144. DirectoryInfo directoryInfo = new DirectoryInfo(CGTool.BaseFolder);
  145. FileInfo[] files = directoryInfo.GetFiles();
  146. for (int i = 0; i < _animeInfoVersionPrefex.Count; i++)
  147. {
  148. foreach (FileInfo fileInfo in files)
  149. {
  150. if (Regex.IsMatch(fileInfo.Name, _animeInfoVersionPrefex[i]))
  151. {
  152. _animeInfoFilePaths.Add(fileInfo.Name);
  153. }
  154. if(Regex.IsMatch(fileInfo.Name,_animeDataVersionPrefex[i]))
  155. {
  156. _animeDataFilePaths.Add(fileInfo.Name);
  157. }
  158. }
  159. }
  160. if(_animeInfoFilePaths.Count==0) Debug.LogError("未找到动画信息文件");
  161. if(_animeDataFilePaths.Count==0) Debug.LogError("未找到动画数据文件");
  162. if(_animeDataFilePaths.Count!=_animeInfoFilePaths.Count) Debug.LogError("动画信息文件与动画数据文件数量不匹配");
  163. //加载动画信息
  164. for (int i = 0; i < _animeInfoFilePaths.Count; i++)
  165. {
  166. Dictionary<uint, AnimeInfo> animeInfos = _loadAnimeInfo(i);
  167. Debug.Log("加载动画信息版本:[" + i + "] 动画数量:" + animeInfos.Count);
  168. }
  169. }
  170. //获取动画数据信息
  171. public static AnimeInfo GetAnimeInfo(uint Index)
  172. {
  173. //返回缓存
  174. if (_animeInfoCache.ContainsKey(Index)) return _animeInfoCache[Index];
  175. //动画编号大于105000的属于 龙之沙漏 版本
  176. int Version = 0;
  177. if (Index >= 105000) Version = 1;
  178. Dictionary<uint, AnimeInfo> animeInfos = _loadAnimeInfo(Version);
  179. if (animeInfos.ContainsKey(Index)) return animeInfos[Index];
  180. return null;
  181. }
  182. //获取动画数据
  183. public static AnimeDetail GetAnimeDetail(uint serial,DirectionType Direction,ActionType Action)
  184. {
  185. AnimeInfo animeInfo = GetAnimeInfo(serial);
  186. if (animeInfo == null) return null;
  187. if (animeInfo.AnimeDatas.ContainsKey((int)Direction))
  188. {
  189. if (animeInfo.AnimeDatas[(int) Direction].ContainsKey((int) Action))
  190. {
  191. AnimeDetail animeDetail = animeInfo.AnimeDatas[(int) Direction][(int) Action];
  192. // if(animeDetail.AnimeTexture == null) prepareAnimeFrames(animeDetail);
  193. return animeInfo.AnimeDatas[(int)Direction][(int) Action];
  194. }
  195. }
  196. return null;
  197. }
  198. //预处理动画图形合批,这个返回的是一个所有帧合并后的Texture2D
  199. private static void prepareAnimeFrames(AnimeDetail animeDetail)
  200. {
  201. //动态合并Texture2D
  202. GraphicData[] graphicDatas = new GraphicData[animeDetail.FrameCount];
  203. uint textureWidth = 0;
  204. uint textureHeight = 0;
  205. for (var i = 0; i < animeDetail.FrameCount; i++)
  206. {
  207. //载入图档
  208. GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoDataByIndex(animeDetail.Version,animeDetail.AnimeFrameInfos[i].GraphicIndex);
  209. if (graphicInfoData == null) continue;
  210. GraphicData graphicData = Graphic.GetGraphicData(graphicInfoData);
  211. if(graphicData == null) continue;
  212. graphicDatas[i] = graphicData;
  213. if(graphicData.Height > textureHeight) textureHeight = graphicData.Height;
  214. textureWidth += graphicData.Width;
  215. animeDetail.AnimeFrameInfos[i].Width = (int) graphicData.Width;
  216. animeDetail.AnimeFrameInfos[i].Height = (int) graphicData.Height;
  217. animeDetail.AnimeFrameInfos[i].OffsetX = (int) graphicInfoData.OffsetX;
  218. animeDetail.AnimeFrameInfos[i].OffsetY = (int) graphicInfoData.OffsetY;
  219. }
  220. //合并图档
  221. Texture2D texture2dMix = new Texture2D((int) textureWidth, (int) textureHeight, TextureFormat.RGBA32, false,
  222. true);
  223. Color32 transparentColor = new Color32(0, 0, 0, 0);
  224. Color32[] transparentColors = new Color32[texture2dMix.width * texture2dMix.height];
  225. for (var i = 0; i < transparentColors.Length; i++)
  226. {
  227. transparentColors[i] = transparentColor;
  228. }
  229. texture2dMix.SetPixels32(transparentColors,0);
  230. int offsetX = 0;
  231. for (var i = 0; i < animeDetail.FrameCount; i++)
  232. {
  233. GraphicData graphicData = graphicDatas[i];
  234. if(graphicData == null) continue;
  235. texture2dMix.SetPixels32((int) offsetX, 0, (int) graphicData.Width,
  236. (int) graphicData.Height,
  237. graphicData.Sprite.texture.GetPixels32());
  238. offsetX += (int) graphicData.Width;
  239. }
  240. texture2dMix.Apply();
  241. animeDetail.AnimeTexture = texture2dMix;
  242. //创建动画每帧Sprite
  243. offsetX = 0;
  244. for (var l = 0; l < animeDetail.FrameCount; l++)
  245. {
  246. if(graphicDatas[l] == null) continue;
  247. AnimeFrameInfo animeFrameInfo = animeDetail.AnimeFrameInfos[l];
  248. Vector2 pivot = new Vector2(0f, 1f);
  249. pivot.x += -(animeFrameInfo.OffsetX * 1f) / animeFrameInfo.Width;
  250. pivot.y -= (-animeFrameInfo.OffsetY * 1f) / animeFrameInfo.Height;
  251. Sprite sprite = Sprite.Create(texture2dMix, new Rect(offsetX, 0,
  252. animeDetail.AnimeFrameInfos[l].Width, animeDetail.AnimeFrameInfos[l].Height),
  253. pivot, 1, 1, SpriteMeshType.FullRect);
  254. offsetX += animeDetail.AnimeFrameInfos[l].Width;
  255. animeFrameInfo.AnimeSprite = sprite;
  256. }
  257. }
  258. //加载动画数据
  259. private static Dictionary<uint, AnimeInfo> _loadAnimeInfo(int Version)
  260. {
  261. //查找Info文件
  262. string infoFileName = _animeInfoFilePaths[Version];
  263. string dataFileName = _animeDataFilePaths[Version];
  264. FileInfo infoFile = new FileInfo(CGTool.BaseFolder + "/" + infoFileName);
  265. FileInfo dataFile = new FileInfo(CGTool.BaseFolder + "/" + dataFileName);
  266. if (!infoFile.Exists || !dataFile.Exists) return null;
  267. //创建流读取器
  268. FileStream infoFileStream = infoFile.OpenRead();
  269. FileStream dataFileStream = dataFile.OpenRead();
  270. BinaryReader infoFileReader = new BinaryReader(infoFileStream);
  271. BinaryReader dataFileReader = new BinaryReader(dataFileStream);
  272. // Dictionary<uint, AnimeInfo> animeInfos = new Dictionary<uint, AnimeInfo>();
  273. long DataLength = infoFileStream.Length / 12;
  274. for (int i = 0; i < DataLength; i++)
  275. {
  276. //初始化对象
  277. AnimeInfo animeInfo = new AnimeInfo();
  278. animeInfo.Version = Version;
  279. animeInfo.Index = BitConverter.ToUInt32(infoFileReader.ReadBytes(4),0);
  280. animeInfo.Addr = BitConverter.ToUInt32(infoFileReader.ReadBytes(4),0);
  281. animeInfo.ActionCount = infoFileReader.ReadUInt16();
  282. animeInfo.Unknow = infoFileReader.ReadBytes(2);
  283. dataFileStream.Position = animeInfo.Addr;
  284. for (int j = 0; j < animeInfo.ActionCount; j++)
  285. {
  286. AnimeDetail animeData = new AnimeDetail();
  287. animeData.Index = animeInfo.Index;
  288. animeData.Version = Version;
  289. animeData.Direction = dataFileReader.ReadUInt16();
  290. animeData.ActionType = dataFileReader.ReadUInt16();
  291. animeData.CycleTime = BitConverter.ToUInt32(dataFileReader.ReadBytes(4),0);
  292. animeData.FrameCount = BitConverter.ToUInt32(dataFileReader.ReadBytes(4),0);
  293. animeData.AnimeFrameInfos = new AnimeFrameInfo[animeData.FrameCount];
  294. // if (animeInfo.Index == 101201) Debug.Log("----------------------------------");
  295. for (int k = 0; k < animeData.FrameCount; k++)
  296. {
  297. animeData.AnimeFrameInfos[k] = new AnimeFrameInfo();
  298. //GraphicIndex序号
  299. animeData.AnimeFrameInfos[k].GraphicIndex = BitConverter.ToUInt32(dataFileReader.ReadBytes(4),0);
  300. //未知字节
  301. // animeData.unknown = dataFileReader.ReadBytes(6);
  302. // if (animeInfo.Index == 101201)
  303. // {
  304. // byte[] tt = dataFileReader.ReadBytes(6);
  305. // }
  306. // else
  307. // {
  308. // dataFileReader.ReadBytes(6);
  309. // }
  310. animeData.AnimeFrameInfos[k].OffsetX = BitConverter.ToInt16(dataFileReader.ReadBytes(2),0);
  311. animeData.AnimeFrameInfos[k].OffsetY = BitConverter.ToInt16(dataFileReader.ReadBytes(2),0);
  312. //标识位
  313. int flag = BitConverter.ToInt16(dataFileReader.ReadBytes(2),0);
  314. // if (animeData.Index == 110053) Debug.Log("FLAG---" + " " + k + " " + flag);
  315. if (flag>20000)
  316. {
  317. //击打判定
  318. animeData.AnimeFrameInfos[k].Effect = EffectType.Hit;
  319. animeData.AnimeFrameInfos[k].AudioIndex = flag - 20000;
  320. }
  321. else if(flag>10000)
  322. {
  323. //攻击动作结束判定
  324. animeData.AnimeFrameInfos[k].Effect = EffectType.HitOver;
  325. animeData.AnimeFrameInfos[k].AudioIndex = flag - 10000;
  326. }
  327. else
  328. {
  329. animeData.AnimeFrameInfos[k].AudioIndex = flag;
  330. }
  331. }
  332. if (!animeInfo.AnimeDatas.ContainsKey(animeData.Direction))
  333. animeInfo.AnimeDatas.Add(animeData.Direction, new Dictionary<int, AnimeDetail>());
  334. if (animeInfo.AnimeDatas[animeData.Direction].ContainsKey(animeData.ActionType))
  335. {
  336. animeInfo.AnimeDatas[animeData.Direction][animeData.ActionType] = animeData;
  337. }
  338. else
  339. {
  340. animeInfo.AnimeDatas[animeData.Direction].Add(animeData.ActionType, animeData);
  341. }
  342. if (_animeInfoCache.ContainsKey(animeInfo.Index))
  343. {
  344. _animeInfoCache[animeInfo.Index] = animeInfo;
  345. }
  346. else
  347. {
  348. _animeInfoCache.Add(animeInfo.Index, animeInfo);
  349. }
  350. }
  351. }
  352. infoFileReader.Dispose();
  353. infoFileReader.Close();
  354. dataFileReader.Dispose();
  355. dataFileReader.Close();
  356. infoFileStream.Close();
  357. dataFileStream.Close();
  358. return _animeInfoCache;
  359. }
  360. }
  361. }