diff --git a/src/common/config.cpp b/src/common/config.cpp index 991065933..fd5094fc7 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -65,6 +65,8 @@ static bool vkCrashDiagnostic = false; static s16 cursorState = HideCursorState::Idle; static int cursorHideTimeout = 5; // 5 seconds (default) static bool separateupdatefolder = false; +static bool compatibilityData = false; +static bool checkCompatibilityOnStartup = false; // Gui std::vector settings_install_dirs = {}; @@ -229,6 +231,14 @@ bool getSeparateUpdateEnabled() { return separateupdatefolder; } +bool getCompatibilityEnabled() { + return compatibilityData; +} + +bool getCheckCompatibilityOnStartup() { + return checkCompatibilityOnStartup; +} + void setGpuId(s32 selectedGpuId) { gpuId = selectedGpuId; } @@ -353,6 +363,14 @@ void setSeparateUpdateEnabled(bool use) { separateupdatefolder = use; } +void setCompatibilityEnabled(bool use) { + compatibilityData = use; +} + +void setCheckCompatibilityOnStartup(bool use) { + checkCompatibilityOnStartup = use; +} + void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h) { main_window_geometry_x = x; main_window_geometry_y = y; @@ -553,6 +571,9 @@ void load(const std::filesystem::path& path) { isShowSplash = toml::find_or(general, "showSplash", true); isAutoUpdate = toml::find_or(general, "autoUpdate", false); separateupdatefolder = toml::find_or(general, "separateUpdateEnabled", false); + compatibilityData = toml::find_or(general, "compatibilityEnabled", false); + checkCompatibilityOnStartup = + toml::find_or(general, "checkCompatibilityOnStartup", false); } if (data.contains("Input")) { @@ -666,6 +687,8 @@ void save(const std::filesystem::path& path) { data["General"]["showSplash"] = isShowSplash; data["General"]["autoUpdate"] = isAutoUpdate; data["General"]["separateUpdateEnabled"] = separateupdatefolder; + data["General"]["compatibilityEnabled"] = compatibilityData; + data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup; data["Input"]["cursorState"] = cursorState; data["Input"]["cursorHideTimeout"] = cursorHideTimeout; data["Input"]["backButtonBehavior"] = backButtonBehavior; @@ -787,6 +810,8 @@ void setDefaultValues() { m_language = 1; gpuId = -1; separateupdatefolder = false; + compatibilityData = false; + checkCompatibilityOnStartup = false; } } // namespace Config diff --git a/src/common/config.h b/src/common/config.h index 0b2cae6ee..0f00dd6da 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -21,6 +21,8 @@ bool getPlayBGM(); int getBGMvolume(); bool getEnableDiscordRPC(); bool getSeparateUpdateEnabled(); +bool getCompatibilityEnabled(); +bool getCheckCompatibilityOnStartup(); std::string getLogFilter(); std::string getLogType(); @@ -70,6 +72,8 @@ void setUserName(const std::string& type); void setUpdateChannel(const std::string& type); void setSeparateUpdateEnabled(bool use); void setGameInstallDirs(const std::vector& settings_install_dirs_config); +void setCompatibilityEnabled(bool use); +void setCheckCompatibilityOnStartup(bool use); void setCursorState(s16 cursorState); void setCursorHideTimeout(int newcursorHideTimeout); diff --git a/src/core/libraries/audio/audioout.cpp b/src/core/libraries/audio/audioout.cpp index 78b04cc90..db43ee928 100644 --- a/src/core/libraries/audio/audioout.cpp +++ b/src/core/libraries/audio/audioout.cpp @@ -2,6 +2,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include +#include #include #include "common/assert.h" @@ -13,7 +15,22 @@ namespace Libraries::AudioOut { -static std::unique_ptr audio; +struct PortOut { + void* impl; + u32 samples_num; + u32 freq; + OrbisAudioOutParamFormat format; + OrbisAudioOutPort type; + int channels_num; + bool is_float; + std::array volume; + u8 sample_size; + bool is_open; +}; +std::shared_mutex ports_mutex; +std::array ports_out{}; + +static std::unique_ptr audio; static std::string_view GetAudioOutPort(OrbisAudioOutPort port) { switch (port) { @@ -70,6 +87,58 @@ static std::string_view GetAudioOutParamAttr(OrbisAudioOutParamAttr attr) { } } +static bool IsFormatFloat(const OrbisAudioOutParamFormat format) { + switch (format) { + case OrbisAudioOutParamFormat::S16Mono: + case OrbisAudioOutParamFormat::S16Stereo: + case OrbisAudioOutParamFormat::S16_8CH: + case OrbisAudioOutParamFormat::S16_8CH_Std: + return false; + case OrbisAudioOutParamFormat::FloatMono: + case OrbisAudioOutParamFormat::FloatStereo: + case OrbisAudioOutParamFormat::Float_8CH: + case OrbisAudioOutParamFormat::Float_8CH_Std: + return true; + default: + UNREACHABLE_MSG("Unknown format"); + } +} + +static int GetFormatNumChannels(const OrbisAudioOutParamFormat format) { + switch (format) { + case OrbisAudioOutParamFormat::S16Mono: + case OrbisAudioOutParamFormat::FloatMono: + return 1; + case OrbisAudioOutParamFormat::S16Stereo: + case OrbisAudioOutParamFormat::FloatStereo: + return 2; + case OrbisAudioOutParamFormat::S16_8CH: + case OrbisAudioOutParamFormat::Float_8CH: + case OrbisAudioOutParamFormat::S16_8CH_Std: + case OrbisAudioOutParamFormat::Float_8CH_Std: + return 8; + default: + UNREACHABLE_MSG("Unknown format"); + } +} + +static u8 GetFormatSampleSize(const OrbisAudioOutParamFormat format) { + switch (format) { + case OrbisAudioOutParamFormat::S16Mono: + case OrbisAudioOutParamFormat::S16Stereo: + case OrbisAudioOutParamFormat::S16_8CH: + case OrbisAudioOutParamFormat::S16_8CH_Std: + return 2; + case OrbisAudioOutParamFormat::FloatMono: + case OrbisAudioOutParamFormat::FloatStereo: + case OrbisAudioOutParamFormat::Float_8CH: + case OrbisAudioOutParamFormat::Float_8CH_Std: + return 4; + default: + UNREACHABLE_MSG("Unknown format"); + } +} + int PS4_SYSV_ABI sceAudioOutDeviceIdOpen() { LOG_ERROR(Lib_AudioOut, "(STUBBED) called"); return ORBIS_OK; @@ -110,8 +179,21 @@ int PS4_SYSV_ABI sceAudioOutChangeAppModuleState() { return ORBIS_OK; } -int PS4_SYSV_ABI sceAudioOutClose() { - LOG_ERROR(Lib_AudioOut, "(STUBBED) called"); +int PS4_SYSV_ABI sceAudioOutClose(s32 handle) { + LOG_INFO(Lib_AudioOut, "handle = {}", handle); + if (handle < 1 || handle > SCE_AUDIO_OUT_NUM_PORTS) { + return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; + } + + std::scoped_lock lock(ports_mutex); + auto& port = ports_out.at(handle - 1); + if (!port.is_open) { + return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; + } + + audio->Close(port.impl); + port.impl = nullptr; + port.is_open = false; return ORBIS_OK; } @@ -180,16 +262,21 @@ int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* sta return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; } - const auto [type, channels_num] = audio->GetStatus(handle); + std::scoped_lock lock(ports_mutex); + const auto& port = ports_out.at(handle - 1); + if (!port.is_open) { + return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; + } + state->rerouteCounter = 0; state->volume = 127; - switch (type) { + switch (port.type) { case OrbisAudioOutPort::Main: case OrbisAudioOutPort::Bgm: case OrbisAudioOutPort::Voice: state->output = 1; - state->channel = (channels_num > 2 ? 2 : channels_num); + state->channel = port.channels_num > 2 ? 2 : port.channels_num; break; case OrbisAudioOutPort::Personal: case OrbisAudioOutPort::Padspk: @@ -276,7 +363,7 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id, u32 sample_rate, OrbisAudioOutParamExtendedInformation param_type) { LOG_INFO(Lib_AudioOut, - "AudioOutOpen id = {} port_type = {} index = {} lenght= {} sample_rate = {} " + "id = {} port_type = {} index = {} length = {} sample_rate = {} " "param_type = {} attr = {}", user_id, GetAudioOutPort(port_type), index, length, sample_rate, GetAudioOutParamFormat(param_type.data_format), @@ -310,7 +397,26 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id, LOG_ERROR(Lib_AudioOut, "Invalid format attribute"); return ORBIS_AUDIO_OUT_ERROR_INVALID_FORMAT; } - return audio->Open(port_type, length, sample_rate, format); + + std::scoped_lock lock{ports_mutex}; + const auto port = std::ranges::find(ports_out, false, &PortOut::is_open); + if (port == ports_out.end()) { + LOG_ERROR(Lib_AudioOut, "Audio ports are full"); + return ORBIS_AUDIO_OUT_ERROR_PORT_FULL; + } + + port->is_open = true; + port->type = port_type; + port->samples_num = length; + port->freq = sample_rate; + port->format = format; + port->is_float = IsFormatFloat(format); + port->channels_num = GetFormatNumChannels(format); + port->sample_size = GetFormatSampleSize(format); + port->volume.fill(SCE_AUDIO_OUT_VOLUME_0DB); + + port->impl = audio->Open(port->is_float, port->channels_num, port->freq); + return std::distance(ports_out.begin(), port) + 1; } int PS4_SYSV_ABI sceAudioOutOpenEx() { @@ -326,7 +432,15 @@ s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, const void* ptr) { // Nothing to output return ORBIS_OK; } - return audio->Output(handle, ptr); + + auto& port = ports_out.at(handle - 1); + if (!port.is_open) { + return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; + } + + const size_t data_size = port.samples_num * port.sample_size * port.channels_num; + audio->Output(port.impl, ptr, data_size); + return ORBIS_OK; } int PS4_SYSV_ABI sceAudioOutOutputs(OrbisAudioOutOutputParam* param, u32 num) { @@ -431,7 +545,42 @@ s32 PS4_SYSV_ABI sceAudioOutSetVolume(s32 handle, s32 flag, s32* vol) { if (handle < 1 || handle > SCE_AUDIO_OUT_NUM_PORTS) { return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; } - return audio->SetVolume(handle, flag, vol); + + std::scoped_lock lock(ports_mutex); + auto& port = ports_out.at(handle - 1); + if (!port.is_open) { + return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; + } + + for (int i = 0; i < port.channels_num; i++, flag >>= 1u) { + auto bit = flag & 0x1u; + if (bit == 1) { + int src_index = i; + if (port.format == OrbisAudioOutParamFormat::Float_8CH_Std || + port.format == OrbisAudioOutParamFormat::S16_8CH_Std) { + switch (i) { + case 4: + src_index = 6; + break; + case 5: + src_index = 7; + break; + case 6: + src_index = 4; + break; + case 7: + src_index = 5; + break; + default: + break; + } + } + port.volume[i] = vol[src_index]; + } + } + + audio->SetVolume(port.impl, port.volume); + return ORBIS_OK; } int PS4_SYSV_ABI sceAudioOutSetVolumeDown() { diff --git a/src/core/libraries/audio/audioout.h b/src/core/libraries/audio/audioout.h index e8e718b87..c66a0e9f5 100644 --- a/src/core/libraries/audio/audioout.h +++ b/src/core/libraries/audio/audioout.h @@ -64,7 +64,7 @@ int PS4_SYSV_ABI sceAudioOutA3dExit(); int PS4_SYSV_ABI sceAudioOutA3dInit(); int PS4_SYSV_ABI sceAudioOutAttachToApplicationByPid(); int PS4_SYSV_ABI sceAudioOutChangeAppModuleState(); -int PS4_SYSV_ABI sceAudioOutClose(); +int PS4_SYSV_ABI sceAudioOutClose(s32 handle); int PS4_SYSV_ABI sceAudioOutDetachFromApplicationByPid(); int PS4_SYSV_ABI sceAudioOutExConfigureOutputMode(); int PS4_SYSV_ABI sceAudioOutExGetSystemInfo(); diff --git a/src/core/libraries/audio/audioout_backend.h b/src/core/libraries/audio/audioout_backend.h new file mode 100644 index 000000000..238ef0201 --- /dev/null +++ b/src/core/libraries/audio/audioout_backend.h @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +namespace Libraries::AudioOut { + +class AudioOutBackend { +public: + AudioOutBackend() = default; + virtual ~AudioOutBackend() = default; + + virtual void* Open(bool is_float, int num_channels, u32 sample_rate) = 0; + virtual void Close(void* impl) = 0; + virtual void Output(void* impl, const void* ptr, size_t size) = 0; + virtual void SetVolume(void* impl, std::array ch_volumes) = 0; +}; + +} // namespace Libraries::AudioOut diff --git a/src/core/libraries/audio/sdl_audio.cpp b/src/core/libraries/audio/sdl_audio.cpp index 8cc823abe..ce385ad9c 100644 --- a/src/core/libraries/audio/sdl_audio.cpp +++ b/src/core/libraries/audio/sdl_audio.cpp @@ -1,141 +1,44 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include #include #include #include #include "common/assert.h" -#include "core/libraries/audio/audioout_error.h" #include "core/libraries/audio/sdl_audio.h" namespace Libraries::AudioOut { constexpr int AUDIO_STREAM_BUFFER_THRESHOLD = 65536; // Define constant for buffer threshold -s32 SDLAudioOut::Open(OrbisAudioOutPort type, u32 samples_num, u32 freq, - OrbisAudioOutParamFormat format) { - std::scoped_lock lock{m_mutex}; - const auto port = std::ranges::find(ports_out, false, &PortOut::is_open); - if (port == ports_out.end()) { - LOG_ERROR(Lib_AudioOut, "Audio ports are full"); - return ORBIS_AUDIO_OUT_ERROR_PORT_FULL; - } - - port->is_open = true; - port->type = type; - port->samples_num = samples_num; - port->freq = freq; - port->format = format; - SDL_AudioFormat sampleFormat; - switch (format) { - case OrbisAudioOutParamFormat::S16Mono: - sampleFormat = SDL_AUDIO_S16; - port->channels_num = 1; - port->sample_size = 2; - break; - case OrbisAudioOutParamFormat::FloatMono: - sampleFormat = SDL_AUDIO_F32; - port->channels_num = 1; - port->sample_size = 4; - break; - case OrbisAudioOutParamFormat::S16Stereo: - sampleFormat = SDL_AUDIO_S16; - port->channels_num = 2; - port->sample_size = 2; - break; - case OrbisAudioOutParamFormat::FloatStereo: - sampleFormat = SDL_AUDIO_F32; - port->channels_num = 2; - port->sample_size = 4; - break; - case OrbisAudioOutParamFormat::S16_8CH: - sampleFormat = SDL_AUDIO_S16; - port->channels_num = 8; - port->sample_size = 2; - break; - case OrbisAudioOutParamFormat::Float_8CH: - sampleFormat = SDL_AUDIO_F32; - port->channels_num = 8; - port->sample_size = 4; - break; - case OrbisAudioOutParamFormat::S16_8CH_Std: - sampleFormat = SDL_AUDIO_S16; - port->channels_num = 8; - port->sample_size = 2; - break; - case OrbisAudioOutParamFormat::Float_8CH_Std: - sampleFormat = SDL_AUDIO_F32; - port->channels_num = 8; - port->sample_size = 4; - break; - default: - UNREACHABLE_MSG("Unknown format"); - } - - port->volume.fill(Libraries::AudioOut::SCE_AUDIO_OUT_VOLUME_0DB); - +void* SDLAudioOut::Open(bool is_float, int num_channels, u32 sample_rate) { SDL_AudioSpec fmt; SDL_zero(fmt); - fmt.format = sampleFormat; - fmt.channels = port->channels_num; - fmt.freq = freq; - port->stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, NULL, NULL); - SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(port->stream)); - return std::distance(ports_out.begin(), port) + 1; + fmt.format = is_float ? SDL_AUDIO_F32 : SDL_AUDIO_S16; + fmt.channels = num_channels; + fmt.freq = sample_rate; + + auto* stream = + SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, nullptr, nullptr); + SDL_ResumeAudioStreamDevice(stream); + return stream; } -s32 SDLAudioOut::Output(s32 handle, const void* ptr) { - auto& port = ports_out.at(handle - 1); - if (!port.is_open) { - return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; - } +void SDLAudioOut::Close(void* impl) { + SDL_DestroyAudioStream(static_cast(impl)); +} - const size_t data_size = port.samples_num * port.sample_size * port.channels_num; - bool result = SDL_PutAudioStreamData(port.stream, ptr, data_size); - while (SDL_GetAudioStreamAvailable(port.stream) > AUDIO_STREAM_BUFFER_THRESHOLD) { +void SDLAudioOut::Output(void* impl, const void* ptr, size_t size) { + auto* stream = static_cast(impl); + SDL_PutAudioStreamData(stream, ptr, size); + while (SDL_GetAudioStreamAvailable(stream) > AUDIO_STREAM_BUFFER_THRESHOLD) { SDL_Delay(0); } - return result ? ORBIS_OK : -1; } -s32 SDLAudioOut::SetVolume(s32 handle, s32 bitflag, s32* volume) { - using Libraries::AudioOut::OrbisAudioOutParamFormat; - auto& port = ports_out.at(handle - 1); - if (!port.is_open) { - return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; - } - - for (int i = 0; i < port.channels_num; i++, bitflag >>= 1u) { - auto bit = bitflag & 0x1u; - - if (bit == 1) { - int src_index = i; - if (port.format == OrbisAudioOutParamFormat::Float_8CH_Std || - port.format == OrbisAudioOutParamFormat::S16_8CH_Std) { - switch (i) { - case 4: - src_index = 6; - break; - case 5: - src_index = 7; - break; - case 6: - src_index = 4; - break; - case 7: - src_index = 5; - break; - default: - break; - } - } - port.volume[i] = volume[src_index]; - } - } - - return ORBIS_OK; +void SDLAudioOut::SetVolume(void* impl, std::array ch_volumes) { + // Not yet implemented } } // namespace Libraries::AudioOut diff --git a/src/core/libraries/audio/sdl_audio.h b/src/core/libraries/audio/sdl_audio.h index 2c34f8e29..d55f2f6e3 100644 --- a/src/core/libraries/audio/sdl_audio.h +++ b/src/core/libraries/audio/sdl_audio.h @@ -3,40 +3,16 @@ #pragma once -#include -#include -#include "core/libraries/audio/audioout.h" +#include "core/libraries/audio/audioout_backend.h" namespace Libraries::AudioOut { -class SDLAudioOut { +class SDLAudioOut final : public AudioOutBackend { public: - explicit SDLAudioOut() = default; - ~SDLAudioOut() = default; - - s32 Open(OrbisAudioOutPort type, u32 samples_num, u32 freq, OrbisAudioOutParamFormat format); - s32 Output(s32 handle, const void* ptr); - s32 SetVolume(s32 handle, s32 bitflag, s32* volume); - - constexpr std::pair GetStatus(s32 handle) const { - const auto& port = ports_out.at(handle - 1); - return std::make_pair(port.type, port.channels_num); - } - -private: - struct PortOut { - SDL_AudioStream* stream; - u32 samples_num; - u32 freq; - OrbisAudioOutParamFormat format; - OrbisAudioOutPort type; - int channels_num; - std::array volume; - u8 sample_size; - bool is_open; - }; - std::shared_mutex m_mutex; - std::array ports_out{}; + void* Open(bool is_float, int num_channels, u32 sample_rate) override; + void Close(void* impl) override; + void Output(void* impl, const void* ptr, size_t size) override; + void SetVolume(void* impl, std::array ch_volumes) override; }; } // namespace Libraries::AudioOut diff --git a/src/qt_gui/compatibility_info.cpp b/src/qt_gui/compatibility_info.cpp index c8d6bf36d..aecac60cd 100644 --- a/src/qt_gui/compatibility_info.cpp +++ b/src/qt_gui/compatibility_info.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "common/path_util.h" #include "compatibility_info.h" @@ -22,7 +23,8 @@ void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent) { return; QNetworkReply* reply = FetchPage(1); - WaitForReply(reply); + if (!WaitForReply(reply)) + return; QProgressDialog dialog(tr("Fetching compatibility data, please wait"), tr("Cancel"), 0, 0, parent); @@ -57,12 +59,17 @@ void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent) { } future_watcher.setFuture(QtConcurrent::map(replies, WaitForReply)); - connect(&future_watcher, &QFutureWatcher::finished, [&]() { + connect(&future_watcher, &QFutureWatcher::finished, [&]() { for (int i = 0; i < remaining_pages; i++) { - if (replies[i]->error() == QNetworkReply::NoError) { - ExtractCompatibilityInfo(replies[i]->readAll()); + if (replies[i]->bytesAvailable()) { + if (replies[i]->error() == QNetworkReply::NoError) { + ExtractCompatibilityInfo(replies[i]->readAll()); + } + replies[i]->deleteLater(); + } else { + // This means the request timed out + return; } - replies[i]->deleteLater(); } QFile compatibility_file(m_compatibility_filename); @@ -83,6 +90,16 @@ void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent) { dialog.reset(); }); + connect(&future_watcher, &QFutureWatcher::canceled, [&]() { + // Cleanup if user cancels pulling data + for (int i = 0; i < remaining_pages; i++) { + if (!replies[i]->bytesAvailable()) { + replies[i]->deleteLater(); + } else if (!replies[i]->isFinished()) { + replies[i]->abort(); + } + } + }); connect(&dialog, &QProgressDialog::canceled, &future_watcher, &QFutureWatcher::cancel); dialog.setRange(0, remaining_pages); connect(&future_watcher, &QFutureWatcher::progressValueChanged, &dialog, @@ -105,20 +122,34 @@ QNetworkReply* CompatibilityInfoClass::FetchPage(int page_num) { return reply; } -void CompatibilityInfoClass::WaitForReply(QNetworkReply* reply) { +bool CompatibilityInfoClass::WaitForReply(QNetworkReply* reply) { + // Returns true if reply succeeded, false if reply timed out + QTimer timer; + timer.setSingleShot(true); + QEventLoop loop; connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); + connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); + timer.start(5000); loop.exec(); - return; + + if (timer.isActive()) { + timer.stop(); + return true; + } else { + disconnect(reply, SIGNAL(finished()), &loop, SLOT(quit())); + reply->abort(); + return false; + } }; CompatibilityEntry CompatibilityInfoClass::GetCompatibilityInfo(const std::string& serial) { QString title_id = QString::fromStdString(serial); if (m_compatibility_database.contains(title_id)) { { + QJsonObject compatibility_obj = m_compatibility_database[title_id].toObject(); for (int os_int = 0; os_int != static_cast(OSType::Last); os_int++) { QString os_string = OSTypeToString.at(static_cast(os_int)); - QJsonObject compatibility_obj = m_compatibility_database[title_id].toObject(); if (compatibility_obj.contains(os_string)) { QJsonObject compatibility_entry_obj = compatibility_obj[os_string].toObject(); CompatibilityEntry compatibility_entry{ @@ -133,7 +164,9 @@ CompatibilityEntry CompatibilityInfoClass::GetCompatibilityInfo(const std::strin } } } - return CompatibilityEntry{CompatibilityStatus::Unknown}; + + return CompatibilityEntry{CompatibilityStatus::Unknown, "", QDateTime::currentDateTime(), "", + 0}; } bool CompatibilityInfoClass::LoadCompatibilityFile() { diff --git a/src/qt_gui/compatibility_info.h b/src/qt_gui/compatibility_info.h index 2b970670a..dcbaef847 100644 --- a/src/qt_gui/compatibility_info.h +++ b/src/qt_gui/compatibility_info.h @@ -57,6 +57,7 @@ class CompatibilityInfoClass : public QObject { public: // Please think of a better alternative inline static const std::unordered_map LabelToCompatStatus = { + {QStringLiteral("status-unknown"), CompatibilityStatus::Unknown}, {QStringLiteral("status-nothing"), CompatibilityStatus::Nothing}, {QStringLiteral("status-boots"), CompatibilityStatus::Boots}, {QStringLiteral("status-menus"), CompatibilityStatus::Menus}, @@ -87,7 +88,7 @@ public: bool LoadCompatibilityFile(); CompatibilityEntry GetCompatibilityInfo(const std::string& serial); void ExtractCompatibilityInfo(QByteArray response); - static void WaitForReply(QNetworkReply* reply); + static bool WaitForReply(QNetworkReply* reply); QNetworkReply* FetchPage(int page_num); private: diff --git a/src/qt_gui/game_list_frame.cpp b/src/qt_gui/game_list_frame.cpp index d43c35ef4..53159d8e7 100644 --- a/src/qt_gui/game_list_frame.cpp +++ b/src/qt_gui/game_list_frame.cpp @@ -80,6 +80,11 @@ GameListFrame::GameListFrame(std::shared_ptr game_info_get, QDesktopServices::openUrl(QUrl(m_game_info->m_games[row].compatibility.url)); } }); + + // Do not show status column if it is not enabled + if (!Config::getCompatibilityEnabled()) { + this->setColumnHidden(2, true); + } } void GameListFrame::onCurrentCellChanged(int currentRow, int currentColumn, int previousRow, diff --git a/src/qt_gui/main_window.cpp b/src/qt_gui/main_window.cpp index 94832c6d5..5e6a8d868 100644 --- a/src/qt_gui/main_window.cpp +++ b/src/qt_gui/main_window.cpp @@ -198,7 +198,9 @@ void MainWindow::CreateDockWindows() { void MainWindow::LoadGameLists() { // Update compatibility database - m_compat_info->UpdateCompatibilityDatabase(this); + if (Config::getCheckCompatibilityOnStartup()) { + m_compat_info->UpdateCompatibilityDatabase(this); + } // Get game info from game folders. m_game_info->GetGameInfo(this); if (isTableList) {