From d7604531eb4c788de2dae8beab3e9add44baffb1 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Sat, 9 Apr 2016 02:21:22 +0100 Subject: [PATCH] Migrate first save state struct and update loading --- rwengine/include/engine/GameState.hpp | 50 +++++++++++++++++ rwengine/include/engine/SaveGame.hpp | 8 ++- rwengine/src/engine/SaveGame.cpp | 80 +++++++++------------------ rwgame/menustate.cpp | 18 ++++-- 4 files changed, 93 insertions(+), 63 deletions(-) diff --git a/rwengine/include/engine/GameState.hpp b/rwengine/include/engine/GameState.hpp index c654ac8b..c4bdd195 100644 --- a/rwengine/include/engine/GameState.hpp +++ b/rwengine/include/engine/GameState.hpp @@ -14,6 +14,56 @@ class ScriptMachine; class PlayerController; struct CutsceneData; +struct SystemTime +{ + uint16_t year; + uint16_t month; + uint16_t dayOfWeek; + uint16_t day; + uint16_t hour; + uint16_t minute; + uint16_t second; + uint16_t millisecond; +}; + +/** Block 0 State */ +struct BasicState +{ + /// /!\ This is wchar_t[24] in the original format /!\ we convert on load for convenience + char saveName[48]; + SystemTime saveTime; + uint16_t unknown; + uint16_t islandNumber; + glm::vec3 cameraPosition; + uint16_t gameMinuteMS; + uint16_t lastTick; + uint8_t gameHour; + uint8_t _align0[3]; + uint8_t gameMinute; + uint8_t _align1[3]; + uint16_t padMode; + uint8_t _align2[2]; + uint16_t timeMS; + float timeScale; + float timeStep; + float timeStep_unclipped; // Unknown purpose + uint16_t frameCounter; + float timeStep2; + float framesPerUpdate; + float timeScale2; + uint16_t lastWeather; + uint8_t _align3[2]; + uint16_t nextWeather; + uint8_t _align4[2]; + uint16_t forcedWeather; + uint8_t _align5[2]; + float weatherInterpolation; + uint8_t dateTime[24]; // Unused + uint16_t weatherType; + float cameraData; + float cameraData2; +}; + struct TextDisplayData { // This is set by the final display text command. diff --git a/rwengine/include/engine/SaveGame.hpp b/rwengine/include/engine/SaveGame.hpp index f1e1aca0..cea07024 100644 --- a/rwengine/include/engine/SaveGame.hpp +++ b/rwengine/include/engine/SaveGame.hpp @@ -4,17 +4,19 @@ #include +#include + #include #include -struct GameState; class GameWorld; class ScriptMachine; struct SaveGameInfo { - std::string saveName; std::string savePath; + bool valid; + BasicState basicState; }; /** @@ -40,7 +42,7 @@ public: */ static bool loadGame(GameState& state, const std::string& file); - static SaveGameInfo getSaveInfo(const std::string& file); + static bool getSaveInfo(const std::string& file, BasicState* outState); /** * Returns save game information for all found saves diff --git a/rwengine/src/engine/SaveGame.cpp b/rwengine/src/engine/SaveGame.cpp index d84c1c18..8a887240 100644 --- a/rwengine/src/engine/SaveGame.cpp +++ b/rwengine/src/engine/SaveGame.cpp @@ -17,48 +17,6 @@ typedef uint16_t BlockWord; typedef uint32_t BlockDword; typedef BlockDword BlockSize; -struct Block0Data { - uint16_t saveName[24]; - BlockWord year; - BlockWord month; - BlockWord weekday; - BlockWord day; - BlockWord hour; - BlockWord minute; - BlockWord second; - BlockWord milliseconds; - BlockDword unknown; - BlockDword islandNumber; - glm::vec3 cameraPosition; - BlockDword gameMinuteMS; - BlockDword lastTick; - uint8_t gameHour; - uint8_t _align0[3]; - uint8_t gameMinute; - uint8_t _align1[3]; - BlockWord padMode; - uint8_t _align2[2]; - BlockDword timeMS; - float timeScale; - float timeStep; - float timeStep_unclipped; // Unknown purpose - BlockDword frameCounter; - float timeStep2; - float framesPerUpdate; - float timeScale2; - BlockWord lastWeather; - uint8_t _align3[2]; - BlockWord nextWeather; - uint8_t _align4[2]; - BlockWord forcedWeather; - uint8_t _align5[2]; - float weatherInterpolation; - uint8_t dateTime[24]; // Unused - BlockDword weatherType; - float cameraData; - float cameraData2; -}; - struct Block0ContactInfo { BlockDword missionFlag; BlockDword baseBrief; @@ -252,7 +210,7 @@ void SaveGame::writeGame(GameState& state, const std::string& file) std::FILE* saveFile = std::fopen(file.c_str(), "w"); // BLOCK 0 - Variables - Block0Data block0Data = {}; + BasicState block0Data = {}; //strcpy(block0Data.saveName, "OpenRW Save Game"); block0Data.islandNumber = 1; block0Data.cameraPosition = glm::vec3(0.f); @@ -340,8 +298,8 @@ bool SaveGame::loadGame(GameState& state, const std::string& file) BlockDword blockSize; fread(&blockSize, sizeof(BlockDword), 1, loadFile); - Block0Data block0Data; - fread(&block0Data, sizeof(block0Data), 1, loadFile); + BasicState block0Data; + fread(&block0Data, sizeof(BasicState), 1, loadFile); BlockDword scriptBlockSize; fread(&scriptBlockSize, sizeof(BlockDword), 1, loadFile); @@ -489,30 +447,40 @@ bool SaveGame::loadGame(GameState& state, const std::string& file) #include #include -SaveGameInfo SaveGame::getSaveInfo(const std::string& file) +bool SaveGame::getSaveInfo(const std::string& file, BasicState *basicState) { std::FILE* loadFile = std::fopen(file.c_str(), "r"); + + SaveGameInfo info; + info.savePath = file; // BLOCK 0 BlockDword blockSize; - fread(&blockSize, sizeof(BlockDword), 1, loadFile); + if( fread(&blockSize, sizeof(BlockDword), 1, loadFile) == 0 ) { + return false; + } - Block0Data block0Data; - fread(&block0Data, sizeof(block0Data), 1, loadFile); + // Read block 0 into state + if( fread(basicState, sizeof(BasicState), 1, loadFile) == 0 ) { + return false; + } std::fclose(loadFile); size_t bytes = 0; for(;; bytes++ ) { - if(block0Data.saveName[bytes-1] == 0 && block0Data.saveName[bytes] == 0) break; + if(basicState->saveName[bytes-1] == 0 && basicState->saveName[bytes] == 0) break; } - size_t len = bytes/2; size_t outSize = 24; - char outBuff[outSize]; + char outBuff[48]; char* outCur = outBuff; auto icv = iconv_open("UTF-8", "UTF-16"); - char* saveName = (char*)block0Data.saveName; + char* saveName = (char*)basicState->saveName; + + // Convert to UTF-8 and copy back to the return struct iconv(icv, &saveName, &bytes, &outCur, &outSize); - return { std::string(outBuff), file }; + strcpy(basicState->saveName, outBuff); + + return true; } std::vector< SaveGameInfo > SaveGame::getAllSaveGameInfo() @@ -540,7 +508,9 @@ std::vector< SaveGameInfo > SaveGame::getAllSaveGameInfo() if ( ep->d_type == DT_REG ) { realName = ep->d_name; if(realName.find(".b") != realName.npos) { - infos.push_back(getSaveInfo(gamePath+"/"+realName)); + std::string path = gamePath+"/"+realName; + infos.emplace_back(SaveGameInfo{path, false, {}}); + infos.back().valid = getSaveInfo(infos.back().savePath, &infos.back().basicState); } } } diff --git a/rwgame/menustate.cpp b/rwgame/menustate.cpp index 4ada928a..54e44c68 100644 --- a/rwgame/menustate.cpp +++ b/rwgame/menustate.cpp @@ -31,14 +31,22 @@ void MenuState::enterMainMenu() void MenuState::enterLoadMenu() { Menu *m = new Menu(2); - m->offset = glm::vec2(200.f, 200.f); + m->offset = glm::vec2(20.f, 30.f); m->addEntry(Menu::lambda("Back", [=] { enterMainMenu(); })); auto saves = SaveGame::getAllSaveGameInfo(); for(SaveGameInfo& save : saves) { - m->addEntry(Menu::lambda(save.saveName, [=] { - StateManager::get().enter(new IngameState(game, false)); - game->loadGame(save.savePath); - })); + if (save.valid) { + std::stringstream ss; + ss << save.basicState.saveTime.year << "/" << save.basicState.saveTime.month << "/" << save.basicState.saveTime.day + << " " << save.basicState.saveTime.hour << ":" << save.basicState.saveTime.minute << " " << save.basicState.saveName; + m->addEntry(Menu::lambda(ss.str(), [=] { + StateManager::get().enter(new IngameState(game, false)); + game->loadGame(save.savePath); + }, 20.f)); + } + else { + m->addEntry(Menu::lambda("Corrupt", [=] { })); + } } this->enterMenu(m); }