Save preferences as json

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.
This commit is contained in:
Nathan Fulton 2017-04-29 21:35:17 -04:00
parent 122a2d198f
commit 71dd4eb5b5
4 changed files with 332 additions and 327 deletions

View File

@ -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)

162
game/ht.h
View File

@ -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;

152
game/preferences.cpp Normal file
View File

@ -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

View File

@ -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);