From 71dd4eb5b5eda820d7ea4afba050fe1659f20c76 Mon Sep 17 00:00:00 2001 From: Nathan Fulton Date: Sat, 29 Apr 2017 21:35:17 -0400 Subject: [PATCH] Save preferences as json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Preferences have keys as defined in ht.h. These keys can be used to read/write preferences. Preferences are saved in a .json on the disk. This is much easier to work with than the old presences binary structures as it doesn’t require preference versioning. --- game/game.cpp | 308 ++++++++++++++----------------------------- game/ht.h | 162 +++++++++++------------ game/preferences.cpp | 152 +++++++++++++++++++++ game/sdl/host.cpp | 37 +----- 4 files changed, 332 insertions(+), 327 deletions(-) create mode 100644 game/preferences.cpp diff --git a/game/game.cpp b/game/game.cpp index bc28bc9..4c21ad8 100644 --- a/game/game.cpp +++ b/game/game.cpp @@ -275,27 +275,27 @@ bool Game::Init(int imm) // Load prefs first - LoadPreferences(); + if (!LoadPreferences()) + return false; - // Suck what we can from preferences + // Suck what we can from preferences - gtGameSpeed = gprefsInit.ctGameSpeed; - gfLassoSelection = gprefsInit.fLassoSelection != 0; - gnHueOffset = gprefsInit.nHueOffset; - gnSatMultiplier = gprefsInit.nSatMultiplier; - gnLumOffset = gprefsInit.nLumOffset; - strncpyz(gszUsername, gprefsInit.szUsername, sizeof(gszUsername)); - strncpyz(gszPassword, gprefsInit.szPassword, sizeof(gszPassword)); - strncpyz(gszToken, gprefsInit.szToken, sizeof(gszToken)); - gfAnonymous = (gprefsInit.fAnonymous != 0); - gwfPerfOptions = gprefsInit.wfPerfOptions; - gwfHandicap = gprefsInit.wfHandicap; - gkey = gprefsInit.key; - gnDemoRank = gprefsInit.nDemoRank; - gnScrollSpeed = gprefsInit.nScrollSpeed; - gfIgnoreBluetoothWarning = (gprefsInit.wfPrefs & kfPrefIgnoreBluetoothWarning) ? true : false; - strncpyz(gszAskURL, gprefsInit.szAskURL, sizeof(gszAskURL)); - strncpyz(gszDeviceId, gprefsInit.szDeviceId, sizeof(gszDeviceId)); + gtGameSpeed = gpprefs->GetInteger(knPrefGameSpeed); + gfLassoSelection = gpprefs->GetBool(kfPrefLassoSelection); + gnHueOffset = gpprefs->GetInteger(knPrefHueOffset); + gnSatMultiplier = gpprefs->GetInteger(knPrefSatMultiplier); + gnLumOffset = gpprefs->GetInteger(knPrefLumOffset); + strncpy(gszUsername, gpprefs->GetString(kszPrefUsername), sizeof(gszUsername)); + strncpy(gszPassword, gpprefs->GetString(kszPrefPassword), sizeof(gszPassword)); + strncpy(gszToken, gpprefs->GetString(kszPrefToken), sizeof(gszToken)); + gfAnonymous = gpprefs->GetBool(kfPrefAnonymous); + gwfPerfOptions = (word)gpprefs->GetInteger(kwfPrefPerfOptions); + gwfHandicap = (word)gpprefs->GetInteger(kwfPrefHandicap); + gnDemoRank = gpprefs->GetInteger(knPrefDemoRank); + gnScrollSpeed = gpprefs->GetFloat(knPrefScrollSpeed); + // gfIgnoreBluetoothWarning = gpprefs->GetBool(kfPrefIgnoreBluetoothWarning); + strncpy(gszAskURL, gpprefs->GetString(kszPrefAskUrl), sizeof(gszAskURL)); + strncpy(gszDeviceId, gpprefs->GetString(kszPrefDeviceId), sizeof(gszDeviceId)); // Temp buffer used for several things, including decompression, TBitmap compiling. @@ -420,9 +420,9 @@ bool Game::Init(int imm) // Init sound system gsndm.Init(); - if (gprefsInit.nVolume != (word)-1) - gsndm.SetVolume(gprefsInit.nVolume); - gsndm.Enable((gprefsInit.wfPrefs & kfPrefSoundMuted) == 0); + if (gpprefs->GetInteger(knPrefVolume) != (word)-1) + gsndm.SetVolume(gpprefs->GetInteger(knPrefVolume)); + gsndm.Enable(!gpprefs->GetBool(kfPrefSoundMuted)); // Clear out stale save games @@ -1071,17 +1071,17 @@ bool Game::InitDisplay(int immRequested) bool fMatchesPrefs = true; ModeInfo mode; gpdisp->GetModeInfo(m_amm[immBest].imode, &mode); - if (mode.cx != gprefsInit.cxModeBest) + if (mode.cx != gpprefs->GetInteger(knPrefCxModeBest)) fMatchesPrefs = false; - if (mode.cy != gprefsInit.cyModeBest) + if (mode.cy != gpprefs->GetInteger(knPrefCyModeBest)) fMatchesPrefs = false; - if (mode.nDepth != gprefsInit.nDepthModeBest) + if (mode.nDepth != gpprefs->GetInteger(knPrefDepthModeBest)) fMatchesPrefs = false; - if (mode.nDegreeOrientation != gprefsInit.nDegreeOrientationBest) + if (mode.nDegreeOrientation != gpprefs->GetInteger(knPrefDegreeOrientationBest)) fMatchesPrefs = false; - if (m_amm[immBest].nDepthData != gprefsInit.nDepthDataBest) + if (m_amm[immBest].nDepthData != gpprefs->GetInteger(knPrefDepthDataBest)) fMatchesPrefs = false; - if (m_amm[immBest].nSizeData != gprefsInit.nSizeDataBest) + if (m_amm[immBest].nSizeData != gpprefs->GetInteger(knPrefSizeDataBest)) fMatchesPrefs = false; if (fMatchesPrefs) { // Looks like there hasn't been a config change (new data / new device) so try @@ -1091,17 +1091,17 @@ bool Game::InitDisplay(int immRequested) ModeMatch *pmmT = &m_amm[immT]; ModeInfo modeT; gpdisp->GetModeInfo(pmmT->imode, &modeT); - if (modeT.cx != gprefsInit.cxModeLast) + if (modeT.cx != gpprefs->GetInteger(knPrefCxModeLast)) continue; - if (modeT.cy != gprefsInit.cyModeLast) + if (modeT.cy != gpprefs->GetInteger(knPrefCyModeLast)) continue; - if (modeT.nDepth != gprefsInit.nDepthModeLast) + if (modeT.nDepth != gpprefs->GetInteger(knPrefDepthModeLast)) continue; - if (modeT.nDegreeOrientation != gprefsInit.nDegreeOrientationLast) + if (modeT.nDegreeOrientation != gpprefs->GetInteger(knPrefDegreeOrientationLast)) continue; - if (pmmT->nDepthData != gprefsInit.nDepthDataLast) + if (pmmT->nDepthData != gpprefs->GetInteger(knPrefDepthDataLast)) continue; - if (pmmT->nSizeData != gprefsInit.nSizeDataLast) + if (pmmT->nSizeData != gpprefs->GetInteger(knPrefSizeDataLast)) continue; immNew = immT; break; @@ -2054,6 +2054,9 @@ void Game::Exit() SavePreferences(); + delete gpprefs; + gpprefs = NULL; + Status("Exit Simulation (one-time)..."); gsim.OneTimeExit(); @@ -2449,219 +2452,108 @@ void Game::SetGameSpeed(int t) } // Preferences support. -// -// Note always save and load assuming a storage format of big endian. -// That way we don't have a headache when someone upgrades from a 68K Palm to a -// ARM Palm with ARM HT and then HotSyncs, restoring a little endian preferences database. -Preferences gprefsInit; +Preferences *gpprefs; -void Game::LoadPreferences() +bool Game::LoadPreferences() { - // Try to load preferences. If this fails, - // initialize preferences to default values. - // gprefsInit is a global that holds the preferences that are used during initialization - // It's a global because we won't be able to process all preferences related initialization - // here. + // Try to load preferences. - if (!LoadPreferences2()) { - // Initialize preferences to default values + gpprefs = PrefsFromFile(); - memset(&gprefsInit, 0, sizeof(gprefsInit)); - Date date; - HostGetCurrentDate(&date); - gprefsInit.fAnonymous = 0; - gprefsInit.nYearLastRun = date.nYear; - gprefsInit.nMonthLastRun = date.nMonth; - gprefsInit.nDayLastRun = date.nDay; - gprefsInit.nVolume = (word)-1; - gprefsInit.wfPerfOptions = kfPerfMax; - gprefsInit.ctGameSpeed = kctUpdate / 2; - gprefsInit.wfHandicap = kfHcapDefault; -#if defined(WIN) && !defined(CE) - gprefsInit.nScale = -1; -#endif - gprefsInit.nScrollSpeed = 1.0; - strncpyz(gprefsInit.szAskURL, "http://", sizeof(gprefsInit.szAskURL)); - strncpyz(gprefsInit.szDeviceId, HostGenerateDeviceId(), sizeof(gprefsInit.szDeviceId)); - } -} + // Failed? Initialize preferences to default values -bool Game::LoadPreferences2() -{ - Preferences prefs; - int cbRead = HostLoadPreferences(&prefs, sizeof(prefs)); - if (cbRead != (int)BigDword(prefs.prefv.cbSize)) - return false; - - switch (BigDword(prefs.prefv.dwVersion)) { - case knVersionPreferencesV100: - if (cbRead != sizeof(PreferencesV100)) + if (gpprefs == NULL) { + gpprefs = PrefsFromDefaults(); + if (gpprefs == NULL) return false; - if (!LoadPreferencesV100((PreferencesV100 *)&prefs)) - return false; - strncpyz(gprefsInit.szDeviceId, HostGenerateDeviceId(), sizeof(gprefsInit.szDeviceId)); - return true; - - case knVersionPreferencesV101: - if (cbRead != sizeof(PreferencesV101)) - return false; - return LoadPreferencesV101((PreferencesV101 *)&prefs); } - return false; -} - -bool Game::LoadPreferencesV100(PreferencesV100 *pprefsV100) -{ - strncpyz(gprefsInit.szUsername, pprefsV100->szUsername, - sizeof(gprefsInit.szUsername)); - strncpyz(gprefsInit.szPassword, pprefsV100->szPassword, - sizeof(gprefsInit.szPassword)); - strncpyz(gprefsInit.szToken, pprefsV100->szToken, - sizeof(gprefsInit.szToken)); - gprefsInit.fAnonymous = BigWord(pprefsV100->fAnonymous); - gprefsInit.nYearLastRun = BigWord(pprefsV100->nYearLastRun); - gprefsInit.nMonthLastRun = BigWord(pprefsV100->nMonthLastRun); - gprefsInit.nDayLastRun = BigWord(pprefsV100->nDayLastRun); - gprefsInit.nVolume = BigWord(pprefsV100->nVolume); - gprefsInit.wfPrefs = BigWord(pprefsV100->wfPrefs); - gprefsInit.wfPerfOptions = BigWord(pprefsV100->wfPerfOptions); - gprefsInit.ctGameSpeed = BigDword(pprefsV100->ctGameSpeed); - gprefsInit.fLassoSelection = BigWord(pprefsV100->fLassoSelection); - gprefsInit.nHueOffset = BigWord(pprefsV100->nHueOffset); - gprefsInit.nSatMultiplier = BigWord(pprefsV100->nSatMultiplier); - gprefsInit.nLumOffset = BigWord(pprefsV100->nLumOffset); - gprefsInit.cxModeBest = BigWord(pprefsV100->cxModeBest); - gprefsInit.cyModeBest = BigWord(pprefsV100->cyModeBest); - gprefsInit.nDepthModeBest = BigWord(pprefsV100->nDepthModeBest); - gprefsInit.nDepthDataBest = BigWord(pprefsV100->nDepthDataBest); - gprefsInit.nSizeDataBest = BigWord(pprefsV100->nSizeDataBest); - gprefsInit.nDegreeOrientationBest = BigWord(pprefsV100->nDegreeOrientationBest); - gprefsInit.cxModeLast = BigWord(pprefsV100->cxModeLast); - gprefsInit.cyModeLast = BigWord(pprefsV100->cyModeLast); - gprefsInit.nDepthModeLast = BigWord(pprefsV100->nDepthModeLast); - gprefsInit.nDepthDataLast = BigWord(pprefsV100->nDepthDataLast); - gprefsInit.nSizeDataLast = BigWord(pprefsV100->nSizeDataLast); - gprefsInit.nDegreeOrientationLast = BigWord(pprefsV100->nDegreeOrientationLast); - gprefsInit.nDemoRank = BigWord(pprefsV100->nDemoRank); - gprefsInit.nScrollSpeed = pprefsV100->nScrollSpeed; - strncpyz(gprefsInit.szAskURL, pprefsV100->szAskURL, - sizeof(gprefsInit.szAskURL)); - - // Migrate obsolete handicap combinations - - gprefsInit.wfHandicap = BigWord(pprefsV100->wfHandicap); - if (gprefsInit.wfHandicap == 0) // old hard - gprefsInit.wfHandicap = kfHcapHard; // new hard - else if (gprefsInit.wfHandicap == (kfHcapDecreasedTimeToBuild | kfHcapIncreasedFirePower | kfHcapIncreasedMinerLoadValue | kfHcapShowEnemyBuildProgress | kfHcapShowEnemyResourceStatus)) - gprefsInit.wfHandicap = kfHcapEasy; - else if (gprefsInit.wfHandicap == (kfHcapDecreasedTimeToBuild | kfHcapShowEnemyBuildProgress | kfHcapShowEnemyResourceStatus)) - gprefsInit.wfHandicap = kfHcapNormal; - else if (gprefsInit.wfHandicap != kfHcapEasy && gprefsInit.wfHandicap != kfHcapNormal && gprefsInit.wfHandicap != kfHcapHard) - gprefsInit.wfHandicap = kfHcapDefault; - - gprefsInit.key = pprefsV100->key; -#if defined(WIN) && !defined(CE) - gprefsInit.nScale = BigWord(pprefsV100->nScale); -#endif - - return true; -} - -bool Game::LoadPreferencesV101(PreferencesV101 *pprefsV101) -{ - // Since order is the same as V100 except for extra fields at the end, load V100 first - if (!LoadPreferencesV100((PreferencesV100 *)pprefsV101)) - return false; - - // PreferencesV101 has this new field, load it - strncpyz(gprefsInit.szDeviceId, pprefsV101->szDeviceId, sizeof(gprefsInit.szDeviceId)); return true; } void Game::SavePreferences() { - // Only if we've gone through initialization ok + // Only if we've gone through initialization ok if (!(m_wf & kfGameInitDone)) return; // Always save the latest version of the preferences - Preferences prefs; + gpprefs->Set(knPrefVersion, knVersionPreferencesLatest); + gpprefs->Set(kszPrefUsername, gszUsername); + gpprefs->Set(kszPrefPassword, gszPassword); + gpprefs->Set(kszPrefToken, gszToken); + gpprefs->Set(kfPrefAnonymous, gfAnonymous); - prefs.prefv.dwVersion = BigDword(knVersionPreferences); - prefs.prefv.cbSize = BigDword(sizeof(prefs)); - strncpyz(prefs.szUsername, gszUsername, sizeof(prefs.szUsername)); - strncpyz(prefs.szPassword, gszPassword, sizeof(prefs.szPassword)); - strncpyz(prefs.szToken, gszToken, sizeof(prefs.szToken)); - prefs.fAnonymous = gfAnonymous ? BigWord(1) : 0; Date date; HostGetCurrentDate(&date); - prefs.nYearLastRun = BigWord(date.nYear); - prefs.nMonthLastRun = BigWord(date.nMonth); - prefs.nDayLastRun = BigWord(date.nDay); - prefs.nVolume = BigWord(gsndm.GetVolume()); - word wfPrefs = gsndm.IsEnabled() ? 0 : kfPrefSoundMuted; - wfPrefs |= gfIgnoreBluetoothWarning ? kfPrefIgnoreBluetoothWarning : 0; - prefs.wfPrefs = BigWord(wfPrefs); - prefs.wfPerfOptions = BigWord((gwfPerfOptions & kfPerfAll) | (kfPerfMax & ~kfPerfAll)); - prefs.ctGameSpeed = BigDword((dword)gtGameSpeed); - prefs.fLassoSelection = gfLassoSelection ? BigWord(1) : 0; - prefs.nHueOffset = BigWord(gnHueOffset); - prefs.nSatMultiplier = BigWord(gnSatMultiplier); - prefs.nLumOffset = BigWord(gnLumOffset); - prefs.wfHandicap = BigWord(gwfHandicap); - prefs.nDemoRank = BigWord(gnDemoRank); - prefs.nScrollSpeed = gnScrollSpeed; - strncpyz(prefs.szAskURL, gszAskURL, sizeof(prefs.szAskURL)); - strncpyz(prefs.szDeviceId, gszDeviceId, sizeof(prefs.szDeviceId)); + gpprefs->Set(knPrefYearLastRun, date.nYear); + gpprefs->Set(knPrefMonthLastRun, date.nMonth); + gpprefs->Set(knPrefDayLastRun, date.nDay); + + gpprefs->Set(knPrefVolume, gsndm.GetVolume()); + gpprefs->Set(kfPrefSoundMuted, !gsndm.IsEnabled()); + // gpprefs->Set(kfPrefIgnoreBluetoothWarning, gfIgnoreBluetoothWarning); + gpprefs->Set(kwfPrefPerfOptions, BigWord((gwfPerfOptions & kfPerfAll) | (kfPerfMax & ~kfPerfAll))); + gpprefs->Set(knPrefGameSpeed, gtGameSpeed); + gpprefs->Set(kfPrefLassoSelection, gfLassoSelection); + gpprefs->Set(knPrefHueOffset, gnHueOffset); + gpprefs->Set(knPrefSatMultiplier, gnSatMultiplier); + gpprefs->Set(knPrefLumOffset, gnLumOffset); + gpprefs->Set(kwfPrefHandicap, gwfHandicap); + gpprefs->Set(knPrefDemoRank, gnDemoRank); + gpprefs->Set(knPrefScrollSpeed, gnScrollSpeed); + gpprefs->Set(kszPrefAskUrl, gszAskURL); + gpprefs->Set(kszPrefDeviceId, gszDeviceId); if (gpdisp == NULL || m_immBest == -1) { - prefs.cxModeBest = 0; - prefs.cyModeBest = 0; - prefs.nDepthModeBest = 0; - prefs.nDepthDataBest = 0; - prefs.nSizeDataBest = 0; - prefs.nDegreeOrientationBest = 0; + gpprefs->Set(knPrefCxModeBest, 0); + gpprefs->Set(knPrefCyModeBest, 0); + gpprefs->Set(knPrefDepthModeBest, 0); + gpprefs->Set(knPrefDepthDataBest, 0); + gpprefs->Set(knPrefSizeDataBest, 0); + gpprefs->Set(knPrefDegreeOrientationBest, 0); } else { ModeInfo mode; gpdisp->GetModeInfo(m_amm[m_immBest].imode, &mode); - prefs.cxModeBest = BigWord(mode.cx); - prefs.cyModeBest = BigWord(mode.cy); - prefs.nDepthModeBest = BigWord(mode.nDepth); - prefs.nDepthDataBest = BigWord(m_amm[m_immBest].nDepthData); - prefs.nSizeDataBest = BigWord(m_amm[m_immBest].nSizeData); - prefs.nDegreeOrientationBest = BigWord(mode.nDegreeOrientation); + gpprefs->Set(knPrefCxModeBest, mode.cx); + gpprefs->Set(knPrefCyModeBest, mode.cy); + gpprefs->Set(knPrefDepthModeBest, mode.nDepth); + gpprefs->Set(knPrefDepthDataBest, m_amm[m_immBest].nDepthData); + gpprefs->Set(knPrefSizeDataBest, m_amm[m_immBest].nSizeData); + gpprefs->Set(knPrefDegreeOrientationBest, mode.nDegreeOrientation); } if (gpdisp == NULL || m_immCurrent == -1) { - prefs.cxModeLast = 0; - prefs.cyModeLast = 0; - prefs.nDepthModeLast = 0; - prefs.nDepthDataLast = 0; - prefs.nSizeDataLast = 0; - prefs.nDegreeOrientationLast = 0; + gpprefs->Set(knPrefCxModeLast, 0); + gpprefs->Set(knPrefCyModeLast, 0); + gpprefs->Set(knPrefDepthModeLast, 0); + gpprefs->Set(knPrefDepthDataLast, 0); + gpprefs->Set(knPrefSizeDataLast, 0); + gpprefs->Set(knPrefDegreeOrientationLast, 0); } else { ModeInfo mode; gpdisp->GetModeInfo(m_amm[m_immCurrent].imode, &mode); - prefs.cxModeLast = BigWord(mode.cx); - prefs.cyModeLast = BigWord(mode.cy); - prefs.nDepthModeLast = BigWord(mode.nDepth); - prefs.nDepthDataLast = BigWord(m_amm[m_immCurrent].nDepthData); - prefs.nSizeDataLast = BigWord(m_amm[m_immCurrent].nSizeData); - prefs.nDegreeOrientationLast = BigWord(mode.nDegreeOrientation); + gpprefs->Set(knPrefCxModeLast, mode.cx); + gpprefs->Set(knPrefCyModeLast, mode.cx); + gpprefs->Set(knPrefDepthModeLast, mode.nDepth); + gpprefs->Set(knPrefDepthDataLast, m_amm[m_immCurrent].nDepthData); + gpprefs->Set(knPrefSizeDataLast, m_amm[m_immCurrent].nSizeData); + gpprefs->Set(knPrefDegreeOrientationLast, mode.nDegreeOrientation); } - prefs.key = gkey; + + gpprefs->Set(kszPrefKey, (const char *)gkey.ab); + #if defined(WIN) && !defined(CE) if (gpdisp == NULL) { - prefs.nScale = (word)-1; + gpprefs->Set(knPrefScale, -1); } else { - prefs.nScale = BigWord(gpdisp->GetScale()); + gpprefs->Set(knPrefScale, gpdisp->GetScale()); } #endif - - HostSavePreferences(&prefs, sizeof(prefs)); + + gpprefs->Save(); } bool Game::GetVar(const char *pszName, char *pszBuff, int cbBuff) diff --git a/game/ht.h b/game/ht.h index 73b66c0..a550316 100644 --- a/game/ht.h +++ b/game/ht.h @@ -266,6 +266,7 @@ typedef word CacheHandle; // hc #define secDrm secCode16 #define secBtTransport secCode17 #define secTexAtlasMgr secCode13 +#define secPreferences secCode9 // Performance options @@ -2273,8 +2274,6 @@ class MultiFormMgr; class InputUIForm; class Form; class Chatter; -struct PreferencesV100; -struct PreferencesV101; class Game // game { public: @@ -2354,10 +2353,7 @@ public: private: bool CheckMemoryAvailable() secGame; void Suspend() secGame; - void LoadPreferences() secGame; - bool LoadPreferences2() secGame; - bool LoadPreferencesV100(PreferencesV100 *pprefsV100); - bool LoadPreferencesV101(PreferencesV101 *pprefsV101); + bool LoadPreferences() secGame; bool InitDisplay(int imm) secGame; int FindBestModeMatch2(int nDepthData, int nSizeData, int nDepthMode, int cxWidthModeMin, int cxWidthModeMax, byte bfMatch) secGame; int FindBestModeMatch(int nSizeDataAbove) secGame; @@ -8320,89 +8316,80 @@ bool DrmValidate() secDrm; // Preferences support // -// Preferences structures change over time. They get backed up by HotSync. -// By carefully versioning the structure HT can load older preference versions -// successfully. Every prefs structure has a version; these are meant to be supported -// versions of preferences; meaning HT will load older versions of each versioned prefs -// structure. They are also sub-versioned by size; this allows us during development to -// add / remove fields and not have HT crash because it is assuming the wrong thing. - -// prefs flags - -#define kfPrefSoundMuted 1 // must be 1 for compatibility with fMute -#define kfPrefIgnoreBluetoothWarning 2 - -// Preferences is stored in pack 2 alignment -#pragma pack(push, 2) - -// The header necessary on all preferences structures - -struct PreferencesVersion -{ - dword dwVersion; - dword cbSize; -}; - -// The versions of preferences structures HT can successfully read -// Use fixed size datatypes - -struct PreferencesV100 // prefs -{ - PreferencesVersion prefv; - char szUsername[kcbPlayerName]; - char szPassword[kcbPlayerName]; - char szToken[kcbTokenMax]; - word fAnonymous; - word nYearLastRun; // demo time check - word nMonthLastRun; - word nDayLastRun; - word nVolume; // volume - word wfPrefs; - word wfPerfOptions; - word wfHandicap; // Difficulty-affecting flags - int ctGameSpeed; // game speed - word fLassoSelection; - short nHueOffset; // HSL settings - short nSatMultiplier; - short nLumOffset; - word cxModeBest; // Remember what mode / data is best. Check against in case config changes - word cyModeBest; - word nDepthModeBest; - word nDepthDataBest; - word nSizeDataBest; - word nDegreeOrientationBest; - word cxModeLast; // Remember what mode / data was chosen - word cyModeLast; - word nDepthModeLast; - word nDepthDataLast; - word nSizeDataLast; - word nDegreeOrientationLast; - Key key; // DRM key - short nDemoRank; -#if defined(WIN) && !defined(CE) - short nScale; -#endif - double nScrollSpeed; - char szAskURL[512]; -}; - -struct PreferencesV101 : public PreferencesV100 -{ - // md5 hash (16 bytes) to hex chars (32 bytes) plus zero terminator, rounded up to even number - char szDeviceId[34]; -}; -typedef PreferencesV101 Preferences; - -#pragma pack(pop) - // The current version -#define knVersionPreferencesV100 0x100 -#define knVersionPreferencesV101 0x101 -#define knVersionPreferences knVersionPreferencesV101 -extern Preferences gprefsInit; -bool HostSavePreferences(void *pv, int cb) secHost; -int HostLoadPreferences(void *pv, int cb) secHost; +#define knVersionPreferencesV01 1 +#define knVersionPreferencesLatest knVersionPreferencesV01 + +// Keys + +#define knPrefVersion "version" +#define kszPrefUsername "username" +#define kszPrefPassword "password" +#define kszPrefToken "token" +#define kfPrefAnonymous "anonymous" +#define knPrefYearLastRun "year_last_run" // demo time check +#define knPrefMonthLastRun "month_last_run" +#define knPrefDayLastRun "day_last_run" +#define kwfPrefPerfOptions "perf_options" +#define knPrefVolume "volume" // in percent (0 - 100) +#define kfPrefSoundMuted "sound_muted" +#define kwfPrefHandicap "handicap" // Difficulty-affecting flags +#define knPrefGameSpeed "game_speed" +#define kfPrefLassoSelection "lassos_election" +#define knPrefHueOffset "hue_offset" // HSL settings +#define knPrefSatMultiplier "sat_multiplier" +#define knPrefLumOffset "lum_offset" +#define knPrefCxModeBest "cx_mode_best" // Remember what mode / data is best. Check against in case config +#define knPrefCyModeBest "cy_mode_best" +#define knPrefDepthModeBest "depth_mode_best" +#define knPrefDepthDataBest "depth_data_best" +#define knPrefSizeDataBest "size_data_best" +#define knPrefDegreeOrientationBest "degree_orientation_best" + +#define knPrefCxModeLast "cx_mode_last" // Remember what mode / data was chosen +#define knPrefCyModeLast "cy_mode_best" +#define knPrefDepthModeLast "depth_mode_last" +#define knPrefDepthDataLast "depth_data_last" +#define knPrefSizeDataLast "size_data_last" +#define knPrefDegreeOrientationLast "degree_orientation_last" + +#define kszPrefKey "key" // DRM key +#define knPrefDemoRank "demo_rank" +// #define knPrefScale "scale" +#define knPrefScrollSpeed "scroll_speed" +// #define kfPrefIgnoreBluetoothWarning "ignore_bluetooth_warning" +#define kszPrefAskUrl "ask_url" +#define kszPrefDeviceId "did" + +class Preferences +{ +public: + Preferences() secPreferences; + ~Preferences() secPreferences; + + bool InitFromFile() secPreferences; + bool InitFromDeafults() secPreferences; + + bool Save() secPreferences; + const char *GetString(const char *key) secPreferences; + int GetInteger(const char *key) secPreferences; + float GetFloat(const char *key) secPreferences; + bool GetBool(const char *key) secPreferences; + + void Set(const char *key, const char *psz) secPreferences; + void Set(const char *key, int n) secPreferences; + void Set(const char *key, float n) secPreferences; + void Set(const char *key, bool f) secPreferences; + +private: + json::JsonMap *m_pmap; + char *m_pszJson; +}; +Preferences *PrefsFromFile() secPreferences; +Preferences *PrefsFromDefaults() secPreferences; + +extern Preferences *gpprefs; // Our in-game MessageBox @@ -8773,6 +8760,7 @@ void HostMessageBox(TCHAR *pszFormat, ...) secHost; Display *HostCreateDisplay() secDisplay; bool HostIsPenDown() secHost; const char *HostGetMainDataDir() secHost; +const char *HostGetPrefsFilename() secHost; void HostSuspendModalLoop(DibBitmap *pbm) secHost; void HostNotEnoughMemory(bool fStorage, dword cbFree, dword cbNeed) secHost; bool HostGetOwnerName(char *pszBuff, int cb, bool fShowError) secHost; diff --git a/game/preferences.cpp b/game/preferences.cpp new file mode 100644 index 0000000..4623959 --- /dev/null +++ b/game/preferences.cpp @@ -0,0 +1,152 @@ +#include "ht.h" +#include "yajl/wrapper/jsonbuilder.h" + +namespace wi { + +Preferences::Preferences() { + m_pmap = NULL; + m_pszJson = NULL; +} + +Preferences::~Preferences() { + delete m_pmap; + delete[] m_pszJson; +} + + +Preferences *PrefsFromFile() { + Preferences *pprefs = new Preferences(); + Assert(pprefs != NULL, "out of memory!"); + if (pprefs == NULL) + return NULL; + + if (!pprefs->InitFromFile()) { + delete pprefs; + return NULL; + } + + return pprefs; +} + +Preferences *PrefsFromDefaults() { + Preferences *pprefs = new Preferences(); + Assert(pprefs != NULL, "out of memory!"); + if (pprefs == NULL) + return NULL; + + if (!pprefs->InitFromDeafults()) { + delete pprefs; + return NULL; + } + + return pprefs; +} + +bool Preferences::InitFromFile() { + FileHandle hf = HostOpenFile(HostGetPrefsFilename(), kfOfRead); + if (hf == NULL) + return NULL; + + // Read length + + dword cb; + HostSeekFile(hf, 0, kfSeekEnd); + cb = HostTellFile(hf); + HostSeekFile(hf, 0, kfSeekSet); + + // Read prefs + + byte *pb = new byte[cb]; + if (HostReadFile(pb, cb, 1, hf) != 1) { + HostCloseFile(hf); + return false; + } + HostCloseFile(hf); + + m_pszJson = (char *)pb; + if (m_pszJson == NULL) + return false; + + json::JsonBuilder builder; + builder.Start(); + + if (!builder.Update(m_pszJson, (int)strlen(m_pszJson))) + return false; + + json::JsonObject *obj = builder.End(); + if (obj == NULL) + return false; + + m_pmap = (json::JsonMap *)obj; + return true; +} + +bool Preferences::InitFromDeafults() { + m_pmap = new json::JsonMap(); + + Date date; + HostGetCurrentDate(&date); + Set(knPrefYearLastRun, date.nYear); + Set(knPrefMonthLastRun, date.nMonth); + Set(knPrefDayLastRun, date.nDay); + + Set(kfPrefAnonymous, 0); + Set(knPrefVolume, 100); + Set(kfPrefSoundMuted, false); + Set(kwfPrefPerfOptions, kfPerfMax); + Set(knPrefGameSpeed, kctUpdate / 2); + Set(kwfPrefHandicap, kfHcapDefault); + Set(knPrefScrollSpeed, 1.0f); + Set(kszPrefAskUrl, "http://"); + Set(kszPrefDeviceId, HostGenerateDeviceId()); + + return true; +} + +bool Preferences::Save() { + FileHandle hf = HostOpenFile(HostGetPrefsFilename(), kfOfWrite); + if (hf == NULL) + return false; + const char *psz = m_pmap->ToJson(); + dword cb = (dword)strlen(psz); + if (HostWriteFile((void *)psz, sizeof(char), cb, hf) < cb) { + HostCloseFile(hf); + return false; + } + HostCloseFile(hf); + return true; +} + +const char *Preferences::GetString(const char *key) { + return m_pmap->GetString(key); +} + +int Preferences::GetInteger(const char *key) { + return m_pmap->GetInteger(key); +} + +float Preferences::GetFloat(const char *key) { + return m_pmap->GetFloat(key); +} + +bool Preferences::GetBool(const char *key) { + return m_pmap->GetBool(key); +} + +void Preferences::Set(const char *key, const char *psz) { + m_pmap->SetObject(key, json::NewJsonString(psz, (int)strlen(psz))); +} + +void Preferences::Set(const char *key, int n) { + m_pmap->SetObject(key, new json::JsonNumber(n)); +} + +void Preferences::Set(const char *key, float n) { + m_pmap->SetObject(key, new json::JsonNumber(n)); +} + +void Preferences::Set(const char *key, bool f) { + m_pmap->SetObject(key, new json::JsonBool(f)); +} + +} // namespace wi diff --git a/game/sdl/host.cpp b/game/sdl/host.cpp index aa38549..bafd283 100644 --- a/game/sdl/host.cpp +++ b/game/sdl/host.cpp @@ -781,38 +781,6 @@ void HostGetCurrentDate(Date *pdate) pdate->nDay = ptm->tm_mday; } -bool HostSavePreferences(void *pv, int cb) -{ - LOG() << HostHelpers::GetPrefsFilename(); - - FILE *pf = fopen(HostHelpers::GetPrefsFilename(), "wb"); - if (pf == NULL) { - LOG() << "error opening preferences! " << errno; - return false; - } - if (fwrite(pv, cb, 1, pf) != 1) { - LOG() << "error writing preferences! " << errno; - fclose(pf); - return false; - } - fclose(pf); - return true; -} - -int HostLoadPreferences(void *pv, int cb) -{ - FILE *pf = fopen(HostHelpers::GetPrefsFilename(), "rb"); - if (pf == NULL) { - return -1; - } - - // Read prefs - - int cbRead = (int)fread(pv, 1, cb, pf); - fclose(pf); - return cbRead; -} - const char *HostGetMainDataDir() { return HostHelpers::GetMainDataDir(); @@ -823,6 +791,11 @@ const char *HostGetSaveGamesDir() return HostHelpers::GetSaveGamesDir(); } +const char *HostGetPrefsFilename() +{ + return HostHelpers::GetPrefsFilename(); +} + void HostNotEnoughMemory(bool fStorage, dword cbFree, dword cbNeed) { HostMessageBox(TEXT((char *)"Need %ld bytes of memory but only %ld bytes are free!"), cbNeed, cbFree);