GRUPO STEAM
Nier: Automata Mining and Moddin N:A M&M
GRUPO STEAM
Nier: Automata Mining and Moddin N:A M&M
31
A JOGAR
155
ONLINE
Criado
24 de março de 2017
Idioma
Inglês
Todas as discussões > General > Detalhes do tópico
SkacikPL 24 mar. 2017 às 13:43
Base information about save files
Graphics.ini - Actually only stores GPU information, not realy relevant to any kind of modding

System data file - Stores actual settings, including PC specific settings, however stored values are only indexes of selected options within the ingame settings menu (thus can't be fed custom values) value range starts with higher values for "lower" settings and always end with 0 for "highest" value.

Actual slot save file - Can be easily edited with hex editor, byte size has to be retained otherwise game won't load save. It's possible to add flags or edit current player and other events. No doubt also stores current inventory but it seems encrypted within the file.

Feel free to expand if you have any relevant information.
< >
A mostrar 1-11 de 11 comentários
Aemony 7 jan. 2018 às 14:14 
The game uses the Steam64 ID as a signature in GameData.dat and SaveSlot_#.dat.

It is stored as little-endian in the following locations:
GameData.dat - offset 00 - 07
SaveSlot_#.dat - offset 04 - 11

GameData.dat stores general purpose settings not tied to any particular save slot nor the systems data settings. Most obvious point being the background of the title screen.

GameData.dat is read after the initial loading screen to the title screen on game launch. If the Steam64 ID stored within this file doesn't match the current player signed in to Steam then the game will overwrite the whole file from scratch, resetting the title screen background in the process.

After that the game loads and compares the signatures of the individual SaveSlot_#.dat to the current player signed in to Steam. If the signatures doesn't match then those saves will not show up under the save slot screen.
Última alteração por Aemony; 7 jan. 2018 às 14:14
Aemony 13 fev. 2018 às 2:08 
Inventory is located at block 30570 -> 31D6F in the save files. There's no separation between inventory slots, but item ID and count is separated by a divider that indicates item slot "status". As with everything else the data is stored as little-endian.

The block is 6 144 bytes large, and covers 512 items with 12 bytes dedicated to each item (6 144 / 12). Further on, this block is split into two sections, with 3072 bytes/256 items in each section. The first section is for the current "active" inventory, while the second section is for the corpse/lost inventory.

Each item is stored side-by-side and is divided into 3x 4 byte sections:

ID ID ID ID ZX ZX ZX ZX NO NO NO NO

ID = Item ID stored at that section

ZX = Status of that item slot. FF FF FF FF == Inactive item slot post-prologue. 00 00 07 00 == Active item slot.

NO = Amount of said item stored

Prologue/new game save slots are slightly different in that they use FF FF FF FF even for active item slots.

Screenshot: https://i.imgur.com/TlNORek.png

15x Small Recovery (item_rec_S, item ID 0) :
00 00 00 00 FF FF FF 0F 00 00 00

5x Medium Recovery (item_rec_M, item ID 1) :
01 00 00 00 FF FF FF 05 00 00 00

1x Large Recovery (item_rec_L, item ID 2) :
02 00 00 00 FF FF FF 01 00 00 00

3x Melee Attack Up (S) (item_stUp_pAtk_S, item ID 100) :
64 00 00 00 FF FF FF 03 00 00 00

3x Melee Defense Up (S) (item_stUp_pDef_S, item ID 120) :
78 00 00 00 FF FF FF 03 00 00 00

Edit: Experience is stored at offset 3056C, as a 2-byte value just before the inventory list begins at offset 30570.

Edit 2: DLC items are not stored in the corpse inventory section between the Prologue and City Ruins chapters. Even if you manually add them to the corpse inventory before retrieving the corpse they will not be read either. Only vanilla game items will be retrieved from the corpse inventory.

Further on, the 5-6 first item slots seems to be dedicated to the various Day One Edition and Valve Accessory Pack DLCs on Steam. If these haven't been added to the inventory yet then the game will rearrange the inventory and store those in the first slots. This can cause loss of data as, again, DLC items are ignored if they're stored in those slots and are overwritten.
Última alteração por Aemony; 13 fev. 2018 às 17:42
Aemony 13 fev. 2018 às 19:58 
Since I was bored, here's the structure of SystemData.dat. Offsets are in decimal, and as usual the values are stored in little-endian.

00-07 - SteamID64

08-11 - Width
12-15 - Height

16-19 - Window Mode | 0 = Window, 1 = Fullscreen
20-23 - Effects | 0 = High, 1 = Low

24-27 - Monitor | 0 = \.\\DISPLAY1, 1 = \.\\DISPLAY2
28-31 - Vertical Sync | 0 = Off, 1 = On

32-35 - Anti-Aliasing | 0 = 8x, 1 = 4x, 2 = 2x, 3 = Off
36-39 - Texture Filtering | 0 = 16x, 1 = 8x, 2 = 4x, 3 = 2x, 4 = Off

40-43 - Blur | 0 = Off, 1 = On
44-47 - Shadows | 0 = High, 1 = Medium, 2 = Low

48-51 - Ambient Occlusion | 0 = Off, 1 = On
52-55 - ?

The last 4 bytes doesn't seem to store anything in particular, or at least I haven't been able to find any setting in-game that changes those, nor have I noticed any discernible difference when playing around with the value of the bytes.
Última alteração por Aemony; 13 fev. 2018 às 19:58
Aemony 13 fev. 2018 às 20:19 
Graphic.ini stores the name of the GPU and output monitor in hexadecimal, with 2 byte for each character.

VideoCard = 100 characters max (meaning 50 characters for Latin alphabet)
Output = 40 characters max (meaning 20 characters for Latin alphabet)

Example output:
VideoCard=N.V.I.D.I.A. .G.e.F.o.r.c.e. .G.T.X. .1.0.8.0. .T.i.............................................................................................................................................................................................................O
Output=\.\...\.D.I.S.P.L.A.Y.1.........................................‰
76561197963075328 7 mai. 2018 às 19:19 
Mostly reversed file read io function that the game uses. Handles SystemData.dat, GameData.dat and SaveData_%d.dat. It's asynchronous due to the usage of the OVERLAPPED struct and it doesn't have any sharemode on CreateFile. Which means it locks the files for modification. Another worthy note is SHGetSpecialFolderPathA is unsupported according to msdn, so it's kind of interesting why they still chose to use it.

SHGetSpecialFolderPathA Docs:
https://msdn.microsoft.com/en-us/library/windows/desktop/bb762204(v=vs.85).aspx

void __fastcall SaveFileIO_Read(CSaveDataDevice *pSavedata) { CSaveDataDevice *pSave; // rbx int v2; // ecx int v3; // ecx int v4; // ecx QWORD v5; // rax HANDLE hFile3; // rcx HANDLE hFile4; // rcx int nSlot2; // eax char *pFileBuffer; // rax void *pData; // rcx size_t size; // r8 void *pFileBufferData; // rdx CSteamID *pSteamId; // rdi SteamInterface_t *pInterfaces; // rax int v15; // edx HANDLE hFile2; // rcx int slot_number; // eax const char *szFileName; // r8 HANDLE hFile; // rcx int nSlot; // eax DWORD bytesIO; // eax void *pBuffer; // rdx __int64 nSlot3; // [rsp+20h] [rbp-378h] char v24; // [rsp+40h] [rbp-358h] char szDest[260]; // [rsp+50h] [rbp-348h] char szAbsoluteFilePath[260]; // [rsp+160h] [rbp-238h] CHAR szPath[260]; // [rsp+270h] [rbp-128h] pSave = pSavedata; v2 = HIDWORD(pSavedata->qwFlags); if ( !v2 ) { if ( !SHGetSpecialFolderPathA((HWND)NULL, szPath, CSIDL_MYDOCUMENTS, FALSE) ) goto CleanupFailure; snprintf(szDest, MAX_PATH, "%s\\%s\\%s\\", szPath, "My Games", "NieR_Automata"); slot_number = pSave->nSlot; if ( slot_number == -2 ) { szFileName = "%sSystemData.dat"; } else { if ( slot_number != -1 ) { LODWORD(nSlot3) = pSave->nSlot; snprintf(szAbsoluteFilePath, MAX_PATH, "%sSlotData_%d.dat", szDest, nSlot3); ReadFile: SetLastError(ERROR_SUCCESS); hFile = CreateFileA(szAbsoluteFilePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); pSave->hFile = hFile; if ( hFile != (HANDLE)INVALID_HANDLE_VALUE ) { nSlot = pSave->nSlot; if ( nSlot == -2 ) { bytesIO = pSave->nBytesIO_SystemData; } else if ( nSlot == -1 ) { bytesIO = pSave->nBytesIO_GameData; } else { bytesIO = pSave->nBytesIO_SaveData; } pBuffer = pSave->pBuffer; pSave->nBytesToIO = bytesIO; HIDWORD(pSave->qwFlags) = 2 - (ReadFile(hFile, pBuffer, pSave->nBytesToIO, &pSave->nBytesIO, &pSave->overlapped) != 0); return; } GetLastError(); if ( GetLastError() - 2 <= 1 ) { SaveFileIO_CloseFileHandle(pSave, 4); return; } CleanupFailure: HIDWORD(pSave->qwFlags) = 2; return; } szFileName = "%sGameData.dat"; } snprintf(szAbsoluteFilePath, MAX_PATH, szFileName, szDest); goto ReadFile; } v3 = v2 - 1; if ( !v3 ) { if ( LODWORD(pSave->overlapped.Internal) == STATUS_PENDING ) return; if ( pSave->nBytesIO != pSave->nBytesToIO ) { HIDWORD(pSave->qwFlags) = 2; goto CloseFileHandle; } nSlot2 = pSave->nSlot; if ( nSlot2 == -2 ) // SystemData { pData = pSave->pSystemDataBuffer; size = pSave->qwSizeSystemDataBuffer; } else { if ( nSlot2 != -1 ) // GameData { pFileBuffer = (char *)pSave->pBuffer; pData = pSave->pGameDataBuffer; size = pSave->qwSizeGameDataBuffer; pFileBufferData = pFileBuffer + 12; pSteamId = (CSteamID *)(pFileBuffer + 4); CopyData: memcpy(pData, pFileBufferData, size); pInterfaces = (SteamInterface_t *)SteamInternal_ContextInit(pSteam_InitInterface_WrapperFn); if ( pSteamId->m_steamid.m_unAll64Bits == *(_QWORD *)(*(__int64 (__fastcall **)(ISteamUser *, char *))(*(_QWORD *)pInterfaces->pISteamUser + 16i64))(pInterfaces->pISteamUser, &v24) ) v15 = 0; else v15 = 7; SaveFileIO_CloseFileHandle(pSave, v15); CloseFileHandle: hFile2 = pSave->hFile; if ( hFile2 != (HANDLE)INVALID_HANDLE_VALUE ) { CloseHandle(hFile2); pSave->hFile = (HANDLE)INVALID_HANDLE_VALUE; } return; } pData = pSave->pSlotDataBuffer; size = pSave->qwSizeSlotDataBuffer; } pSteamId = (CSteamID *)pSave->pBuffer; pFileBufferData = &pSteamId[1]; // = (void*)(pSave->pBuffer + 8) goto CopyData; } v4 = v3 - 1; if ( v4 ) { if ( v4 != 1 ) return; v5 = pSave->qwUnk0xC8; if ( v5 ) { if ( !*(_DWORD *)(v5 + 8) ) return; if ( v5 ) *(_DWORD *)(v5 + 12) = 1; } pSave->qwUnk0xC8 = 0i64; hFile3 = pSave->hFile; if ( hFile3 != (HANDLE)INVALID_HANDLE_VALUE ) { CloseHandle(hFile3); pSave->hFile = (HANDLE)INVALID_HANDLE_VALUE; } pSave->field_1C = 3; pSave->qwFlags = 0i64; } else { hFile4 = pSave->hFile; if ( hFile4 != (HANDLE)INVALID_HANDLE_VALUE ) { CloseHandle(hFile4); pSave->hFile = (HANDLE)INVALID_HANDLE_VALUE; } pSave->field_1C = 3; pSave->qwFlags = 0i64; } }
Última alteração por martymoose21; 7 mai. 2018 às 19:21
Drakaenae 12 ago. 2018 às 22:48 
Any idea where intel information is stored, specifically fishing data in SaveSlot_#.dat?
76561197963075328 13 ago. 2018 às 11:40 
Originalmente postado por Drakaenae:
Any idea where intel information is stored, specifically fishing data in SaveSlot_#.dat?

Me personaly not a clue.
Drakaenae 17 ago. 2018 às 22:52 
Alright, I found most of the addresses for fish intel.

For intel (at least fish intel) it looks like each bit is a boolean and some bytes store this data.
So 10000001 means 2/8 fish in the byte are unlocked

000385d8 - 000385db: unlocks 32 fishes (too lazy to find which ones)
000385de: one of the bits unlock Broken Firearm, not sure about the rest
000385df: unlocks another 8 fishes (too lazy to find which ones)

000385e0 - 000385e3: corresponds to the first 32 fishes, determines if the intel has been read
000385e6: probably corresponds to 000385de (did not check)
000385e7: probably corresponds to 000385df

I'm planning on writing a save editor, but this seems like a lot of work. Maybe I'll just write one for the fishes. But if I do, i'll figure out which bits correspond to which fish then.
Drakaenae 18 ago. 2018 às 23:53 
based on https://steamcommunity.com/app/524220/discussions/0/1327844097113668255/
The plugin-chips are saved from around address 0x00032698 to 0x000349BF as 24 bytes values
76561197963075328 3 set. 2018 às 7:08 
https://github.com/CensoredUsername/Nier-Automata-editor
I guess you're in luck, creds to _xxk for the link. Also, you're welcome to join our modding discord for NieR:Automata. https://discord.gg/v8Yyrrg
Última alteração por martymoose21; 3 set. 2018 às 7:08
76561197963075328 9 set. 2018 às 0:27 
also there is a csv (comma seperated values) file somewhere called FishParam.csv

Originalmente postado por Drakaenae:
based on https://steamcommunity.com/app/524220/discussions/0/1327844097113668255/
The plugin-chips are saved from around address 0x00032698 to 0x000349BF as 24 bytes values


Originalmente postado por Drakaenae:
based on https://steamcommunity.com/app/524220/discussions/0/1327844097113668255/
The plugin-chips are saved from around address 0x00032698 to 0x000349BF as 24 bytes values
< >
A mostrar 1-11 de 11 comentários
Por página: 1530 50

Todas as discussões > General > Detalhes do tópico