static string Write(Action <ISerializer> action, Action <string> assertHandler = null) { using var byteStream = new MemoryStream(); using var binaryWriter = new BinaryWriter(byteStream); using var binarySerializer = new GenericBinaryWriter( binaryWriter, Encoding.UTF8.GetBytes, assertHandler ?? (m => throw new InvalidOperationException(m))); using var textStream = new MemoryStream(); using var textWriter = new StreamWriter(textStream); using var annotatingSerializer = new AnnotationFacadeSerializer(binarySerializer, textWriter, Encoding.ASCII.GetBytes); action(annotatingSerializer); textWriter.Flush(); textStream.Position = 0; using var sr = new StreamReader(textStream, null, true, -1, true); return(sr.ReadToEnd().Trim()); }
static void RoundTrip(string file) { AssetMapping.GlobalIsThreadLocal = true; AssetMapping.Global.Clear() .RegisterAssetType(typeof(Base.Automap), AssetType.Automap) .RegisterAssetType(typeof(Base.Chest), AssetType.Chest) .RegisterAssetType(typeof(Base.EventSet), AssetType.EventSet) .RegisterAssetType(typeof(Base.Item), AssetType.Item) .RegisterAssetType(typeof(Base.LargeNpc), AssetType.LargeNpcGraphics) .RegisterAssetType(typeof(Base.LargePartyMember), AssetType.LargePartyGraphics) .RegisterAssetType(typeof(Base.Map), AssetType.Map) .RegisterAssetType(typeof(Base.Merchant), AssetType.Merchant) .RegisterAssetType(typeof(Base.Npc), AssetType.Npc) .RegisterAssetType(typeof(Base.PartyMember), AssetType.Party) .RegisterAssetType(typeof(Base.Portrait), AssetType.Portrait) .RegisterAssetType(typeof(Base.SmallNpc), AssetType.SmallNpcGraphics) .RegisterAssetType(typeof(Base.SmallPartyMember), AssetType.SmallPartyGraphics) .RegisterAssetType(typeof(Base.Spell), AssetType.Spell) .RegisterAssetType(typeof(Base.Switch), AssetType.Switch) .RegisterAssetType(typeof(Base.Ticker), AssetType.Ticker); var mapping = AssetMapping.Global; var jsonUtil = new FormatJsonUtil(); var spellManager = new MockSpellManager(); foreach (var school in Enum.GetValues <SpellClass>()) { for (byte i = 0; i < 30; i++) { var id = new SpellId(AssetType.Spell, (int)school * 30 + i); var spell = new SpellData(id, school, i); spellManager.Add(spell); } } // === Load === using var stream = File.Open(file, FileMode.Open, FileAccess.Read); using var br = new BinaryReader(stream); using var annotationReadStream = new MemoryStream(); using var annotationReader = new StreamWriter(annotationReadStream); using var ar = new AnnotationFacadeSerializer(new AlbionReader(br, stream.Length), annotationReader, FormatUtil.BytesFrom850String); var save = SavedGame.Serdes(null, mapping, ar, spellManager); // === Save === using var ms = new MemoryStream(); using var bw = new BinaryWriter(ms); using var annotationWriteStream = new MemoryStream(); using var annotationWriter = new StreamWriter(annotationWriteStream); using var aw = new AnnotationFacadeSerializer(new AlbionWriter(bw), annotationWriter, FormatUtil.BytesFrom850String); SavedGame.Serdes(save, mapping, aw, spellManager); File.WriteAllText(file + ".json", jsonUtil.Serialize(save)); // write out debugging files and compare round-tripped data br.BaseStream.Position = 0; var originalBytes = br.ReadBytes((int)stream.Length); var roundTripBytes = ms.ToArray(); ApiUtil.Assert(originalBytes.Length == roundTripBytes.Length, $"Save game size changed after round trip (delta {roundTripBytes.Length - originalBytes.Length})"); ApiUtil.Assert(originalBytes.SequenceEqual(roundTripBytes)); var diffs = XDelta.Compare(originalBytes, roundTripBytes).ToArray(); if (diffs.Length != 1) {