Anime.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  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,Sprite>> AnimeSprites = new Dictionary<int, Dictionary<bool, Sprite>>();
  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;
  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. public class AnimeFlag
  88. {
  89. public bool REVERSE_X;
  90. public bool REVERSE_Y;
  91. public bool LOCK_PAL;
  92. public bool LIGHT_THROUGH;
  93. }
  94. //动画相关Enum类型
  95. public class Anime : MonoBehaviour
  96. {
  97. //方向
  98. public enum DirectionType
  99. {
  100. NULL = -1,
  101. North = 0,
  102. NorthEast = 1,
  103. East = 2,
  104. SouthEast = 3,
  105. South = 4,
  106. SouthWest = 5,
  107. West = 6,
  108. NorthWest = 7
  109. }
  110. //方向九宫映射表
  111. public static DirectionType[,] DirectionTypeMap = new DirectionType[3,3]
  112. {
  113. {DirectionType.North,DirectionType.NorthEast,DirectionType.East},
  114. {DirectionType.NorthWest,DirectionType.NULL,DirectionType.SouthEast},
  115. {DirectionType.West,DirectionType.SouthWest,DirectionType.South}
  116. };
  117. //动作
  118. public enum ActionType
  119. {
  120. NULL = -1,
  121. Idle = 0,
  122. Walk = 1,
  123. BeforeRun = 2,
  124. Run = 3,
  125. AfterRun = 4,
  126. Attack = 5,
  127. Magic = 6,
  128. Throw = 7,
  129. Hurt = 8,
  130. Defence = 9,
  131. Dead = 10,
  132. Sit = 11,
  133. Hi = 12,
  134. Happy = 13,
  135. Angry = 14,
  136. Sad = 15,
  137. Shake = 16,
  138. Rock = 17,
  139. Scissors = 18,
  140. Paper = 19,
  141. Fishing = 20,
  142. }
  143. //动效
  144. public enum EffectType
  145. {
  146. Hit =1,
  147. HitOver =2
  148. }
  149. public enum PlayType
  150. {
  151. Loop,
  152. Once,
  153. OnceAndDestroy
  154. }
  155. private static byte[] highVersionFlag = { 0xFF, 0xFF, 0xFF, 0xFF };
  156. //动画列表缓存 Serial -> AnimeInfo
  157. private static Dictionary<uint, AnimeInfo> _animeInfoCache = new Dictionary<uint, AnimeInfo>();
  158. //加载动画数据
  159. public static void Init(string Version,FileInfo animeInfoFile,FileInfo animeFile)
  160. {
  161. //创建流读取器
  162. FileStream infoFileStream = animeInfoFile.OpenRead();
  163. FileStream dataFileStream = animeFile.OpenRead();
  164. BinaryReader infoFileReader = new BinaryReader(infoFileStream);
  165. BinaryReader dataFileReader = new BinaryReader(dataFileStream);
  166. long DataLength = infoFileStream.Length / 12;
  167. // 循环初始化动画数据
  168. for (int i = 0; i < DataLength; i++)
  169. {
  170. //初始化对象
  171. AnimeInfo animeInfo = new AnimeInfo
  172. {
  173. Version = Version,
  174. Serial = BitConverter.ToUInt32(infoFileReader.ReadBytes(4),0),
  175. Addr = BitConverter.ToUInt32(infoFileReader.ReadBytes(4),0),
  176. ActionCount = infoFileReader.ReadUInt16(),
  177. Unknow = infoFileReader.ReadBytes(2)
  178. };
  179. if (animeInfo.Addr > dataFileStream.Length) break;
  180. animeInfo.DataReader = dataFileReader;
  181. _animeInfoCache[animeInfo.Serial] = animeInfo;
  182. }
  183. infoFileReader.Dispose();
  184. infoFileReader.Close();
  185. infoFileStream.Close();
  186. Debug.Log("[CGTool] 加载AnimeInfo - 文件: [" +
  187. // (Graphic.Flag_HighVersion[Version] ? "H" : "N") + "] [" +
  188. Version + "] " +
  189. animeInfoFile.Name +
  190. " 动画总量: " + DataLength);
  191. }
  192. private static void ReadAnimeData(AnimeInfo animeInfo)
  193. {
  194. animeInfo.DataReader.BaseStream.Position = animeInfo.Addr;
  195. animeInfo.AnimeDatas = new Dictionary<int, Dictionary<int, AnimeDetail>>();
  196. for (int j = 0; j < animeInfo.ActionCount; j++)
  197. {
  198. // 高版本标识
  199. bool isHighVersion = false;
  200. animeInfo.DataReader.BaseStream.Position += 16;
  201. if(animeInfo.DataReader.ReadBytes(4).SequenceEqual(highVersionFlag)) isHighVersion = true;
  202. animeInfo.DataReader.BaseStream.Position -= 20;
  203. AnimeDetail animeData = new AnimeDetail();
  204. animeData.Version = animeInfo.Version;
  205. animeData.Serial = animeInfo.Serial;
  206. animeData.Direction = animeInfo.DataReader.ReadUInt16();
  207. animeData.ActionType = animeInfo.DataReader.ReadUInt16();
  208. animeData.CycleTime = BitConverter.ToUInt32(animeInfo.DataReader.ReadBytes(4),0);
  209. animeData.FrameCount = BitConverter.ToUInt32(animeInfo.DataReader.ReadBytes(4),0);
  210. // 高版本
  211. if (isHighVersion)
  212. {
  213. animeData.IsHighVersion = true;
  214. animeData.Palet = animeInfo.DataReader.ReadUInt16();
  215. int flag = animeInfo.DataReader.ReadUInt16();
  216. if (flag > 0)
  217. {
  218. animeData.FLAG = new AnimeFlag();
  219. if ((flag & 1) == (1 << 0)) animeData.FLAG.REVERSE_X = true;
  220. if ((flag & 2) == (1 << 1)) animeData.FLAG.REVERSE_Y = true;
  221. if ((flag & 4) == (1 << 2)) animeData.FLAG.LOCK_PAL = true;
  222. if ((flag & 8) == (1 << 3)) animeData.FLAG.LIGHT_THROUGH = true;
  223. }
  224. animeData.FLAG_END = animeInfo.DataReader.ReadBytes(4);
  225. }
  226. animeData.AnimeFrameInfos = new List<AnimeFrameInfo>();
  227. // if (animeInfo.Index == 101201) Debug.Log("----------------------------------");
  228. for (int k = 0; k < animeData.FrameCount; k++)
  229. {
  230. byte[] frameBytes = animeInfo.DataReader.ReadBytes(10);
  231. if (frameBytes.Length <10) break;
  232. BinaryReader frameReader = new BinaryReader(new MemoryStream(frameBytes));
  233. AnimeFrameInfo animeFrameInfo = new AnimeFrameInfo();
  234. //GraphicIndex序号
  235. animeFrameInfo.GraphicIndex = BitConverter.ToUInt32(frameReader.ReadBytes(4),0);
  236. animeFrameInfo.OffsetX = BitConverter.ToInt16(frameReader.ReadBytes(2),0);
  237. animeFrameInfo.OffsetY = BitConverter.ToInt16(frameReader.ReadBytes(2), 0);
  238. //标识位
  239. int flag = BitConverter.ToInt16(frameReader.ReadBytes(2),0);
  240. if (flag>20000)
  241. {
  242. //击打判定
  243. animeFrameInfo.Effect = EffectType.Hit;
  244. animeFrameInfo.AudioIndex = flag - 20000;
  245. }
  246. else if(flag>10000)
  247. {
  248. //攻击动作结束判定
  249. animeFrameInfo.Effect = EffectType.HitOver;
  250. animeFrameInfo.AudioIndex = flag - 10000;
  251. }
  252. else
  253. {
  254. animeFrameInfo.AudioIndex = flag;
  255. }
  256. animeData.AnimeFrameInfos.Add(animeFrameInfo);
  257. }
  258. animeData.FrameCount = (uint) animeData.AnimeFrameInfos.Count;
  259. if (!animeInfo.AnimeDatas.ContainsKey(animeData.Direction))
  260. animeInfo.AnimeDatas.Add(animeData.Direction, new Dictionary<int, AnimeDetail>());
  261. animeInfo.AnimeDatas[animeData.Direction][animeData.ActionType] = animeData;
  262. }
  263. }
  264. //获取动画数据信息
  265. public static AnimeInfo GetAnimeInfo(uint serial)
  266. {
  267. _animeInfoCache.TryGetValue(serial, out AnimeInfo animeInfo);
  268. if (animeInfo is { AnimeDatas: null }) ReadAnimeData(animeInfo);
  269. return animeInfo;
  270. }
  271. //获取动画数据
  272. public static AnimeDetail GetAnimeDetail(uint serial,DirectionType Direction,ActionType Action)
  273. {
  274. AnimeInfo animeInfo = GetAnimeInfo(serial);
  275. if (animeInfo == null) return null;
  276. if (animeInfo.AnimeDatas.ContainsKey((int)Direction))
  277. {
  278. if (animeInfo.AnimeDatas[(int) Direction].ContainsKey((int) Action))
  279. {
  280. AnimeDetail animeDetail = animeInfo.AnimeDatas[(int) Direction][(int) Action];
  281. // if(animeDetail.AnimeTexture == null) prepareAnimeFrames(animeDetail);
  282. return animeDetail;
  283. }
  284. }
  285. return null;
  286. }
  287. //预处理动画图形合批烘焙
  288. public static void BakeAnimeFrames(AnimeDetail animeDetail,int palet = 0, bool linear = false)
  289. {
  290. if (animeDetail.AnimeTextures.ContainsKey(palet))
  291. {
  292. if(animeDetail.AnimeTextures[palet].ContainsKey(linear)) return;
  293. }
  294. //所有帧的图形数据
  295. GraphicDetail[] graphicDetails = new GraphicDetail[animeDetail.FrameCount];
  296. //合并后的Texture2D尺寸
  297. uint textureWidth = 0;
  298. uint textureHeight = 0;
  299. for (var i = 0; i < animeDetail.FrameCount; i++)
  300. {
  301. //载入图档
  302. GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoDataByIndex(animeDetail.Version,animeDetail.AnimeFrameInfos[i].GraphicIndex);
  303. if (graphicInfoData == null) continue;
  304. int subPaletIndex = 0;
  305. if (animeDetail.IsHighVersion) subPaletIndex = (int)animeDetail.Serial;
  306. GraphicDetail graphicDetail = GraphicData.GetGraphicDetail(graphicInfoData, palet, subPaletIndex, linear);
  307. if(graphicDetail == null) continue;
  308. graphicDetails[i] = graphicDetail;
  309. if(graphicDetail.Height > textureHeight) textureHeight = graphicDetail.Height;
  310. textureWidth += graphicDetail.Width + 5;
  311. animeDetail.AnimeFrameInfos[i].Width = (int) graphicDetail.Width;
  312. animeDetail.AnimeFrameInfos[i].Height = (int) graphicDetail.Height;
  313. animeDetail.AnimeFrameInfos[i].OffsetX = (int) graphicInfoData.OffsetX;
  314. animeDetail.AnimeFrameInfos[i].OffsetY = (int) graphicInfoData.OffsetY;
  315. animeDetail.AnimeFrameInfos[i].GraphicInfo = graphicInfoData;
  316. }
  317. //合并图档
  318. Texture2D texture2dMix = new Texture2D((int) textureWidth, (int) textureHeight, TextureFormat.RGBA4444, false,linear);
  319. if(linear) texture2dMix.filterMode = FilterMode.Bilinear;
  320. else texture2dMix.filterMode = FilterMode.Point;
  321. Color32 transparentColor = new Color32(0, 0, 0, 0);
  322. Color32[] transparentColors = new Color32[texture2dMix.width * texture2dMix.height];
  323. for (var i = 0; i < transparentColors.Length; i++)
  324. {
  325. transparentColors[i] = transparentColor;
  326. }
  327. texture2dMix.SetPixels32(transparentColors,0);
  328. int offsetX = 0;
  329. for (var i = 0; i < animeDetail.FrameCount; i++)
  330. {
  331. GraphicDetail graphicDetail = graphicDetails[i];
  332. if(graphicDetail == null) continue;
  333. texture2dMix.SetPixels32((int) offsetX, 0, (int) graphicDetail.Width,
  334. (int) graphicDetail.Height,
  335. graphicDetail.Sprite.texture.GetPixels32());
  336. offsetX += (int) graphicDetail.Width + 5;
  337. }
  338. texture2dMix.Apply();
  339. if(!animeDetail.AnimeTextures.ContainsKey(palet)) animeDetail.AnimeTextures.Add(palet,new Dictionary<bool, Texture2D>());
  340. animeDetail.AnimeTextures[palet].Add(linear, texture2dMix);
  341. //创建动画每帧Sprite
  342. offsetX = 0;
  343. for (var l = 0; l < animeDetail.FrameCount; l++)
  344. {
  345. if(graphicDetails[l] == null) continue;
  346. AnimeFrameInfo animeFrameInfo = animeDetail.AnimeFrameInfos[l];
  347. Vector2 pivot = new Vector2(0f, 1f);
  348. pivot.x += -(animeFrameInfo.OffsetX * 1f) / animeFrameInfo.Width;
  349. pivot.y -= (-animeFrameInfo.OffsetY * 1f) / animeFrameInfo.Height;
  350. Sprite sprite = Sprite.Create(texture2dMix, new Rect(offsetX, 0,
  351. animeDetail.AnimeFrameInfos[l].Width, animeDetail.AnimeFrameInfos[l].Height),
  352. pivot, 1, 1, SpriteMeshType.FullRect);
  353. offsetX += animeDetail.AnimeFrameInfos[l].Width + 5;
  354. if(!animeFrameInfo.AnimeSprites.ContainsKey(palet)) animeFrameInfo.AnimeSprites.Add(palet,new Dictionary<bool, Sprite>());
  355. animeFrameInfo.AnimeSprites[palet].Add(linear, sprite);
  356. }
  357. }
  358. }
  359. }