public void Dispose() { if (!m_disposed) { if (WorkBuff != null) { WorkBuff.Dispose(); WorkBuff = null; } m_disposed = true; } }
/// <summary> /// Loads an object from the buffer. /// </summary> protected int LoadObject <T>(T obj) where T : SaveDataObject { int size = WorkBuff.ReadInt32(); int bytesRead = Serializer.Read(obj, WorkBuff, FileFormat); WorkBuff.Align4(); Debug.WriteLine($"{typeof(T).Name}: {bytesRead} bytes read."); Debug.Assert(bytesRead <= DataBuffer.Align4(size)); return(bytesRead); }
private void ReInitWorkBuff() { if (WorkBuff != null) { WorkBuff.Dispose(); } WorkBuff = new DataBuffer(GetBufferSize()) { BigEndian = false, PaddingType = PaddingType, PaddingBytes = PaddingBytes }; }
protected override void LoadAllData(DataBuffer file) { int dataSize = 0; dataSize += ReadBlock(file); SimpleVars = WorkBuff.ReadObject <SimpleVariables>(FileFormat); Scripts = LoadTypePreAlloc <Dummy>(); dataSize += ReadBlock(file); PedPool = LoadType <PedPool>(); dataSize += ReadBlock(file); Garages = LoadTypePreAlloc <Dummy>(); dataSize += ReadBlock(file); GameLogic = LoadTypePreAlloc <Dummy>(); dataSize += ReadBlock(file); Vehicles = LoadTypePreAlloc <Dummy>(); dataSize += ReadBlock(file); Objects = LoadType <ObjectPool>(); dataSize += ReadBlock(file); Paths = LoadTypePreAlloc <Dummy>(); dataSize += ReadBlock(file); Cranes = LoadTypePreAlloc <Dummy>(); dataSize += ReadBlock(file); Pickups = LoadTypePreAlloc <Dummy>(); dataSize += ReadBlock(file); PhoneInfo = LoadTypePreAlloc <Dummy>(); dataSize += ReadBlock(file); RestartPoints = LoadTypePreAlloc <Dummy>(); dataSize += ReadBlock(file); RadarBlips = LoadTypePreAlloc <Dummy>(); dataSize += ReadBlock(file); Zones = LoadTypePreAlloc <Dummy>(); dataSize += ReadBlock(file); Gangs = LoadTypePreAlloc <Dummy>(); dataSize += ReadBlock(file); CarGenerators = LoadType <CarGeneratorData>(); dataSize += ReadBlock(file); ParticleObjects = LoadTypePreAlloc <Dummy>(); dataSize += ReadBlock(file); AudioScriptObjects = LoadTypePreAlloc <Dummy>(); dataSize += ReadBlock(file); ScriptPaths = LoadTypePreAlloc <Dummy>(); dataSize += ReadBlock(file); PlayerInfo = LoadTypePreAlloc <Dummy>(); dataSize += ReadBlock(file); Stats = LoadType <Stats>(); dataSize += ReadBlock(file); SetPieces = LoadTypePreAlloc <Dummy>(); dataSize += ReadBlock(file); Streaming = LoadTypePreAlloc <Dummy>(); dataSize += ReadBlock(file); PedTypeInfo = LoadTypePreAlloc <Dummy>(); // Skip over padding int numPaddingBlocks = 0; while (file.Position < file.Length - 4) { dataSize += ReadBlock(file); numPaddingBlocks++; } // Size checks int expectedDataSize = DataSize; int expectedFileSize = expectedDataSize + ((NumOuterBlocks + numPaddingBlocks) * sizeof(int)) + sizeof(int); Debug.Assert(expectedDataSize == dataSize); Debug.Assert(expectedFileSize == file.Length); Debug.WriteLine("Load successful!"); }
/// <summary> /// Writes an object to the buffer. /// </summary> /// <param name="obj"></param> protected void SaveObject(SaveDataObject obj) { int size, preSize, postData; preSize = WorkBuff.Position; WorkBuff.Skip(4); size = Serializer.Write(WorkBuff, obj, FileFormat); postData = WorkBuff.Position; WorkBuff.Seek(preSize); WorkBuff.Write(size); WorkBuff.Seek(postData); WorkBuff.Align4(); Debug.WriteLine($"{obj.GetType().Name}: {size} bytes written."); }
/// <summary> /// Allocates the required space for the specified type, /// then loads in an instance of that type. /// </summary> protected T LoadTypePreAlloc <T>() where T : SaveDataObject { int size = WorkBuff.ReadInt32(); if (!(Activator.CreateInstance(typeof(T), size) is T obj)) { throw new SerializationException(Strings.Error_Serialization_NoPreAlloc, typeof(T)); } Debug.WriteLine($"{typeof(T).Name}: {size} bytes pre-allocated."); int bytesRead = Serializer.Read(obj, WorkBuff, FileFormat); WorkBuff.Align4(); Debug.WriteLine($"{typeof(T).Name}: {bytesRead} bytes read."); Debug.Assert(bytesRead <= DataBuffer.Align4(size)); return(obj); }
/// <summary> /// Reads a block of data from the file into the work buffer. /// </summary> protected int ReadBlock(DataBuffer file) { file.Mark(); WorkBuff.Reset(); int size = file.ReadInt32(); if ((uint)size > WorkBuff.Length) { throw new SerializationException(Strings.Error_Serialization_BadBlockSize, (uint)size); } WorkBuff.Write(file.ReadBytes(size)); file.Align4(); Debug.Assert(file.Offset == size + 4); WorkBuff.Reset(); return(size); }
/// <summary> /// Writes a block of data from the work buffer into the file. /// </summary> protected int WriteBlock(DataBuffer file) { file.Mark(); byte[] data = WorkBuff.GetBytes(); int size = data.Length; file.Write(size); file.Write(data); file.Align4(); Debug.Assert(file.Offset == size + 4); CheckSum += file.GetBytesFromMark().Sum(x => x); WorkBuff.Reset(); // game code has a bug where the size of the 'size' itself is not // factored in to the total file size, so savefiles are always // 4 * numBlocks bytes larger than told by SizeOfGameInBytes return(size); }
protected override void SaveAllData(DataBuffer file) { int dataSize = 0; int size; int numOuterBlocks; WorkBuff.Reset(); CheckSum = 0; SimpleVars.SizeOfGameInBytes = DataSize; if (FileFormat.IsPS2) { if (!FileFormat.IsJapanese) { SimpleVars.SizeOfGameInBytes += 1; } WorkBuff.Write(SimpleVars, FileFormat); SaveObject(Scripts); SaveObject(PlayerPeds); SaveObject(Garages); SaveObject(Vehicles); dataSize += WriteBlock(file); SaveObject(Objects); SaveObject(Paths); SaveObject(Cranes); dataSize += WriteBlock(file); SaveObject(Pickups); SaveObject(PhoneInfo); SaveObject(RestartPoints); SaveObject(RadarBlips); SaveObject(Zones); SaveObject(Gangs); SaveObject(CarGenerators); SaveObject(ParticleObjects); SaveObject(AudioScriptObjects); SaveObject(PlayerInfo); SaveObject(Stats); SaveObject(Streaming); SaveObject(PedTypeInfo); dataSize += WriteBlock(file); numOuterBlocks = NumOuterBlocksPS2; } else { SimpleVars.SizeOfGameInBytes += 1; WorkBuff.Write(SimpleVars, FileFormat); SaveObject(Scripts); dataSize += WriteBlock(file); SaveObject(PlayerPeds); dataSize += WriteBlock(file); SaveObject(Garages); dataSize += WriteBlock(file); SaveObject(Vehicles); dataSize += WriteBlock(file); SaveObject(Objects); dataSize += WriteBlock(file); SaveObject(Paths); dataSize += WriteBlock(file); SaveObject(Cranes); dataSize += WriteBlock(file); SaveObject(Pickups); dataSize += WriteBlock(file); SaveObject(PhoneInfo); dataSize += WriteBlock(file); SaveObject(RestartPoints); dataSize += WriteBlock(file); SaveObject(RadarBlips); dataSize += WriteBlock(file); SaveObject(Zones); dataSize += WriteBlock(file); SaveObject(Gangs); dataSize += WriteBlock(file); SaveObject(CarGenerators); dataSize += WriteBlock(file); SaveObject(ParticleObjects); dataSize += WriteBlock(file); SaveObject(AudioScriptObjects); dataSize += WriteBlock(file); SaveObject(PlayerInfo); dataSize += WriteBlock(file); SaveObject(Stats); dataSize += WriteBlock(file); SaveObject(Streaming); dataSize += WriteBlock(file); SaveObject(PedTypeInfo); dataSize += WriteBlock(file); numOuterBlocks = NumOuterBlocks; } int numPaddingBlocks = 0; for (int i = 0; i < MaxNumPaddingBlocks; i++) { size = (SimpleVars.SizeOfGameInBytes - dataSize - 1) & 0x7FFFFFFC; if (size > GetBufferSize()) { size = GetBufferSize(); } if (size > 4) { WorkBuff.Reset(); WorkBuff.Pad(size); dataSize += WriteBlock(file); numPaddingBlocks++; } } file.Write(CheckSum); if (FileFormat.IsXbox) { byte[] data = file.GetBytes(); byte[] sig = XboxHelper.CalculateGameSaveSignature(XboxTitleKey, data, 0, data.Length - 4); file.Write(sig); } // Size checks int expectedDataSize = DataSize; if (!(FileFormat.IsPS2 && FileFormat.IsJapanese)) { expectedDataSize += 1; } expectedDataSize = (expectedDataSize - 1) & 0x7FFFFFFC; int expectedFileSize = expectedDataSize + ((numOuterBlocks + numPaddingBlocks) * sizeof(int)) + sizeof(int); if (FileFormat.IsXbox) { expectedFileSize += XboxHelper.SignatureLength; } Debug.Assert(expectedDataSize == dataSize); Debug.Assert(expectedFileSize == file.Length); Debug.WriteLine("Save successful!"); }
protected override void LoadAllData(DataBuffer file) { int dataSize = 0; int numOuterBlocks; if (FileFormat.IsPS2) { dataSize += ReadBlock(file); SimpleVars = WorkBuff.ReadObject <SimpleVariables>(FileFormat); Scripts = LoadType <ScriptData>(); PlayerPeds = LoadType <PedPool>(); Garages = LoadType <GarageData>(); Vehicles = LoadType <VehiclePool>(); dataSize += ReadBlock(file); Objects = LoadType <ObjectPool>(); Paths = LoadTypePreAlloc <PathData>(); Cranes = LoadType <CraneData>(); dataSize += ReadBlock(file); Pickups = LoadType <PickupData>(); PhoneInfo = LoadType <PhoneData>(); RestartPoints = LoadType <RestartData>(); RadarBlips = LoadType <RadarData>(); Zones = LoadType <ZoneData>(); Gangs = LoadType <GangData>(); CarGenerators = LoadType <CarGeneratorData>(); ParticleObjects = LoadType <ParticleData>(); AudioScriptObjects = LoadType <AudioScriptData>(); PlayerInfo = LoadType <PlayerInfo>(); Stats = LoadType <Stats>(); Streaming = LoadType <Streaming>(); PedTypeInfo = LoadType <PedTypeData>(); numOuterBlocks = NumOuterBlocksPS2; } else { dataSize += ReadBlock(file); SimpleVars = WorkBuff.ReadObject <SimpleVariables>(FileFormat); Scripts = LoadType <ScriptData>(); dataSize += ReadBlock(file); PlayerPeds = LoadType <PedPool>(); dataSize += ReadBlock(file); Garages = LoadType <GarageData>(); dataSize += ReadBlock(file); Vehicles = LoadType <VehiclePool>(); dataSize += ReadBlock(file); Objects = LoadType <ObjectPool>(); dataSize += ReadBlock(file); Paths = LoadTypePreAlloc <PathData>(); dataSize += ReadBlock(file); Cranes = LoadType <CraneData>(); dataSize += ReadBlock(file); Pickups = LoadType <PickupData>(); dataSize += ReadBlock(file); PhoneInfo = LoadType <PhoneData>(); dataSize += ReadBlock(file); RestartPoints = LoadType <RestartData>(); dataSize += ReadBlock(file); RadarBlips = LoadType <RadarData>(); dataSize += ReadBlock(file); Zones = LoadType <ZoneData>(); dataSize += ReadBlock(file); Gangs = LoadType <GangData>(); dataSize += ReadBlock(file); CarGenerators = LoadType <CarGeneratorData>(); dataSize += ReadBlock(file); ParticleObjects = LoadType <ParticleData>(); dataSize += ReadBlock(file); AudioScriptObjects = LoadType <AudioScriptData>(); dataSize += ReadBlock(file); PlayerInfo = LoadType <PlayerInfo>(); dataSize += ReadBlock(file); Stats = LoadType <Stats>(); dataSize += ReadBlock(file); Streaming = LoadType <Streaming>(); dataSize += ReadBlock(file); PedTypeInfo = LoadType <PedTypeData>(); numOuterBlocks = NumOuterBlocks; } // Skip over padding int numPaddingBlocks = 0; int size = file.Length; if (FileFormat.IsXbox) { size -= XboxHelper.SignatureLength; } while (file.Position < size - 4) { dataSize += ReadBlock(file); numPaddingBlocks++; } // Size checks int expectedDataSize = DataSize; if (!(FileFormat.IsPS2 && FileFormat.IsJapanese)) { expectedDataSize += 1; } expectedDataSize = (expectedDataSize - 1) & 0x7FFFFFFC; int expectedFileSize = expectedDataSize + ((numOuterBlocks + numPaddingBlocks) * sizeof(int)) + sizeof(int); if (FileFormat.IsXbox) { expectedFileSize += XboxHelper.SignatureLength; } Debug.Assert(expectedDataSize == dataSize); Debug.Assert(expectedFileSize == file.Length); Debug.WriteLine("Load successful!"); }
protected override void SaveAllData(DataBuffer file) { int dataSize = 0; int size; WorkBuff.Reset(); CheckSum = 0; SimpleVars.SizeOfGameInBytes = DataSize + 1; WorkBuff.Write(SimpleVars, FileFormat); SaveObject(Scripts); dataSize += WriteBlock(file); SaveObject(PedPool); dataSize += WriteBlock(file); SaveObject(Garages); dataSize += WriteBlock(file); SaveObject(GameLogic); dataSize += WriteBlock(file); SaveObject(Vehicles); dataSize += WriteBlock(file); SaveObject(Objects); dataSize += WriteBlock(file); SaveObject(Paths); dataSize += WriteBlock(file); SaveObject(Cranes); dataSize += WriteBlock(file); SaveObject(Pickups); dataSize += WriteBlock(file); SaveObject(PhoneInfo); dataSize += WriteBlock(file); SaveObject(RestartPoints); dataSize += WriteBlock(file); SaveObject(RadarBlips); dataSize += WriteBlock(file); SaveObject(Zones); dataSize += WriteBlock(file); SaveObject(Gangs); dataSize += WriteBlock(file); SaveObject(CarGenerators); dataSize += WriteBlock(file); SaveObject(ParticleObjects); dataSize += WriteBlock(file); SaveObject(AudioScriptObjects); dataSize += WriteBlock(file); SaveObject(ScriptPaths); dataSize += WriteBlock(file); SaveObject(PlayerInfo); dataSize += WriteBlock(file); SaveObject(Stats); dataSize += WriteBlock(file); SaveObject(SetPieces); dataSize += WriteBlock(file); SaveObject(Streaming); dataSize += WriteBlock(file); SaveObject(PedTypeInfo); dataSize += WriteBlock(file); int numPaddingBlocks = 0; for (int i = 0; i < MaxNumPaddingBlocks; i++) { size = (SimpleVars.SizeOfGameInBytes - dataSize - 1) & 0x7FFFFFFC; if (size > GetBufferSize()) { size = GetBufferSize(); } if (size > 4) { WorkBuff.Reset(); WorkBuff.Pad(size); dataSize += WriteBlock(file); numPaddingBlocks++; } } file.Write(CheckSum); // Size checks int expectedDataSize = DataSize; int expectedFileSize = expectedDataSize + ((NumOuterBlocks + numPaddingBlocks) * sizeof(int)) + sizeof(int); Debug.Assert(expectedDataSize == dataSize); Debug.Assert(expectedFileSize == file.Length); Debug.WriteLine("Save successful!"); }