BattleRecoder.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. using CommonLang.IO;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. namespace CommonAI.Zone.Replay
  6. {
  7. public class BattleRecordData
  8. {
  9. public const string VERSION_1_0 = "1.0.0";
  10. public readonly static uint HEAD = BitConverter.ToUInt32(new byte[] { (byte)'B', (byte)'R', (byte)'E', (byte)'C' }, 0);
  11. public string Name;
  12. public string Desc;
  13. public int SceneID;
  14. public DateTime Time = DateTime.Now;
  15. public string Version = VERSION_1_0;
  16. public string ResVersion;
  17. public LinkedList<EventLog> Events = new LinkedList<EventLog>();
  18. public class EventLog
  19. {
  20. public long PassTimeMS;
  21. public Event EventData;
  22. }
  23. public static void EncodeHead(OutputStream output, BattleRecordData data)
  24. {
  25. output.PutU32(BattleRecordData.HEAD);
  26. output.PutUTF(data.Name);
  27. output.PutUTF(data.Desc);
  28. output.PutS64(data.Time.ToBinary());
  29. output.PutUTF(data.Version);
  30. output.PutS32(data.SceneID);
  31. output.PutUTF(data.ResVersion);
  32. }
  33. public static bool DecodeHead(InputStream input, BattleRecordData data)
  34. {
  35. uint head = input.GetU32();
  36. if (head == HEAD)
  37. {
  38. data.Name = input.GetUTF();
  39. data.Desc = input.GetUTF();
  40. data.Time = DateTime.FromBinary(input.GetS64());
  41. data.Version = input.GetUTF();
  42. data.SceneID = input.GetS32();
  43. data.ResVersion = input.GetUTF();
  44. return true;
  45. }
  46. return false;
  47. }
  48. public static void EncodeLog(TemplateManager templates, OutputStream output, EventLog log)
  49. {
  50. if (log.EventData is BattleMessage)
  51. {
  52. (log.EventData as BattleMessage).BeforeWrite(templates);
  53. }
  54. output.PutS64(log.PassTimeMS);
  55. output.PutExt(log.EventData);
  56. }
  57. public static void DecodeLog(TemplateManager templates, InputStream input, EventLog log)
  58. {
  59. log.PassTimeMS = input.GetS64();
  60. log.EventData = (Event)input.GetExtAny();
  61. if (log.EventData is BattleMessage)
  62. {
  63. (log.EventData as BattleMessage).EndRead(templates);
  64. }
  65. }
  66. public static void EncodeToStream(TemplateManager templates, Stream stream, BattleRecordData data)
  67. {
  68. OutputStream output = new OutputStream(stream, TemplateManager.MessageCodec);
  69. EncodeHead(output, data);
  70. foreach (BattleRecordData.EventLog log in data.Events)
  71. {
  72. EncodeLog(templates, output, log);
  73. }
  74. }
  75. public static bool DecodeFromStream(TemplateManager templates, Stream stream, out BattleRecordData ret)
  76. {
  77. InputStream input = new InputStream(stream, TemplateManager.MessageCodec);
  78. ret = new BattleRecordData();
  79. if (DecodeHead(input, ret))
  80. {
  81. while (stream.CanRead)
  82. {
  83. try
  84. {
  85. BattleRecordData.EventLog log = new BattleRecordData.EventLog();
  86. DecodeLog(templates, input, log);
  87. ret.Events.AddLast(log);
  88. }
  89. catch (Exception err)
  90. {
  91. Console.WriteLine("UnitBooleanAttribute : " + templates.ToString() + ", catch: " + err);
  92. break;
  93. }
  94. }
  95. return true;
  96. }
  97. ret = null;
  98. return false;
  99. }
  100. public static byte[] ToBinary(TemplateManager templates, BattleRecordData data)
  101. {
  102. byte[] ret;
  103. using (MemoryStream ms = new MemoryStream())
  104. {
  105. EncodeToStream(templates, ms, data);
  106. ret = new byte[ms.Length];
  107. Array.Copy(ms.GetBuffer(), ret, ret.Length);
  108. }
  109. return ret;
  110. }
  111. public static BattleRecordData FromBinary(TemplateManager templates, byte[] data)
  112. {
  113. BattleRecordData ret = null;
  114. using (MemoryStream ms = new MemoryStream(data))
  115. {
  116. DecodeFromStream(templates, ms, out ret);
  117. }
  118. return ret;
  119. }
  120. }
  121. public class BattleRecorder
  122. {
  123. public int SceneID { get; private set; }
  124. public string Name { get; set; }
  125. public string Desc { get; set; }
  126. public DateTime Time { get; set; }
  127. public string ResVersion { get; private set; }
  128. private bool mIsRunning = false;
  129. private OutputStream mStream;
  130. private MemoryStream mDefaultStream;
  131. private Stream mCurrentStream;
  132. private TemplateManager mTemplates;
  133. public BattleRecorder(TemplateManager templates, int sceneID, string name)
  134. {
  135. this.mTemplates = templates;
  136. this.SceneID = sceneID;
  137. this.Name = name;
  138. this.Desc = "";
  139. this.Time = DateTime.Now;
  140. this.ResVersion = templates.ResourceVersion;
  141. this.mDefaultStream = new MemoryStream();
  142. this.mStream = new OutputStream(mDefaultStream, TemplateManager.MessageCodec);
  143. SetOut(mDefaultStream);
  144. }
  145. public void SetOut(Stream stream)
  146. {
  147. mCurrentStream = stream;
  148. mStream.SetStream(stream);
  149. }
  150. public void Record(Event evt, long passTimeMS)
  151. {
  152. if (mIsRunning == false)
  153. {
  154. mIsRunning = true;
  155. BattleRecordData data = new BattleRecordData();
  156. data.Name = this.Name;
  157. data.Desc = this.Desc;
  158. data.Time = this.Time;
  159. data.SceneID = this.SceneID;
  160. data.ResVersion = this.ResVersion;
  161. BattleRecordData.EncodeHead(mStream, data);
  162. }
  163. BattleRecordData.EventLog log = new BattleRecordData.EventLog();
  164. log.PassTimeMS = passTimeMS;
  165. log.EventData = evt;
  166. BattleRecordData.EncodeLog(mTemplates, mStream, log);
  167. }
  168. public byte[] ToBinary()
  169. {
  170. if (mDefaultStream == mCurrentStream)
  171. {
  172. byte[] data = new byte[mDefaultStream.Position];
  173. Array.Copy(mDefaultStream.GetBuffer(), data, data.Length);
  174. return data;
  175. }
  176. else if (mCurrentStream is MemoryStream)
  177. {
  178. byte[] data = new byte[mCurrentStream.Position];
  179. Array.Copy((mCurrentStream as MemoryStream).GetBuffer(), data, data.Length);
  180. return data;
  181. }
  182. return null;
  183. }
  184. }
  185. public interface IBattleRecordListener
  186. {
  187. void onEventHandler(Event evt);
  188. }
  189. public class BattleRecordPlayer : IDisposable
  190. {
  191. public int SceneID { get; private set; }
  192. public string Name { get; private set; }
  193. public string Desc { get; private set; }
  194. public DateTime Time { get; private set; }
  195. public string Version { get; private set; }
  196. public string ResVersion { get; private set; }
  197. public TemplateManager Templates { get; private set; }
  198. public BattleRecordPlayer(TemplateManager templates, Stream data)
  199. {
  200. this.Templates = templates;
  201. this.mStream = data;
  202. this.mInput = new InputStream(data, TemplateManager.MessageCodec);
  203. BattleRecordData hd = new BattleRecordData();
  204. if (BattleRecordData.DecodeHead(mInput, hd))
  205. {
  206. this.Name = hd.Name;
  207. this.Desc = hd.Desc;
  208. this.Time = hd.Time;
  209. this.Version = hd.Version;
  210. this.SceneID = hd.SceneID;
  211. this.ResVersion = hd.ResVersion;
  212. }
  213. else { throw new Exception("Error - 数据不包含战报文件头 BattleRecordData.HEAD !"); }
  214. }
  215. public BattleRecordPlayer(TemplateManager templates, BattleRecordData data)
  216. {
  217. this.Templates = templates;
  218. this.mData = data;
  219. this.mLogs = new Queue<BattleRecordData.EventLog>(data.Events);
  220. {
  221. this.Name = data.Name;
  222. this.Desc = data.Desc;
  223. this.Time = data.Time;
  224. this.Version = data.Version;
  225. this.SceneID = data.SceneID;
  226. this.ResVersion = data.ResVersion;
  227. }
  228. }
  229. public void Dispose()
  230. {
  231. mData = null;
  232. mListener = null;
  233. Templates = null;
  234. mWaittingEvent = null;
  235. mLogs.Clear();
  236. }
  237. public bool IsDone { get { return mIsDone; } }
  238. private IBattleRecordListener mListener;
  239. private BattleRecordData mData;
  240. private Queue<BattleRecordData.EventLog> mLogs;
  241. private Stream mStream;
  242. private InputStream mInput;
  243. private BattleRecordData.EventLog mWaittingEvent;
  244. private long mPassTime;
  245. private bool mIsDone = false;
  246. private bool mIsRunning = false;
  247. public void Start(IBattleRecordListener listener)
  248. {
  249. if (mIsDone) return;
  250. if (!mIsRunning)
  251. {
  252. this.mListener = listener;
  253. this.mIsDone = false;
  254. this.mPassTime = 0;
  255. this.mIsRunning = true;
  256. }
  257. }
  258. public void Update(int intervalMS)
  259. {
  260. if (mIsRunning)
  261. {
  262. mPassTime += intervalMS;
  263. while (true)
  264. {
  265. if (mWaittingEvent == null)
  266. {
  267. mWaittingEvent = PickNextLog();
  268. }
  269. if (mWaittingEvent != null)
  270. {
  271. if (mWaittingEvent.PassTimeMS <= mPassTime)
  272. {
  273. mListener.onEventHandler(mWaittingEvent.EventData);
  274. mWaittingEvent = PickNextLog();
  275. continue;
  276. }
  277. else
  278. {
  279. break;
  280. }
  281. }
  282. else
  283. {
  284. mIsDone = true;
  285. mIsRunning = false;
  286. break;
  287. }
  288. }
  289. }
  290. }
  291. private BattleRecordData.EventLog PickNextLog()
  292. {
  293. if (mData != null)
  294. {
  295. if (mLogs.Count > 0)
  296. {
  297. return mLogs.Dequeue();
  298. }
  299. }
  300. else if (mStream != null)
  301. {
  302. try
  303. {
  304. BattleRecordData.EventLog log = new BattleRecordData.EventLog();
  305. if (mStream.CanRead)
  306. {
  307. BattleRecordData.DecodeLog(Templates, mInput, log);
  308. return log;
  309. }
  310. }
  311. catch (Exception err)
  312. {
  313. Console.WriteLine("PickNextLog catch: " + err);
  314. }
  315. }
  316. return null;
  317. }
  318. }
  319. }