Anime.cs 16 KB

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