aboutsummaryrefslogtreecommitdiff
path: root/libs/game_bethesda/src/games/skyrim/skyrimsavegame.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/game_bethesda/src/games/skyrim/skyrimsavegame.cpp')
-rw-r--r--libs/game_bethesda/src/games/skyrim/skyrimsavegame.cpp105
1 files changed, 105 insertions, 0 deletions
diff --git a/libs/game_bethesda/src/games/skyrim/skyrimsavegame.cpp b/libs/game_bethesda/src/games/skyrim/skyrimsavegame.cpp
new file mode 100644
index 0000000..bd16036
--- /dev/null
+++ b/libs/game_bethesda/src/games/skyrim/skyrimsavegame.cpp
@@ -0,0 +1,105 @@
+#include "skyrimsavegame.h"
+
+#ifdef _WIN32
+#include <Windows.h>
+#else
+#include <QDateTime>
+
+// SYSTEMTIME is _SYSTEMTIME (defined in gamebryosavegame.h for Linux)
+using SYSTEMTIME = _SYSTEMTIME;
+
+// Portable FileTimeToSystemTime: converts Windows FILETIME to SYSTEMTIME
+static void FileTimeToSystemTime(const FILETIME* ft, SYSTEMTIME* st)
+{
+ const uint64_t ticks = (static_cast<uint64_t>(ft->dwHighDateTime) << 32) |
+ static_cast<uint64_t>(ft->dwLowDateTime);
+ const int64_t unixSecs = static_cast<int64_t>(ticks / 10000000ULL) - 11644473600LL;
+ const uint64_t remainderHns = ticks % 10000000ULL; // leftover 100ns units
+
+ const QDateTime dt = QDateTime::fromSecsSinceEpoch(unixSecs, Qt::UTC);
+ const QDate d = dt.date();
+ const QTime t = dt.time();
+
+ st->wYear = static_cast<uint16_t>(d.year());
+ st->wMonth = static_cast<uint16_t>(d.month());
+ st->wDayOfWeek = static_cast<uint16_t>(d.dayOfWeek() % 7); // Qt Mon=1..Sun=7 -> Win Sun=0..Sat=6
+ st->wDay = static_cast<uint16_t>(d.day());
+ st->wHour = static_cast<uint16_t>(t.hour());
+ st->wMinute = static_cast<uint16_t>(t.minute());
+ st->wSecond = static_cast<uint16_t>(t.second());
+ st->wMilliseconds = static_cast<uint16_t>(remainderHns / 10000);
+}
+#endif
+
+#include "gameskyrim.h"
+
+SkyrimSaveGame::SkyrimSaveGame(QString const& fileName, GameSkyrim const* game)
+ : GamebryoSaveGame(fileName, game)
+{
+ FileWrapper file(getFilepath(), "TESV_SAVEGAME");
+
+ FILETIME ftime;
+ fetchInformationFields(file, m_SaveNumber, m_PCName, m_PCLevel, m_PCLocation, ftime);
+
+ // A file time is a 64-bit value that represents the number of 100-nanosecond
+ // intervals that have elapsed since 12:00 A.M. January 1, 1601 Coordinated Universal
+ // Time (UTC). So we need to convert that to something useful
+ SYSTEMTIME ctime;
+ ::FileTimeToSystemTime(&ftime, &ctime);
+ setCreationTime(ctime);
+}
+
+void SkyrimSaveGame::fetchInformationFields(
+ FileWrapper& file, uint32_t& saveNumber, QString& playerName,
+ unsigned short& playerLevel, QString& playerLocation, FILETIME& creationTime) const
+{
+ file.skip<uint32_t>(); // header size
+ file.skip<uint32_t>(); // header version
+ file.read(saveNumber);
+
+ file.read(playerName);
+
+ uint32_t temp;
+ file.read(temp);
+ playerLevel = static_cast<unsigned short>(temp);
+
+ file.setPluginStringFormat(GamebryoSaveGame::StringFormat::LOCAL8BIT);
+ file.read(playerLocation);
+ file.setPluginStringFormat(GamebryoSaveGame::StringFormat::UTF8);
+
+ QString timeOfDay;
+ file.read(timeOfDay);
+
+ QString race;
+ file.read(race); // race name (i.e. BretonRace)
+
+ file.skip<unsigned short>(); // Player gender (0 = male)
+ file.skip<float>(2); // experience gathered, experience required
+
+ file.read(creationTime);
+}
+
+std::unique_ptr<GamebryoSaveGame::DataFields> SkyrimSaveGame::fetchDataFields() const
+{
+ FileWrapper file(getFilepath(), "TESV_SAVEGAME");
+ std::unique_ptr<DataFields> fields = std::make_unique<DataFields>();
+
+ {
+ QString dummyName, dummyLocation;
+ unsigned short dummyLevel;
+ uint32_t dummySaveNumber;
+ FILETIME dummyTime;
+
+ fetchInformationFields(file, dummySaveNumber, dummyName, dummyLevel, dummyLocation,
+ dummyTime);
+ }
+
+ fields->Screenshot = file.readImage();
+
+ file.skip<unsigned char>(); // form version
+ file.skip<uint32_t>(); // plugin info size
+
+ fields->Plugins = file.readPlugins();
+
+ return fields;
+}