From 8204d0fb6edd59420b435d81d9f7a297f97007f2 Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Sun, 3 Jan 2021 22:41:59 +0100 Subject: [PATCH] Move highscores to DB. --- src/common/HighScoresManager.cxx | 155 +++++++----------- src/common/HighScoresManager.hxx | 20 +-- src/common/module.mk | 3 +- .../repository/CompositeKVRJsonAdapter.cxx | 4 +- .../CompositeKeyValueRepository.cxx | 51 ++++++ .../CompositeKeyValueRepository.hxx | 24 +++ .../CompositeKeyValueRepositoryNoop.hxx | 5 +- src/common/repository/KeyValueRepository.hxx | 2 +- .../repository/KeyValueRepositoryNoop.hxx | 2 +- .../AbstractKeyValueRepositorySqlite.cxx | 2 +- .../AbstractKeyValueRepositorySqlite.hxx | 2 +- .../CompositeKeyValueRepositorySqlite.hxx | 5 +- src/common/repository/sqlite/StellaDb.cxx | 5 + src/common/repository/sqlite/StellaDb.hxx | 3 +- src/emucore/OSystem.cxx | 3 + src/emucore/OSystem.hxx | 2 + src/emucore/OSystemStandalone.cxx | 6 + src/emucore/OSystemStandalone.hxx | 2 + src/gui/HighScoresDialog.cxx | 4 +- src/libretro/OSystemLIBRETRO.cxx | 6 + src/libretro/OSystemLIBRETRO.hxx | 2 + src/macos/stella.xcodeproj/project.pbxproj | 4 + 22 files changed, 193 insertions(+), 119 deletions(-) create mode 100644 src/common/repository/CompositeKeyValueRepository.cxx diff --git a/src/common/HighScoresManager.cxx b/src/common/HighScoresManager.cxx index 4cb4add9f..169020ea2 100644 --- a/src/common/HighScoresManager.cxx +++ b/src/common/HighScoresManager.cxx @@ -64,6 +64,12 @@ HighScoresManager::HighScoresManager(OSystem& osystem) { } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void HighScoresManager::setRepository(shared_ptr repo) +{ + myHighscoreRepository = repo; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Int16 HighScoresManager::peek(uInt16 addr) const { @@ -559,97 +565,7 @@ Int32 HighScoresManager::fromBCD(uInt8 bcd) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void HighScoresManager::saveHighScores(const string& cartName, ScoresData& data) const -{ - ostringstream buf; - - buf << myOSystem.stateDir() << cartName << ".hs" << data.variation; - - // Make sure the file can be opened for writing - FilesystemNode node(buf.str()); - - if(!node.isWritable()) - { - buf.str(""); - buf << "Can't open/save to high scores file for variation " << data.variation; - myOSystem.frameBuffer().showTextMessage(buf.str()); - } - - // Do a complete high data save - if(!save(node, data)) - { - buf.str(""); - buf << "Error saving high scores for variation" << data.variation; - myOSystem.frameBuffer().showTextMessage(buf.str()); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void HighScoresManager::loadHighScores(const string& cartName, ScoresData& data) -{ - for(uInt32 r = 0; r < NUM_RANKS; ++r) - { - data.scores[r].score = 0; - data.scores[r].special = 0; - data.scores[r].name = ""; - data.scores[r].date = ""; - } - - ostringstream buf; - - buf << myOSystem.stateDir() << cartName << ".hs" << data.variation; - - FilesystemNode node(buf.str()); - stringstream in; - - // Make sure the file can be opened - try { - node.read(in); - } - catch(...) { return; } - - bool invalid = false; - try { - string highscores; - - buf.str(""); - - if(getline(in, highscores) && highscores.length() != 0) - { - const json hsObject = json::parse(highscores); - - if(hsObject.contains(DATA)) - { - const json hsData = hsObject.at(DATA); - - // First test if we have a valid header - // If so, do a complete high data load - if(!hsData.contains(VERSION) || hsData.at(VERSION) != HIGHSCORE_HEADER) - buf << "Error: Incompatible high scores file for variation " - << data.variation << "."; - else - { - if(!load(hsData, data) - || !hsData.contains(PROPCHECK) || hsData.at(PROPCHECK) != md5Props() - || !hsObject.contains(CHECKSUM) || hsObject.at(CHECKSUM) != MD5::hash(hsData.dump())) - invalid = true; - else - return; - } - } - else - invalid = true; - } - } - catch(...) { invalid = true; } - - if(invalid) - buf << "Error: Invalid data in high scores file for variation " << data.variation << "."; - myOSystem.frameBuffer().showTextMessage(buf.str()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool HighScoresManager::save(FilesystemNode& node, const ScoresData& data) const +void HighScoresManager::saveHighScores(ScoresData& data) const { try { @@ -681,15 +597,64 @@ bool HighScoresManager::save(FilesystemNode& node, const ScoresData& data) const hsObject[DATA] = hsData; hsObject[CHECKSUM] = MD5::hash(hsData.dump()); - stringstream ss(hsObject.dump()); - node.write(ss); + myHighscoreRepository->save(data.md5, to_string(data.variation), hsObject.dump(2)); } catch(...) { cerr << "ERROR: HighScoresManager::save() exception\n"; - return false; } - return true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void HighScoresManager::loadHighScores(ScoresData& data) +{ + for(uInt32 r = 0; r < NUM_RANKS; ++r) + { + data.scores[r].score = 0; + data.scores[r].special = 0; + data.scores[r].name = ""; + data.scores[r].date = ""; + } + + ostringstream buf; + + bool invalid = false; + try { + Variant serializedHighscore; + + if(myHighscoreRepository->get(data.md5, to_string(data.variation), serializedHighscore)) + { + const json hsObject = json::parse(serializedHighscore.toString()); + + if(hsObject.contains(DATA)) + { + const json hsData = hsObject.at(DATA); + + // First test if we have a valid header + // If so, do a complete high data load + if(!hsData.contains(VERSION) || hsData.at(VERSION) != HIGHSCORE_HEADER) + buf << "Error: Incompatible high scores file for variation " + << data.variation << "."; + else + { + if(!load(hsData, data) + || !hsData.contains(PROPCHECK) || hsData.at(PROPCHECK) != md5Props() + || !hsObject.contains(CHECKSUM) || hsObject.at(CHECKSUM) != MD5::hash(hsData.dump())) + invalid = true; + else + return; + } + } + else + invalid = true; + } + } + catch(...) { invalid = true; } + + if (invalid) + buf << "Error: Invalid data in high scores file for variation " << data.variation << "."; + + myOSystem.frameBuffer().showTextMessage(buf.str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/HighScoresManager.hxx b/src/common/HighScoresManager.hxx index 3b293c172..73c982529 100644 --- a/src/common/HighScoresManager.hxx +++ b/src/common/HighScoresManager.hxx @@ -25,6 +25,8 @@ class OSystem; #include "Props.hxx" #include "json_lib.hxx" #include "FSNode.hxx" +#include "repository/CompositeKeyValueRepository.hxx" +#include "repository/CompositeKeyValueRepositoryNoop.hxx" using json = nlohmann::json; @@ -95,6 +97,7 @@ class HighScoresManager explicit HighScoresManager(OSystem& osystem); virtual ~HighScoresManager() = default; + void setRepository(shared_ptr repo); // check if high score data has been defined bool enabled() const; @@ -147,8 +150,8 @@ class HighScoresManager // Peek into memory Int16 peek(uInt16 addr) const; - void saveHighScores(const string& cartName, HSM::ScoresData& scores) const; - void loadHighScores(const string& cartName, HSM::ScoresData& scores); + void loadHighScores(HSM::ScoresData& scores); + void saveHighScores(HSM::ScoresData& scores) const; private: static const string VARIATIONS_COUNT; @@ -230,16 +233,6 @@ class HighScoresManager uInt16 fromHexStr(const string& addr) const; Int32 fromBCD(uInt8 bcd) const; - /** - Saves the current high scores for this game and variation to the given file system node. - - @param node The file system node to save to. - @param scores The saved high score data - - @return The result of the save. True on success, false on failure. - */ - bool save(FilesystemNode& node, const HSM::ScoresData& scores) const; - /** Loads the current high scores for this game and variation from the given JSON object. @@ -254,6 +247,9 @@ class HighScoresManager // Reference to the osystem object OSystem& myOSystem; + shared_ptr myHighscoreRepository + = make_shared(); + private: // Following constructors and assignment operators not supported HighScoresManager() = delete; diff --git a/src/common/module.mk b/src/common/module.mk index 2b0152305..7b5c09015 100644 --- a/src/common/module.mk +++ b/src/common/module.mk @@ -35,7 +35,8 @@ MODULE_OBJS := \ src/common/repository/KeyValueRepositoryPropertyFile.o \ src/common/repository/KeyValueRepositoryJsonFile.o \ src/common/repository/KeyValueRepositoryConfigfile.o \ - src/common/repository/CompositeKVRJsonAdapter.o + src/common/repository/CompositeKVRJsonAdapter.o \ + src/common/repository/CompositeKeyValueRepository.o MODULE_DIRS += \ src/common diff --git a/src/common/repository/CompositeKVRJsonAdapter.cxx b/src/common/repository/CompositeKVRJsonAdapter.cxx index d6081b652..0ef8cd8c0 100644 --- a/src/common/repository/CompositeKVRJsonAdapter.cxx +++ b/src/common/repository/CompositeKVRJsonAdapter.cxx @@ -30,10 +30,10 @@ namespace { std::map load() override { if (!myKvr.has(myKey)) return std::map(); - string serialized; + Variant serialized; myKvr.get(myKey, serialized); - stringstream in{serialized}; + stringstream in{serialized.toString()}; return KeyValueRepositoryJsonFile::load(in); } diff --git a/src/common/repository/CompositeKeyValueRepository.cxx b/src/common/repository/CompositeKeyValueRepository.cxx new file mode 100644 index 000000000..ccc099f78 --- /dev/null +++ b/src/common/repository/CompositeKeyValueRepository.cxx @@ -0,0 +1,51 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2021 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#include "repository/CompositeKeyValueRepository.hxx" + + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CompositeKeyValueRepositoryAtomic::get(const string& key1, const string& key2, Variant& value) +{ + return getAtomic(key1)->get(key2, value); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +shared_ptr CompositeKeyValueRepositoryAtomic::getAtomic(const string& key) +{ + auto repo = get(key); + + return shared_ptr(repo, repo->atomic()); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CompositeKeyValueRepositoryAtomic::save(const string& key1, const string& key2, const Variant& value) +{ + return getAtomic(key1)->save(key2, value); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CompositeKeyValueRepositoryAtomic::has(const string& key1, const string& key2) +{ + return getAtomic(key1)->has(key2); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CompositeKeyValueRepositoryAtomic::remove(const string& key1, const string key2) +{ + getAtomic(key1)->remove(key2); +} diff --git a/src/common/repository/CompositeKeyValueRepository.hxx b/src/common/repository/CompositeKeyValueRepository.hxx index 3c325b93a..dc7683ad8 100644 --- a/src/common/repository/CompositeKeyValueRepository.hxx +++ b/src/common/repository/CompositeKeyValueRepository.hxx @@ -23,6 +23,8 @@ #include "KeyValueRepository.hxx" #include "bspf.hxx" +class CompositeKeyValueRepositoryAtomic; + class CompositeKeyValueRepository { public: @@ -34,6 +36,28 @@ class CompositeKeyValueRepository virtual bool has(const string& key) = 0; virtual void remove(const string& key) = 0; + + virtual CompositeKeyValueRepositoryAtomic* atomic() { return nullptr; } +}; + +class CompositeKeyValueRepositoryAtomic : public CompositeKeyValueRepository +{ + public: + using CompositeKeyValueRepository::get; + using CompositeKeyValueRepository::remove; + using CompositeKeyValueRepository::has; + + virtual bool get(const string& key1, const string& key2, Variant& value); + + virtual shared_ptr getAtomic(const string& key); + + virtual bool save(const string& key1, const string& key2, const Variant& value); + + virtual bool has(const string& key1, const string& key2); + + virtual void remove(const string& key1, const string key2); + + CompositeKeyValueRepositoryAtomic* atomic() override { return this; } }; #endif // COMPOSITE_KEY_VALUE_REPOSITORY_HXX diff --git a/src/common/repository/CompositeKeyValueRepositoryNoop.hxx b/src/common/repository/CompositeKeyValueRepositoryNoop.hxx index 23bec4ecd..cfe659e56 100644 --- a/src/common/repository/CompositeKeyValueRepositoryNoop.hxx +++ b/src/common/repository/CompositeKeyValueRepositoryNoop.hxx @@ -22,9 +22,12 @@ #include "repository/KeyValueRepositoryNoop.hxx" #include "bspf.hxx" -class CompositeKeyValueRepositoryNoop : public CompositeKeyValueRepository +class CompositeKeyValueRepositoryNoop : public CompositeKeyValueRepositoryAtomic { public: + using CompositeKeyValueRepositoryAtomic::has; + using CompositeKeyValueRepositoryAtomic::remove; + using CompositeKeyValueRepositoryAtomic::get; shared_ptr get(const string& key) { return make_shared(); } diff --git a/src/common/repository/KeyValueRepository.hxx b/src/common/repository/KeyValueRepository.hxx index 43b89f2a9..7a61763d1 100644 --- a/src/common/repository/KeyValueRepository.hxx +++ b/src/common/repository/KeyValueRepository.hxx @@ -44,7 +44,7 @@ class KeyValueRepositoryAtomic : public KeyValueRepository { virtual bool has(const string& key) = 0; - virtual bool get(const string& key, string& value) = 0; + virtual bool get(const string& key, Variant& value) = 0; virtual bool save(const string& key, const Variant& value) = 0; diff --git a/src/common/repository/KeyValueRepositoryNoop.hxx b/src/common/repository/KeyValueRepositoryNoop.hxx index 631e8bd7f..849171b0e 100644 --- a/src/common/repository/KeyValueRepositoryNoop.hxx +++ b/src/common/repository/KeyValueRepositoryNoop.hxx @@ -30,7 +30,7 @@ class KeyValueRepositoryNoop : public KeyValueRepositoryAtomic bool has(const string& key) override { return false; } - bool get(const string& key, string& value) override { return false; } + bool get(const string& key, Variant& value) override { return false; } bool save(const std::map& values) override { return false; } diff --git a/src/common/repository/sqlite/AbstractKeyValueRepositorySqlite.cxx b/src/common/repository/sqlite/AbstractKeyValueRepositorySqlite.cxx index 01c39b366..a02788fd4 100644 --- a/src/common/repository/sqlite/AbstractKeyValueRepositorySqlite.cxx +++ b/src/common/repository/sqlite/AbstractKeyValueRepositorySqlite.cxx @@ -61,7 +61,7 @@ bool AbstractKeyValueRepositorySqlite::has(const string& key) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool AbstractKeyValueRepositorySqlite::get(const string& key, string& value) +bool AbstractKeyValueRepositorySqlite::get(const string& key, Variant& value) { try { SqliteStatement& stmt{stmtSelectOne(key)}; diff --git a/src/common/repository/sqlite/AbstractKeyValueRepositorySqlite.hxx b/src/common/repository/sqlite/AbstractKeyValueRepositorySqlite.hxx index 1d9b7232a..5d3ef5a9f 100644 --- a/src/common/repository/sqlite/AbstractKeyValueRepositorySqlite.hxx +++ b/src/common/repository/sqlite/AbstractKeyValueRepositorySqlite.hxx @@ -12,7 +12,7 @@ class AbstractKeyValueRepositorySqlite : public KeyValueRepositoryAtomic bool has(const string& key) override; - bool get(const string& key, string& value) override; + bool get(const string& key, Variant& value) override; std::map load() override; diff --git a/src/common/repository/sqlite/CompositeKeyValueRepositorySqlite.hxx b/src/common/repository/sqlite/CompositeKeyValueRepositorySqlite.hxx index 4d9a17be7..318bd6f8f 100644 --- a/src/common/repository/sqlite/CompositeKeyValueRepositorySqlite.hxx +++ b/src/common/repository/sqlite/CompositeKeyValueRepositorySqlite.hxx @@ -24,8 +24,11 @@ #include "SqliteStatement.hxx" #include "AbstractKeyValueRepositorySqlite.hxx" -class CompositeKeyValueRepositorySqlite : public CompositeKeyValueRepository { +class CompositeKeyValueRepositorySqlite : public CompositeKeyValueRepositoryAtomic { public: + using CompositeKeyValueRepositoryAtomic::has; + using CompositeKeyValueRepositoryAtomic::remove; + using CompositeKeyValueRepositoryAtomic::get; CompositeKeyValueRepositorySqlite( SqliteDatabase& db, diff --git a/src/common/repository/sqlite/StellaDb.cxx b/src/common/repository/sqlite/StellaDb.cxx index 20d4f07d4..faca5a886 100644 --- a/src/common/repository/sqlite/StellaDb.cxx +++ b/src/common/repository/sqlite/StellaDb.cxx @@ -26,6 +26,7 @@ #include "repository/KeyValueRepositoryConfigfile.hxx" #include "repository/KeyValueRepositoryPropertyFile.hxx" #include "KeyValueRepositorySqlite.hxx" +#include "CompositeKeyValueRepositorySqlite.hxx" #include "SqliteStatement.hxx" #include "FSNode.hxx" @@ -59,6 +60,10 @@ void StellaDb::initialize() propertyRepositoryHost->initialize(); myPropertyRepositoryHost = std::move(propertyRepositoryHost); + auto highscoreRepository = make_unique(*myDb, "highscores", "md5", "variation", "highscore_data"); + highscoreRepository->initialize(); + myHighscoreRepository = std::move(highscoreRepository); + myPropertyRepository = make_unique(*myPropertyRepositoryHost); if (myDb->getUserVersion() == 0) { diff --git a/src/common/repository/sqlite/StellaDb.hxx b/src/common/repository/sqlite/StellaDb.hxx index 86dc7e762..fdad7c078 100644 --- a/src/common/repository/sqlite/StellaDb.hxx +++ b/src/common/repository/sqlite/StellaDb.hxx @@ -33,8 +33,8 @@ class StellaDb void initialize(); KeyValueRepositoryAtomic& settingsRepository() const { return *mySettingsRepository; } - CompositeKeyValueRepository& propertyRepository() const { return *myPropertyRepository; } + CompositeKeyValueRepositoryAtomic& highscoreRepository() const { return *myHighscoreRepository; } const string databaseFileName() const; @@ -59,6 +59,7 @@ class StellaDb unique_ptr mySettingsRepository; unique_ptr myPropertyRepositoryHost; unique_ptr myPropertyRepository; + unique_ptr myHighscoreRepository; }; #endif // STELLA_DB_HXX diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index ba129bd8a..4e59c742d 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -181,6 +181,8 @@ bool OSystem::initialize(const Settings::Options& options) myMessageMenu = make_unique(*this); myTimeMachine = make_unique(*this); myLauncher = make_unique(*this); + + myHighScoresManager->setRepository(getHighscoreRepository()); #endif #ifdef PNG_SUPPORT @@ -222,6 +224,7 @@ void OSystem::loadConfig(const Settings::Options& options) mySettings->setRepository(getSettingsRepository()); myPropSet->setRepository(getPropertyRepository()); + mySettings->load(options); // userDir is NOT affected by '-baseDir'and '-basedirinapp' params diff --git a/src/emucore/OSystem.hxx b/src/emucore/OSystem.hxx index 23d70042a..308c207e5 100644 --- a/src/emucore/OSystem.hxx +++ b/src/emucore/OSystem.hxx @@ -443,6 +443,8 @@ class OSystem virtual shared_ptr getPropertyRepository() = 0; + virtual shared_ptr getHighscoreRepository() = 0; + protected: ////////////////////////////////////////////////////////////////////// diff --git a/src/emucore/OSystemStandalone.cxx b/src/emucore/OSystemStandalone.cxx index 541d63dfd..f7008edfe 100644 --- a/src/emucore/OSystemStandalone.cxx +++ b/src/emucore/OSystemStandalone.cxx @@ -42,3 +42,9 @@ shared_ptr OSystemStandalone::getPropertyRepository { return shared_ptr(myStellaDb, &myStellaDb->propertyRepository()); } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +shared_ptr OSystemStandalone::getHighscoreRepository() +{ + return shared_ptr(myStellaDb, &myStellaDb->highscoreRepository()); +} diff --git a/src/emucore/OSystemStandalone.hxx b/src/emucore/OSystemStandalone.hxx index bcc8d9b62..34e0aaf42 100644 --- a/src/emucore/OSystemStandalone.hxx +++ b/src/emucore/OSystemStandalone.hxx @@ -32,6 +32,8 @@ class OSystemStandalone : public OSystem shared_ptr getPropertyRepository() override; + shared_ptr getHighscoreRepository() override; + protected: void initPersistence(FilesystemNode& basedir) override; diff --git a/src/gui/HighScoresDialog.cxx b/src/gui/HighScoresDialog.cxx index 5fc7e54e4..21ad3c0fe 100644 --- a/src/gui/HighScoresDialog.cxx +++ b/src/gui/HighScoresDialog.cxx @@ -296,7 +296,7 @@ void HighScoresDialog::saveConfig() instance().settings().setValue("initials", myInitials); } // save selected variation - instance().highScores().saveHighScores(cartName(), myScores); + instance().highScores().saveHighScores(myScores); if(myScores.variation == instance().highScores().variation() || myUserDefVar) myHighScoreSaved = true; } @@ -360,7 +360,7 @@ void HighScoresDialog::handleVariation(bool init) { myScores.variation = myVariationPopup->getSelectedTag().toInt(); - instance().highScores().loadHighScores(cartName(), myScores); + instance().highScores().loadHighScores(myScores); myEditRank = -1; diff --git a/src/libretro/OSystemLIBRETRO.cxx b/src/libretro/OSystemLIBRETRO.cxx index f38e56c80..24a21b990 100644 --- a/src/libretro/OSystemLIBRETRO.cxx +++ b/src/libretro/OSystemLIBRETRO.cxx @@ -55,3 +55,9 @@ shared_ptr OSystemLIBRETRO::getPropertyRepository() { return make_shared(); } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +shared_ptr OSystemLIBRETRO::getHighscoreRepository() +{ + return make_shared(); +} diff --git a/src/libretro/OSystemLIBRETRO.hxx b/src/libretro/OSystemLIBRETRO.hxx index 40a1679d6..e862c47af 100644 --- a/src/libretro/OSystemLIBRETRO.hxx +++ b/src/libretro/OSystemLIBRETRO.hxx @@ -53,6 +53,8 @@ class OSystemLIBRETRO : public OSystem shared_ptr getPropertyRepository() override; + shared_ptr getHighscoreRepository() override; + protected: void initPersistence(FilesystemNode& basedir) override; diff --git a/src/macos/stella.xcodeproj/project.pbxproj b/src/macos/stella.xcodeproj/project.pbxproj index 7947b42e0..4858a7917 100644 --- a/src/macos/stella.xcodeproj/project.pbxproj +++ b/src/macos/stella.xcodeproj/project.pbxproj @@ -745,6 +745,7 @@ E0A755792244294600101889 /* CartCDFInfoWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = E0A755772244294600101889 /* CartCDFInfoWidget.cxx */; }; E0D4153C25A120340031A8D6 /* SettingsRepositoryMACOS.hxx in Headers */ = {isa = PBXBuildFile; fileRef = E0D4153A25A120340031A8D6 /* SettingsRepositoryMACOS.hxx */; }; E0D4153D25A120340031A8D6 /* SettingsRepositoryMACOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = E0D4153B25A120340031A8D6 /* SettingsRepositoryMACOS.mm */; }; + E0D7E6F425A271A0006991C7 /* CompositeKeyValueRepository.cxx in Sources */ = {isa = PBXBuildFile; fileRef = E0D7E6F325A271A0006991C7 /* CompositeKeyValueRepository.cxx */; }; E0DCD3A720A64E96000B614E /* LanczosResampler.hxx in Headers */ = {isa = PBXBuildFile; fileRef = E0DCD3A320A64E95000B614E /* LanczosResampler.hxx */; }; E0DCD3A820A64E96000B614E /* LanczosResampler.cxx in Sources */ = {isa = PBXBuildFile; fileRef = E0DCD3A420A64E95000B614E /* LanczosResampler.cxx */; }; E0DCD3A920A64E96000B614E /* ConvolutionBuffer.hxx in Headers */ = {isa = PBXBuildFile; fileRef = E0DCD3A520A64E96000B614E /* ConvolutionBuffer.hxx */; }; @@ -1552,6 +1553,7 @@ E0A755772244294600101889 /* CartCDFInfoWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartCDFInfoWidget.cxx; sourceTree = ""; }; E0D4153A25A120340031A8D6 /* SettingsRepositoryMACOS.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SettingsRepositoryMACOS.hxx; sourceTree = ""; }; E0D4153B25A120340031A8D6 /* SettingsRepositoryMACOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SettingsRepositoryMACOS.mm; sourceTree = ""; }; + E0D7E6F325A271A0006991C7 /* CompositeKeyValueRepository.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CompositeKeyValueRepository.cxx; sourceTree = ""; }; E0DCD3A320A64E95000B614E /* LanczosResampler.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = LanczosResampler.hxx; path = audio/LanczosResampler.hxx; sourceTree = ""; }; E0DCD3A420A64E95000B614E /* LanczosResampler.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LanczosResampler.cxx; path = audio/LanczosResampler.cxx; sourceTree = ""; }; E0DCD3A520A64E96000B614E /* ConvolutionBuffer.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ConvolutionBuffer.hxx; path = audio/ConvolutionBuffer.hxx; sourceTree = ""; }; @@ -2481,6 +2483,7 @@ E06508B72272447200B341AC /* repository */ = { isa = PBXGroup; children = ( + E0D7E6F325A271A0006991C7 /* CompositeKeyValueRepository.cxx */, DC2ABA5B259BD544007E57D3 /* CompositeKeyValueRepository.hxx */, DC2ABA66259D466C007E57D3 /* CompositeKeyValueRepositoryNoop.hxx */, DC2ABA6B25A0C9B1007E57D3 /* CompositeKVRJsonAdapter.cxx */, @@ -3070,6 +3073,7 @@ DC3EE8671E2C0E6D00905161 /* inftrees.c in Sources */, 2D91747609BA90380026E9FF /* Cart.cxx in Sources */, 2D91747709BA90380026E9FF /* Cart2K.cxx in Sources */, + E0D7E6F425A271A0006991C7 /* CompositeKeyValueRepository.cxx in Sources */, E034A5EE209FB25D00C89E9E /* EmulationTiming.cxx in Sources */, 2D91747809BA90380026E9FF /* Cart3F.cxx in Sources */, 2D91747909BA90380026E9FF /* Cart4K.cxx in Sources */,