From e280e4f55c1b590d4a9653956da61f26d55ef484 Mon Sep 17 00:00:00 2001 From: nattthebear Date: Sun, 19 Jul 2015 15:57:40 -0400 Subject: [PATCH] TasMovie Branch internals --- BizHawk.Client.Common/BinarySaveStates.cs | 173 +++++++++++------- .../movie/tasproj/TasBranch.cs | 104 ++++++++++- .../movie/tasproj/TasMovie.IO.cs | 10 +- 3 files changed, 214 insertions(+), 73 deletions(-) diff --git a/BizHawk.Client.Common/BinarySaveStates.cs b/BizHawk.Client.Common/BinarySaveStates.cs index f8dd794c08..bd4ac6c3cf 100644 --- a/BizHawk.Client.Common/BinarySaveStates.cs +++ b/BizHawk.Client.Common/BinarySaveStates.cs @@ -2,82 +2,134 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Reflection; using ICSharpCode.SharpZipLib.Zip; //using Ionic.Zip; namespace BizHawk.Client.Common { - public enum BinaryStateLump + public class BinaryStateLump { - Versiontag, - Corestate, - Framebuffer, - Input, - CorestateText, + [Name("BizState 1.0")] + public static BinaryStateLump Versiontag { get; private set; } + [Name("Core")] + public static BinaryStateLump Corestate { get; private set; } + [Name("Framebuffer.bmp")] + public static BinaryStateLump Framebuffer { get; private set; } + [Name("Input Log.txt")] + public static BinaryStateLump Input { get; private set; } + [Name("CoreText.txt")] + public static BinaryStateLump CorestateText { get; private set; } // Only for movies they probably shoudln't be leaching this stuff - Movieheader, - Comments, - Subtitles, - SyncSettings, + [Name("Header.txt")] + public static BinaryStateLump Movieheader { get; private set; } + [Name("Comments.txt")] + public static BinaryStateLump Comments { get; private set; } + [Name("Subtitles.txt")] + public static BinaryStateLump Subtitles { get; private set; } + [Name("SyncSettings.json")] + public static BinaryStateLump SyncSettings { get; private set; } // TasMovie - LagLog, - StateHistory, - StateHistorySettings, - Markers, - ClientSettings, - VerificationLog, - Branches, + [Name("LagLog")] + public static BinaryStateLump LagLog { get; private set; } + [Name("GreenZone")] + public static BinaryStateLump StateHistory { get; private set; } + [Name("GreenZoneSettings.txt")] + public static BinaryStateLump StateHistorySettings { get; private set; } + [Name("Markers.txt")] + public static BinaryStateLump Markers { get; private set; } + [Name("ClientSettings.json")] + public static BinaryStateLump ClientSettings { get; private set; } + [Name("VerificationLog.txt")] + public static BinaryStateLump VerificationLog { get; private set; } - UserData + [Name("UserData.txt")] + public static BinaryStateLump UserData { get; private set; } + + // branchstuff + [Name("Branches\\CoreData.bin")] + public static BinaryStateLump BranchCoreData { get; private set; } + [Name("Branches\\InputLog.txt")] + public static BinaryStateLump BranchInputLog { get; private set; } + [Name("Branches\\FrameBuffer.bmp")] + public static BinaryStateLump BranchFrameBuffer { get; private set; } + [Name("Branches\\LagLog.bin")] + public static BinaryStateLump BranchLagLog { get; private set; } + [Name("Branches\\Header.json")] + public static BinaryStateLump BranchHeader { get; private set; } + + + [AttributeUsage(AttributeTargets.Property)] + private class NameAttribute : Attribute + { + public string Name { get; private set; } + public NameAttribute(string name) + { + Name = name; + } + } + + public virtual string ReadName { get; private set; } + public virtual string WriteName { get; private set; } + + private BinaryStateLump(string name) + { + WriteName = name; + // for reading, all extensions are stripped + ReadName = Path.GetFileNameWithoutExtension(name); + } + + protected BinaryStateLump() { } + + static BinaryStateLump() + { + foreach (var prop in typeof(BinaryStateLump).GetProperties(BindingFlags.Public | BindingFlags.Static)) + { + string name = prop.GetCustomAttributes(false).OfType().Single().Name; + object value = new BinaryStateLump(name); + prop.SetValue(null, value, null); + } + } } - public static class BinaryStateFileNames + /// + /// describes a BinaryStateLump virtual name that has a numerical index + /// + public class IndexedStateLump : BinaryStateLump { - private static readonly Dictionary ReadNames; - private static readonly Dictionary WriteNames; - - static void AddLumpName(BinaryStateLump token, string name) + private BinaryStateLump _root; + private int _idx; + public IndexedStateLump(BinaryStateLump root) { - ReadNames[token] = Path.GetFileNameWithoutExtension(name); - WriteNames[token] = name; - } - static BinaryStateFileNames() - { - ReadNames = new Dictionary(); - WriteNames = new Dictionary(); - AddLumpName(BinaryStateLump.Versiontag, "BizState 1.0"); - AddLumpName(BinaryStateLump.Corestate, "Core"); - AddLumpName(BinaryStateLump.Framebuffer, "Framebuffer.bmp"); - AddLumpName(BinaryStateLump.Input, "Input Log.txt"); - AddLumpName(BinaryStateLump.CorestateText, "CoreText.txt"); - AddLumpName(BinaryStateLump.Movieheader, "Header.txt"); - - // Only for movies they probably shoudln't be leaching this stuff - AddLumpName(BinaryStateLump.Comments, "Comments.txt"); - AddLumpName(BinaryStateLump.Subtitles, "Subtitles.txt"); - AddLumpName(BinaryStateLump.SyncSettings, "SyncSettings.json"); - - // TasMovie - AddLumpName(BinaryStateLump.LagLog, "LagLog"); - AddLumpName(BinaryStateLump.StateHistory, "GreenZone"); - AddLumpName(BinaryStateLump.StateHistorySettings, "GreenZoneSettings.txt"); - AddLumpName(BinaryStateLump.Markers, "Markers.txt"); - AddLumpName(BinaryStateLump.ClientSettings, "ClientSettings.json"); - AddLumpName(BinaryStateLump.VerificationLog, "VerificationLog.txt"); - AddLumpName(BinaryStateLump.UserData, "UserData.txt"); - AddLumpName(BinaryStateLump.Branches, "Branches"); + _root = root; } - public static string GetReadName(BinaryStateLump lump) + public void Increment() { - return ReadNames[lump]; + _idx++; } - public static string GetWriteName(BinaryStateLump lump) + + public override string ReadName { - return WriteNames[lump]; + get + { + return base.ReadName + _idx; + } + } + + public override string WriteName + { + get + { + string fn = Path.GetFileNameWithoutExtension(base.WriteName); + string ext = Path.GetExtension(base.WriteName); + if (!string.IsNullOrEmpty(ext)) + ext = ext.Substring(1); + return string.Format("{0}{1}.{2}", fn, _idx, ext); + } } } @@ -171,9 +223,8 @@ namespace BizHawk.Client.Common public bool HasLump(BinaryStateLump lump) { - string name = BinaryStateFileNames.GetReadName(lump); ZipEntry e; - return _entriesbyname.TryGetValue(name, out e); + return _entriesbyname.TryGetValue(lump.ReadName, out e); } /// @@ -185,9 +236,8 @@ namespace BizHawk.Client.Common /// true if callback was called and stream was loaded public bool GetLump(BinaryStateLump lump, bool abort, Action callback) { - string name = BinaryStateFileNames.GetReadName(lump); ZipEntry e; - if (_entriesbyname.TryGetValue(name, out e)) + if (_entriesbyname.TryGetValue(lump.ReadName, out e)) { using (var zs = _zip.GetInputStream(e)) { @@ -199,7 +249,7 @@ namespace BizHawk.Client.Common if (abort) { - throw new Exception("Essential zip section not found: " + name); + throw new Exception("Essential zip section not found: " + lump.ReadName); } return false; @@ -279,8 +329,7 @@ namespace BizHawk.Client.Common public void PutLump(BinaryStateLump lump, Action callback) { - var name = BinaryStateFileNames.GetWriteName(lump); - _zip.WriteItem(name, callback); + _zip.WriteItem(lump.WriteName, callback); } public void PutLump(BinaryStateLump lump, Action callback) diff --git a/BizHawk.Client.Common/movie/tasproj/TasBranch.cs b/BizHawk.Client.Common/movie/tasproj/TasBranch.cs index d7fe08ac64..99c339be40 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasBranch.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasBranch.cs @@ -1,6 +1,8 @@ -using System.Collections; +using System; +using System.Collections; using System.Collections.Generic; using System.IO; +using Newtonsoft.Json; namespace BizHawk.Client.Common { @@ -17,14 +19,110 @@ namespace BizHawk.Client.Common { private List Branches = new List(); - public void Save(BinaryWriter bw) + public void Save(BinaryStateSaver bs) { + var nheader = new IndexedStateLump(BinaryStateLump.BranchHeader); + var ncore = new IndexedStateLump(BinaryStateLump.BranchCoreData); + var ninput = new IndexedStateLump(BinaryStateLump.BranchInputLog); + var nframebuffer = new IndexedStateLump(BinaryStateLump.BranchFrameBuffer); + var nlaglog = new IndexedStateLump(BinaryStateLump.BranchLagLog); + foreach (var b in Branches) + { + bs.PutLump(nheader, delegate(TextWriter tw) + { + // if this header needs more stuff in it, handle it sensibly + tw.WriteLine(JsonConvert.SerializeObject(new { Frame = b.Frame })); + }); + bs.PutLump(ncore, delegate(Stream s) + { + s.Write(b.CoreData, 0, b.CoreData.Length); + }); + bs.PutLump(ninput, delegate(TextWriter tw) + { + foreach (var line in b.InputLog) + tw.WriteLine(line); + }); + bs.PutLump(nframebuffer, delegate(Stream s) + { + // todo: do we want to do something more clever here? + byte[] buff = new byte[2048]; + var src = b.OSDFrameBuffer; + for (int i = 0; i < src.Length; i += 512) + { + int n = Math.Min(512, src.Length - i); + Buffer.BlockCopy(src, i * 4, buff, 0, n * 4); + s.Write(buff, 0, n * 4); + } + }); + bs.PutLump(nframebuffer, delegate(BinaryWriter bw) + { + b.LagLog.Save(bw); + }); + nheader.Increment(); + ncore.Increment(); + ninput.Increment(); + nframebuffer.Increment(); + nlaglog.Increment(); + } } - public void Load(BinaryReader br, long length) + public void Load(BinaryStateLoader bl) { + var nheader = new IndexedStateLump(BinaryStateLump.BranchHeader); + var ncore = new IndexedStateLump(BinaryStateLump.BranchCoreData); + var ninput = new IndexedStateLump(BinaryStateLump.BranchInputLog); + var nframebuffer = new IndexedStateLump(BinaryStateLump.BranchFrameBuffer); + var nlaglog = new IndexedStateLump(BinaryStateLump.BranchLagLog); + Branches.Clear(); + + while (true) + { + var b = new TasBranch(); + + if (!bl.GetLump(nheader, false, delegate(TextReader tr) + { + b.Frame = (int)((dynamic)JsonConvert.DeserializeObject(tr.ReadLine())).Frame; + })) + { + return; + } + + bl.GetLump(ncore, true, delegate(Stream s, long length) + { + b.CoreData = new byte[length]; + s.Read(b.CoreData, 0, b.CoreData.Length); + }); + + bl.GetLump(ninput, true, delegate(TextReader tr) + { + b.InputLog = new List(); + string line; + while ((line = tr.ReadLine()) != null) + b.InputLog.Add(line); + }); + + bl.GetLump(nframebuffer, true, delegate(Stream s, long length) + { + int[] dst = new int[length / 4]; + byte[] buff = new byte[2048]; + for (int i = 0; i < dst.Length; i++) + { + int n = Math.Min(512, dst.Length - i); + s.Read(buff, 0, n * 4); + Buffer.BlockCopy(buff, 0, dst, i * 4, n * 4); + } + }); + + bl.GetLump(nlaglog, true, delegate(BinaryReader br) + { + b.LagLog = new TasLagLog(); + b.LagLog.Load(br); + }); + + Branches.Add(b); + } } } } diff --git a/BizHawk.Client.Common/movie/tasproj/TasMovie.IO.cs b/BizHawk.Client.Common/movie/tasproj/TasMovie.IO.cs index 63e2c7cb27..e75528624b 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasMovie.IO.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasMovie.IO.cs @@ -93,7 +93,7 @@ namespace BizHawk.Client.Common if (Branches.Any()) { - bs.PutLump(BinaryStateLump.Branches, (BinaryWriter bw) => Branches.Save(bw)); + Branches.Save(bs); } ReportProgress(PROGRESS_STEP); @@ -270,13 +270,7 @@ namespace BizHawk.Client.Common }); } - if (bl.HasLump(BinaryStateLump.Branches)) - { - bl.GetLump(BinaryStateLump.Branches, true, delegate(BinaryReader br, long length) - { - Branches.Load(br, length); - }); - } + Branches.Load(bl); } Changes = false;