Anime.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  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.Linq;
  14. using UnityEngine;
  15. namespace CrossgateToolkit
  16. {
  17. //动画信息
  18. public class AnimeInfo
  19. {
  20. // 版本
  21. public string Version;
  22. //4 bytes 动画序号
  23. public uint Serial;
  24. //4 bytes 动画文件地址
  25. public uint Addr;
  26. //2 bytes 动作数量
  27. public int ActionCount;
  28. //2 bytes 未知字节
  29. public byte[] Unknow;
  30. //动画数据 Direction -> ActionType -> AnimeData
  31. public Dictionary<int, Dictionary<int, AnimeDetail>> AnimeDatas;
  32. // 数据读取对象
  33. public BinaryReader DataReader;
  34. }
  35. //动画帧数据
  36. public class AnimeFrameInfo
  37. {
  38. //图档编号
  39. public uint GraphicIndex;
  40. //宽度
  41. public int Width;
  42. //高度
  43. public int Height;
  44. //偏移X
  45. public int OffsetX;
  46. //偏移Y
  47. public int OffsetY;
  48. //音效编号
  49. public int AudioIndex;
  50. //动效编号
  51. public Anime.EffectType Effect;
  52. //GraphicInfo;
  53. public GraphicInfoData GraphicInfo;
  54. //动画Sprite
  55. // public Dictionary<int,Sprite> AnimeSprites = new Dictionary<int, Sprite>();
  56. public Dictionary<int,Dictionary<bool,GraphicDetail>> AnimeSprites = new Dictionary<int, Dictionary<bool, GraphicDetail>>();
  57. }
  58. //动画数据
  59. public class AnimeDetail
  60. {
  61. // 动画编号
  62. public uint Serial;
  63. // 动画版本
  64. public string Version;
  65. // 方向
  66. public int Direction;
  67. // 动作
  68. public int ActionType;
  69. // 动画循环时间
  70. public uint CycleTime;
  71. // 帧数
  72. public uint FrameCount;
  73. // 高版本 - 标识
  74. public bool IsHighVersion;
  75. // 高版本 - 调色板
  76. public int Palet;
  77. // 高版本 - 图像反转
  78. public AnimeFlag FLAG = AnimeFlag.NULL;
  79. // 高版本 - 结束标识
  80. public byte[] FLAG_END;
  81. // public Dictionary<int,Texture2D> AnimeTextures = new Dictionary<int, Texture2D>();
  82. public Dictionary<int,Dictionary<bool,Texture2D>> AnimeTextures = new Dictionary<int, Dictionary<bool, Texture2D>>();
  83. // public Texture2D AnimeTexture;
  84. public List<AnimeFrameInfo> AnimeFrameInfos;
  85. // public byte[] unknown;
  86. }
  87. [Flags]
  88. public enum AnimeFlag
  89. {
  90. NULL = 0,
  91. REVERSE_X = 1<<0,
  92. REVERSE_Y = 1<<1,
  93. LOCK_PAL = 1<<2,
  94. LIGHT_THROUGH = 1<<3
  95. }
  96. //动画相关Enum类型
  97. public class Anime : MonoBehaviour
  98. {
  99. //方向
  100. public enum DirectionType
  101. {
  102. NULL = -1,
  103. North = 0,
  104. NorthEast = 1,
  105. East = 2,
  106. SouthEast = 3,
  107. South = 4,
  108. SouthWest = 5,
  109. West = 6,
  110. NorthWest = 7
  111. }
  112. //方向九宫映射表
  113. public static DirectionType[,] DirectionTypeMap = new DirectionType[3,3]
  114. {
  115. {DirectionType.North,DirectionType.NorthEast,DirectionType.East},
  116. {DirectionType.NorthWest,DirectionType.NULL,DirectionType.SouthEast},
  117. {DirectionType.West,DirectionType.SouthWest,DirectionType.South}
  118. };
  119. //动作
  120. public enum ActionType
  121. {
  122. NULL = -1,
  123. Idle = 0,
  124. Walk = 1,
  125. BeforeRun = 2,
  126. Run = 3,
  127. AfterRun = 4,
  128. Attack = 5,
  129. Magic = 6,
  130. Throw = 7,
  131. Hurt = 8,
  132. Defence = 9,
  133. Dead = 10,
  134. Sit = 11,
  135. Hi = 12,
  136. Happy = 13,
  137. Angry = 14,
  138. Sad = 15,
  139. Shake = 16,
  140. Rock = 17,
  141. Scissors = 18,
  142. Paper = 19,
  143. Fishing = 20,
  144. }
  145. //动效
  146. public enum EffectType
  147. {
  148. Hit =1,
  149. HitOver =2
  150. }
  151. public enum PlayType
  152. {
  153. Loop,
  154. Once,
  155. OnceAndDestroy
  156. }
  157. private static byte[] highVersionFlag = { 0xFF, 0xFF, 0xFF, 0xFF };
  158. //动画列表缓存 Serial -> AnimeInfo
  159. private static Dictionary<uint, AnimeInfo> _animeInfoCache = new Dictionary<uint, AnimeInfo>();
  160. //加载动画数据
  161. public static void Init(string Version,FileInfo animeInfoFile,FileInfo animeFile)
  162. {
  163. //创建流读取器
  164. FileStream infoFileStream = animeInfoFile.OpenRead();
  165. FileStream dataFileStream = animeFile.OpenRead();
  166. BinaryReader infoFileReader = new BinaryReader(infoFileStream);
  167. BinaryReader dataFileReader = new BinaryReader(dataFileStream);
  168. long DataLength = infoFileStream.Length / 12;
  169. // 循环初始化动画数据
  170. for (int i = 0; i < DataLength; i++)
  171. {
  172. //初始化对象
  173. AnimeInfo animeInfo = new AnimeInfo
  174. {
  175. Version = Version,
  176. Serial = BitConverter.ToUInt32(infoFileReader.ReadBytes(4),0),
  177. Addr = BitConverter.ToUInt32(infoFileReader.ReadBytes(4),0),
  178. ActionCount = infoFileReader.ReadUInt16(),
  179. Unknow = infoFileReader.ReadBytes(2)
  180. };
  181. if (animeInfo.Addr > dataFileStream.Length) break;
  182. animeInfo.DataReader = dataFileReader;
  183. _animeInfoCache[animeInfo.Serial] = animeInfo;
  184. }
  185. infoFileReader.Dispose();
  186. infoFileReader.Close();
  187. infoFileStream.Close();
  188. Debug.Log("[CGTool] 加载AnimeInfo - 文件: [" +
  189. // (Graphic.Flag_HighVersion[Version] ? "H" : "N") + "] [" +
  190. Version + "] " +
  191. animeInfoFile.Name +
  192. " 动画总量: " + DataLength);
  193. }
  194. private static void ReadAnimeData(AnimeInfo animeInfo)
  195. {
  196. animeInfo.DataReader.BaseStream.Position = animeInfo.Addr;
  197. animeInfo.AnimeDatas = new Dictionary<int, Dictionary<int, AnimeDetail>>();
  198. for (int j = 0; j < animeInfo.ActionCount; j++)
  199. {
  200. // 高版本标识
  201. bool isHighVersion = false;
  202. animeInfo.DataReader.BaseStream.Position += 16;
  203. if(animeInfo.DataReader.ReadBytes(4).SequenceEqual(highVersionFlag)) isHighVersion = true;
  204. animeInfo.DataReader.BaseStream.Position -= 20;
  205. AnimeDetail animeData = new AnimeDetail();
  206. animeData.Version = animeInfo.Version;
  207. animeData.Serial = animeInfo.Serial;
  208. animeData.Direction = animeInfo.DataReader.ReadUInt16();
  209. animeData.ActionType = animeInfo.DataReader.ReadUInt16();
  210. animeData.CycleTime = BitConverter.ToUInt32(animeInfo.DataReader.ReadBytes(4),0);
  211. animeData.FrameCount = BitConverter.ToUInt32(animeInfo.DataReader.ReadBytes(4),0);
  212. // 高版本
  213. if (isHighVersion)
  214. {
  215. animeData.IsHighVersion = true;
  216. animeData.Palet = animeInfo.DataReader.ReadUInt16();
  217. int flag = animeInfo.DataReader.ReadUInt16();
  218. if (flag > 0)
  219. {
  220. if ((flag & 1) == (1 << 0)) animeData.FLAG |= AnimeFlag.REVERSE_X;
  221. if ((flag & 2) == (1 << 1)) animeData.FLAG |= AnimeFlag.REVERSE_Y;
  222. if ((flag & 4) == (1 << 2)) animeData.FLAG |= AnimeFlag.LOCK_PAL;
  223. if ((flag & 8) == (1 << 3)) animeData.FLAG |= AnimeFlag.LIGHT_THROUGH;
  224. }
  225. animeData.FLAG_END = animeInfo.DataReader.ReadBytes(4);
  226. }
  227. animeData.AnimeFrameInfos = new List<AnimeFrameInfo>();
  228. // if (animeInfo.Index == 101201) Debug.Log("----------------------------------");
  229. for (int k = 0; k < animeData.FrameCount; k++)
  230. {
  231. byte[] frameBytes = animeInfo.DataReader.ReadBytes(10);
  232. if (frameBytes.Length <10) break;
  233. BinaryReader frameReader = new BinaryReader(new MemoryStream(frameBytes));
  234. AnimeFrameInfo animeFrameInfo = new AnimeFrameInfo();
  235. //GraphicIndex序号
  236. animeFrameInfo.GraphicIndex = BitConverter.ToUInt32(frameReader.ReadBytes(4),0);
  237. animeFrameInfo.OffsetX = BitConverter.ToInt16(frameReader.ReadBytes(2),0);
  238. animeFrameInfo.OffsetY = BitConverter.ToInt16(frameReader.ReadBytes(2), 0);
  239. //标识位
  240. int flag = BitConverter.ToInt16(frameReader.ReadBytes(2),0);
  241. if (flag>20000)
  242. {
  243. //击打判定
  244. animeFrameInfo.Effect = EffectType.Hit;
  245. animeFrameInfo.AudioIndex = flag - 20000;
  246. }
  247. else if(flag>10000)
  248. {
  249. //攻击动作结束判定
  250. animeFrameInfo.Effect = EffectType.HitOver;
  251. animeFrameInfo.AudioIndex = flag - 10000;
  252. }
  253. else
  254. {
  255. animeFrameInfo.AudioIndex = flag;
  256. }
  257. animeData.AnimeFrameInfos.Add(animeFrameInfo);
  258. }
  259. animeData.FrameCount = (uint) animeData.AnimeFrameInfos.Count;
  260. if (!animeInfo.AnimeDatas.ContainsKey(animeData.Direction))
  261. animeInfo.AnimeDatas.Add(animeData.Direction, new Dictionary<int, AnimeDetail>());
  262. animeInfo.AnimeDatas[animeData.Direction][animeData.ActionType] = animeData;
  263. }
  264. }
  265. //获取动画数据信息
  266. public static AnimeInfo GetAnimeInfo(uint serial)
  267. {
  268. _animeInfoCache.TryGetValue(serial, out AnimeInfo animeInfo);
  269. if (animeInfo is { AnimeDatas: null }) ReadAnimeData(animeInfo);
  270. return animeInfo;
  271. }
  272. //获取动画数据
  273. public static AnimeDetail GetAnimeDetail(uint serial,DirectionType Direction,ActionType Action)
  274. {
  275. AnimeInfo animeInfo = GetAnimeInfo(serial);
  276. if (animeInfo == null) return null;
  277. if (animeInfo.AnimeDatas.ContainsKey((int)Direction))
  278. {
  279. if (animeInfo.AnimeDatas[(int) Direction].ContainsKey((int) Action))
  280. {
  281. AnimeDetail animeDetail = animeInfo.AnimeDatas[(int) Direction][(int) Action];
  282. // if(animeDetail.AnimeTexture == null) prepareAnimeFrames(animeDetail);
  283. return animeDetail;
  284. }
  285. }
  286. return null;
  287. }
  288. //预处理动画图形合批烘焙
  289. public static void BakeAnimeFrames(AnimeDetail animeDetail,int palet = 0, bool linear = false,bool compress = false)
  290. {
  291. // 查看是否存在缓存Texture数据
  292. animeDetail.AnimeTextures.TryGetValue(palet, out var textureDict);
  293. if(textureDict!=null)
  294. {
  295. if(textureDict.ContainsKey(linear)) return;
  296. }
  297. //所有帧的图形数据
  298. GraphicDetail[] graphicDetails = new GraphicDetail[animeDetail.FrameCount];
  299. //合并后的Texture2D尺寸
  300. List<GraphicInfoData> graphicInfoDatas = new List<GraphicInfoData>();
  301. Dictionary<uint,GraphicInfoData> graphicInfoDataDict = new Dictionary<uint, GraphicInfoData>();
  302. int subPaletIndex = -1;
  303. if (animeDetail.IsHighVersion) subPaletIndex = (int)animeDetail.Serial;
  304. for (var i = 0; i < animeDetail.FrameCount; i++)
  305. {
  306. //载入图档
  307. GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoDataByIndex(animeDetail.Version,animeDetail.AnimeFrameInfos[i].GraphicIndex);
  308. if (graphicInfoData == null) continue;
  309. graphicInfoDatas.Add(graphicInfoData);
  310. graphicInfoDataDict[graphicInfoData.Index] = graphicInfoData;
  311. animeDetail.AnimeFrameInfos[i].GraphicInfo = graphicInfoData;
  312. animeDetail.AnimeFrameInfos[i].OffsetX = (int) graphicInfoData.OffsetX;
  313. animeDetail.AnimeFrameInfos[i].OffsetY = (int) graphicInfoData.OffsetY;
  314. }
  315. Dictionary<uint, GraphicDetail> graphicDetailDict =
  316. GraphicData.BakeGraphics(graphicInfoDatas, false, palet, subPaletIndex, linear, 2048, 5, compress);
  317. Texture2D texture2dMix = null;
  318. for (var i = 0; i < animeDetail.FrameCount; i++)
  319. {
  320. graphicDetailDict.TryGetValue(animeDetail.AnimeFrameInfos[i].GraphicInfo.Index,out var graphicDetail);
  321. if(graphicDetail == null) continue;
  322. graphicDetails[i] = graphicDetail;
  323. if (texture2dMix == null) texture2dMix = graphicDetail.Sprite.texture;
  324. AnimeFrameInfo animeFrameInfo = animeDetail.AnimeFrameInfos[i];
  325. animeFrameInfo.Width = (int) graphicDetail.Width;
  326. animeFrameInfo.Height = (int) graphicDetail.Height;
  327. if(!animeFrameInfo.AnimeSprites.ContainsKey(palet)) animeFrameInfo.AnimeSprites[palet] = new Dictionary<bool, GraphicDetail>();
  328. if(!animeFrameInfo.AnimeSprites[palet].ContainsKey(linear)) animeFrameInfo.AnimeSprites[palet]
  329. .Add(linear,graphicDetail);
  330. }
  331. if(!animeDetail.AnimeTextures.ContainsKey(palet)) animeDetail.AnimeTextures.Add(palet,new Dictionary<bool, Texture2D>());
  332. animeDetail.AnimeTextures[palet][linear] = texture2dMix;
  333. }
  334. }
  335. }