diff --git a/src/citra_qt/configuration/configure_system.cpp b/src/citra_qt/configuration/configure_system.cpp index b7a475c5f..1fe5b41ee 100644 --- a/src/citra_qt/configuration/configure_system.cpp +++ b/src/citra_qt/configuration/configure_system.cpp @@ -8,6 +8,7 @@ #include "core/core.h" #include "core/hle/service/cfg/cfg.h" #include "core/hle/service/fs/archive.h" +#include "core/hle/service/ptm/ptm.h" #include "core/settings.h" #include "ui_configure_system.h" @@ -254,9 +255,9 @@ void ConfigureSystem::setConfiguration() { // Temporarily register archive types and load the config savegame file to memory. Service::FS::RegisterArchiveTypes(); cfg = std::make_shared(); + ReadSystemSettings(); Service::FS::UnregisterArchiveTypes(); - ReadSystemSettings(); ui->label_disable_info->hide(); } } @@ -293,6 +294,10 @@ void ConfigureSystem::ReadSystemSettings() { u64 console_id = cfg->GetConsoleUniqueId(); ui->label_console_id->setText( tr("Console ID: 0x%1").arg(QString::number(console_id, 16).toUpper())); + + // set play coin + play_coin = Service::PTM::Module::GetPlayCoins(); + ui->spinBox_play_coins->setValue(play_coin); } void ConfigureSystem::applyConfiguration() { @@ -340,6 +345,15 @@ void ConfigureSystem::applyConfiguration() { modified = true; } + // apply play coin + u16 new_play_coin = static_cast(ui->spinBox_play_coins->value()); + if (play_coin != new_play_coin) { + // archive types must be registered to set play coins + Service::FS::RegisterArchiveTypes(); + Service::PTM::Module::SetPlayCoins(new_play_coin); + Service::FS::UnregisterArchiveTypes(); + } + // update the config savegame if any item is modified. if (modified) cfg->UpdateConfigNANDSavegame(); diff --git a/src/citra_qt/configuration/configure_system.h b/src/citra_qt/configuration/configure_system.h index 53e5a328e..36c7d2e94 100644 --- a/src/citra_qt/configuration/configure_system.h +++ b/src/citra_qt/configuration/configure_system.h @@ -47,4 +47,5 @@ private: int language_index; int sound_index; u8 country_code; + u16 play_coin; }; diff --git a/src/citra_qt/configuration/configure_system.ui b/src/citra_qt/configuration/configure_system.ui index 925e86b89..74efa3b27 100644 --- a/src/citra_qt/configuration/configure_system.ui +++ b/src/citra_qt/configuration/configure_system.ui @@ -264,13 +264,27 @@ + + + Play Coins: + + + + + + + 300 + + + + Console ID: - + diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp index eb5142cc8..5f22e9ba6 100644 --- a/src/core/hle/service/ptm/ptm.cpp +++ b/src/core/hle/service/ptm/ptm.cpp @@ -135,12 +135,12 @@ void Module::Interface::CheckNew3DS(Kernel::HLERequestContext& ctx) { Service::PTM::CheckNew3DS(rb); } -Module::Module() { - // Open the SharedExtSaveData archive 0xF000000B and create the gamecoin.dat file if it doesn't - // exist +static void WriteGameCoinData(GameCoin gamecoin_data) { FileSys::Path archive_path(ptm_shared_extdata_id); auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); + + FileSys::Path gamecoin_path("/gamecoin.dat"); // If the archive didn't exist, create the files inside if (archive_result.Code() == FileSys::ERR_NOT_FORMATTED) { // Format the archive to create the directories @@ -149,22 +149,74 @@ Module::Module() { // Open it again to get a valid archive now that the folder exists archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); - ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!"); - - FileSys::Path gamecoin_path("/gamecoin.dat"); + // Create the game coin file Service::FS::CreateFileInArchive(*archive_result, gamecoin_path, sizeof(GameCoin)); - FileSys::Mode open_mode = {}; - open_mode.write_flag.Assign(1); - // Open the file and write the default gamecoin information - auto gamecoin_result = - Service::FS::OpenFileFromArchive(*archive_result, gamecoin_path, open_mode); - if (gamecoin_result.Succeeded()) { - auto gamecoin = std::move(gamecoin_result).Unwrap(); - gamecoin->backend->Write(0, sizeof(GameCoin), true, - reinterpret_cast(&default_game_coin)); - gamecoin->backend->Close(); - } + } else { + ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!"); } + + FileSys::Mode open_mode = {}; + open_mode.write_flag.Assign(1); + // Open the file and write the default gamecoin information + auto gamecoin_result = + Service::FS::OpenFileFromArchive(*archive_result, gamecoin_path, open_mode); + if (gamecoin_result.Succeeded()) { + auto gamecoin = std::move(gamecoin_result).Unwrap(); + gamecoin->backend->Write(0, sizeof(GameCoin), true, + reinterpret_cast(&gamecoin_data)); + gamecoin->backend->Close(); + } +} + +static GameCoin ReadGameCoinData() { + FileSys::Path archive_path(ptm_shared_extdata_id); + auto archive_result = + Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); + if (!archive_result.Succeeded()) { + LOG_ERROR(Service_PTM, "Could not open the PTM SharedExtSaveData archive!"); + return default_game_coin; + } + + FileSys::Path gamecoin_path("/gamecoin.dat"); + FileSys::Mode open_mode = {}; + open_mode.read_flag.Assign(1); + + auto gamecoin_result = + Service::FS::OpenFileFromArchive(*archive_result, gamecoin_path, open_mode); + if (!gamecoin_result.Succeeded()) { + LOG_ERROR(Service_PTM, "Could not open the game coin data file!"); + return default_game_coin; + } + u16 result; + auto gamecoin = std::move(gamecoin_result).Unwrap(); + GameCoin gamecoin_data; + gamecoin->backend->Read(0, sizeof(GameCoin), reinterpret_cast(&gamecoin_data)); + gamecoin->backend->Close(); + return gamecoin_data; +} + +Module::Module() { + // Open the SharedExtSaveData archive 0xF000000B and create the gamecoin.dat file if it doesn't + // exist + FileSys::Path archive_path(ptm_shared_extdata_id); + auto archive_result = + Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); + // If the archive didn't exist, write the default game coin file + if (archive_result.Code() == FileSys::ERR_NOT_FORMATTED) { + WriteGameCoinData(default_game_coin); + } +} + +u16 Module::GetPlayCoins() { + return ReadGameCoinData().total_coins; +} + +void Module::SetPlayCoins(u16 play_coins) { + GameCoin game_coin = ReadGameCoinData(); + game_coin.total_coins = play_coins; + // TODO: This may introduce potential race condition if the game is reading the + // game coin data at the same time + WriteGameCoinData(game_coin); } Module::Interface::Interface(std::shared_ptr ptm, const char* name, u32 max_session) diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h index 09ac31059..7da9189e0 100644 --- a/src/core/hle/service/ptm/ptm.h +++ b/src/core/hle/service/ptm/ptm.h @@ -41,6 +41,8 @@ void CheckNew3DS(IPC::RequestBuilder& rb); class Module final { public: Module(); + static u16 GetPlayCoins(); + static void SetPlayCoins(u16 play_coins); class Interface : public ServiceFramework { public: