Skip to content

Commit

Permalink
Updated to support save version 140
Browse files Browse the repository at this point in the history
  • Loading branch information
insomnious committed Sep 2, 2024
1 parent 3f67923 commit b56947c
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 41 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.

The format is based on [Common Changelog](https://common-changelog.org/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.3.0] - 2024-09-02

- Updated to support save version 140 that was added in Starfield 1.13.61.0

## [1.2.0] - 2024-07-24

- Increased stdout buffer size to 64 KB to handle larger save files
Expand All @@ -24,6 +28,7 @@ The format is based on [Common Changelog](https://common-changelog.org/) and thi

- Initial release

[1.3.0]: https://github.com/Nexus-Mods/StarfieldSaveTool/releases/tag/v1.3.0
[1.2.0]: https://github.com/Nexus-Mods/StarfieldSaveTool/releases/tag/v1.2.0
[1.1.0]: https://github.com/Nexus-Mods/StarfieldSaveTool/releases/tag/v1.1.0
[1.0.1]: https://github.com/Nexus-Mods/StarfieldSaveTool/releases/tag/v1.0.1
Expand Down
44 changes: 25 additions & 19 deletions DatFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -228,32 +228,38 @@ string ReadString(BinaryReader br)

private FilePlugin ReadPlugin(BinaryReader br, byte infoSaveVersion)
{
// record the current position
// var offset = br.BaseStream.Position;

// blank plugin
var plugin = new FilePlugin();

// read the plugin name
plugin.PluginName = ReadString(br);

// reset the position
//br.BaseStream.Seek(offset, SeekOrigin.Begin);

if (NATIVE_PLUGINS.Contains(plugin.PluginName))

// if save version is 140 or higher, then the next byte is a flag for extra data or not
// if it doesn't, then just return as it's probably a native plugin
if (infoSaveVersion >= 140)
{
_logger.Info($"{plugin.PluginName} is a native plugin.");
return plugin;
var hasExtraData = br.ReadByte();

if (hasExtraData == 0)
{
_logger.Info($"{plugin.PluginName} has no extra data.");
return plugin;
}
}
else
{
// if save version is less than 140, then we have to use the native plugins list to
// determine if it will have extra data or not

// if it's a native plugin then we are done
if (NATIVE_PLUGINS.Contains(plugin.PluginName))
{
_logger.Info($"{plugin.PluginName} is a native plugin.");
return plugin;
}
}

/*
// read ahead if next short is 00 then it's a creation plugin
var nextShort = br.ReadUInt16();
// reset position
br.BaseStream.Seek(-2, SeekOrigin.Current);
*/

// non-native plugin so we are expecting some extra info and possibly creation info
// non-native plugin OR flag is set to show we are expecting some extra info and possibly creation info

// previous save versions doesn't have this extra data
if (infoSaveVersion >= 122)
Expand Down
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Below is the file that is decompressed from the compressed chunks in the `.sfs`
| magic | `char[12]` | Magic bytes `"SFS_SAVEGAME"` |
| headerSize | `uint` | Size of header |
| header | [HEADER](#HEADER) | Header data block |
| saveVersion | `byte` | Save file format version. Currently `122` |
| saveVersion | `ubyte` | Save file format version. Currently `122` |
| currentGameVersionSize | `ushort` | Size of the current game version string |
| currentGameVersion | `string` | Current game version string |
| createdGameVersionSize | `ushort` | Size of the created game version string |
Expand Down Expand Up @@ -147,11 +147,13 @@ There are different types of Plugin data blocks.

* Native game plugins only contain the pluginName
* Non-native plugins (if `SaveVersion >= 122`) contain extra data, including Creation information and flags where appropriate. If an older SaveVersion, the extra data is not present.
* If `SaveVersion >= 140`, there is an extra byte to indicate if there is extra data for the plugin.

| Name | Type | Description |
|----------------|----------|---------------------|
| pluginNameSize | `ushort` | Size of plugin name |
| pluginName | `string` | Plugin name |
| Name | Type | Description | Comment |
|----------------|---------------|---------------------|-----------------------------------|
| pluginNameSize | `ushort` | Size of plugin name | |
| pluginName | `string` | Plugin name | |
| extraInfo | `ubyte` | 0=no, 1=yes | Only exists if `SaveVersion >= 140` |

#### Extra Data

Expand Down
60 changes: 44 additions & 16 deletions SFS-decompressed.bt
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ int isCreation( char name[] )

typedef struct {
ushort size;
char text[size];
uchar text[size];
} QSTRING;

typedef struct {
uint engineVersion;
byte saveVersion;
ubyte saveVersion;
uint saveNumber;
ushort playerNameSize;
char playerName[playerNameSize];
Expand All @@ -77,7 +77,7 @@ typedef struct {
} HEADER;

typedef struct {
byte saveVersion;
ubyte saveVersion;
ushort currentGameVersionSize;
char currentGameVersion[currentGameVersionSize];
ushort createdGameVersionSize;
Expand All @@ -90,35 +90,63 @@ typedef struct {
ushort pluginNameSize;
char pluginName[pluginNameSize];

if( !isGamePlugin(pluginName) ) {
// if saveVersion is 140 or more, it has a byte to say if we have extra info
// if less than 140, then we need to use game plugin names to check

if( header.saveVersion >= 140 ) {

ubyte extraInfo;

// isn't game plugin so we are expecting some extra info

if(header.saveVersion >= 122) { // newer save format support creations and have extra data

if ( extraInfo == 1 ) {

ushort creationNameSize;
char creationName[creationNameSize];
ushort creationIdSize;
char creationId[creationIdSize];
ushort flagsSize;
byte flags[flagsSize];
byte achivementFriendly;
}

Printf("%s is a plugin\n", pluginName);

Printf("%s is a plugin\n", pluginName);

} else {

Printf("%s is a game plugin\n", pluginName);
}

} else {

Printf("%s is a game plugin\n", pluginName);
}
if( !isGamePlugin(pluginName) ) {

// isn't game plugin so we are expecting some extra info

if(header.saveVersion >= 122) { // newer save format support creations and have extra data
ushort creationNameSize;
char creationName[creationNameSize];
ushort creationIdSize;
char creationId[creationIdSize];
ushort flagsSize;
byte flags[flagsSize];
byte achivementFriendly;
}

Printf("%s is a plugin\n", pluginName);

} else {

Printf("%s is a game plugin\n", pluginName);
}
}



} PLUGIN <name=pluginName>;

typedef struct {
byte unknown0;
byte count0;
ubyte unknown0;
ubyte count0;

byte pluginCount;
ubyte pluginCount;
Printf("===== plugins (%d)\n", pluginCount);
PLUGIN plugins[pluginCount] <optimize=false>;

Expand Down
2 changes: 1 addition & 1 deletion StarfieldSaveTool.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<Company>Black Tree Gaming Ltd</Company>
<AssemblyVersion>1.2.0.0</AssemblyVersion>
<AssemblyVersion>1.3.0.0</AssemblyVersion>
<PublishTrimmed>true</PublishTrimmed>
<PublishAot>true</PublishAot>
</PropertyGroup>
Expand Down

0 comments on commit b56947c

Please sign in to comment.