public void TestSaveHeaderV5Writing() { using (var stream = new MemoryStream()) using (var writer = new BinaryWriter(stream)) { var header = new SaveHeader { SaveVersion = SaveHeaderV5SaveVersion, BuildVersion = SaveHeaderV5BuildVersion, Magic = SaveHeaderV5Magic, MapName = SaveHeaderV5MapName, MapOptions = SaveHeaderV5MapOptions, SessionName = SaveHeaderV5SessionName, PlayDuration = SaveHeaderV5PlayDuration, SaveDateTime = SaveHeaderV5SaveDateTime, SessionVisibility = SaveHeaderV5SessionVisibility }; header.Serialize(writer); CollectionAssert.AreEqual(SaveHeaderV5Bytes, stream.ToArray()); } }
/// <summary> /// Open a savefile from disk /// </summary> /// <param name="file">Full path to the .sav file, usually found in %localappdata%/FactoryGame/Saved/SaveGames</param> public SatisfactorySave(string file) { FileName = Environment.ExpandEnvironmentVariables(file); using (var stream = new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using (var reader = new BinaryReader(stream)) { Header = SaveHeader.Parse(reader); // Does not need to be a public property because it's equal to Entries.Count var totalEntries = reader.ReadUInt32(); // Saved entities loop for (int i = 0; i < totalEntries; i++) { var type = reader.ReadInt32(); switch (type) { case SaveEntity.TypeID: Entries.Add(new SaveEntity(reader)); break; case SaveComponent.TypeID: Entries.Add(new SaveComponent(reader)); break; default: throw new InvalidOperationException($"Unexpected type {type}"); } } var totalEntries2 = reader.ReadInt32(); Trace.Assert(Entries.Count == totalEntries); Trace.Assert(Entries.Count == totalEntries2); for (int i = 0; i < Entries.Count; i++) { var len = reader.ReadInt32(); var before = reader.BaseStream.Position; Entries[i].ParseData(len, reader); var after = reader.BaseStream.Position; if (before + len != after) { throw new InvalidOperationException($"Expected {len} bytes read but got {after - before}"); } } var unk10 = reader.ReadInt32(); for (int i = 0; i < unk10; i++) { var str1 = reader.ReadLengthPrefixedString(); var str2 = reader.ReadLengthPrefixedString(); UnknownMap.Add(new ObjectReference(str1, str2)); } Trace.Assert(reader.BaseStream.Position == reader.BaseStream.Length); } }
internal SaveInfo(string fileName, int version, int slot, SaveHeader header) { FileName = fileName; Header = header; Slot = slot; Version = version; SaveName = slot switch { 0 => StringResources.Slot0Name, 1 => StringResources.Slot1Name, 2 => StringResources.Slot2Name, 3 => StringResources.Slot3Name, 4 => StringResources.Slot4Name, _ => StringResources.UnknownSlotName, }; }
public void TestSaveHeaderV4Reading() { using (var stream = new MemoryStream(SaveHeaderV4Bytes)) using (var reader = new BinaryReader(stream)) { var header = SaveHeader.Parse(reader); Assert.AreEqual(SaveHeaderV4SaveVersion, header.SaveVersion); Assert.AreEqual(SaveHeaderV4BuildVersion, header.BuildVersion); Assert.AreEqual(SaveHeaderV4Magic, header.Magic); Assert.AreEqual(SaveHeaderV4MapName, header.MapName); Assert.AreEqual(SaveHeaderV4MapOptions, header.MapOptions); Assert.AreEqual(SaveHeaderV4SessionName, header.SessionName); Assert.AreEqual(SaveHeaderV4PlayDuration, header.PlayDuration); Assert.AreEqual(SaveHeaderV4SaveDateTime, header.SaveDateTime); Assert.AreEqual(stream.Length, stream.Position); } }
public SaveHeaderViewModel(DataBlockWrapperBuffer header, DataBlockWrapper pSeat) { PlayerSeat = pSeat; SaveCommand = new RelayCommand(() => { if (SaveHeader.SaveChanges != null) { SaveHeader.SaveChanges(); } }, () => SaveHeader.HasChanges); ReloadCommand = new RelayCommand(() => { if (SaveHeader.Reload != null) { SaveHeader.Reload(); } }, () => SaveHeader.HasChanges); SaveHeader = header; }
/// <summary> /// Open a savefile from disk /// </summary> /// <param name="file">Full path to the .sav file, usually found in %localappdata%/FactoryGame/Saved/SaveGames</param> public SatisfactorySave(string file) { log.Info($"Opening save file: {file}"); FileName = Environment.ExpandEnvironmentVariables(file); using (var stream = new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using (var reader = new BinaryReader(stream)) { Header = SaveHeader.Parse(reader); // Does not need to be a public property because it's equal to Entries.Count var totalSaveObjects = reader.ReadUInt32(); log.Info($"Save contains {totalSaveObjects} object headers"); // Saved entities loop for (int i = 0; i < totalSaveObjects; i++) { var type = reader.ReadInt32(); switch (type) { case SaveEntity.TypeID: Entries.Add(new SaveEntity(reader)); break; case SaveComponent.TypeID: Entries.Add(new SaveComponent(reader)); break; default: throw new InvalidOperationException($"Unexpected type {type}"); } } var totalSaveObjectData = reader.ReadInt32(); log.Info($"Save contains {totalSaveObjectData} object data"); Trace.Assert(Entries.Count == totalSaveObjects); Trace.Assert(Entries.Count == totalSaveObjectData); for (int i = 0; i < Entries.Count; i++) { var len = reader.ReadInt32(); var before = reader.BaseStream.Position; Entries[i].ParseData(len, reader); var after = reader.BaseStream.Position; if (before + len != after) { throw new InvalidOperationException($"Expected {len} bytes read but got {after - before}"); } } var collectedObjectsCount = reader.ReadInt32(); log.Info($"Save contains {collectedObjectsCount} collected objects"); for (int i = 0; i < collectedObjectsCount; i++) { CollectedObjects.Add(new ObjectReference(reader)); } log.Debug($"Read {reader.BaseStream.Position} of total {reader.BaseStream.Length} bytes"); Trace.Assert(reader.BaseStream.Position == reader.BaseStream.Length); } }
/// <summary> /// Open a savefile from disk /// </summary> /// <param name="file">Full path to the .sav file, usually found in %localappdata%/FactoryGame/Saved/SaveGames</param> public SatisfactorySave(string file) { log.Info($"Opening save file: {file}"); FileName = Environment.ExpandEnvironmentVariables(file); using (var stream = new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using (var reader = new BinaryReader(stream)) { Header = SaveHeader.Parse(reader); // Does not need to be a public property because it's equal to Entries.Count var totalSaveObjects = reader.ReadUInt32(); log.Info($"Save contains {totalSaveObjects} object headers"); // Saved entities loop for (int i = 0; i < totalSaveObjects; i++) { var type = reader.ReadInt32(); var typePath = reader.ReadLengthPrefixedString(); SaveObject so = SaveObjectFactory.CreateObjectFromType(type, typePath); if (null != so) { so.TypePath = typePath; so.ParseHeader(reader); Entries.Add(so); } else { throw new InvalidOperationException($"Couldn't find proper class for TypeId={type}, TypePath={typePath}"); } } var totalSaveObjectData = reader.ReadInt32(); log.Info($"Save contains {totalSaveObjectData} object data"); Trace.Assert(Entries.Count == totalSaveObjects); Trace.Assert(Entries.Count == totalSaveObjectData); for (int i = 0; i < Entries.Count; i++) { var len = reader.ReadInt32(); var before = reader.BaseStream.Position; #if DEBUG //log.Trace($"Reading {len} bytes @ {before} for {Entries[i].TypePath}"); #endif Entries[i].ParseData(len, reader); var after = reader.BaseStream.Position; if (before + len != after) { throw new InvalidOperationException($"Expected {len} bytes read but got {after - before}"); } } var collectedObjectsCount = reader.ReadInt32(); log.Info($"Save contains {collectedObjectsCount} collected objects"); for (int i = 0; i < collectedObjectsCount; i++) { CollectedObjects.Add(new ObjectReference(reader)); } log.Debug($"Read {reader.BaseStream.Position} of total {reader.BaseStream.Length} bytes"); Trace.Assert(reader.BaseStream.Position == reader.BaseStream.Length); } }