From 1f7690eb743dbe782d66ff3c8c35bce661a0064f Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 21 Aug 2024 03:13:44 +0200 Subject: [PATCH 01/35] Fix crash with SongDownloader --- src/CP_SDK_BS/UI/LevelDetail.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/CP_SDK_BS/UI/LevelDetail.cpp b/src/CP_SDK_BS/UI/LevelDetail.cpp index 1770aca..b445cad 100644 --- a/src/CP_SDK_BS/UI/LevelDetail.cpp +++ b/src/CP_SDK_BS/UI/LevelDetail.cpp @@ -68,6 +68,10 @@ namespace CP_SDK_BS::UI { m_SongDetailViewTemplate = GameObject::Instantiate(l_Result->get_gameObject()); m_SongDetailViewTemplate->set_name(u"CP_SDK_BS_StandardLevelDetailView_Template"); + auto l_LevelBarBig = m_SongDetailViewTemplate->get_transform()->Find(u"LevelBarBig"); + if (l_LevelBarBig) + l_LevelBarBig->set_name("CP_SDK_BS_LevelBarBig"); + try { auto l_Component = m_SongDetailViewTemplate->GetComponent(); @@ -75,7 +79,13 @@ namespace CP_SDK_BS::UI { { auto l_Loader = BeatmapLevelLoader::New_ctor(nullptr, MockBeatmapDataAssetFileModel::New_ctor()->i___GlobalNamespace__IBeatmapDataAssetFileModel(), nullptr, BeatmapLevelLoader::InitData::New_ctor(0)); auto l_Packs = System::Collections::Generic::List_1<::UnityW>::New_ctor(); - l_Component->____beatmapLevelsModel = BeatmapLevelsModel::New_ctor(nullptr, l_Loader->i___GlobalNamespace__IBeatmapLevelLoader(), l_Packs->i___System__Collections__Generic__IEnumerable_1_T_()); + l_Component->____beatmapLevelsModel = BeatmapLevelsModel::New_ctor( + nullptr, + l_Loader->i___GlobalNamespace__IBeatmapLevelLoader(), + nullptr, + nullptr, + l_Packs->i___System__Collections__Generic__IEnumerable_1_T_() + ); GameObject::DestroyImmediate(l_Component); } @@ -286,7 +296,7 @@ namespace CP_SDK_BS::UI { m_DifficultiesSegmentedControllerClone = m_GameObject->get_transform()->Find(u"BeatmapDifficulty")->GetComponentInChildren(); m_SongDiffSegmentedControl = HMUITextSegmentedControl::Create(m_DifficultiesSegmentedControllerClone->get_transform().try_cast().value_or(nullptr), true); - auto l_LevelBarBig = m_GameObject->get_transform()->Find(u"LevelBarBig"); + auto l_LevelBarBig = m_GameObject->get_transform()->Find(u"CP_SDK_BS_LevelBarBig"); m_SongNameText = l_LevelBarBig->GetComponentsInChildren()->First([](auto x) { return x->get_gameObject()->get_name() == u"SongNameText"; }); m_AuthorNameText = l_LevelBarBig->GetComponentsInChildren()->First([](auto x) { return x->get_gameObject()->get_name() == u"AuthorNameText"; }); From 6cef171af3a56889c7644d7edd6ee8d65dc223e1 Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 21 Aug 2024 03:39:08 +0200 Subject: [PATCH 02/35] ChatPlexSDK: Fix documentation --- shared/CP_SDK/ChatPlexSDK.hpp | 28 ++++++++++++++-------------- src/CP_SDK/ChatPlexSDK.cpp | 24 ++++++++++++------------ 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/shared/CP_SDK/ChatPlexSDK.hpp b/shared/CP_SDK/ChatPlexSDK.hpp index 2e5e66d..896f480 100644 --- a/shared/CP_SDK/ChatPlexSDK.hpp +++ b/shared/CP_SDK/ChatPlexSDK.hpp @@ -29,7 +29,6 @@ namespace CP_SDK { CP_SDK_NO_DEF_CTORS(ChatPlexSDK); public: - /// Logger instance static Logging::ILogger* Logger() { return m_Logger; } static std::u16string_view ProductName() { return m_ProductName; } @@ -49,38 +48,39 @@ namespace CP_SDK { /// @param p_BasePath Base path for file storage /// @param p_RenderPipeline Rendering pipeline static void Configure(Logging::ILogger* p_Logger, std::u16string_view p_ProductName, std::string_view p_BasePath, ERenderPipeline p_RenderPipeline); - /// When the assembly is loaded + /// @brief When the assembly is loaded static void OnAssemblyLoaded(); - /// On assembly exit + /// @brief On assembly exit static void OnAssemblyExit(); public: - /// When unity is ready + /// @brief When unity is ready static void OnUnityReady(); - /// When unity is exiting + /// @brief When unity is exiting static void OnUnityExit(); public: - /// Register a module - /// @p_Module: Module instance + /// @brief Register a module + /// @param p_Module: Module instance static void RegisterModule(IModuleBase* p_Module); - /// Init all the available modules + /// @brief Init all the available modules static void InitModules(); - /// Stop modules + /// @brief Stop modules static void StopModules(); - /// Get modules + /// @brief Get modules + /// @return Const reference of a list containing the modules static const std::vector & GetModules() { return m_Modules; } public: - /// On generic menu scene + /// @brief On generic menu scene static void Fire_OnGenericMenuSceneLoaded(); - /// On generic menu scene + /// @brief On generic menu scene static void Fire_OnGenericMenuScene(); - /// On generic play scene + /// @brief On generic play scene static void Fire_OnGenericPlayingScene(); private: - /// Install WEBP codecs + /// @brief Install WEBP codecs static void InstallWEBPCodecs(); private: diff --git a/src/CP_SDK/ChatPlexSDK.cpp b/src/CP_SDK/ChatPlexSDK.cpp index c623f94..ad3b98f 100644 --- a/src/CP_SDK/ChatPlexSDK.cpp +++ b/src/CP_SDK/ChatPlexSDK.cpp @@ -44,7 +44,7 @@ namespace CP_SDK { m_NetworkUserAgent = std::u16string(u"ChatPlexSDK_") + m_ProductName; m_RenderPipeline = p_RenderPipeline; } - /// When the assembly is loaded + /// @brief When the assembly is loaded void ChatPlexSDK::OnAssemblyLoaded() { InstallWEBPCodecs(); @@ -52,7 +52,7 @@ namespace CP_SDK { /// Init config Chat::Service::Init(); } - /// On assembly exit + /// @brief On assembly exit void ChatPlexSDK::OnAssemblyExit() { try @@ -69,7 +69,7 @@ namespace CP_SDK { //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// - /// When unity is ready + /// @brief When unity is ready void ChatPlexSDK::OnUnityReady() { try @@ -92,7 +92,7 @@ namespace CP_SDK { m_Logger->Error(p_Exception); } } - /// When unity is exiting + /// @brief When unity is exiting void ChatPlexSDK::OnUnityExit() { try @@ -122,13 +122,13 @@ namespace CP_SDK { //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// - /// Register a module - /// @p_Module: Module instance + /// @brief Register a module + /// @param p_Module Module instance void ChatPlexSDK::RegisterModule(IModuleBase * p_Module) { m_Modules.push_back(p_Module); } - /// Init all the available modules + /// @brief Init all the available modules void ChatPlexSDK::InitModules() { try @@ -153,7 +153,7 @@ namespace CP_SDK { m_Logger->Error(p_Exception); } } - /// Stop modules + /// @brief Stop modules void ChatPlexSDK::StopModules() { for (auto l_Module : m_Modules) @@ -173,7 +173,7 @@ namespace CP_SDK { //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// - /// On generic menu scene + /// @brief On generic menu scene void ChatPlexSDK::Fire_OnGenericMenuSceneLoaded() { try @@ -204,7 +204,7 @@ namespace CP_SDK { m_Logger->Error(l_Exception); } } - /// On generic menu scene + /// @brief On generic menu scene void ChatPlexSDK::Fire_OnGenericMenuScene() { m_ActiveGenericScene = EGenericScene::Menu; @@ -221,7 +221,7 @@ namespace CP_SDK { m_Logger->Error(l_Exception); } } - /// On generic play scene + /// @brief On generic play scene void ChatPlexSDK::Fire_OnGenericPlayingScene() { m_ActiveGenericScene = EGenericScene::Playing; @@ -240,7 +240,7 @@ namespace CP_SDK { //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// - /// Install WEBP codecs + /// @brief Install WEBP codecs void ChatPlexSDK::InstallWEBPCodecs() { /// Codecs are built-in sources From a8bb730aeecd644ec790e719c482350423b7de5c Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 21 Aug 2024 03:39:23 +0200 Subject: [PATCH 03/35] Add Vector3RotateTowards --- shared/CP_SDK/Unity/Operators.hpp | 33 +++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/shared/CP_SDK/Unity/Operators.hpp b/shared/CP_SDK/Unity/Operators.hpp index ce524ca..17e4f42 100644 --- a/shared/CP_SDK/Unity/Operators.hpp +++ b/shared/CP_SDK/Unity/Operators.hpp @@ -6,6 +6,9 @@ #include #include #include +#include + +#include constexpr System::TimeSpan operator- (const System::DateTime& p_A, const System::DateTime& p_B) { @@ -122,4 +125,34 @@ constexpr UnityEngine::Quaternion operator* (const UnityEngine::Quaternion& p_A, constexpr UnityEngine::Vector3 operator* (const UnityEngine::Quaternion& p_A, const UnityEngine::Vector3& p_B) { return UnityEngine::Quaternion::op_Multiply(p_A, p_B); +} + +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// + +static UnityEngine::Vector3 Vector3RotateTowards(UnityEngine::Vector3 p_Current, UnityEngine::Vector3 p_Target, float p_MaxRadiansDelta, float p_MaxMagnitudeDelta) +{ + const float Deg2Rad = static_cast(std::numbers::pi) / 180.0f; + const float Rad2Deg = 57.29578f; + + auto l_FromDirection = p_Current.get_normalized(); + auto l_ToDirection = p_Target.get_normalized(); + auto l_AngleRadians = UnityEngine::Mathf::Acos(UnityEngine::Vector3::Dot(l_FromDirection, l_ToDirection)); + + if (l_AngleRadians < std::numeric_limits::epsilon()) + return p_Current; + + auto l_ClampedAngleRad = UnityEngine::Mathf::Min(p_MaxRadiansDelta, l_AngleRadians); + auto l_Axis = UnityEngine::Vector3::Cross(l_FromDirection, l_ToDirection); + + if (l_Axis.get_sqrMagnitude() < std::numeric_limits::epsilon()) + l_Axis = UnityEngine::Vector3::get_up(); + + auto l_Rotation = UnityEngine::Quaternion::AngleAxis(l_ClampedAngleRad * Rad2Deg, l_Axis); + auto l_RotatedVector = l_Rotation * l_FromDirection; + auto l_CurrentMagnitude = p_Current.get_magnitude(); + auto l_TargetMagnitude = p_Target.get_magnitude(); + auto l_ClampedMagnitude = UnityEngine::Mathf::MoveTowards(l_CurrentMagnitude, l_TargetMagnitude, p_MaxMagnitudeDelta); + + return l_RotatedVector * l_ClampedMagnitude; } \ No newline at end of file From e895d166a2ab9c6961984a850a814be62acd92b2 Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 21 Aug 2024 03:39:33 +0200 Subject: [PATCH 04/35] Fix MonoPtr life check --- shared/CP_SDK/Utils/MonoPtr.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/CP_SDK/Utils/MonoPtr.hpp b/shared/CP_SDK/Utils/MonoPtr.hpp index ed29807..5e08201 100644 --- a/shared/CP_SDK/Utils/MonoPtr.hpp +++ b/shared/CP_SDK/Utils/MonoPtr.hpp @@ -41,7 +41,7 @@ namespace CP_SDK::Utils { if constexpr (std::is_assignable_v) { auto l_UObject = reinterpret_cast(m_Wrapper->Ptr); - if (l_IsDead || !l_UObject->m_CachedPtr) + if (l_IsDead || !l_UObject->___m_CachedPtr.m_value) l_IsDead = true; } @@ -132,7 +132,7 @@ namespace CP_SDK::Utils { return false; auto l_UObject = reinterpret_cast(p_Ptr); - if (!l_UObject->m_CachedPtr) + if (!l_UObject->___m_CachedPtr.m_value) return false; return true; From 4e1775038f73f047f46cb596d4c860ef735bdc3c Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 21 Aug 2024 03:40:13 +0200 Subject: [PATCH 05/35] Update qpm.json --- qpm.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/qpm.json b/qpm.json index 8a7c889..55d779a 100644 --- a/qpm.json +++ b/qpm.json @@ -40,17 +40,17 @@ "dependencies": [ { "id": "beatsaber-hook", - "versionRange": "^5.1.6", + "versionRange": "^5.1.9", "additionalData": {} }, { "id": "bs-cordl", - "versionRange": "^3500.0.0", + "versionRange": "^3700.*", "additionalData": {} }, { "id": "custom-types", - "versionRange": "^0.17.6", + "versionRange": "^0.17.8", "additionalData": {} }, { @@ -63,7 +63,7 @@ }, { "id": "bsml", - "versionRange": "^0.4.20", + "versionRange": "^0.4.34", "additionalData": { "private": true } @@ -75,7 +75,7 @@ }, { "id": "songcore", - "versionRange": "^1.1.9", + "versionRange": "^1.1.12", "additionalData": { "private": true } From 9d390f3919225297e7ee8c31ccd31a1dee50b72d Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 21 Aug 2024 03:40:22 +0200 Subject: [PATCH 06/35] Update game version --- mod.template.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod.template.json b/mod.template.json index 6b636a6..74565b0 100644 --- a/mod.template.json +++ b/mod.template.json @@ -6,7 +6,7 @@ "author": "HardCPP", "version": "${version}", "packageId": "com.beatgames.beatsaber", - "packageVersion": "1.35.0_8016709773", + "packageVersion": "1.37.0_9064817954", "description": "ChatPlex BeatSaber modding SDK (Dependence for other mods)", "coverImage": "cover.png", "dependencies": [], From 000f1d423486a2c625cb976f3c42aabea3180931 Mon Sep 17 00:00:00 2001 From: HardCPP Date: Thu, 22 Aug 2024 22:53:07 +0200 Subject: [PATCH 07/35] UI: Fix game level details widget --- src/CP_SDK_BS/UI/LevelDetail.cpp | 54 +++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/src/CP_SDK_BS/UI/LevelDetail.cpp b/src/CP_SDK_BS/UI/LevelDetail.cpp index b445cad..5a9a778 100644 --- a/src/CP_SDK_BS/UI/LevelDetail.cpp +++ b/src/CP_SDK_BS/UI/LevelDetail.cpp @@ -5,6 +5,7 @@ #include "CP_SDK/UI/UISystem.hpp" #include "CP_SDK/Unity/SpriteU.hpp" #include "CP_SDK/Unity/Operators.hpp" +#include "CP_SDK/Unity/MTThreadInvoker.hpp" #include "assets.hpp" #include @@ -17,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -38,8 +40,6 @@ #include "songcore/shared/SongLoader/CustomBeatmapLevel.hpp" -#include "CP_SDK_BS/UI/DefaultComponentsOverrides/Subs/SubFloatingPanelMover.hpp" - using namespace GlobalNamespace; using namespace TMPro; using namespace UnityEngine; @@ -66,11 +66,11 @@ namespace CP_SDK_BS::UI { return; m_SongDetailViewTemplate = GameObject::Instantiate(l_Result->get_gameObject()); - m_SongDetailViewTemplate->set_name(u"CP_SDK_BS_StandardLevelDetailView_Template"); + m_SongDetailViewTemplate->set_name(u"CP_SDK_BS_SongDetailViewTemplate"); auto l_LevelBarBig = m_SongDetailViewTemplate->get_transform()->Find(u"LevelBarBig"); if (l_LevelBarBig) - l_LevelBarBig->set_name("CP_SDK_BS_LevelBarBig"); + l_LevelBarBig->get_gameObject()->set_name("CP_SDK_BS_LevelBarBig"); try { @@ -321,7 +321,7 @@ namespace CP_SDK_BS::UI { m_SongBombsText = l_BeatmapParamsPanel->GetComponentsInChildren()->First([](auto x) { return x->get_gameObject()->get_transform()->get_parent()->get_name() == u"BombsCount";}); auto l_SizeDelta = m_SongNPSText->get_transform()->get_parent()->get_transform().try_cast().value_or(nullptr)->get_sizeDelta(); - l_SizeDelta.y *= 2; + l_SizeDelta.y *= 2.0f; m_SongNPSText->get_transform()->get_parent()->get_gameObject()->AddComponent()->set_padding(RectOffset::New_ctor(0, 0, 0, 3)); m_SongNPSText->get_transform()->get_parent()->get_gameObject()->AddComponent(); @@ -333,7 +333,7 @@ namespace CP_SDK_BS::UI { m_SongObstaclesText->get_transform()->get_parent()->get_gameObject()->AddComponent()->set_padding(RectOffset::New_ctor(0, 0, 0, 3)); m_SongObstaclesText->get_transform()->get_parent()->get_gameObject()->AddComponent(); - m_SongObstaclesText->get_transform()->get_parent()->get_transform()->get_transform()->get_parent()->get_transform().try_cast().value_or(nullptr)->set_sizeDelta(l_SizeDelta); + m_SongObstaclesText->get_transform()->get_parent()->get_transform().try_cast().value_or(nullptr)->set_sizeDelta(l_SizeDelta); m_SongBombsText->get_transform()->get_parent()->get_gameObject()->AddComponent()->set_padding(RectOffset::New_ctor(0, 0, 0, 3)); m_SongBombsText->get_transform()->get_parent()->get_gameObject()->AddComponent(); @@ -428,11 +428,11 @@ namespace CP_SDK_BS::UI { /// Display mode Characteristic(HMUI::IconSegmentedControl::DataItem::New_ctor(p_Characteristic->____icon, BGLib::Polyglot::Localization::Get(p_Characteristic->____descriptionLocalizationKey))); - auto l_DifficultyBeatmap = p_BeatMap->GetDifficultyBeatmapData(p_Characteristic, p_Difficulty); - /// Display difficulty Difficulty(Game::Levels::BeatmapDifficultySerializedNameToDifficultyName(BeatmapDifficultySerializedMethods::SerializedName(p_Difficulty))); + auto l_DifficultyBeatmap = p_BeatMap->GetDifficultyBeatmapData(p_Characteristic, p_Difficulty); + Name (p_BeatMap->___songName); AuthorNameText(u"Mapped by " + p_BeatMap->___allMappers->FirstOrDefault() + u""); Cover (p_Cover ? p_Cover : Game::Levels::GetDefaultPackCover()); @@ -440,10 +440,34 @@ namespace CP_SDK_BS::UI { BPM (p_BeatMap->___beatsPerMinute); NJS ((int)l_DifficultyBeatmap->___noteJumpMovementSpeed); Offset (l_DifficultyBeatmap->___noteJumpStartBeatOffset); - NPS (l_DifficultyBeatmap->___notesCount / p_BeatMap->___songDuration); - Notes (l_DifficultyBeatmap->___notesCount); - Obstacles (l_DifficultyBeatmap->___obstaclesCount); - Bombs (l_DifficultyBeatmap->___bombsCount); + + auto l_CustomBeatmapLevelCast = il2cpp_utils::try_cast(p_BeatMap); + if (l_CustomBeatmapLevelCast) + { + auto l_CustomBeatmapLevel = l_CustomBeatmapLevelCast.value(); + + NPS (-1); + Notes (-1); + Obstacles(-1); + Bombs (-1); + + BeatmapKey l_BeatmapKey; + if (Game::Levels::BeatmapLevel_TryGetBeatmapKey(p_BeatMap, p_Characteristic, p_Difficulty, &l_BeatmapKey)) + { + auto l_DifficultyBeatmap = BeatmapDataLoader::New_ctor()->LoadBasicBeatmapData(l_CustomBeatmapLevel->get_beatmapLevelData(), byref(l_BeatmapKey)); + NPS (static_cast(l_DifficultyBeatmap->get_cuttableNotesCount()) / std::max(static_cast(p_BeatMap->___songDuration), 1.0f)); + Notes (l_DifficultyBeatmap->get_cuttableNotesCount()); + Obstacles (l_DifficultyBeatmap->get_obstaclesCount()); + Bombs (l_DifficultyBeatmap->get_bombsCount()); + } + } + else + { + NPS (static_cast(l_DifficultyBeatmap->___notesCount) / std::max(static_cast(p_BeatMap->___songDuration), 1.0f)); + Notes (l_DifficultyBeatmap->___notesCount); + Obstacles (l_DifficultyBeatmap->___obstaclesCount); + Bombs (l_DifficultyBeatmap->___bombsCount); + } return true; } @@ -703,7 +727,7 @@ namespace CP_SDK_BS::UI { BPM (m_LocalBeatMap->___beatsPerMinute); NJS ((int)l_DifficultyBeatmap->___noteJumpMovementSpeed); Offset (l_DifficultyBeatmap->___noteJumpStartBeatOffset); - NPS (l_DifficultyBeatmap->___notesCount / m_LocalBeatMap->___songDuration); + NPS (static_cast(l_DifficultyBeatmap->___notesCount) / std::max(static_cast(m_LocalBeatMap->___songDuration), 1.0f)); Notes (l_DifficultyBeatmap->___notesCount); Obstacles (l_DifficultyBeatmap->___obstaclesCount); Bombs (l_DifficultyBeatmap->___bombsCount); @@ -735,8 +759,8 @@ namespace CP_SDK_BS::UI { SelectedBeatmapDifficulty = Game::Levels::BeatmapDifficultySerializedNameToBeatmapDifficulty(l_SelectedBeatmapCharacteristicDifficulty->difficulty); /// Display informations - Time ((double)m_BeatMap->metadata.value().duration); - NPS ((float)l_SelectedBeatmapCharacteristicDifficulty->nps); + Time (static_cast(m_BeatMap->metadata.value().duration)); + NPS (static_cast(l_SelectedBeatmapCharacteristicDifficulty->nps)); NJS ((int)l_SelectedBeatmapCharacteristicDifficulty->njs); Offset (l_SelectedBeatmapCharacteristicDifficulty->offset); Notes (l_SelectedBeatmapCharacteristicDifficulty->notes); From 228292d9a47a3e6cd9eab97e2bb084a76a29b7c2 Mon Sep 17 00:00:00 2001 From: HardCPP Date: Thu, 22 Aug 2024 22:53:28 +0200 Subject: [PATCH 08/35] Game: Fix mapping capabilities detection --- shared/CP_SDK_BS/Game/Levels.hpp | 4 +++ src/CP_SDK_BS/Game/LevelCompletionData.cpp | 8 +++--- src/CP_SDK_BS/Game/LevelData.cpp | 14 ++++----- src/CP_SDK_BS/Game/Levels.cpp | 33 ++++++++++++++++++---- 4 files changed, 43 insertions(+), 16 deletions(-) diff --git a/shared/CP_SDK_BS/Game/Levels.hpp b/shared/CP_SDK_BS/Game/Levels.hpp index 9ba6dcd..3a33b4c 100644 --- a/shared/CP_SDK_BS/Game/Levels.hpp +++ b/shared/CP_SDK_BS/Game/Levels.hpp @@ -67,6 +67,10 @@ namespace CP_SDK_BS::Game { /// @param p_Capability Capability name /// @return True or false static bool HasMappingCapability(std::u16string_view p_Capability); + /// @brief Sanatrize a mapping capability + /// @param p_Capability Capability name + /// @return Sanatized mapping capability + static std::u16string SanatizeMappingCapability(std::u16string_view p_Capability); public: /// @brief Sanitize a level ID for case matching diff --git a/src/CP_SDK_BS/Game/LevelCompletionData.cpp b/src/CP_SDK_BS/Game/LevelCompletionData.cpp index ac22363..17a3442 100644 --- a/src/CP_SDK_BS/Game/LevelCompletionData.cpp +++ b/src/CP_SDK_BS/Game/LevelCompletionData.cpp @@ -14,11 +14,11 @@ namespace CP_SDK_BS::Game { return false; std::vector l_Requirements; - if (Levels::TryGetCustomRequirementsFor(Data->beatmapLevel, Data->beatmapKey.beatmapCharacteristic, Data->beatmapKey.difficulty, &l_Requirements)) + if (Levels::TryGetCustomRequirementsFor(Data->___beatmapLevel, Data->___beatmapKey.beatmapCharacteristic, Data->___beatmapKey.difficulty, &l_Requirements)) { for (auto& l_Current : l_Requirements) { - if (_v::U16EqualsToCaseInsensitive(l_Current, u"Noodle Extensions")) + if (CP_SDK::Utils::U16EqualsToCaseInsensitive(Levels::SanatizeMappingCapability(l_Current), u"NoodleExtensions")) continue; return true; @@ -33,11 +33,11 @@ namespace CP_SDK_BS::Game { return false; std::vector l_Requirements; - if (Levels::TryGetCustomRequirementsFor(Data->beatmapLevel, Data->beatmapKey.beatmapCharacteristic, Data->beatmapKey.difficulty, &l_Requirements)) + if (Levels::TryGetCustomRequirementsFor(Data->___beatmapLevel, Data->___beatmapKey.beatmapCharacteristic, Data->___beatmapKey.difficulty, &l_Requirements)) { for (auto& l_Current : l_Requirements) { - if (_v::U16EqualsToCaseInsensitive(l_Current, u"Chroma")) + if (CP_SDK::Utils::U16EqualsToCaseInsensitive(Levels::SanatizeMappingCapability(l_Current), u"Chroma")) continue; return true; diff --git a/src/CP_SDK_BS/Game/LevelData.cpp b/src/CP_SDK_BS/Game/LevelData.cpp index 489172f..3b3350a 100644 --- a/src/CP_SDK_BS/Game/LevelData.cpp +++ b/src/CP_SDK_BS/Game/LevelData.cpp @@ -10,22 +10,22 @@ namespace CP_SDK_BS::Game { bool LevelData::HasRotations() { - if (!Data || !Data->transformedBeatmapData) + if (!Data || !Data->get_transformedBeatmapData()) return false; - return Data->transformedBeatmapData->get_spawnRotationEventsCount() > 0; + return Data->get_transformedBeatmapData()->get_spawnRotationEventsCount() > 0; } bool LevelData::IsNoodle() { - if (!Data || !Data->beatmapLevel) + if (!Data || !Data->___beatmapLevel) return false; std::vector l_Requirements; - if (Levels::TryGetCustomRequirementsFor(Data->beatmapLevel, Data->beatmapKey.beatmapCharacteristic, Data->beatmapKey.difficulty, &l_Requirements)) + if (Levels::TryGetCustomRequirementsFor(Data->___beatmapLevel, Data->___beatmapKey.beatmapCharacteristic, Data->___beatmapKey.difficulty, &l_Requirements)) { for (auto& l_Current : l_Requirements) { - if (CP_SDK::Utils::U16EqualsToCaseInsensitive(l_Current, u"Noodle Extensions")) + if (CP_SDK::Utils::U16EqualsToCaseInsensitive(Levels::SanatizeMappingCapability(l_Current), u"NoodleExtensions")) continue; return true; @@ -40,11 +40,11 @@ namespace CP_SDK_BS::Game { return false; std::vector l_Requirements; - if (Levels::TryGetCustomRequirementsFor(Data->beatmapLevel, Data->beatmapKey.beatmapCharacteristic, Data->beatmapKey.difficulty, &l_Requirements)) + if (Levels::TryGetCustomRequirementsFor(Data->___beatmapLevel, Data->___beatmapKey.beatmapCharacteristic, Data->___beatmapKey.difficulty, &l_Requirements)) { for (auto& l_Current : l_Requirements) { - if (CP_SDK::Utils::U16EqualsToCaseInsensitive(l_Current, u"Chroma")) + if (CP_SDK::Utils::U16EqualsToCaseInsensitive(Levels::SanatizeMappingCapability(l_Current), u"Chroma")) continue; return true; diff --git a/src/CP_SDK_BS/Game/Levels.cpp b/src/CP_SDK_BS/Game/Levels.cpp index 4f7882a..84e2d0f 100644 --- a/src/CP_SDK_BS/Game/Levels.cpp +++ b/src/CP_SDK_BS/Game/Levels.cpp @@ -122,9 +122,12 @@ namespace CP_SDK_BS::Game { bool Levels::HasMappingCapability(std::u16string_view p_Capability) { auto l_Capabilities = SongCore::API::Capabilities::GetRegisteredCapabilities(); + auto l_Sanatized = SanatizeMappingCapability(p_Capability); + CP_SDK::ChatPlexSDK::Logger()->Error(u"HasMappingCapability: " + l_Sanatized); for (auto& l_Capability : l_Capabilities) { - if (!CP_SDK::Utils::U16EqualsToCaseInsensitive(p_Capability, CP_SDK::Utils::StrToU16Str(l_Capability))) + CP_SDK::ChatPlexSDK::Logger()->Error(u"Mapping cap: " + CP_SDK::Utils::StrToU16Str(l_Capability)); + if (!CP_SDK::Utils::U16EqualsToCaseInsensitive(l_Sanatized, CP_SDK::Utils::StrToU16Str(l_Capability))) continue; return true; @@ -132,6 +135,24 @@ namespace CP_SDK_BS::Game { return false; } + /// @brief Sanatrize a mapping capability + /// @param p_Capability Capability name + /// @return Sanatized mapping capability + std::u16string Levels::SanatizeMappingCapability(std::u16string_view p_Capability) + { + std::u16string l_Result; + + l_Result.reserve(p_Capability.size()); + for (auto l_Char : p_Capability) + { + if (l_Char == u' ') + continue; + + l_Result.push_back(std::towlower(l_Char)); + } + + return l_Result; + } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// @@ -591,21 +612,23 @@ namespace CP_SDK_BS::Game { return false; } - auto l_StandardLevelInfoSaveData = il2cpp_utils::try_cast(l_CustomLevel->get_standardLevelInfoSaveData()).value_or(nullptr); - if (!l_StandardLevelInfoSaveData) + auto l_CustomSaveDataInfoWrapper = l_CustomLevel->get_CustomSaveDataInfo(); + if (!l_CustomSaveDataInfoWrapper) { CP_SDK::ChatPlexSDK::Logger()->Error(u"[CP_SDK_BS.Game][Levels.TryGetCustomRequirementsFor] Failed to retrieve custom data level for id: " + p_BeatmapLevel->___levelID); return false; } - auto l_CharacteristicAndDifficultyWrapper = l_StandardLevelInfoSaveData->TryGetCharacteristicAndDifficulty(p_BeatmapCharacteristicSO->____serializedName, p_BeatmapDifficulty); + auto& l_CustomSaveDataInfo = l_CustomSaveDataInfoWrapper->get(); + + auto l_CharacteristicAndDifficultyWrapper = l_CustomSaveDataInfo.TryGetCharacteristicAndDifficulty(p_BeatmapCharacteristicSO->____serializedName, p_BeatmapDifficulty); if (!l_CharacteristicAndDifficultyWrapper) { CP_SDK::ChatPlexSDK::Logger()->Error(u"[CP_SDK_BS.Game][Levels.TryGetCustomRequirementsFor] Failed to retrieve custom data level for id: " + p_BeatmapLevel->___levelID); return false; } - auto l_CharacteristicAndDifficulty = l_CharacteristicAndDifficultyWrapper.value().get(); + const auto& l_CharacteristicAndDifficulty = l_CharacteristicAndDifficultyWrapper.value().get(); p_CustomRequirements->reserve(l_CharacteristicAndDifficulty.requirements.size()); for (auto& l_Requirement : l_CharacteristicAndDifficulty.requirements) From 820cfd415d343cbe78dc7f71c311d02e76e37b8f Mon Sep 17 00:00:00 2001 From: HardCPP Date: Thu, 22 Aug 2024 22:53:44 +0200 Subject: [PATCH 09/35] Font manager hotfix until proper unstripped libunity.so --- src/CP_SDK/Unity/FontManager.cpp | 50 ++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/CP_SDK/Unity/FontManager.cpp b/src/CP_SDK/Unity/FontManager.cpp index 0b06c0a..c331d0a 100644 --- a/src/CP_SDK/Unity/FontManager.cpp +++ b/src/CP_SDK/Unity/FontManager.cpp @@ -9,6 +9,41 @@ using namespace TMPro; using namespace UnityEngine; +/// Temp fix from BSML until libunity is properly unstripped + #include + #include + #include + #include + #include + + bool TryGetSoloButton(UnityEngine::UI::Button*& p_Button) + { + static SafePtrUnity g_SoloButton; + if(!g_SoloButton) + { + auto l_MainMenuViewController = UnityEngine::Resources::FindObjectsOfTypeAll()->First(); + g_SoloButton = l_MainMenuViewController->____soloButton; + } + + p_Button = g_SoloButton.ptr(); + return g_SoloButton; + } + bool TryGetUITextTemplate(TMPro::TextMeshProUGUI*& p_TextMeshProUGUI) + { + UnityEngine::UI::Button* l_SoloButton; + if (!TryGetSoloButton(l_SoloButton)) + { + p_TextMeshProUGUI = nullptr; + return false; + } + auto l_Transform = l_SoloButton->get_transform(); + auto l_Text = l_Transform->Find("Text"); + + p_TextMeshProUGUI = l_Text->GetComponent(); + return p_TextMeshProUGUI; + } +/// End of temp fix + namespace CP_SDK::Unity { bool FontManager::m_IsInitialized = false; @@ -33,6 +68,8 @@ namespace CP_SDK::Unity { { ChatPlexSDK::Logger()->Error(u"[CP_SDK.Unity][FontManager.Init] Loading font asset bundle..."); + /// Temp disable until libunity is properly unstripped + /* static auto s_LoadFromMemory = reinterpret_cast(il2cpp_functions::resolve_icall("UnityEngine.AssetBundle::LoadFromMemory_Internal")); m_AssetBundle = s_LoadFromMemory(Assets::QuestFonts_bundle, 0); @@ -43,6 +80,7 @@ namespace CP_SDK::Unity { } Object::DontDestroyOnLoad(m_AssetBundle.Ptr()); + */ ChatPlexSDK::Logger()->Info(u"[CP_SDK.Unity][FontManager.Init] Font asset bundle loaded"); m_IsInitialized = true; @@ -59,19 +97,31 @@ namespace CP_SDK::Unity { if (!m_MainFont) { + /// Temp fix from BSML until libunity is properly unstripped + TMPro::TextMeshProUGUI* p_TextMeshProUGUI; + if (TryGetUITextTemplate(p_TextMeshProUGUI)) + m_MainFont = p_TextMeshProUGUI->get_font(); + /// End of temp fix + + /// Temp disable until libunity is properly unstripped + /* if (!m_BundleMainFont) m_BundleMainFont = m_AssetBundle->LoadAsset("[CP_SDK]segoeui SDF Main"); m_MainFont = m_BundleMainFont; + */ if (m_TMPFontAssetSetup.IsValid()) m_MainFont = m_TMPFontAssetSetup(m_MainFont.Ptr()); + /// Temp disable until libunity is properly unstripped + /* m_MainFont->___normalStyle = 0.5f; m_MainFont->___normalSpacingOffset = -1.0f; m_MainFont->___boldStyle = 2.0f; m_MainFont->___boldSpacing = 2.0f; m_MainFont->___italicStyle = 15; + */ } return m_MainFont.Ptr(); From 7edf8402c355b23b53532e5eea088064892f2770 Mon Sep 17 00:00:00 2001 From: HardCPP Date: Thu, 22 Aug 2024 22:59:34 +0200 Subject: [PATCH 10/35] UI: Flix Dropdown / Slider / TextInput disabled style --- shared/CP_SDK/UI/UISystem.hpp | 1 + src/CP_SDK/UI/DefaultComponents/DefaultCDropdown.cpp | 2 +- src/CP_SDK/UI/DefaultComponents/DefaultCSlider.cpp | 2 ++ src/CP_SDK/UI/DefaultComponents/DefaultCTextInput.cpp | 2 +- src/CP_SDK/UI/UISystem.cpp | 1 + 5 files changed, 6 insertions(+), 2 deletions(-) diff --git a/shared/CP_SDK/UI/UISystem.hpp b/shared/CP_SDK/UI/UISystem.hpp index bb909e4..7ad66ba 100644 --- a/shared/CP_SDK/UI/UISystem.hpp +++ b/shared/CP_SDK/UI/UISystem.hpp @@ -105,6 +105,7 @@ namespace CP_SDK::UI { static _u::Color TooltipBGColor; static _u::Color TextColor; + static _u::Color TextColorDisabled; public: static SafePtr<_u::Type> Override_UnityComponent_Image; diff --git a/src/CP_SDK/UI/DefaultComponents/DefaultCDropdown.cpp b/src/CP_SDK/UI/DefaultComponents/DefaultCDropdown.cpp index 8855826..8b5c883 100644 --- a/src/CP_SDK/UI/DefaultComponents/DefaultCDropdown.cpp +++ b/src/CP_SDK/UI/DefaultComponents/DefaultCDropdown.cpp @@ -146,7 +146,7 @@ namespace CP_SDK::UI::DefaultComponents { { m_Button->set_interactable(p_Interactable); - m_ValueText->SetColor(p_Interactable ? UISystem::PrimaryColor : UISystem::SecondaryColor); + m_ValueText->SetColor(p_Interactable ? UISystem::TextColor : UISystem::TextColorDisabled); m_Icon->SetInteractable(p_Interactable); } /// @brief Set available options diff --git a/src/CP_SDK/UI/DefaultComponents/DefaultCSlider.cpp b/src/CP_SDK/UI/DefaultComponents/DefaultCSlider.cpp index 82d2eab..0911149 100644 --- a/src/CP_SDK/UI/DefaultComponents/DefaultCSlider.cpp +++ b/src/CP_SDK/UI/DefaultComponents/DefaultCSlider.cpp @@ -552,6 +552,8 @@ namespace CP_SDK::UI::DefaultComponents { m_IncButton->SetInteractable(l_IsInteractable); m_BG->set_color(ColorU::WithAlpha(l_IsInteractable ? m_OnColor : m_OffColor, l_IsInteractable ? 110.0f / 255.0f : 50.0f / 255.0f)); } + + m_ValueText->SetColor(l_IsInteractable ? UISystem::TextColor : UISystem::TextColorDisabled); } /// @brief Update visuals void DefaultCSlider::UpdateVisuals() diff --git a/src/CP_SDK/UI/DefaultComponents/DefaultCTextInput.cpp b/src/CP_SDK/UI/DefaultComponents/DefaultCTextInput.cpp index bb08752..c9c4bee 100644 --- a/src/CP_SDK/UI/DefaultComponents/DefaultCTextInput.cpp +++ b/src/CP_SDK/UI/DefaultComponents/DefaultCTextInput.cpp @@ -140,7 +140,7 @@ namespace CP_SDK::UI::DefaultComponents { { m_Button->set_interactable(p_Interactable); - m_ValueText->SetColor(ColorU::WithAlpha(Color::get_white(), p_Interactable ? 1.0f : 0.5f)); + m_ValueText->SetColor(p_Interactable ? UISystem::TextColor : UISystem::TextColorDisabled); m_Icon->SetColor(ColorU::WithAlpha(Color::get_white(), p_Interactable ? 1.0f : 0.5f)); } /// @brief Set is password diff --git a/src/CP_SDK/UI/UISystem.cpp b/src/CP_SDK/UI/UISystem.cpp index 19c8e03..e56fc2a 100644 --- a/src/CP_SDK/UI/UISystem.cpp +++ b/src/CP_SDK/UI/UISystem.cpp @@ -105,6 +105,7 @@ namespace CP_SDK::UI { Color UISystem::TooltipBGColor = ColorU::WithAlpha("#3A3A3B", 0.9875f); Color UISystem::TextColor = ColorU::WithAlpha("#FFFFFF", 1.0000f); + Color UISystem::TextColorDisabled = Color::op_Multiply(TextColor, 0.75f); //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// From e6aa730952d133c4c1c1307329446be3e4aeafea Mon Sep 17 00:00:00 2001 From: HardCPP Date: Thu, 22 Aug 2024 23:08:22 +0200 Subject: [PATCH 11/35] Implement a proxy for Application::OpenURL --- shared/CP_SDK/ChatPlexSDK.hpp | 5 +++++ src/CP_SDK/ChatPlexSDK.cpp | 14 ++++++++++++++ src/CP_SDK/UI/DefaultComponents/DefaultCSlider.cpp | 6 +++--- src/CP_SDK/UI/Views/MainLeftView.cpp | 8 +++----- src/CP_SDK/UI/Views/SettingsMainView.cpp | 4 +--- 5 files changed, 26 insertions(+), 11 deletions(-) diff --git a/shared/CP_SDK/ChatPlexSDK.hpp b/shared/CP_SDK/ChatPlexSDK.hpp index 896f480..c616b61 100644 --- a/shared/CP_SDK/ChatPlexSDK.hpp +++ b/shared/CP_SDK/ChatPlexSDK.hpp @@ -71,6 +71,11 @@ namespace CP_SDK { /// @return Const reference of a list containing the modules static const std::vector & GetModules() { return m_Modules; } + public: + /// @brief Open an URL on the system + /// @param p_URL URL to open + static void OpenURL(std::u16string_view p_URL); + public: /// @brief On generic menu scene static void Fire_OnGenericMenuSceneLoaded(); diff --git a/src/CP_SDK/ChatPlexSDK.cpp b/src/CP_SDK/ChatPlexSDK.cpp index ad3b98f..6baed2f 100644 --- a/src/CP_SDK/ChatPlexSDK.cpp +++ b/src/CP_SDK/ChatPlexSDK.cpp @@ -10,6 +10,8 @@ #include "CP_SDK/Unity/MTThreadInvoker.hpp" #include "CP_SDK/ModuleBase.hpp" +#include + namespace CP_SDK { Logging::ILogger* ChatPlexSDK::m_Logger = nullptr; @@ -173,6 +175,18 @@ namespace CP_SDK { //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// + /// @brief Open an URL on the system + /// @param p_URL URL to open + void ChatPlexSDK::OpenURL(std::u16string_view p_URL) + { + static auto s_Application_OpenURL = il2cpp_utils::resolve_icall("UnityEngine.Application::OpenURL"); + if (s_Application_OpenURL) + s_Application_OpenURL(p_URL); + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + /// @brief On generic menu scene void ChatPlexSDK::Fire_OnGenericMenuSceneLoaded() { diff --git a/src/CP_SDK/UI/DefaultComponents/DefaultCSlider.cpp b/src/CP_SDK/UI/DefaultComponents/DefaultCSlider.cpp index 0911149..3fedd0b 100644 --- a/src/CP_SDK/UI/DefaultComponents/DefaultCSlider.cpp +++ b/src/CP_SDK/UI/DefaultComponents/DefaultCSlider.cpp @@ -424,10 +424,10 @@ namespace CP_SDK::UI::DefaultComponents { void DefaultCSlider::UpdateDrag(PointerEventData* p_EventData) { Vector2 l_LocalPoint; - if (p_EventData->button != PointerEventData::InputButton::Left + if (p_EventData->get_button() != PointerEventData::InputButton::Left || !m_SlidingArea - || p_EventData->hovered->get_Count() == 0 - || !RectTransformUtility::ScreenPointToLocalPointInRectangle(m_SlidingArea.Ptr(), p_EventData->position, p_EventData->get_pressEventCamera(), /*OUT*/l_LocalPoint) + || p_EventData->___hovered->get_Count() == 0 + || !RectTransformUtility::ScreenPointToLocalPointInRectangle(m_SlidingArea.Ptr(), p_EventData->get_position(), p_EventData->get_pressEventCamera(), /*OUT*/l_LocalPoint) || std::isnan(l_LocalPoint.x) || std::isnan(l_LocalPoint.y)) return; diff --git a/src/CP_SDK/UI/Views/MainLeftView.cpp b/src/CP_SDK/UI/Views/MainLeftView.cpp index b15559d..5f33e14 100644 --- a/src/CP_SDK/UI/Views/MainLeftView.cpp +++ b/src/CP_SDK/UI/Views/MainLeftView.cpp @@ -2,8 +2,6 @@ #include "CP_SDK/UI/FlowCoordinators/MainFlowCoordinator.hpp" #include "CP_SDK/Unity/SpriteU.hpp" -#include - using namespace CP_SDK::XUI; using namespace UnityEngine; @@ -59,13 +57,13 @@ namespace CP_SDK::UI::Views { void MainLeftView::OnDocumentationButton() { ShowMessageModal(u"URL opened in your web browser."); - Application::OpenURL("https://github.com/hardcpp/BeatSaberPlus/wiki"); + ChatPlexSDK::OpenURL(u"https://github.com/hardcpp/BeatSaberPlus/wiki"); } /// @brief Go to discord void MainLeftView::OnDiscordButton() { ShowMessageModal(u"URL opened in your web browser."); - Application::OpenURL("https://discord.chatplex.org"); + ChatPlexSDK::OpenURL(u"https://discord.chatplex.org"); } //////////////////////////////////////////////////////////////////////////// @@ -75,7 +73,7 @@ namespace CP_SDK::UI::Views { void MainLeftView::OnDonateButton() { ShowMessageModal(u"URL opened in your web browser."); - Application::OpenURL("https://donate.chatplex.org"); + ChatPlexSDK::OpenURL(u"https://donate.chatplex.org"); } } ///< namespace CP_SDK::UI::Views \ No newline at end of file diff --git a/src/CP_SDK/UI/Views/SettingsMainView.cpp b/src/CP_SDK/UI/Views/SettingsMainView.cpp index 795e5d1..2460d59 100644 --- a/src/CP_SDK/UI/Views/SettingsMainView.cpp +++ b/src/CP_SDK/UI/Views/SettingsMainView.cpp @@ -5,8 +5,6 @@ #include "CP_SDK/CPConfig.hpp" #include "CP_SDK/ModuleBase.hpp" -#include - using namespace CP_SDK::XUI; using namespace UnityEngine; @@ -163,7 +161,7 @@ namespace CP_SDK::UI::Views { void SettingsMainView::OnDocumentationButton(IModuleBase* p_Module) { ShowMessageModal(u"URL opened in your web browser."); - Application::OpenURL(p_Module->DocumentationURL()); + ChatPlexSDK::OpenURL(p_Module->DocumentationURL()); } //////////////////////////////////////////////////////////////////////////// From c593a3cfd04281d24c796be35630a7cdb24af23f Mon Sep 17 00:00:00 2001 From: HardCPP Date: Thu, 22 Aug 2024 23:20:58 +0200 Subject: [PATCH 12/35] Bump version 6.3.2 --- .vscode/settings.json | 3 +- mod.json | 20 +++++------ qpm.json | 2 +- qpm.shared.json | 77 ++++++++++++++++++++++--------------------- 4 files changed, 52 insertions(+), 50 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 17a6f4e..7e40a45 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -124,7 +124,8 @@ "__std_stream": "cpp", "memory_resource": "cpp", "ranges": "cpp", - "__verbose_abort": "cpp" + "__verbose_abort": "cpp", + "numbers": "cpp" }, "editor.formatOnSave": false, "editor.trimAutoWhitespace": true, diff --git a/mod.json b/mod.json index f814e01..f66b260 100644 --- a/mod.json +++ b/mod.json @@ -4,31 +4,31 @@ "id": "chatplex-sdk-bs", "modloader": "Scotland2", "author": "HardCPP", - "version": "6.3.1", + "version": "6.3.2", "packageId": "com.beatgames.beatsaber", - "packageVersion": "1.35.0_8016709773", + "packageVersion": "1.37.0_9064817954", "description": "ChatPlex BeatSaber modding SDK (Dependence for other mods)", "coverImage": "cover.png", "dependencies": [ { - "version": "^0.17.6", + "version": "^0.17.8", "id": "custom-types", - "downloadIfMissing": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.17.8/CustomTypes.qmod" + "downloadIfMissing": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.17.10/CustomTypes.qmod" }, { - "version": "^0.4.20", + "version": "^0.4.34", "id": "bsml", - "downloadIfMissing": "https://github.com/RedBrumbler/Quest-BSML/releases/download/v0.4.41/BSML.qmod" + "downloadIfMissing": "https://github.com/RedBrumbler/Quest-BSML/releases/download/v0.4.43/BSML.qmod" }, { - "version": "^1.1.9", + "version": "^1.1.12", "id": "songcore", - "downloadIfMissing": "https://github.com/raineio/Quest-SongCore/releases/download/v1.1.9/SongCore.qmod" + "downloadIfMissing": "https://github.com/raineio/Quest-SongCore/releases/download/v1.1.15/SongCore.qmod" }, { "version": "^3.6.3", "id": "paper", - "downloadIfMissing": "https://github.com/Fernthedev/paperlog/releases/download/v3.6.3/paperlog.qmod" + "downloadIfMissing": "https://github.com/Fernthedev/paperlog/releases/download/v3.6.4/paperlog.qmod" } ], "modFiles": [], @@ -36,7 +36,7 @@ "libchatplex-sdk-bs.so" ], "libraryFiles": [ - "libbeatsaber-hook_5_1_7.so" + "libbeatsaber-hook_5_1_9.so" ], "fileCopies": [], "copyExtensions": [] diff --git a/qpm.json b/qpm.json index 55d779a..b96c1d0 100644 --- a/qpm.json +++ b/qpm.json @@ -5,7 +5,7 @@ "info": { "name": "ChatPlexSDK-BS", "id": "chatplex-sdk-bs", - "version": "6.3.1", + "version": "6.3.2", "url": "https://github.com/hardcpp/QuestChatPlexSDK-BS", "additionalData": { "overrideSoName": "libchatplex-sdk-bs.so", diff --git a/qpm.shared.json b/qpm.shared.json index 65485f0..b6ff0ad 100644 --- a/qpm.shared.json +++ b/qpm.shared.json @@ -6,7 +6,7 @@ "info": { "name": "ChatPlexSDK-BS", "id": "chatplex-sdk-bs", - "version": "6.3.1", + "version": "6.3.2", "url": "https://github.com/hardcpp/QuestChatPlexSDK-BS", "additionalData": { "overrideSoName": "libchatplex-sdk-bs.so", @@ -44,17 +44,17 @@ "dependencies": [ { "id": "beatsaber-hook", - "versionRange": "^5.1.6", + "versionRange": "^5.1.9", "additionalData": {} }, { "id": "bs-cordl", - "versionRange": "^3500.0.0", + "versionRange": "3700.*", "additionalData": {} }, { "id": "custom-types", - "versionRange": "^0.17.6", + "versionRange": "^0.17.8", "additionalData": {} }, { @@ -67,7 +67,7 @@ }, { "id": "bsml", - "versionRange": "^0.4.20", + "versionRange": "^0.4.34", "additionalData": { "private": true } @@ -79,7 +79,7 @@ }, { "id": "songcore", - "versionRange": "^1.1.9", + "versionRange": "^1.1.12", "additionalData": { "private": true } @@ -107,13 +107,13 @@ { "dependency": { "id": "paper", - "versionRange": "=3.6.3", + "versionRange": "=3.6.4", "additionalData": { - "soLink": "https://github.com/Fernthedev/paperlog/releases/download/v3.6.3/libpaperlog.so", - "debugSoLink": "https://github.com/Fernthedev/paperlog/releases/download/v3.6.3/debug_libpaperlog.so", + "soLink": "https://github.com/Fernthedev/paperlog/releases/download/v3.6.4/libpaperlog.so", + "debugSoLink": "https://github.com/Fernthedev/paperlog/releases/download/v3.6.4/debug_libpaperlog.so", "overrideSoName": "libpaperlog.so", - "modLink": "https://github.com/Fernthedev/paperlog/releases/download/v3.6.3/paperlog.qmod", - "branchName": "version/v3_6_3", + "modLink": "https://github.com/Fernthedev/paperlog/releases/download/v3.6.4/paperlog.qmod", + "branchName": "version/v3_6_4", "compileOptions": { "systemIncludes": [ "shared/utfcpp/source" @@ -122,7 +122,7 @@ "cmake": false } }, - "version": "3.6.3" + "version": "3.6.4" }, { "dependency": { @@ -138,28 +138,28 @@ { "dependency": { "id": "bsml", - "versionRange": "=0.4.41", + "versionRange": "=0.4.43", "additionalData": { - "soLink": "https://github.com/RedBrumbler/Quest-BSML/releases/download/v0.4.41/libbsml.so", - "debugSoLink": "https://github.com/RedBrumbler/Quest-BSML/releases/download/v0.4.41/debug_libbsml.so", + "soLink": "https://github.com/RedBrumbler/Quest-BSML/releases/download/v0.4.43/libbsml.so", + "debugSoLink": "https://github.com/RedBrumbler/Quest-BSML/releases/download/v0.4.43/debug_libbsml.so", "overrideSoName": "libbsml.so", - "modLink": "https://github.com/RedBrumbler/Quest-BSML/releases/download/v0.4.41/BSML.qmod", - "branchName": "version/v0_4_41", + "modLink": "https://github.com/RedBrumbler/Quest-BSML/releases/download/v0.4.43/BSML.qmod", + "branchName": "version/v0_4_43", "cmake": true } }, - "version": "0.4.41" + "version": "0.4.43" }, { "dependency": { "id": "custom-types", - "versionRange": "=0.17.8", + "versionRange": "=0.17.10", "additionalData": { - "soLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.17.8/libcustom-types.so", - "debugSoLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.17.8/debug_libcustom-types.so", + "soLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.17.10/libcustom-types.so", + "debugSoLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.17.10/debug_libcustom-types.so", "overrideSoName": "libcustom-types.so", - "modLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.17.8/CustomTypes.qmod", - "branchName": "version/v0_17_8", + "modLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.17.10/CustomTypes.qmod", + "branchName": "version/v0_17_10", "compileOptions": { "cppFlags": [ "-Wno-invalid-offsetof" @@ -168,7 +168,7 @@ "cmake": true } }, - "version": "0.17.8" + "version": "0.17.10" }, { "dependency": { @@ -190,10 +190,10 @@ { "dependency": { "id": "bs-cordl", - "versionRange": "=3500.0.0", + "versionRange": "=3700.0.0", "additionalData": { "headersOnly": true, - "branchName": "version/v3500_0_0", + "branchName": "version/v3700_0_0", "compileOptions": { "includePaths": [ "include" @@ -208,7 +208,7 @@ } } }, - "version": "3500.0.0" + "version": "3700.0.0" }, { "dependency": { @@ -225,29 +225,30 @@ { "dependency": { "id": "songcore", - "versionRange": "=1.1.9", + "versionRange": "=1.1.15", "additionalData": { - "soLink": "https://github.com/raineio/Quest-SongCore/releases/download/v1.1.9/libsongcore.so", - "debugSoLink": "https://github.com/raineio/Quest-SongCore/releases/download/v1.1.9/debug_libsongcore.so", + "soLink": "https://github.com/raineio/Quest-SongCore/releases/download/v1.1.15/libsongcore.so", + "debugSoLink": "https://github.com/raineio/Quest-SongCore/releases/download/v1.1.15/debug_libsongcore.so", "overrideSoName": "libsongcore.so", - "modLink": "https://github.com/raineio/Quest-SongCore/releases/download/v1.1.9/SongCore.qmod", - "branchName": "version/v1_1_9" + "modLink": "https://github.com/raineio/Quest-SongCore/releases/download/v1.1.15/SongCore.qmod", + "branchName": "version/v1_1_15", + "cmake": true } }, - "version": "1.1.9" + "version": "1.1.15" }, { "dependency": { "id": "beatsaber-hook", - "versionRange": "=5.1.7", + "versionRange": "=5.1.9", "additionalData": { - "soLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v5.1.7/libbeatsaber-hook_5_1_7.so", - "debugSoLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v5.1.7/debug_libbeatsaber-hook_5_1_7.so", - "branchName": "version/v5_1_7", + "soLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v5.1.9/libbeatsaber-hook_5_1_9.so", + "debugSoLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v5.1.9/debug_libbeatsaber-hook_5_1_9.so", + "branchName": "version/v5_1_9", "cmake": true } }, - "version": "5.1.7" + "version": "5.1.9" }, { "dependency": { From e9685e5651d64a250c1d054f0319bee36f871bf0 Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 7 May 2025 12:33:59 +0200 Subject: [PATCH 13/35] 6.4.0 WIP --- .gitignore | 3 +- CMakeLists.txt | 150 +++++++-------- include/git_info.h | 5 + mod.json | 36 ++-- mod.template.json | 4 +- qpm.json | 31 +-- qpm.shared.json | 180 ++++++++++-------- .../Animation/AnimationControllerInstance.hpp | 2 +- .../Animation/AnimationControllerManager.hpp | 2 +- shared/CP_SDK/Animation/AnimationInfo.hpp | 2 +- shared/CP_SDK/Animation/AnimationLoader.hpp | 2 +- shared/CP_SDK/Animation/WEBP/WEBPDecoder.hpp | 2 +- shared/CP_SDK/BuildConfig.hpp | 3 + shared/CP_SDK/CPConfig.hpp | 2 +- shared/CP_SDK/Chat/Service.hpp | 2 +- shared/CP_SDK/ChatPlexSDK.hpp | 2 +- shared/CP_SDK/Config/JsonConfig.hpp | 2 +- shared/CP_SDK/Logging/ILogger.hpp | 6 +- shared/CP_SDK/Logging/PaperLogger.hpp | 4 +- shared/CP_SDK/Misc/FastCancellationToken.hpp | 2 +- shared/CP_SDK/Misc/Time.hpp | 2 +- shared/CP_SDK/ModuleBase.hpp | 2 +- shared/CP_SDK/Network/WebClientUnity.hpp | 2 +- shared/CP_SDK/Network/WebContent.hpp | 2 +- shared/CP_SDK/Network/WebResponse.hpp | 2 +- shared/CP_SDK/UI/Components/CColorInput.hpp | 2 +- shared/CP_SDK/UI/Components/CDropdown.hpp | 2 +- shared/CP_SDK/UI/Components/CFLayout.hpp | 2 +- .../CP_SDK/UI/Components/CFloatingPanel.hpp | 2 +- shared/CP_SDK/UI/Components/CGLayout.hpp | 2 +- shared/CP_SDK/UI/Components/CHLayout.hpp | 2 +- shared/CP_SDK/UI/Components/CIconButton.hpp | 2 +- shared/CP_SDK/UI/Components/CImage.hpp | 2 +- .../CP_SDK/UI/Components/CPrimaryButton.hpp | 2 +- .../CP_SDK/UI/Components/CSecondaryButton.hpp | 2 +- shared/CP_SDK/UI/Components/CSlider.hpp | 2 +- shared/CP_SDK/UI/Components/CTabControl.hpp | 2 +- shared/CP_SDK/UI/Components/CText.hpp | 2 +- shared/CP_SDK/UI/Components/CTextInput.hpp | 2 +- .../UI/Components/CTextSegmentedControl.hpp | 2 +- shared/CP_SDK/UI/Components/CToggle.hpp | 2 +- shared/CP_SDK/UI/Components/CVLayout.hpp | 2 +- shared/CP_SDK/UI/Components/CVScrollView.hpp | 2 +- shared/CP_SDK/UI/Components/CVVList.hpp | 2 +- .../UI/Components/Generics/CHOrVLayout.hpp | 2 +- .../UI/Components/Generics/CPOrSButton.hpp | 2 +- .../CP_SDK/UI/Components/Generics/CVXList.hpp | 2 +- shared/CP_SDK/UI/Data/IListCell.hpp | 2 +- shared/CP_SDK/UI/Data/IListItem.hpp | 2 +- shared/CP_SDK/UI/Data/ListCellPrefabs.hpp | 2 +- shared/CP_SDK/UI/Data/TextListCell.hpp | 2 +- shared/CP_SDK/UI/Data/TextListItem.hpp | 2 +- .../DefaultComponents/DefaultCColorInput.hpp | 2 +- .../UI/DefaultComponents/DefaultCDropdown.hpp | 2 +- .../UI/DefaultComponents/DefaultCFLayout.hpp | 2 +- .../DefaultCFloatingPanel.hpp | 2 +- .../UI/DefaultComponents/DefaultCGLayout.hpp | 2 +- .../UI/DefaultComponents/DefaultCHLayout.hpp | 2 +- .../DefaultComponents/DefaultCIconButton.hpp | 2 +- .../UI/DefaultComponents/DefaultCImage.hpp | 2 +- .../DefaultCPrimaryButton.hpp | 2 +- .../DefaultCSecondaryButton.hpp | 2 +- .../UI/DefaultComponents/DefaultCSlider.hpp | 2 +- .../DefaultComponents/DefaultCTabControl.hpp | 2 +- .../UI/DefaultComponents/DefaultCText.hpp | 2 +- .../DefaultComponents/DefaultCTextInput.hpp | 2 +- .../DefaultCTextSegmentedControl.hpp | 2 +- .../UI/DefaultComponents/DefaultCToggle.hpp | 2 +- .../UI/DefaultComponents/DefaultCVLayout.hpp | 2 +- .../DefaultComponents/DefaultCVScrollView.hpp | 2 +- .../UI/DefaultComponents/DefaultCVVList.hpp | 2 +- .../Subs/SubStackLayoutGroup.hpp | 2 +- .../Subs/SubToggleWithCallbacks.hpp | 2 +- .../Subs/SubVScrollIndicator.hpp | 2 +- .../Subs/SubVScrollViewContent.hpp | 2 +- .../DefaultColorInputFactory.hpp | 2 +- .../DefaultDropdownFactory.hpp | 2 +- .../DefaultFLayoutFactory.hpp | 2 +- .../DefaultFloatingPanelFactory.hpp | 2 +- .../DefaultGLayoutFactory.hpp | 2 +- .../DefaultHLayoutFactory.hpp | 2 +- .../DefaultIconButtonFactory.hpp | 2 +- .../DefaultFactories/DefaultImageFactory.hpp | 2 +- .../DefaultPrimaryButtonFactory.hpp | 2 +- .../DefaultSecondaryButtonFactory.hpp | 2 +- .../DefaultFactories/DefaultSliderFactory.hpp | 2 +- .../DefaultTabControlFactory.hpp | 2 +- .../DefaultFactories/DefaultTextFactory.hpp | 2 +- .../DefaultTextInputFactory.hpp | 2 +- .../DefaultTextSegmentedControlFactory.hpp | 2 +- .../DefaultFactories/DefaultToggleFactory.hpp | 2 +- .../DefaultVLayoutFactory.hpp | 2 +- .../DefaultVScrollViewFactory.hpp | 2 +- .../DefaultFactories/DefaultVVListFactory.hpp | 2 +- shared/CP_SDK/UI/FlowCoordinator.hpp | 2 +- .../FlowCoordinators/MainFlowCoordinator.hpp | 2 +- shared/CP_SDK/UI/IFlowCoordinator.hpp | 2 +- shared/CP_SDK/UI/IModal.hpp | 2 +- shared/CP_SDK/UI/IScreen.hpp | 2 +- shared/CP_SDK/UI/IViewController.hpp | 2 +- shared/CP_SDK/UI/LoadingProgressBar.hpp | 2 +- shared/CP_SDK/UI/ModButton.hpp | 2 +- shared/CP_SDK/UI/ModMenu.hpp | 2 +- shared/CP_SDK/UI/Modals/ColorPicker.hpp | 2 +- shared/CP_SDK/UI/Modals/Confirmation.hpp | 2 +- shared/CP_SDK/UI/Modals/Dropdown.hpp | 2 +- shared/CP_SDK/UI/Modals/Keyboard.hpp | 2 +- shared/CP_SDK/UI/Modals/Loading.hpp | 2 +- shared/CP_SDK/UI/Modals/Message.hpp | 2 +- shared/CP_SDK/UI/ScreenSystem.hpp | 2 +- shared/CP_SDK/UI/Tooltip.hpp | 2 +- shared/CP_SDK/UI/UISystem.hpp | 2 +- shared/CP_SDK/UI/ValueFormatters.hpp | 3 +- shared/CP_SDK/UI/ViewController.hpp | 2 +- shared/CP_SDK/UI/Views/MainLeftView.hpp | 2 +- shared/CP_SDK/UI/Views/MainMainView.hpp | 2 +- shared/CP_SDK/UI/Views/MainRightView.hpp | 2 +- shared/CP_SDK/UI/Views/ModMenuView.hpp | 2 +- shared/CP_SDK/UI/Views/SettingsLeftView.hpp | 2 +- shared/CP_SDK/UI/Views/SettingsMainView.hpp | 2 +- shared/CP_SDK/UI/Views/SettingsRightView.hpp | 2 +- shared/CP_SDK/UI/Views/TopNavigationView.hpp | 2 +- shared/CP_SDK/Unity/EnhancedImage.hpp | 2 +- shared/CP_SDK/Unity/Extensions/ColorU.hpp | 2 +- .../CP_SDK/Unity/Extensions/GameObjectU.hpp | 2 +- shared/CP_SDK/Unity/FontManager.hpp | 2 +- shared/CP_SDK/Unity/MTCoroutineStarter.hpp | 2 +- shared/CP_SDK/Unity/MTMainThreadInvoker.hpp | 2 +- shared/CP_SDK/Unity/MTThreadInvoker.hpp | 2 +- shared/CP_SDK/Unity/MonoPtrHolder.hpp | 2 +- shared/CP_SDK/Unity/SpriteU.hpp | 2 +- shared/CP_SDK/Unity/Texture2DU.hpp | 2 +- shared/CP_SDK/Unity/TextureRaw.hpp | 2 +- shared/CP_SDK/Utils/Il2cpp.hpp | 8 +- .../CP_SDK/Utils/Internals/Il2cpp_string.hpp | 10 +- shared/CP_SDK/Utils/Json.hpp | 2 +- shared/CP_SDK/XUI/Templates.hpp | 2 +- shared/CP_SDK_BS/Game/BeatMaps/MapDetail.hpp | 2 +- shared/CP_SDK_BS/Game/BeatMapsClient.hpp | 2 +- shared/CP_SDK_BS/Game/LevelCompletionData.hpp | 2 +- shared/CP_SDK_BS/Game/LevelData.hpp | 2 +- shared/CP_SDK_BS/Game/LevelSelection.hpp | 2 +- shared/CP_SDK_BS/Game/Levels.hpp | 2 +- shared/CP_SDK_BS/Game/Logic.hpp | 10 +- ...issionLevelScenesTransitionSetupDataSO.hpp | 20 -- shared/CP_SDK_BS/Game/PlayerAvatarPicture.hpp | 2 +- shared/CP_SDK_BS/Game/Scoring.hpp | 2 +- shared/CP_SDK_BS/Game/UserPlatform.hpp | 2 +- .../Subs/SubFloatingPanelMover.hpp | 2 +- .../Subs/SubFloatingPanelMoverHandle.hpp | 2 +- .../BS_FloatingPanelFactory.hpp | 2 +- shared/CP_SDK_BS/UI/GameFont.hpp | 2 +- .../CP_SDK_BS/UI/HMUIIconSegmentedControl.hpp | 7 +- .../CP_SDK_BS/UI/HMUITextSegmentedControl.hpp | 6 +- shared/CP_SDK_BS/UI/HMUIUIUtils.hpp | 2 +- .../CP_SDK_BS/UI/HMUIViewFlowCoordinator.hpp | 2 +- shared/CP_SDK_BS/UI/LevelDetail.hpp | 6 +- shared/CP_SDK_BS/UI/Patches/PVRPointer.hpp | 2 +- shared/CP_SDK_BS/UI/ViewController.hpp | 2 +- .../DefaultCFloatingPanel.cpp | 2 + src/CP_SDK/UI/Tooltip.cpp | 4 +- src/CP_SDK/UI/ValueFormatters.cpp | 9 + src/CP_SDK_BS/Game/LevelData.cpp | 17 +- src/CP_SDK_BS/Game/LevelSelection.cpp | 22 ++- src/CP_SDK_BS/Game/Levels.cpp | 43 ++++- src/CP_SDK_BS/Game/Logic.cpp | 13 +- ...issionLevelScenesTransitionSetupDataSO.cpp | 101 ---------- .../Subs/SubFloatingPanelMover.cpp | 4 +- src/CP_SDK_BS/UI/HMUIIconSegmentedControl.cpp | 9 + src/CP_SDK_BS/UI/HMUITextSegmentedControl.cpp | 11 +- src/CP_SDK_BS/UI/LevelDetail.cpp | 19 +- src/main.cpp | 6 +- start-logging.ps1 | 2 +- 173 files changed, 532 insertions(+), 504 deletions(-) create mode 100644 include/git_info.h create mode 100644 shared/CP_SDK/BuildConfig.hpp delete mode 100644 shared/CP_SDK_BS/Game/Patches/PMissionLevelScenesTransitionSetupDataSO.hpp delete mode 100644 src/CP_SDK_BS/Game/Patches/PMissionLevelScenesTransitionSetupDataSO.cpp diff --git a/.gitignore b/.gitignore index 1537357..61cccbb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .vs/ +.cache/ # Prerequisites *.d @@ -67,4 +68,4 @@ extern.cmake # QMOD Schema mod.json.schema -doxygen-build/ +doxygen-build/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b4888e..bc3260a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,12 +1,13 @@ # include some defines automatically made by qpm include(qpm_defines.cmake) -include(${EXTERN_DIR}/includes/kaleb/shared/cmake/assets.cmake) -add_definitions(-DCP_SDK_BMBF) -add_definitions(-DDEBUG_SCENES) +cmake_minimum_required(VERSION 3.22) +project(${COMPILE_ID}) +include(${EXTERN_DIR}/includes/kaleb/shared/cmake/assets.cmake) -# override mod id -set(MOD_ID "ChatPlexSDK-BS") +# c++ standard +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED 20) # Enable link time optimization # In my experience, this can be highly unstable but it nets a huge size optimization and likely performance @@ -14,25 +15,16 @@ set(MOD_ID "ChatPlexSDK-BS") # As always, test thoroughly # - Fern # set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) - -cmake_minimum_required(VERSION 3.21) -project(${COMPILE_ID}) - # export compile commands for significantly better intellisense set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -# c++ standard -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED 20) - # define that stores the actual source directory set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) set(INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) set(SHARED_DIR ${CMAKE_CURRENT_SOURCE_DIR}/shared) # compile options used -add_compile_options(-frtti -fexceptions) -add_compile_options(-O3) +add_compile_options(-frtti -fPIE -fPIC -fexceptions -fdeclspec -fvisibility=hidden -Wno-extra-qualification -O3) # get git info execute_process(COMMAND git config user.name OUTPUT_VARIABLE GIT_USER) @@ -50,70 +42,74 @@ message(STATUS "GIT_BRANCH: ${GIT_BRANCH}") message(STATUS "GIT_COMMIT: 0x${GIT_COMMIT}") message(STATUS "GIT_MODIFIED: ${GIT_MODIFIED}") -# set git defines -add_compile_definitions(GIT_USER=\"${GIT_USER}\") -add_compile_definitions(GIT_BRANCH=\"${GIT_BRANCH}\") -add_compile_definitions(GIT_COMMIT=0x${GIT_COMMIT}) -add_compile_definitions(GIT_MODIFIED=${GIT_MODIFIED}) + +# Check for file presence and read current contents +set(GIT_INFO_H_PATH "${CMAKE_CURRENT_SOURCE_DIR}/include/git_info.h") +if(EXISTS "${GIT_INFO_H_PATH}") + file(READ "${GIT_INFO_H_PATH}" GIT_INFO_H_CURRENT) +else() + set(GIT_INFO_H_CURRENT "") +endif() + +# Define new git info content +set(GIT_INFO_H "#pragma once +#define GIT_USER \"${GIT_USER}\" +#define GIT_BRANCH \"${GIT_BRANCH}\" +#define GIT_COMMIT 0x${GIT_COMMIT} +#define GIT_MODIFIED ${GIT_MODIFIED} +") + +# Write git info to file if the contents have changed +if(NOT "${GIT_INFO_H}" STREQUAL "${GIT_INFO_H_CURRENT}") + file(WRITE "${GIT_INFO_H_PATH}" "${GIT_INFO_H}") +endif() + # compile definitions used add_compile_definitions(VERSION=\"${MOD_VERSION}\") add_compile_definitions(MOD_ID=\"${MOD_ID}\") +add_compile_definitions(UNITY_2021) +add_compile_definitions(CORDL_RUNTIME_FIELD_NULL_CHECKS) add_compile_definitions(__USE_LARGEFILE64) -add_compile_definitions(BEATSABER_1_29_4_OR_NEWER) + +# compile options used +add_compile_definitions(CP_SDK_BMBF) +add_compile_definitions(DEBUG_SCENES) + +string(LENGTH "${CMAKE_CURRENT_LIST_DIR}/" FOLDER_LENGTH) +add_compile_definitions("PAPER_ROOT_FOLDER_LENGTH=${FOLDER_LENGTH}") # recursively get all src files -RECURSE_FILES(h_file_lista ${INCLUDE_DIR}/*.hpp) -RECURSE_FILES(h_file_listb ${SHARED_DIR}/*.hpp) -RECURSE_FILES(hpp_file_lista ${INCLUDE_DIR}/*.hpp) -RECURSE_FILES(hpp_file_listb ${SHARED_DIR}/*.hpp) -RECURSE_FILES(cpp_file_list ${SOURCE_DIR}/*.cpp) -RECURSE_FILES(c_file_list ${SOURCE_DIR}/*.c) +recurse_files(cpp_file_list ${SOURCE_DIR}/*.cpp) +recurse_files(c_file_list ${SOURCE_DIR}/*.c) list(APPEND c_file_list ${INCLUDE_DIR}/zip/src/zip.c) +recurse_files(inline_hook_c ${EXTERN_DIR}/includes/beatsaber-hook/shared/inline-hook/*.c) +recurse_files(inline_hook_cpp ${EXTERN_DIR}/includes/beatsaber-hook/shared/inline-hook/*.cpp) + # add all src files to compile add_library( - ${COMPILE_ID} - SHARED - ${h_file_lista} - ${h_file_listb} - ${hpp_file_lista} - ${hpp_file_listb} - ${cpp_file_list} - ${c_file_list} + ${COMPILE_ID} SHARED ${cpp_file_list} ${c_file_list} ${inline_hook_c} ${inline_hook_cpp} ) -# Add any assets -add_assets(assets_${COMPILE_ID} STATIC ${CMAKE_CURRENT_LIST_DIR}/assets ${INCLUDE_DIR}/assets.hpp) - -# get the vcpkg dir from env variables -if(EXISTS $ENV{VCPKG_ROOT}) - set(VCPKG_ROOT $ENV{VCPKG_ROOT}) -else() - MESSAGE(ERROR "Please define the environment variable VCPKG_ROOT with the root to your vcpkg install!") -endif() - -target_include_directories(${COMPILE_ID} PRIVATE .) - # add src dir as include dir target_include_directories(${COMPILE_ID} PRIVATE ${SOURCE_DIR}) # add include dir as include dir target_include_directories(${COMPILE_ID} PRIVATE ${INCLUDE_DIR}) # add shared dir as include dir target_include_directories(${COMPILE_ID} PUBLIC ${SHARED_DIR}) -# codegen includes -target_include_directories(${COMPILE_ID} PRIVATE ${EXTERN_DIR}/includes/${CODEGEN_ID}/include) -target_link_libraries(${COMPILE_ID} PRIVATE -llog) -target_link_libraries(${COMPILE_ID} PRIVATE assets_${COMPILE_ID}) +# Add any assets +add_assets(${COMPILE_ID}-assets STATIC ${CMAKE_CURRENT_LIST_DIR}/assets ${INCLUDE_DIR}/assets.hpp) +target_link_libraries(${COMPILE_ID} PRIVATE -llog -lz ${COMPILE_ID}-assets) # add extern stuff like libs and other includes include(extern.cmake) add_custom_command(TARGET ${COMPILE_ID} POST_BUILD - COMMAND ${CMAKE_STRIP} -d --strip-all - "lib${COMPILE_ID}.so" -o "stripped_lib${COMPILE_ID}.so" - COMMENT "Strip debug symbols done on final binary.") + COMMAND ${CMAKE_STRIP} -g -S -d --strip-all + "lib${COMPILE_ID}.so" -o "stripped_lib${COMPILE_ID}.so" + COMMENT "Strip debug symbols done on final binary.") add_custom_command(TARGET ${COMPILE_ID} POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory debug @@ -121,32 +117,32 @@ add_custom_command(TARGET ${COMPILE_ID} POST_BUILD ) add_custom_command(TARGET ${COMPILE_ID} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E rename lib${COMPILE_ID}.so debug/lib${COMPILE_ID}.so - COMMENT "Rename the lib to debug_ since it has debug symbols" - ) + COMMAND ${CMAKE_COMMAND} -E rename lib${COMPILE_ID}.so debug/lib${COMPILE_ID}.so + COMMENT "Rename the lib to debug_ since it has debug symbols" + ) -# strip debug symbols from the .so and all dependencies add_custom_command(TARGET ${COMPILE_ID} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E rename stripped_lib${COMPILE_ID}.so lib${COMPILE_ID}.so - COMMENT "Rename the stripped lib to regular" - ) - foreach(so_file ${so_list}) - cmake_path(GET so_file FILENAME file) + COMMAND ${CMAKE_COMMAND} -E rename stripped_lib${COMPILE_ID}.so lib${COMPILE_ID}.so + COMMENT "Rename the stripped lib to regular" + ) - add_custom_command(TARGET ${COMPILE_ID} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${so_file} debug/${file} - COMMENT "Copy so files for ndk stack" - ) +foreach(so_file ${so_list}) + cmake_path(GET so_file FILENAME file) - add_custom_command(TARGET ${COMPILE_ID} POST_BUILD - COMMAND ${CMAKE_STRIP} -g -S -d --strip-all ${so_file} -o ${file} - COMMENT "Strip debug symbols from the dependencies") - endforeach() + add_custom_command(TARGET ${COMPILE_ID} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${so_file} debug/${file} + COMMENT "Copy so files for ndk stack" + ) - foreach(a_file ${a_list}) - cmake_path(GET a_file FILENAME file) + add_custom_command(TARGET ${COMPILE_ID} POST_BUILD + COMMAND ${CMAKE_STRIP} -g -S -d --strip-all ${so_file} -o ${file} + COMMENT "Strip debug symbols from the dependencies") +endforeach() - add_custom_command(TARGET ${COMPILE_ID} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${a_file} debug/${file} - COMMENT "Copy a files for ndk stack") - endforeach() \ No newline at end of file +foreach(a_file ${a_list}) +cmake_path(GET a_file FILENAME file) + +add_custom_command(TARGET ${COMPILE_ID} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${a_file} debug/${file} + COMMENT "Copy a files for ndk stack") +endforeach() diff --git a/include/git_info.h b/include/git_info.h new file mode 100644 index 0000000..2297089 --- /dev/null +++ b/include/git_info.h @@ -0,0 +1,5 @@ +#pragma once +#define GIT_USER "HardCPP" +#define GIT_BRANCH "dev" +#define GIT_COMMIT 0xc593a3c +#define GIT_MODIFIED 1 diff --git a/mod.json b/mod.json index f66b260..330b8b7 100644 --- a/mod.json +++ b/mod.json @@ -1,43 +1,47 @@ { + "$schema": "https://raw.githubusercontent.com/Lauriethefish/QuestPatcher.QMod/refs/heads/main/QuestPatcher.QMod/Resources/qmod.schema.json", "_QPVersion": "0.1.1", "name": "ChatPlexSDK-BS", "id": "chatplex-sdk-bs", "modloader": "Scotland2", "author": "HardCPP", - "version": "6.3.2", + "version": "6.4.0", "packageId": "com.beatgames.beatsaber", - "packageVersion": "1.37.0_9064817954", + "packageVersion": "1.40.4_5283", "description": "ChatPlex BeatSaber modding SDK (Dependence for other mods)", "coverImage": "cover.png", "dependencies": [ { - "version": "^0.17.8", + "version": "^6.4.1", + "id": "beatsaber-hook", + "downloadIfMissing": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.1/beatsaber-hook.qmod" + }, + { + "version": "^0.18.2", "id": "custom-types", - "downloadIfMissing": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.17.10/CustomTypes.qmod" + "downloadIfMissing": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.18.2/CustomTypes.qmod" }, { - "version": "^0.4.34", + "version": "^0.4.51", "id": "bsml", - "downloadIfMissing": "https://github.com/RedBrumbler/Quest-BSML/releases/download/v0.4.43/BSML.qmod" + "downloadIfMissing": "https://github.com/bsq-ports/Quest-BSML/releases/download/v0.4.51/BSML.qmod" }, { - "version": "^1.1.12", + "version": "^1.1.20", "id": "songcore", - "downloadIfMissing": "https://github.com/raineio/Quest-SongCore/releases/download/v1.1.15/SongCore.qmod" + "downloadIfMissing": "https://github.com/raineaeternal/Quest-SongCore/releases/download/v1.1.20/SongCore.qmod" }, { - "version": "^3.6.3", - "id": "paper", - "downloadIfMissing": "https://github.com/Fernthedev/paperlog/releases/download/v3.6.4/paperlog.qmod" + "version": "^4.6.1", + "id": "paper2_scotland2", + "downloadIfMissing": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.1/paper2_scotland2.qmod" } ], - "modFiles": [], - "lateModFiles": [ + "modFiles": [ "libchatplex-sdk-bs.so" ], - "libraryFiles": [ - "libbeatsaber-hook_5_1_9.so" - ], + "lateModFiles": [], + "libraryFiles": [], "fileCopies": [], "copyExtensions": [] } \ No newline at end of file diff --git a/mod.template.json b/mod.template.json index 74565b0..6eabf18 100644 --- a/mod.template.json +++ b/mod.template.json @@ -6,11 +6,11 @@ "author": "HardCPP", "version": "${version}", "packageId": "com.beatgames.beatsaber", - "packageVersion": "1.37.0_9064817954", + "packageVersion": "1.40.4_5283", "description": "ChatPlex BeatSaber modding SDK (Dependence for other mods)", "coverImage": "cover.png", "dependencies": [], - "modFiles": [], + "modFiles": ["${binary}"], "libraryFiles": [], "fileCopies": [], "copyExtensions": [] diff --git a/qpm.json b/qpm.json index b96c1d0..88070e9 100644 --- a/qpm.json +++ b/qpm.json @@ -1,11 +1,11 @@ { - "version": "0.1.0", + "version": "0.4.0", "sharedDir": "shared", "dependenciesDir": "extern", "info": { "name": "ChatPlexSDK-BS", "id": "chatplex-sdk-bs", - "version": "6.3.2", + "version": "6.4.0", "url": "https://github.com/hardcpp/QuestChatPlexSDK-BS", "additionalData": { "overrideSoName": "libchatplex-sdk-bs.so", @@ -35,27 +35,34 @@ "qpm qmod build", "pwsh ./createqmod.ps1 -clean" ] - } + }, + "ndk": "^27.2.12479018", + "qmodIncludeDirs": [ + "build", + "extern/libs" + ], + "qmodIncludeFiles": [], + "qmodOutput": "./ChatPlexSDK-BS.qmod" }, "dependencies": [ { "id": "beatsaber-hook", - "versionRange": "^5.1.9", + "versionRange": "^6.4.1", "additionalData": {} }, { "id": "bs-cordl", - "versionRange": "^3700.*", + "versionRange": "^4004.0.0", "additionalData": {} }, { "id": "custom-types", - "versionRange": "^0.17.8", + "versionRange": "^0.18.2", "additionalData": {} }, { "id": "scotland2", - "versionRange": "^0.1.4", + "versionRange": "^0.1.6", "additionalData": { "includeQmod": false, "private": true @@ -63,19 +70,19 @@ }, { "id": "bsml", - "versionRange": "^0.4.34", + "versionRange": "^0.4.51", "additionalData": { "private": true } }, { "id": "libil2cpp", - "versionRange": "^0.3.1", + "versionRange": "^0.4.0", "additionalData": {} }, { "id": "songcore", - "versionRange": "^1.1.12", + "versionRange": "^1.1.20", "additionalData": { "private": true } @@ -88,8 +95,8 @@ } }, { - "id": "paper", - "versionRange": "^3.6.3", + "id": "paper2_scotland2", + "versionRange": "^4.6.1", "additionalData": {} }, { diff --git a/qpm.shared.json b/qpm.shared.json index b6ff0ad..cefba26 100644 --- a/qpm.shared.json +++ b/qpm.shared.json @@ -1,12 +1,13 @@ { + "$schema": "https://raw.githubusercontent.com/QuestPackageManager/QPM.Package/refs/heads/main/qpm.shared.schema.json", "config": { - "version": "0.1.0", + "version": "0.4.0", "sharedDir": "shared", "dependenciesDir": "extern", "info": { "name": "ChatPlexSDK-BS", "id": "chatplex-sdk-bs", - "version": "6.3.2", + "version": "6.4.0", "url": "https://github.com/hardcpp/QuestChatPlexSDK-BS", "additionalData": { "overrideSoName": "libchatplex-sdk-bs.so", @@ -37,29 +38,33 @@ "pwsh ./createqmod.ps1 -clean" ] }, - "qmodIncludeDirs": [], + "ndk": "^27.2.12479018", + "qmodIncludeDirs": [ + "build", + "extern/libs" + ], "qmodIncludeFiles": [], - "qmodOutput": null + "qmodOutput": "./ChatPlexSDK-BS.qmod" }, "dependencies": [ { "id": "beatsaber-hook", - "versionRange": "^5.1.9", + "versionRange": "^6.4.1", "additionalData": {} }, { "id": "bs-cordl", - "versionRange": "3700.*", + "versionRange": "^4004.0.0", "additionalData": {} }, { "id": "custom-types", - "versionRange": "^0.17.8", + "versionRange": "^0.18.2", "additionalData": {} }, { "id": "scotland2", - "versionRange": "^0.1.4", + "versionRange": "^0.1.6", "additionalData": { "includeQmod": false, "private": true @@ -67,19 +72,19 @@ }, { "id": "bsml", - "versionRange": "^0.4.34", + "versionRange": "^0.4.51", "additionalData": { "private": true } }, { "id": "libil2cpp", - "versionRange": "^0.3.1", + "versionRange": "^0.4.0", "additionalData": {} }, { "id": "songcore", - "versionRange": "^1.1.12", + "versionRange": "^1.1.20", "additionalData": { "private": true } @@ -92,8 +97,8 @@ } }, { - "id": "paper", - "versionRange": "^3.6.3", + "id": "paper2_scotland2", + "versionRange": "^4.6.1", "additionalData": {} }, { @@ -106,14 +111,28 @@ "restoredDependencies": [ { "dependency": { - "id": "paper", - "versionRange": "=3.6.4", + "id": "bsml", + "versionRange": "=0.4.51", "additionalData": { - "soLink": "https://github.com/Fernthedev/paperlog/releases/download/v3.6.4/libpaperlog.so", - "debugSoLink": "https://github.com/Fernthedev/paperlog/releases/download/v3.6.4/debug_libpaperlog.so", - "overrideSoName": "libpaperlog.so", - "modLink": "https://github.com/Fernthedev/paperlog/releases/download/v3.6.4/paperlog.qmod", - "branchName": "version/v3_6_4", + "soLink": "https://github.com/bsq-ports/Quest-BSML/releases/download/v0.4.51/libbsml.so", + "debugSoLink": "https://github.com/bsq-ports/Quest-BSML/releases/download/v0.4.51/debug_libbsml.so", + "overrideSoName": "libbsml.so", + "modLink": "https://github.com/bsq-ports/Quest-BSML/releases/download/v0.4.51/BSML.qmod", + "branchName": "version/v0_4_51", + "cmake": true + } + }, + "version": "0.4.51" + }, + { + "dependency": { + "id": "paper2_scotland2", + "versionRange": "=4.6.1", + "additionalData": { + "soLink": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.1/libpaper2_scotland2.so", + "overrideSoName": "libpaper2_scotland2.so", + "modLink": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.1/paper2_scotland2.qmod", + "branchName": "version/v4_6_1", "compileOptions": { "systemIncludes": [ "shared/utfcpp/source" @@ -122,44 +141,34 @@ "cmake": false } }, - "version": "3.6.4" + "version": "4.6.1" }, { "dependency": { "id": "libil2cpp", - "versionRange": "=0.3.2", + "versionRange": "=0.4.0", "additionalData": { "headersOnly": true, - "cmake": false - } - }, - "version": "0.3.2" - }, - { - "dependency": { - "id": "bsml", - "versionRange": "=0.4.43", - "additionalData": { - "soLink": "https://github.com/RedBrumbler/Quest-BSML/releases/download/v0.4.43/libbsml.so", - "debugSoLink": "https://github.com/RedBrumbler/Quest-BSML/releases/download/v0.4.43/debug_libbsml.so", - "overrideSoName": "libbsml.so", - "modLink": "https://github.com/RedBrumbler/Quest-BSML/releases/download/v0.4.43/BSML.qmod", - "branchName": "version/v0_4_43", - "cmake": true + "compileOptions": { + "systemIncludes": [ + "il2cpp/external/baselib/Include", + "il2cpp/external/baselib/Platforms/Android/Include" + ] + } } }, - "version": "0.4.43" + "version": "0.4.0" }, { "dependency": { "id": "custom-types", - "versionRange": "=0.17.10", + "versionRange": "=0.18.2", "additionalData": { - "soLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.17.10/libcustom-types.so", - "debugSoLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.17.10/debug_libcustom-types.so", + "soLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.18.2/libcustom-types.so", + "debugSoLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.18.2/debug_libcustom-types.so", "overrideSoName": "libcustom-types.so", - "modLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.17.10/CustomTypes.qmod", - "branchName": "version/v0_17_10", + "modLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.18.2/CustomTypes.qmod", + "branchName": "version/v0_18_2", "compileOptions": { "cppFlags": [ "-Wno-invalid-offsetof" @@ -168,7 +177,7 @@ "cmake": true } }, - "version": "0.17.10" + "version": "0.18.2" }, { "dependency": { @@ -190,10 +199,10 @@ { "dependency": { "id": "bs-cordl", - "versionRange": "=3700.0.0", + "versionRange": "=4004.0.0", "additionalData": { "headersOnly": true, - "branchName": "version/v3700_0_0", + "branchName": "version/v4004_0_0", "compileOptions": { "includePaths": [ "include" @@ -203,12 +212,13 @@ "-DNEED_UNSAFE_CSHARP", "-fdeclspec", "-DUNITY_2021", - "-DHAS_CODEGEN" + "-DHAS_CODEGEN", + "-Wno-invalid-offsetof" ] } } }, - "version": "3700.0.0" + "version": "4004.0.0" }, { "dependency": { @@ -225,43 +235,64 @@ { "dependency": { "id": "songcore", - "versionRange": "=1.1.15", + "versionRange": "=1.1.20", "additionalData": { - "soLink": "https://github.com/raineio/Quest-SongCore/releases/download/v1.1.15/libsongcore.so", - "debugSoLink": "https://github.com/raineio/Quest-SongCore/releases/download/v1.1.15/debug_libsongcore.so", + "soLink": "https://github.com/raineaeternal/Quest-SongCore/releases/download/v1.1.20/libsongcore.so", + "debugSoLink": "https://github.com/raineaeternal/Quest-SongCore/releases/download/v1.1.20/debug_libsongcore.so", "overrideSoName": "libsongcore.so", - "modLink": "https://github.com/raineio/Quest-SongCore/releases/download/v1.1.15/SongCore.qmod", - "branchName": "version/v1_1_15", + "modLink": "https://github.com/raineaeternal/Quest-SongCore/releases/download/v1.1.20/SongCore.qmod", + "branchName": "version/v1_1_20", "cmake": true } }, - "version": "1.1.15" + "version": "1.1.20" }, { "dependency": { "id": "beatsaber-hook", - "versionRange": "=5.1.9", + "versionRange": "=6.4.1", "additionalData": { - "soLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v5.1.9/libbeatsaber-hook_5_1_9.so", - "debugSoLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v5.1.9/debug_libbeatsaber-hook_5_1_9.so", - "branchName": "version/v5_1_9", + "soLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.1/libbeatsaber-hook.so", + "debugSoLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.1/debug_libbeatsaber-hook.so", + "overrideSoName": "libbeatsaber-hook.so", + "modLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.1/beatsaber-hook.qmod", + "branchName": "version/v6_4_1", "cmake": true } }, - "version": "5.1.9" + "version": "6.4.1" + }, + { + "dependency": { + "id": "fmt", + "versionRange": "=11.0.2", + "additionalData": { + "headersOnly": true, + "branchName": "version/v11_0_2", + "compileOptions": { + "systemIncludes": [ + "fmt/include/" + ], + "cppFlags": [ + "-DFMT_HEADER_ONLY" + ] + } + } + }, + "version": "11.0.2" }, { "dependency": { "id": "scotland2", - "versionRange": "=0.1.4", + "versionRange": "=0.1.6", "additionalData": { - "soLink": "https://github.com/sc2ad/scotland2/releases/download/v0.1.4/libsl2.so", - "debugSoLink": "https://github.com/sc2ad/scotland2/releases/download/v0.1.4/debug_libsl2.so", + "soLink": "https://github.com/sc2ad/scotland2/releases/download/v0.1.6/libsl2.so", + "debugSoLink": "https://github.com/sc2ad/scotland2/releases/download/v0.1.6/debug_libsl2.so", "overrideSoName": "libsl2.so", - "branchName": "version/v0_1_4" + "branchName": "version/v0_1_6" } }, - "version": "0.1.4" + "version": "0.1.6" }, { "dependency": { @@ -277,25 +308,6 @@ } }, "version": "10.0.0" - }, - { - "dependency": { - "id": "fmt", - "versionRange": "=10.0.0", - "additionalData": { - "headersOnly": true, - "branchName": "version/v10_0_0", - "compileOptions": { - "systemIncludes": [ - "fmt/include/" - ], - "cppFlags": [ - "-DFMT_HEADER_ONLY" - ] - } - } - }, - "version": "10.0.0" } ] } \ No newline at end of file diff --git a/shared/CP_SDK/Animation/AnimationControllerInstance.hpp b/shared/CP_SDK/Animation/AnimationControllerInstance.hpp index 6493b48..b7de08b 100644 --- a/shared/CP_SDK/Animation/AnimationControllerInstance.hpp +++ b/shared/CP_SDK/Animation/AnimationControllerInstance.hpp @@ -25,7 +25,7 @@ namespace CP_SDK::Animation { } /// @brief Animation controller data object - class CP_SDK_EXPORT_VISIBILITY AnimationControllerInstance + class CP_SDK_EXPORT AnimationControllerInstance { CP_SDK_NO_COPYMOVE_CTORS(AnimationControllerInstance); CP_SDK_PRIV_TAG(); diff --git a/shared/CP_SDK/Animation/AnimationControllerManager.hpp b/shared/CP_SDK/Animation/AnimationControllerManager.hpp index 6e2ecf8..e8cb8b2 100644 --- a/shared/CP_SDK/Animation/AnimationControllerManager.hpp +++ b/shared/CP_SDK/Animation/AnimationControllerManager.hpp @@ -20,7 +20,7 @@ namespace CP_SDK::Animation { } /// @brief Animation controller manager - class AnimationControllerManager : public _u::MonoBehaviour + class CP_SDK_EXPORT AnimationControllerManager : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.Animation", AnimationControllerManager, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(AnimationControllerManager); diff --git a/shared/CP_SDK/Animation/AnimationInfo.hpp b/shared/CP_SDK/Animation/AnimationInfo.hpp index 667b142..a513e25 100644 --- a/shared/CP_SDK/Animation/AnimationInfo.hpp +++ b/shared/CP_SDK/Animation/AnimationInfo.hpp @@ -23,7 +23,7 @@ namespace CP_SDK::Animation { } /// @brief Animation frame info - class CP_SDK_EXPORT_VISIBILITY AnimationInfo + class CP_SDK_EXPORT AnimationInfo { CP_SDK_NO_COPYMOVE_CTORS(AnimationInfo); CP_SDK_PRIV_TAG(); diff --git a/shared/CP_SDK/Animation/AnimationLoader.hpp b/shared/CP_SDK/Animation/AnimationLoader.hpp index 2ce420a..69b3f24 100644 --- a/shared/CP_SDK/Animation/AnimationLoader.hpp +++ b/shared/CP_SDK/Animation/AnimationLoader.hpp @@ -31,7 +31,7 @@ namespace CP_SDK::Animation { }; /// @brief Animation loader - class CP_SDK_EXPORT_VISIBILITY AnimationLoader + class CP_SDK_EXPORT AnimationLoader { CP_SDK_NO_DEF_CTORS(AnimationLoader); diff --git a/shared/CP_SDK/Animation/WEBP/WEBPDecoder.hpp b/shared/CP_SDK/Animation/WEBP/WEBPDecoder.hpp index 831c237..6545bd5 100644 --- a/shared/CP_SDK/Animation/WEBP/WEBPDecoder.hpp +++ b/shared/CP_SDK/Animation/WEBP/WEBPDecoder.hpp @@ -19,7 +19,7 @@ namespace CP_SDK::Animation::WEBP { } /// @brief WEBP decoder - class CP_SDK_EXPORT_VISIBILITY WEBPDecoder + class CP_SDK_EXPORT WEBPDecoder { CP_SDK_NO_DEF_CTORS(WEBPDecoder); diff --git a/shared/CP_SDK/BuildConfig.hpp b/shared/CP_SDK/BuildConfig.hpp new file mode 100644 index 0000000..ef34f98 --- /dev/null +++ b/shared/CP_SDK/BuildConfig.hpp @@ -0,0 +1,3 @@ +#pragma once + +#define CP_SDK_EXPORT __attribute__((visibility("default"))) \ No newline at end of file diff --git a/shared/CP_SDK/CPConfig.hpp b/shared/CP_SDK/CPConfig.hpp index 412f372..1cfd370 100644 --- a/shared/CP_SDK/CPConfig.hpp +++ b/shared/CP_SDK/CPConfig.hpp @@ -5,7 +5,7 @@ namespace CP_SDK { /// @brief ChatPlex SDK config - class CPConfig : public Config::JsonConfig + class CP_SDK_EXPORT CPConfig : public Config::JsonConfig { CP_SDK_CONFIG_JSONCONFIG_INSTANCE_DECL(CPConfig); diff --git a/shared/CP_SDK/Chat/Service.hpp b/shared/CP_SDK/Chat/Service.hpp index c912274..0740de6 100644 --- a/shared/CP_SDK/Chat/Service.hpp +++ b/shared/CP_SDK/Chat/Service.hpp @@ -4,7 +4,7 @@ namespace CP_SDK::Chat { - class CP_SDK_EXPORT_VISIBILITY Service + class CP_SDK_EXPORT Service { CP_SDK_NO_DEF_CTORS(Service); diff --git a/shared/CP_SDK/ChatPlexSDK.hpp b/shared/CP_SDK/ChatPlexSDK.hpp index c616b61..ef4e9fc 100644 --- a/shared/CP_SDK/ChatPlexSDK.hpp +++ b/shared/CP_SDK/ChatPlexSDK.hpp @@ -24,7 +24,7 @@ namespace CP_SDK { }; /// ChatPlex SDK main class - class CP_SDK_EXPORT_VISIBILITY ChatPlexSDK + class CP_SDK_EXPORT ChatPlexSDK { CP_SDK_NO_DEF_CTORS(ChatPlexSDK); diff --git a/shared/CP_SDK/Config/JsonConfig.hpp b/shared/CP_SDK/Config/JsonConfig.hpp index 8e2ac59..f57746e 100644 --- a/shared/CP_SDK/Config/JsonConfig.hpp +++ b/shared/CP_SDK/Config/JsonConfig.hpp @@ -28,7 +28,7 @@ namespace CP_SDK::Config { /// @brief Json config file - class JsonConfig + class CP_SDK_EXPORT JsonConfig { CP_SDK_NO_COPYMOVE_CTORS(JsonConfig); diff --git a/shared/CP_SDK/Logging/ILogger.hpp b/shared/CP_SDK/Logging/ILogger.hpp index 36f4097..7ebc301 100644 --- a/shared/CP_SDK/Logging/ILogger.hpp +++ b/shared/CP_SDK/Logging/ILogger.hpp @@ -1,12 +1,14 @@ #pragma once -#include +#include "../BuildConfig.hpp" + +#include #include namespace CP_SDK::Logging { /// @brief Base logger - class ILogger + class CP_SDK_EXPORT ILogger { public: enum class ELogType diff --git a/shared/CP_SDK/Logging/PaperLogger.hpp b/shared/CP_SDK/Logging/PaperLogger.hpp index a0246d9..2629af0 100644 --- a/shared/CP_SDK/Logging/PaperLogger.hpp +++ b/shared/CP_SDK/Logging/PaperLogger.hpp @@ -4,12 +4,12 @@ #include -#include "paper/shared/logger.hpp" +#include "paper2_scotland2/shared/logger.hpp" namespace CP_SDK::Logging { /// @brief Paper Logger - class PaperLogger : public ILogger + class CP_SDK_EXPORT PaperLogger : public ILogger { public: /// @brief Constructor diff --git a/shared/CP_SDK/Misc/FastCancellationToken.hpp b/shared/CP_SDK/Misc/FastCancellationToken.hpp index b2d8238..70eae58 100644 --- a/shared/CP_SDK/Misc/FastCancellationToken.hpp +++ b/shared/CP_SDK/Misc/FastCancellationToken.hpp @@ -8,7 +8,7 @@ namespace CP_SDK::Misc { /// @brief Fast cancellation token - class CP_SDK_EXPORT_VISIBILITY FastCancellationToken + class CP_SDK_EXPORT FastCancellationToken { CP_SDK_NO_DEF_CTORS(FastCancellationToken); CP_SDK_PRIV_TAG(); diff --git a/shared/CP_SDK/Misc/Time.hpp b/shared/CP_SDK/Misc/Time.hpp index a5d412c..ac96979 100644 --- a/shared/CP_SDK/Misc/Time.hpp +++ b/shared/CP_SDK/Misc/Time.hpp @@ -29,7 +29,7 @@ namespace CP_SDK::Misc { }; /// @brief Time helper - class CP_SDK_EXPORT_VISIBILITY Time + class CP_SDK_EXPORT Time { CP_SDK_NO_DEF_CTORS(Time); diff --git a/shared/CP_SDK/ModuleBase.hpp b/shared/CP_SDK/ModuleBase.hpp index fc79e7e..e67b2e5 100644 --- a/shared/CP_SDK/ModuleBase.hpp +++ b/shared/CP_SDK/ModuleBase.hpp @@ -39,7 +39,7 @@ namespace CP_SDK { //////////////////////////////////////////////////////////////////////////// /// @brief Module base interface - class IModuleBase + class CP_SDK_EXPORT IModuleBase { CP_SDK_NO_COPYMOVE_CTORS(IModuleBase); diff --git a/shared/CP_SDK/Network/WebClientUnity.hpp b/shared/CP_SDK/Network/WebClientUnity.hpp index 5357c39..c06bb1e 100644 --- a/shared/CP_SDK/Network/WebClientUnity.hpp +++ b/shared/CP_SDK/Network/WebClientUnity.hpp @@ -22,7 +22,7 @@ namespace CP_SDK::Network { } /// @brief WebClientUnity using unity web requests - class CP_SDK_EXPORT_VISIBILITY WebClientUnity : public IWebClient, public std::enable_shared_from_this + class CP_SDK_EXPORT WebClientUnity : public IWebClient, public std::enable_shared_from_this { CP_SDK_NO_COPYMOVE_CTORS(WebClientUnity); CP_SDK_PRIV_TAG(); diff --git a/shared/CP_SDK/Network/WebContent.hpp b/shared/CP_SDK/Network/WebContent.hpp index e98ff09..750da47 100644 --- a/shared/CP_SDK/Network/WebContent.hpp +++ b/shared/CP_SDK/Network/WebContent.hpp @@ -14,7 +14,7 @@ namespace CP_SDK::Network { } /// @brief WebContent - class CP_SDK_EXPORT_VISIBILITY WebContent + class CP_SDK_EXPORT WebContent { CP_SDK_NO_COPYMOVE_CTORS(WebContent); CP_SDK_PRIV_TAG(); diff --git a/shared/CP_SDK/Network/WebResponse.hpp b/shared/CP_SDK/Network/WebResponse.hpp index 1f82651..c89ba58 100644 --- a/shared/CP_SDK/Network/WebResponse.hpp +++ b/shared/CP_SDK/Network/WebResponse.hpp @@ -23,7 +23,7 @@ namespace CP_SDK::Network { } /// @brief Web Response class - class WebResponse + class CP_SDK_EXPORT WebResponse { CP_SDK_NO_COPYMOVE_CTORS(WebResponse); CP_SDK_PRIV_TAG(); diff --git a/shared/CP_SDK/UI/Components/CColorInput.hpp b/shared/CP_SDK/UI/Components/CColorInput.hpp index 2f34e1f..245300b 100644 --- a/shared/CP_SDK/UI/Components/CColorInput.hpp +++ b/shared/CP_SDK/UI/Components/CColorInput.hpp @@ -19,7 +19,7 @@ namespace CP_SDK::UI::Components { } /// @brief CColorInput component - class CColorInput : public _u::MonoBehaviour + class CP_SDK_EXPORT CColorInput : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Components", CColorInput, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(CColorInput); diff --git a/shared/CP_SDK/UI/Components/CDropdown.hpp b/shared/CP_SDK/UI/Components/CDropdown.hpp index 25b3310..70200dd 100644 --- a/shared/CP_SDK/UI/Components/CDropdown.hpp +++ b/shared/CP_SDK/UI/Components/CDropdown.hpp @@ -19,7 +19,7 @@ namespace CP_SDK::UI::Components { } /// @brief CDropdown component - class CDropdown : public _u::MonoBehaviour + class CP_SDK_EXPORT CDropdown : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Components", CDropdown, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(CDropdown); diff --git a/shared/CP_SDK/UI/Components/CFLayout.hpp b/shared/CP_SDK/UI/Components/CFLayout.hpp index 84065dd..7492dde 100644 --- a/shared/CP_SDK/UI/Components/CFLayout.hpp +++ b/shared/CP_SDK/UI/Components/CFLayout.hpp @@ -24,7 +24,7 @@ namespace CP_SDK::UI::Components { } /// @brief Flow layout group - class CFLayout : public _u::LayoutGroup + class CP_SDK_EXPORT CFLayout : public _u::LayoutGroup { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Components", CFLayout, _u::LayoutGroup); CP_SDK_IL2CPP_DECLARE_CTOR(CFLayout); diff --git a/shared/CP_SDK/UI/Components/CFloatingPanel.hpp b/shared/CP_SDK/UI/Components/CFloatingPanel.hpp index 57cada8..aafb11d 100644 --- a/shared/CP_SDK/UI/Components/CFloatingPanel.hpp +++ b/shared/CP_SDK/UI/Components/CFloatingPanel.hpp @@ -22,7 +22,7 @@ namespace CP_SDK::UI::Components { } /// @brief Floating Panel component - class CFloatingPanel : public IScreen + class CP_SDK_EXPORT CFloatingPanel : public IScreen { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Components", CFloatingPanel, IScreen); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(CFloatingPanel); diff --git a/shared/CP_SDK/UI/Components/CGLayout.hpp b/shared/CP_SDK/UI/Components/CGLayout.hpp index 78a104b..731f51a 100644 --- a/shared/CP_SDK/UI/Components/CGLayout.hpp +++ b/shared/CP_SDK/UI/Components/CGLayout.hpp @@ -22,7 +22,7 @@ namespace CP_SDK::UI::Components { } /// @brief Grid layout group - class CGLayout : public _u::MonoBehaviour + class CP_SDK_EXPORT CGLayout : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Components", CGLayout, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(CGLayout); diff --git a/shared/CP_SDK/UI/Components/CHLayout.hpp b/shared/CP_SDK/UI/Components/CHLayout.hpp index ae56dea..fa3196a 100644 --- a/shared/CP_SDK/UI/Components/CHLayout.hpp +++ b/shared/CP_SDK/UI/Components/CHLayout.hpp @@ -17,7 +17,7 @@ namespace CP_SDK::UI::Components { } /// @brief Horizontal layout component - class CHLayout : public CHOrVLayout + class CP_SDK_EXPORT CHLayout : public CHOrVLayout { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Components", CHLayout, CHOrVLayout); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(CHLayout); diff --git a/shared/CP_SDK/UI/Components/CIconButton.hpp b/shared/CP_SDK/UI/Components/CIconButton.hpp index 04164cd..6b27f02 100644 --- a/shared/CP_SDK/UI/Components/CIconButton.hpp +++ b/shared/CP_SDK/UI/Components/CIconButton.hpp @@ -24,7 +24,7 @@ namespace CP_SDK::UI::Components { } /// @brief Icon button component - class CIconButton : public _u::MonoBehaviour + class CP_SDK_EXPORT CIconButton : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Components", CIconButton, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(CIconButton); diff --git a/shared/CP_SDK/UI/Components/CImage.hpp b/shared/CP_SDK/UI/Components/CImage.hpp index 85febcc..9e6f2df 100644 --- a/shared/CP_SDK/UI/Components/CImage.hpp +++ b/shared/CP_SDK/UI/Components/CImage.hpp @@ -21,7 +21,7 @@ namespace CP_SDK::UI::Components { } /// @brief CImage component - class CImage : public _u::MonoBehaviour + class CP_SDK_EXPORT CImage : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Components", CImage, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(CImage); diff --git a/shared/CP_SDK/UI/Components/CPrimaryButton.hpp b/shared/CP_SDK/UI/Components/CPrimaryButton.hpp index 79e4abc..327baf6 100644 --- a/shared/CP_SDK/UI/Components/CPrimaryButton.hpp +++ b/shared/CP_SDK/UI/Components/CPrimaryButton.hpp @@ -15,7 +15,7 @@ namespace CP_SDK::UI::Components { } /// @brief Primary button component - class CPrimaryButton : public CPOrSButton + class CP_SDK_EXPORT CPrimaryButton : public CPOrSButton { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Components", CPrimaryButton, CPOrSButton); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(CPrimaryButton); diff --git a/shared/CP_SDK/UI/Components/CSecondaryButton.hpp b/shared/CP_SDK/UI/Components/CSecondaryButton.hpp index b679d92..813a359 100644 --- a/shared/CP_SDK/UI/Components/CSecondaryButton.hpp +++ b/shared/CP_SDK/UI/Components/CSecondaryButton.hpp @@ -15,7 +15,7 @@ namespace CP_SDK::UI::Components { } /// @brief Secondary button component - class CSecondaryButton : public CPOrSButton + class CP_SDK_EXPORT CSecondaryButton : public CPOrSButton { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Components", CSecondaryButton, CPOrSButton); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(CSecondaryButton); diff --git a/shared/CP_SDK/UI/Components/CSlider.hpp b/shared/CP_SDK/UI/Components/CSlider.hpp index 2bb4224..5802e54 100644 --- a/shared/CP_SDK/UI/Components/CSlider.hpp +++ b/shared/CP_SDK/UI/Components/CSlider.hpp @@ -21,7 +21,7 @@ namespace CP_SDK::UI::Components { } /// @brief CSlider component - class CSlider : public _u::Selectable + class CP_SDK_EXPORT CSlider : public _u::Selectable { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Components", CSlider, _u::Selectable); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(CSlider); diff --git a/shared/CP_SDK/UI/Components/CTabControl.hpp b/shared/CP_SDK/UI/Components/CTabControl.hpp index 006a83d..fa398c4 100644 --- a/shared/CP_SDK/UI/Components/CTabControl.hpp +++ b/shared/CP_SDK/UI/Components/CTabControl.hpp @@ -22,7 +22,7 @@ namespace CP_SDK::UI::Components { } /// @brief CTabControl component - class CTabControl : public _u::MonoBehaviour + class CP_SDK_EXPORT CTabControl : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Components", CTabControl, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(CTabControl); diff --git a/shared/CP_SDK/UI/Components/CText.hpp b/shared/CP_SDK/UI/Components/CText.hpp index 88ee907..9e6caa7 100644 --- a/shared/CP_SDK/UI/Components/CText.hpp +++ b/shared/CP_SDK/UI/Components/CText.hpp @@ -25,7 +25,7 @@ namespace CP_SDK::UI::Components { } /// @brief CText component - class CText : public _u::MonoBehaviour + class CP_SDK_EXPORT CText : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Components", CText, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(CText); diff --git a/shared/CP_SDK/UI/Components/CTextInput.hpp b/shared/CP_SDK/UI/Components/CTextInput.hpp index 00326f2..e0e8700 100644 --- a/shared/CP_SDK/UI/Components/CTextInput.hpp +++ b/shared/CP_SDK/UI/Components/CTextInput.hpp @@ -21,7 +21,7 @@ namespace CP_SDK::UI::Components { } /// @brief CTextInput component - class CTextInput : public _u::MonoBehaviour + class CP_SDK_EXPORT CTextInput : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Components", CTextInput, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(CTextInput); diff --git a/shared/CP_SDK/UI/Components/CTextSegmentedControl.hpp b/shared/CP_SDK/UI/Components/CTextSegmentedControl.hpp index 053a3ad..0e90996 100644 --- a/shared/CP_SDK/UI/Components/CTextSegmentedControl.hpp +++ b/shared/CP_SDK/UI/Components/CTextSegmentedControl.hpp @@ -22,7 +22,7 @@ namespace CP_SDK::UI::Components { } /// @brief CTextSegmentedControl component - class CTextSegmentedControl : public _u::MonoBehaviour + class CP_SDK_EXPORT CTextSegmentedControl : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Components", CTextSegmentedControl, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(CTextSegmentedControl); diff --git a/shared/CP_SDK/UI/Components/CToggle.hpp b/shared/CP_SDK/UI/Components/CToggle.hpp index 7e8726d..d98960d 100644 --- a/shared/CP_SDK/UI/Components/CToggle.hpp +++ b/shared/CP_SDK/UI/Components/CToggle.hpp @@ -22,7 +22,7 @@ namespace CP_SDK::UI::Components { } /// @brief CToggle component - class CToggle : public _u::MonoBehaviour + class CP_SDK_EXPORT CToggle : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Components", CToggle, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(CToggle); diff --git a/shared/CP_SDK/UI/Components/CVLayout.hpp b/shared/CP_SDK/UI/Components/CVLayout.hpp index 59c0d04..2f8cccd 100644 --- a/shared/CP_SDK/UI/Components/CVLayout.hpp +++ b/shared/CP_SDK/UI/Components/CVLayout.hpp @@ -17,7 +17,7 @@ namespace CP_SDK::UI::Components { } /// @brief Vertical layout component - class CVLayout : public CHOrVLayout + class CP_SDK_EXPORT CVLayout : public CHOrVLayout { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Components", CVLayout, CHOrVLayout); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(CVLayout); diff --git a/shared/CP_SDK/UI/Components/CVScrollView.hpp b/shared/CP_SDK/UI/Components/CVScrollView.hpp index 46a83e2..6fd2104 100644 --- a/shared/CP_SDK/UI/Components/CVScrollView.hpp +++ b/shared/CP_SDK/UI/Components/CVScrollView.hpp @@ -19,7 +19,7 @@ namespace CP_SDK::UI::Components { } /// @brief CVScrollView component - class CVScrollView : public _u::MonoBehaviour + class CP_SDK_EXPORT CVScrollView : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Components", CVScrollView, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(CVScrollView); diff --git a/shared/CP_SDK/UI/Components/CVVList.hpp b/shared/CP_SDK/UI/Components/CVVList.hpp index 6b9f243..401ff83 100644 --- a/shared/CP_SDK/UI/Components/CVVList.hpp +++ b/shared/CP_SDK/UI/Components/CVVList.hpp @@ -15,7 +15,7 @@ namespace CP_SDK::UI::Components { } /// @brief Virtual Vertical List - class CVVList : public CVXList + class CP_SDK_EXPORT CVVList : public CVXList { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Components", CVVList, CVXList); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(CVVList); diff --git a/shared/CP_SDK/UI/Components/Generics/CHOrVLayout.hpp b/shared/CP_SDK/UI/Components/Generics/CHOrVLayout.hpp index 2002dcf..34aa4a2 100644 --- a/shared/CP_SDK/UI/Components/Generics/CHOrVLayout.hpp +++ b/shared/CP_SDK/UI/Components/Generics/CHOrVLayout.hpp @@ -23,7 +23,7 @@ namespace CP_SDK::UI::Components { } /// @brief Horizontal or vertical layout base component - class CHOrVLayout : public _u::MonoBehaviour + class CP_SDK_EXPORT CHOrVLayout : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Components", CHOrVLayout, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(CHOrVLayout); diff --git a/shared/CP_SDK/UI/Components/Generics/CPOrSButton.hpp b/shared/CP_SDK/UI/Components/Generics/CPOrSButton.hpp index 6ac1eb5..20ac274 100644 --- a/shared/CP_SDK/UI/Components/Generics/CPOrSButton.hpp +++ b/shared/CP_SDK/UI/Components/Generics/CPOrSButton.hpp @@ -28,7 +28,7 @@ namespace CP_SDK::UI::Components { } /// @brief Primary or Secondary button component - class CPOrSButton : public _u::MonoBehaviour + class CP_SDK_EXPORT CPOrSButton : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Components", CPOrSButton, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(CPOrSButton); diff --git a/shared/CP_SDK/UI/Components/Generics/CVXList.hpp b/shared/CP_SDK/UI/Components/Generics/CVXList.hpp index 778d58f..b74cde7 100644 --- a/shared/CP_SDK/UI/Components/Generics/CVXList.hpp +++ b/shared/CP_SDK/UI/Components/Generics/CVXList.hpp @@ -25,7 +25,7 @@ namespace CP_SDK::UI::Components { } /// @brief Generic virtual list interface - class CVXList : public _u::MonoBehaviour + class CP_SDK_EXPORT CVXList : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Components", CVXList, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(CVXList); diff --git a/shared/CP_SDK/UI/Data/IListCell.hpp b/shared/CP_SDK/UI/Data/IListCell.hpp index 99303c0..746b68b 100644 --- a/shared/CP_SDK/UI/Data/IListCell.hpp +++ b/shared/CP_SDK/UI/Data/IListCell.hpp @@ -34,7 +34,7 @@ namespace CP_SDK::UI::Data { class IListItem; /// @brief Abstract List Cell component - class IListCell : public _u::MonoBehaviour + class CP_SDK_EXPORT IListCell : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Data", IListCell, _u::MonoBehaviour, CP_SDK_IL2CPP_INTERFACES( _u::IEventSystemHandler, diff --git a/shared/CP_SDK/UI/Data/IListItem.hpp b/shared/CP_SDK/UI/Data/IListItem.hpp index 374892e..681b7db 100644 --- a/shared/CP_SDK/UI/Data/IListItem.hpp +++ b/shared/CP_SDK/UI/Data/IListItem.hpp @@ -7,7 +7,7 @@ namespace CP_SDK::UI::Data { /// @brief Abstract List Item - class IListItem : public std::enable_shared_from_this + class CP_SDK_EXPORT IListItem : public std::enable_shared_from_this { CP_SDK_NO_COPYMOVE_CTORS(IListItem); diff --git a/shared/CP_SDK/UI/Data/ListCellPrefabs.hpp b/shared/CP_SDK/UI/Data/ListCellPrefabs.hpp index dc4f28d..a6af2d9 100644 --- a/shared/CP_SDK/UI/Data/ListCellPrefabs.hpp +++ b/shared/CP_SDK/UI/Data/ListCellPrefabs.hpp @@ -19,7 +19,7 @@ namespace CP_SDK::UI::Data { /// @brief List cell prefabs getter /// @tparam t_ListCellType List cell type template - class CP_SDK_EXPORT_VISIBILITY ListCellPrefabs + class CP_SDK_EXPORT ListCellPrefabs { private: static _v::MonoPtr m_Prefab; diff --git a/shared/CP_SDK/UI/Data/TextListCell.hpp b/shared/CP_SDK/UI/Data/TextListCell.hpp index fdf41e4..46b1497 100644 --- a/shared/CP_SDK/UI/Data/TextListCell.hpp +++ b/shared/CP_SDK/UI/Data/TextListCell.hpp @@ -6,7 +6,7 @@ namespace CP_SDK::UI::Data { /// @brief Text list cell - class TextListCell : public IListCell + class CP_SDK_EXPORT TextListCell : public IListCell { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Data", TextListCell, IListCell); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(TextListCell); diff --git a/shared/CP_SDK/UI/Data/TextListItem.hpp b/shared/CP_SDK/UI/Data/TextListItem.hpp index 705e96a..f4e69f8 100644 --- a/shared/CP_SDK/UI/Data/TextListItem.hpp +++ b/shared/CP_SDK/UI/Data/TextListItem.hpp @@ -7,7 +7,7 @@ namespace CP_SDK::UI::Data { /// @brief Abstract List Item - class CP_SDK_EXPORT_VISIBILITY TextListItem : public IListItem + class CP_SDK_EXPORT TextListItem : public IListItem { CP_SDK_NO_DEF_CTORS(TextListItem); diff --git a/shared/CP_SDK/UI/DefaultComponents/DefaultCColorInput.hpp b/shared/CP_SDK/UI/DefaultComponents/DefaultCColorInput.hpp index 2702a25..81c6b18 100644 --- a/shared/CP_SDK/UI/DefaultComponents/DefaultCColorInput.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/DefaultCColorInput.hpp @@ -20,7 +20,7 @@ namespace CP_SDK::UI::DefaultComponents { } /// @brief Default CColorInput component - class DefaultCColorInput : public Components::CColorInput + class CP_SDK_EXPORT DefaultCColorInput : public Components::CColorInput { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.DefaultComponents", DefaultCColorInput, Components::CColorInput); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(DefaultCColorInput); diff --git a/shared/CP_SDK/UI/DefaultComponents/DefaultCDropdown.hpp b/shared/CP_SDK/UI/DefaultComponents/DefaultCDropdown.hpp index 9fde96f..83c6fba 100644 --- a/shared/CP_SDK/UI/DefaultComponents/DefaultCDropdown.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/DefaultCDropdown.hpp @@ -21,7 +21,7 @@ namespace CP_SDK::UI::DefaultComponents { } /// @brief Default CDropdown component - class DefaultCDropdown : public Components::CDropdown + class CP_SDK_EXPORT DefaultCDropdown : public Components::CDropdown { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.DefaultComponents", DefaultCDropdown, Components::CDropdown); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(DefaultCDropdown); diff --git a/shared/CP_SDK/UI/DefaultComponents/DefaultCFLayout.hpp b/shared/CP_SDK/UI/DefaultComponents/DefaultCFLayout.hpp index bd348d5..22ebda6 100644 --- a/shared/CP_SDK/UI/DefaultComponents/DefaultCFLayout.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/DefaultCFLayout.hpp @@ -18,7 +18,7 @@ namespace CP_SDK::UI::DefaultComponents { } /// @brief Default CFLayout component - class DefaultCFLayout : public Components::CFLayout + class CP_SDK_EXPORT DefaultCFLayout : public Components::CFLayout { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.DefaultComponents", DefaultCFLayout, Components::CFLayout); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(DefaultCFLayout); diff --git a/shared/CP_SDK/UI/DefaultComponents/DefaultCFloatingPanel.hpp b/shared/CP_SDK/UI/DefaultComponents/DefaultCFloatingPanel.hpp index cb20945..cd6d02f 100644 --- a/shared/CP_SDK/UI/DefaultComponents/DefaultCFloatingPanel.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/DefaultCFloatingPanel.hpp @@ -16,7 +16,7 @@ namespace CP_SDK::UI::DefaultComponents { } /// @brief Default CFloatingPanel component - class DefaultCFloatingPanel : public Components::CFloatingPanel + class CP_SDK_EXPORT DefaultCFloatingPanel : public Components::CFloatingPanel { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.DefaultComponents", DefaultCFloatingPanel, Components::CFloatingPanel); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(DefaultCFloatingPanel); diff --git a/shared/CP_SDK/UI/DefaultComponents/DefaultCGLayout.hpp b/shared/CP_SDK/UI/DefaultComponents/DefaultCGLayout.hpp index 8876cb2..9c984da 100644 --- a/shared/CP_SDK/UI/DefaultComponents/DefaultCGLayout.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/DefaultCGLayout.hpp @@ -16,7 +16,7 @@ namespace CP_SDK::UI::DefaultComponents { } /// @brief Default CGLayout component - class DefaultCGLayout : public Components::CGLayout + class CP_SDK_EXPORT DefaultCGLayout : public Components::CGLayout { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.DefaultComponents", DefaultCGLayout, Components::CGLayout); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(DefaultCGLayout); diff --git a/shared/CP_SDK/UI/DefaultComponents/DefaultCHLayout.hpp b/shared/CP_SDK/UI/DefaultComponents/DefaultCHLayout.hpp index 4e44a73..2e0d331 100644 --- a/shared/CP_SDK/UI/DefaultComponents/DefaultCHLayout.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/DefaultCHLayout.hpp @@ -16,7 +16,7 @@ namespace CP_SDK::UI::DefaultComponents { } /// @brief Default CHLayout component - class DefaultCHLayout : public Components::CHLayout + class CP_SDK_EXPORT DefaultCHLayout : public Components::CHLayout { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.DefaultComponents", DefaultCHLayout, Components::CHLayout); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(DefaultCHLayout); diff --git a/shared/CP_SDK/UI/DefaultComponents/DefaultCIconButton.hpp b/shared/CP_SDK/UI/DefaultComponents/DefaultCIconButton.hpp index 29ff24e..9dcd9a3 100644 --- a/shared/CP_SDK/UI/DefaultComponents/DefaultCIconButton.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/DefaultCIconButton.hpp @@ -24,7 +24,7 @@ namespace CP_SDK::UI::DefaultComponents { } /// @brief Default CIconButton component - class DefaultCIconButton : public Components::CIconButton + class CP_SDK_EXPORT DefaultCIconButton : public Components::CIconButton { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.DefaultComponents", DefaultCIconButton, Components::CIconButton, CP_SDK_IL2CPP_INTERFACES( _u::IEventSystemHandler, diff --git a/shared/CP_SDK/UI/DefaultComponents/DefaultCImage.hpp b/shared/CP_SDK/UI/DefaultComponents/DefaultCImage.hpp index 9e2b5bd..c1e28d7 100644 --- a/shared/CP_SDK/UI/DefaultComponents/DefaultCImage.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/DefaultCImage.hpp @@ -16,7 +16,7 @@ namespace CP_SDK::UI::DefaultComponents { } /// @brief Default CImage component - class DefaultCImage : public Components::CImage + class CP_SDK_EXPORT DefaultCImage : public Components::CImage { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.DefaultComponents", DefaultCImage, Components::CImage); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(DefaultCImage); diff --git a/shared/CP_SDK/UI/DefaultComponents/DefaultCPrimaryButton.hpp b/shared/CP_SDK/UI/DefaultComponents/DefaultCPrimaryButton.hpp index 7e2eb36..e375aa6 100644 --- a/shared/CP_SDK/UI/DefaultComponents/DefaultCPrimaryButton.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/DefaultCPrimaryButton.hpp @@ -26,7 +26,7 @@ namespace CP_SDK::UI::DefaultComponents { } /// @brief Default CPrimaryButton component - class DefaultCPrimaryButton : public Components::CPrimaryButton + class CP_SDK_EXPORT DefaultCPrimaryButton : public Components::CPrimaryButton { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.DefaultComponents", DefaultCPrimaryButton, Components::CPrimaryButton, CP_SDK_IL2CPP_INTERFACES( _u::IEventSystemHandler, diff --git a/shared/CP_SDK/UI/DefaultComponents/DefaultCSecondaryButton.hpp b/shared/CP_SDK/UI/DefaultComponents/DefaultCSecondaryButton.hpp index 77e4dce..c7f98ba 100644 --- a/shared/CP_SDK/UI/DefaultComponents/DefaultCSecondaryButton.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/DefaultCSecondaryButton.hpp @@ -26,7 +26,7 @@ namespace CP_SDK::UI::DefaultComponents { } /// @brief Default CSecondaryButton component - class DefaultCSecondaryButton : public Components::CSecondaryButton + class CP_SDK_EXPORT DefaultCSecondaryButton : public Components::CSecondaryButton { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.DefaultComponents", DefaultCSecondaryButton, Components::CSecondaryButton, CP_SDK_IL2CPP_INTERFACES( _u::IEventSystemHandler, diff --git a/shared/CP_SDK/UI/DefaultComponents/DefaultCSlider.hpp b/shared/CP_SDK/UI/DefaultComponents/DefaultCSlider.hpp index f0fe47a..47f04f4 100644 --- a/shared/CP_SDK/UI/DefaultComponents/DefaultCSlider.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/DefaultCSlider.hpp @@ -32,7 +32,7 @@ namespace CP_SDK::UI::DefaultComponents { } /// @brief Default CSlider component - class DefaultCSlider : public Components::CSlider + class CP_SDK_EXPORT DefaultCSlider : public Components::CSlider { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.DefaultComponents", DefaultCSlider, Components::CSlider, CP_SDK_IL2CPP_INTERFACES( _u::IEventSystemHandler, diff --git a/shared/CP_SDK/UI/DefaultComponents/DefaultCTabControl.hpp b/shared/CP_SDK/UI/DefaultComponents/DefaultCTabControl.hpp index 527e87e..3dc3897 100644 --- a/shared/CP_SDK/UI/DefaultComponents/DefaultCTabControl.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/DefaultCTabControl.hpp @@ -17,7 +17,7 @@ namespace CP_SDK::UI::DefaultComponents { } /// @brief Default CTabControl component - class DefaultCTabControl : public Components::CTabControl + class CP_SDK_EXPORT DefaultCTabControl : public Components::CTabControl { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.DefaultComponents", DefaultCTabControl, Components::CTabControl); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(DefaultCTabControl); diff --git a/shared/CP_SDK/UI/DefaultComponents/DefaultCText.hpp b/shared/CP_SDK/UI/DefaultComponents/DefaultCText.hpp index 57296f0..6b0c884 100644 --- a/shared/CP_SDK/UI/DefaultComponents/DefaultCText.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/DefaultCText.hpp @@ -17,7 +17,7 @@ namespace CP_SDK::UI::DefaultComponents { } /// @brief Default CText component - class DefaultCText : public Components::CText + class CP_SDK_EXPORT DefaultCText : public Components::CText { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.DefaultComponents", DefaultCText, Components::CText); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(DefaultCText); diff --git a/shared/CP_SDK/UI/DefaultComponents/DefaultCTextInput.hpp b/shared/CP_SDK/UI/DefaultComponents/DefaultCTextInput.hpp index b00f286..fe399d2 100644 --- a/shared/CP_SDK/UI/DefaultComponents/DefaultCTextInput.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/DefaultCTextInput.hpp @@ -20,7 +20,7 @@ namespace CP_SDK::UI::DefaultComponents { } /// @brief Default CTextInput component - class DefaultCTextInput : public Components::CTextInput + class CP_SDK_EXPORT DefaultCTextInput : public Components::CTextInput { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.DefaultComponents", DefaultCTextInput, Components::CTextInput); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(DefaultCTextInput); diff --git a/shared/CP_SDK/UI/DefaultComponents/DefaultCTextSegmentedControl.hpp b/shared/CP_SDK/UI/DefaultComponents/DefaultCTextSegmentedControl.hpp index f17e981..0b9735f 100644 --- a/shared/CP_SDK/UI/DefaultComponents/DefaultCTextSegmentedControl.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/DefaultCTextSegmentedControl.hpp @@ -18,7 +18,7 @@ namespace CP_SDK::UI::DefaultComponents { } /// @brief Default CTextSegmentedControl component - class DefaultCTextSegmentedControl : public Components::CTextSegmentedControl + class CP_SDK_EXPORT DefaultCTextSegmentedControl : public Components::CTextSegmentedControl { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.DefaultComponents", DefaultCTextSegmentedControl, Components::CTextSegmentedControl); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(DefaultCTextSegmentedControl); diff --git a/shared/CP_SDK/UI/DefaultComponents/DefaultCToggle.hpp b/shared/CP_SDK/UI/DefaultComponents/DefaultCToggle.hpp index f0e2fb3..b033372 100644 --- a/shared/CP_SDK/UI/DefaultComponents/DefaultCToggle.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/DefaultCToggle.hpp @@ -21,7 +21,7 @@ namespace CP_SDK::UI::DefaultComponents { } /// @brief Default CToggle component - class DefaultCToggle : public Components::CToggle + class CP_SDK_EXPORT DefaultCToggle : public Components::CToggle { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.DefaultComponents", DefaultCToggle, Components::CToggle); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(DefaultCToggle); diff --git a/shared/CP_SDK/UI/DefaultComponents/DefaultCVLayout.hpp b/shared/CP_SDK/UI/DefaultComponents/DefaultCVLayout.hpp index b56a3fd..385d220 100644 --- a/shared/CP_SDK/UI/DefaultComponents/DefaultCVLayout.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/DefaultCVLayout.hpp @@ -16,7 +16,7 @@ namespace CP_SDK::UI::DefaultComponents { } /// @brief Default CVLayout component - class DefaultCVLayout : public Components::CVLayout + class CP_SDK_EXPORT DefaultCVLayout : public Components::CVLayout { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.DefaultComponents", DefaultCVLayout, Components::CVLayout); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(DefaultCVLayout); diff --git a/shared/CP_SDK/UI/DefaultComponents/DefaultCVScrollView.hpp b/shared/CP_SDK/UI/DefaultComponents/DefaultCVScrollView.hpp index 39b1d93..40b92f5 100644 --- a/shared/CP_SDK/UI/DefaultComponents/DefaultCVScrollView.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/DefaultCVScrollView.hpp @@ -21,7 +21,7 @@ namespace CP_SDK::UI::DefaultComponents { } /// @brief Default CVScrollView component - class DefaultCVScrollView : public Components::CVScrollView + class CP_SDK_EXPORT DefaultCVScrollView : public Components::CVScrollView { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.DefaultComponents", DefaultCVScrollView, Components::CVScrollView); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(DefaultCVScrollView); diff --git a/shared/CP_SDK/UI/DefaultComponents/DefaultCVVList.hpp b/shared/CP_SDK/UI/DefaultComponents/DefaultCVVList.hpp index 6ccfd20..c0c7d85 100644 --- a/shared/CP_SDK/UI/DefaultComponents/DefaultCVVList.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/DefaultCVVList.hpp @@ -18,7 +18,7 @@ namespace CP_SDK::UI::DefaultComponents { } /// @brief Default CVVList component - class DefaultCVVList : public Components::CVVList + class CP_SDK_EXPORT DefaultCVVList : public Components::CVVList { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.DefaultComponents", DefaultCVVList, Components::CVVList); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(DefaultCVVList); diff --git a/shared/CP_SDK/UI/DefaultComponents/Subs/SubStackLayoutGroup.hpp b/shared/CP_SDK/UI/DefaultComponents/Subs/SubStackLayoutGroup.hpp index 927a155..5495fe4 100644 --- a/shared/CP_SDK/UI/DefaultComponents/Subs/SubStackLayoutGroup.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/Subs/SubStackLayoutGroup.hpp @@ -19,7 +19,7 @@ namespace CP_SDK::UI::DefaultComponents::Subs { } /// @brief Stack layout group - class SubStackLayoutGroup : public _u::LayoutGroup + class CP_SDK_EXPORT SubStackLayoutGroup : public _u::LayoutGroup { CP_SDK_IL2CPP_INHERIT("CP_SDK::UI::DefaultComponents::Subs", SubStackLayoutGroup, _u::LayoutGroup); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(SubStackLayoutGroup); diff --git a/shared/CP_SDK/UI/DefaultComponents/Subs/SubToggleWithCallbacks.hpp b/shared/CP_SDK/UI/DefaultComponents/Subs/SubToggleWithCallbacks.hpp index 10d3cf6..3eab17b 100644 --- a/shared/CP_SDK/UI/DefaultComponents/Subs/SubToggleWithCallbacks.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/Subs/SubToggleWithCallbacks.hpp @@ -19,7 +19,7 @@ namespace CP_SDK::UI::DefaultComponents::Subs { } /// @brief Toggle with callbacks component - class SubToggleWithCallbacks : public _u::Toggle + class CP_SDK_EXPORT SubToggleWithCallbacks : public _u::Toggle { CP_SDK_IL2CPP_INHERIT("CP_SDK::UI::DefaultComponents::Subs", SubToggleWithCallbacks, _u::Toggle); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(SubToggleWithCallbacks); diff --git a/shared/CP_SDK/UI/DefaultComponents/Subs/SubVScrollIndicator.hpp b/shared/CP_SDK/UI/DefaultComponents/Subs/SubVScrollIndicator.hpp index f147075..d89dd68 100644 --- a/shared/CP_SDK/UI/DefaultComponents/Subs/SubVScrollIndicator.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/Subs/SubVScrollIndicator.hpp @@ -18,7 +18,7 @@ namespace CP_SDK::UI::DefaultComponents::Subs { } /// @brief Vertical scroll indicator component - class SubVScrollIndicator : public _u::MonoBehaviour + class CP_SDK_EXPORT SubVScrollIndicator : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK::UI::DefaultComponents::Subs", SubVScrollIndicator, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(SubVScrollIndicator); diff --git a/shared/CP_SDK/UI/DefaultComponents/Subs/SubVScrollViewContent.hpp b/shared/CP_SDK/UI/DefaultComponents/Subs/SubVScrollViewContent.hpp index 30c0688..d12a523 100644 --- a/shared/CP_SDK/UI/DefaultComponents/Subs/SubVScrollViewContent.hpp +++ b/shared/CP_SDK/UI/DefaultComponents/Subs/SubVScrollViewContent.hpp @@ -17,7 +17,7 @@ namespace CP_SDK::UI::DefaultComponents::Subs { } /// @brief Vertical scroll view content updater - class SubVScrollViewContent : public _u::MonoBehaviour + class CP_SDK_EXPORT SubVScrollViewContent : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK::UI::DefaultComponents::Subs", SubVScrollViewContent, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(SubVScrollViewContent); diff --git a/shared/CP_SDK/UI/DefaultFactories/DefaultColorInputFactory.hpp b/shared/CP_SDK/UI/DefaultFactories/DefaultColorInputFactory.hpp index 84ad9c9..c57467a 100644 --- a/shared/CP_SDK/UI/DefaultFactories/DefaultColorInputFactory.hpp +++ b/shared/CP_SDK/UI/DefaultFactories/DefaultColorInputFactory.hpp @@ -10,7 +10,7 @@ namespace CP_SDK::UI::DefaultFactories { } /// @brief Default CColorInput factory - class DefaultColorInputFactory : public FactoryInterfaces::IColorInputFactory + class CP_SDK_EXPORT DefaultColorInputFactory : public FactoryInterfaces::IColorInputFactory { public: /// @brief Create an CColorInput into the parent diff --git a/shared/CP_SDK/UI/DefaultFactories/DefaultDropdownFactory.hpp b/shared/CP_SDK/UI/DefaultFactories/DefaultDropdownFactory.hpp index 5960701..3b1a28d 100644 --- a/shared/CP_SDK/UI/DefaultFactories/DefaultDropdownFactory.hpp +++ b/shared/CP_SDK/UI/DefaultFactories/DefaultDropdownFactory.hpp @@ -10,7 +10,7 @@ namespace CP_SDK::UI::DefaultFactories { } /// @brief Default CDropdown factory - class DefaultDropdownFactory : public FactoryInterfaces::IDropdownFactory + class CP_SDK_EXPORT DefaultDropdownFactory : public FactoryInterfaces::IDropdownFactory { public: /// @brief Create an CDropdown into the parent diff --git a/shared/CP_SDK/UI/DefaultFactories/DefaultFLayoutFactory.hpp b/shared/CP_SDK/UI/DefaultFactories/DefaultFLayoutFactory.hpp index d2e9f3c..f76539a 100644 --- a/shared/CP_SDK/UI/DefaultFactories/DefaultFLayoutFactory.hpp +++ b/shared/CP_SDK/UI/DefaultFactories/DefaultFLayoutFactory.hpp @@ -10,7 +10,7 @@ namespace CP_SDK::UI::DefaultFactories { } /// @brief Default CFLayout factory - class DefaultFLayoutFactory : public FactoryInterfaces::IFLayoutFactory + class CP_SDK_EXPORT DefaultFLayoutFactory : public FactoryInterfaces::IFLayoutFactory { public: /// @brief Create an CFLayout into the parent diff --git a/shared/CP_SDK/UI/DefaultFactories/DefaultFloatingPanelFactory.hpp b/shared/CP_SDK/UI/DefaultFactories/DefaultFloatingPanelFactory.hpp index 68f7fa4..4f25e95 100644 --- a/shared/CP_SDK/UI/DefaultFactories/DefaultFloatingPanelFactory.hpp +++ b/shared/CP_SDK/UI/DefaultFactories/DefaultFloatingPanelFactory.hpp @@ -10,7 +10,7 @@ namespace CP_SDK::UI::DefaultFactories { } /// @brief Default CFloatingPanel factory - class DefaultFloatingPanelFactory : public FactoryInterfaces::IFloatingPanelFactory + class CP_SDK_EXPORT DefaultFloatingPanelFactory : public FactoryInterfaces::IFloatingPanelFactory { public: /// @brief Create an CFloatingPanel into the parent diff --git a/shared/CP_SDK/UI/DefaultFactories/DefaultGLayoutFactory.hpp b/shared/CP_SDK/UI/DefaultFactories/DefaultGLayoutFactory.hpp index 6b27d48..84095f6 100644 --- a/shared/CP_SDK/UI/DefaultFactories/DefaultGLayoutFactory.hpp +++ b/shared/CP_SDK/UI/DefaultFactories/DefaultGLayoutFactory.hpp @@ -10,7 +10,7 @@ namespace CP_SDK::UI::DefaultFactories { } /// @brief Default CGLayout factory - class DefaultGLayoutFactory : public FactoryInterfaces::IGLayoutFactory + class CP_SDK_EXPORT DefaultGLayoutFactory : public FactoryInterfaces::IGLayoutFactory { public: /// @brief Create an CGLayout into the parent diff --git a/shared/CP_SDK/UI/DefaultFactories/DefaultHLayoutFactory.hpp b/shared/CP_SDK/UI/DefaultFactories/DefaultHLayoutFactory.hpp index 91f1ec1..a47516f 100644 --- a/shared/CP_SDK/UI/DefaultFactories/DefaultHLayoutFactory.hpp +++ b/shared/CP_SDK/UI/DefaultFactories/DefaultHLayoutFactory.hpp @@ -10,7 +10,7 @@ namespace CP_SDK::UI::DefaultFactories { } /// @brief Default CHLayout factory - class DefaultHLayoutFactory : public FactoryInterfaces::IHLayoutFactory + class CP_SDK_EXPORT DefaultHLayoutFactory : public FactoryInterfaces::IHLayoutFactory { public: /// @brief Create an CHLayout into the parent diff --git a/shared/CP_SDK/UI/DefaultFactories/DefaultIconButtonFactory.hpp b/shared/CP_SDK/UI/DefaultFactories/DefaultIconButtonFactory.hpp index 2e1dc85..2b88e43 100644 --- a/shared/CP_SDK/UI/DefaultFactories/DefaultIconButtonFactory.hpp +++ b/shared/CP_SDK/UI/DefaultFactories/DefaultIconButtonFactory.hpp @@ -10,7 +10,7 @@ namespace CP_SDK::UI::DefaultFactories { } /// @brief Default CIconButton factory - class DefaultIconButtonFactory : public FactoryInterfaces::IIconButtonFactory + class CP_SDK_EXPORT DefaultIconButtonFactory : public FactoryInterfaces::IIconButtonFactory { public: /// @brief Create an CIconButton into the parent diff --git a/shared/CP_SDK/UI/DefaultFactories/DefaultImageFactory.hpp b/shared/CP_SDK/UI/DefaultFactories/DefaultImageFactory.hpp index c66ddad..32a367f 100644 --- a/shared/CP_SDK/UI/DefaultFactories/DefaultImageFactory.hpp +++ b/shared/CP_SDK/UI/DefaultFactories/DefaultImageFactory.hpp @@ -10,7 +10,7 @@ namespace CP_SDK::UI::DefaultFactories { } /// @brief Default CImage factory - class DefaultImageFactory : public FactoryInterfaces::IImageFactory + class CP_SDK_EXPORT DefaultImageFactory : public FactoryInterfaces::IImageFactory { public: /// @brief Create an CImage into the parent diff --git a/shared/CP_SDK/UI/DefaultFactories/DefaultPrimaryButtonFactory.hpp b/shared/CP_SDK/UI/DefaultFactories/DefaultPrimaryButtonFactory.hpp index e96c7df..1b6582a 100644 --- a/shared/CP_SDK/UI/DefaultFactories/DefaultPrimaryButtonFactory.hpp +++ b/shared/CP_SDK/UI/DefaultFactories/DefaultPrimaryButtonFactory.hpp @@ -10,7 +10,7 @@ namespace CP_SDK::UI::DefaultFactories { } /// @brief Default CPrimaryButton factory - class DefaultPrimaryButtonFactory : public FactoryInterfaces::IPrimaryButtonFactory + class CP_SDK_EXPORT DefaultPrimaryButtonFactory : public FactoryInterfaces::IPrimaryButtonFactory { public: /// @brief Create an CPrimaryButton into the parent diff --git a/shared/CP_SDK/UI/DefaultFactories/DefaultSecondaryButtonFactory.hpp b/shared/CP_SDK/UI/DefaultFactories/DefaultSecondaryButtonFactory.hpp index 09e5432..dd2be74 100644 --- a/shared/CP_SDK/UI/DefaultFactories/DefaultSecondaryButtonFactory.hpp +++ b/shared/CP_SDK/UI/DefaultFactories/DefaultSecondaryButtonFactory.hpp @@ -10,7 +10,7 @@ namespace CP_SDK::UI::DefaultFactories { } /// @brief Default CSecondaryButton factory - class DefaultSecondaryButtonFactory : public FactoryInterfaces::ISecondaryButtonFactory + class CP_SDK_EXPORT DefaultSecondaryButtonFactory : public FactoryInterfaces::ISecondaryButtonFactory { public: /// @brief Create an CSecondaryButton into the parent diff --git a/shared/CP_SDK/UI/DefaultFactories/DefaultSliderFactory.hpp b/shared/CP_SDK/UI/DefaultFactories/DefaultSliderFactory.hpp index 210ffa7..ebbb129 100644 --- a/shared/CP_SDK/UI/DefaultFactories/DefaultSliderFactory.hpp +++ b/shared/CP_SDK/UI/DefaultFactories/DefaultSliderFactory.hpp @@ -10,7 +10,7 @@ namespace CP_SDK::UI::DefaultFactories { } /// @brief Default CSlider factory - class DefaultSliderFactory : public FactoryInterfaces::ISliderFactory + class CP_SDK_EXPORT DefaultSliderFactory : public FactoryInterfaces::ISliderFactory { public: /// @brief Create an CSlider into the parent diff --git a/shared/CP_SDK/UI/DefaultFactories/DefaultTabControlFactory.hpp b/shared/CP_SDK/UI/DefaultFactories/DefaultTabControlFactory.hpp index f23d0e3..b89a997 100644 --- a/shared/CP_SDK/UI/DefaultFactories/DefaultTabControlFactory.hpp +++ b/shared/CP_SDK/UI/DefaultFactories/DefaultTabControlFactory.hpp @@ -10,7 +10,7 @@ namespace CP_SDK::UI::DefaultFactories { } /// @brief Default CTabControl factory - class DefaultTabControlFactory : public FactoryInterfaces::ITabControlFactory + class CP_SDK_EXPORT DefaultTabControlFactory : public FactoryInterfaces::ITabControlFactory { public: /// @brief Create an CTabControl into the parent diff --git a/shared/CP_SDK/UI/DefaultFactories/DefaultTextFactory.hpp b/shared/CP_SDK/UI/DefaultFactories/DefaultTextFactory.hpp index a9496c3..784a159 100644 --- a/shared/CP_SDK/UI/DefaultFactories/DefaultTextFactory.hpp +++ b/shared/CP_SDK/UI/DefaultFactories/DefaultTextFactory.hpp @@ -10,7 +10,7 @@ namespace CP_SDK::UI::DefaultFactories { } /// @brief Default CText factory - class DefaultTextFactory : public FactoryInterfaces::ITextFactory + class CP_SDK_EXPORT DefaultTextFactory : public FactoryInterfaces::ITextFactory { public: /// @brief Create an CText into the parent diff --git a/shared/CP_SDK/UI/DefaultFactories/DefaultTextInputFactory.hpp b/shared/CP_SDK/UI/DefaultFactories/DefaultTextInputFactory.hpp index 0549ec1..78f1b90 100644 --- a/shared/CP_SDK/UI/DefaultFactories/DefaultTextInputFactory.hpp +++ b/shared/CP_SDK/UI/DefaultFactories/DefaultTextInputFactory.hpp @@ -10,7 +10,7 @@ namespace CP_SDK::UI::DefaultFactories { } /// @brief Default CTextInput factory - class DefaultTextInputFactory : public FactoryInterfaces::ITextInputFactory + class CP_SDK_EXPORT DefaultTextInputFactory : public FactoryInterfaces::ITextInputFactory { public: /// @brief Create an CTextInput into the parent diff --git a/shared/CP_SDK/UI/DefaultFactories/DefaultTextSegmentedControlFactory.hpp b/shared/CP_SDK/UI/DefaultFactories/DefaultTextSegmentedControlFactory.hpp index 30b1dc8..e9930a5 100644 --- a/shared/CP_SDK/UI/DefaultFactories/DefaultTextSegmentedControlFactory.hpp +++ b/shared/CP_SDK/UI/DefaultFactories/DefaultTextSegmentedControlFactory.hpp @@ -10,7 +10,7 @@ namespace CP_SDK::UI::DefaultFactories { } /// @brief Default CTextSegmentedControl factory - class DefaultTextSegmentedControlFactory : public FactoryInterfaces::ITextSegmentedControlFactory + class CP_SDK_EXPORT DefaultTextSegmentedControlFactory : public FactoryInterfaces::ITextSegmentedControlFactory { public: /// @brief Create an CTextSegmentedControl into the parent diff --git a/shared/CP_SDK/UI/DefaultFactories/DefaultToggleFactory.hpp b/shared/CP_SDK/UI/DefaultFactories/DefaultToggleFactory.hpp index c3b9d44..a19ba9a 100644 --- a/shared/CP_SDK/UI/DefaultFactories/DefaultToggleFactory.hpp +++ b/shared/CP_SDK/UI/DefaultFactories/DefaultToggleFactory.hpp @@ -10,7 +10,7 @@ namespace CP_SDK::UI::DefaultFactories { } /// @brief Default CToggle factory - class DefaultToggleFactory : public FactoryInterfaces::IToggleFactory + class CP_SDK_EXPORT DefaultToggleFactory : public FactoryInterfaces::IToggleFactory { public: /// @brief Create an CToggle into the parent diff --git a/shared/CP_SDK/UI/DefaultFactories/DefaultVLayoutFactory.hpp b/shared/CP_SDK/UI/DefaultFactories/DefaultVLayoutFactory.hpp index ed7317a..6eb5a0b 100644 --- a/shared/CP_SDK/UI/DefaultFactories/DefaultVLayoutFactory.hpp +++ b/shared/CP_SDK/UI/DefaultFactories/DefaultVLayoutFactory.hpp @@ -10,7 +10,7 @@ namespace CP_SDK::UI::DefaultFactories { } /// @brief Default CVLayout factory - class DefaultVLayoutFactory : public FactoryInterfaces::IVLayoutFactory + class CP_SDK_EXPORT DefaultVLayoutFactory : public FactoryInterfaces::IVLayoutFactory { public: /// @brief Create an CVLayout into the parent diff --git a/shared/CP_SDK/UI/DefaultFactories/DefaultVScrollViewFactory.hpp b/shared/CP_SDK/UI/DefaultFactories/DefaultVScrollViewFactory.hpp index e704fe7..ec19109 100644 --- a/shared/CP_SDK/UI/DefaultFactories/DefaultVScrollViewFactory.hpp +++ b/shared/CP_SDK/UI/DefaultFactories/DefaultVScrollViewFactory.hpp @@ -10,7 +10,7 @@ namespace CP_SDK::UI::DefaultFactories { } /// @brief Default CVScrollView factory - class DefaultVScrollViewFactory : public FactoryInterfaces::IVScrollViewFactory + class CP_SDK_EXPORT DefaultVScrollViewFactory : public FactoryInterfaces::IVScrollViewFactory { public: /// @brief Create an CVScrollView into the parent diff --git a/shared/CP_SDK/UI/DefaultFactories/DefaultVVListFactory.hpp b/shared/CP_SDK/UI/DefaultFactories/DefaultVVListFactory.hpp index 34042dc..05f2ac7 100644 --- a/shared/CP_SDK/UI/DefaultFactories/DefaultVVListFactory.hpp +++ b/shared/CP_SDK/UI/DefaultFactories/DefaultVVListFactory.hpp @@ -10,7 +10,7 @@ namespace CP_SDK::UI::DefaultFactories { } /// @brief Default CVVList factory - class DefaultVVListFactory : public FactoryInterfaces::IVVListFactory + class CP_SDK_EXPORT DefaultVVListFactory : public FactoryInterfaces::IVVListFactory { public: /// @brief Create an CVVList into the parent diff --git a/shared/CP_SDK/UI/FlowCoordinator.hpp b/shared/CP_SDK/UI/FlowCoordinator.hpp index 1035fb6..42894d9 100644 --- a/shared/CP_SDK/UI/FlowCoordinator.hpp +++ b/shared/CP_SDK/UI/FlowCoordinator.hpp @@ -24,7 +24,7 @@ namespace CP_SDK::UI { } /// @brief Flow coordinator base class - class CP_SDK_EXPORT_VISIBILITY FlowCoordinator : public IFlowCoordinator + class CP_SDK_EXPORT FlowCoordinator : public IFlowCoordinator { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI", FlowCoordinator, IFlowCoordinator); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(FlowCoordinator); diff --git a/shared/CP_SDK/UI/FlowCoordinators/MainFlowCoordinator.hpp b/shared/CP_SDK/UI/FlowCoordinators/MainFlowCoordinator.hpp index ad24323..6f32f49 100644 --- a/shared/CP_SDK/UI/FlowCoordinators/MainFlowCoordinator.hpp +++ b/shared/CP_SDK/UI/FlowCoordinators/MainFlowCoordinator.hpp @@ -16,7 +16,7 @@ namespace CP_SDK::UI::FlowCoordinators { } /// @brief UI flow coordinator - class CP_SDK_EXPORT_VISIBILITY MainFlowCoordinator : public FlowCoordinator + class CP_SDK_EXPORT MainFlowCoordinator : public FlowCoordinator { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.FlowCoordinators", MainFlowCoordinator, FlowCoordinator); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(MainFlowCoordinator); diff --git a/shared/CP_SDK/UI/IFlowCoordinator.hpp b/shared/CP_SDK/UI/IFlowCoordinator.hpp index 84ee27b..62cf779 100644 --- a/shared/CP_SDK/UI/IFlowCoordinator.hpp +++ b/shared/CP_SDK/UI/IFlowCoordinator.hpp @@ -14,7 +14,7 @@ namespace CP_SDK::UI { } /// @brief Flow coordinator interface - class IFlowCoordinator : public _u::MonoBehaviour + class CP_SDK_EXPORT IFlowCoordinator : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI", IFlowCoordinator, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(IFlowCoordinator); diff --git a/shared/CP_SDK/UI/IModal.hpp b/shared/CP_SDK/UI/IModal.hpp index 2bfa4b2..1e35edd 100644 --- a/shared/CP_SDK/UI/IModal.hpp +++ b/shared/CP_SDK/UI/IModal.hpp @@ -18,7 +18,7 @@ namespace CP_SDK::UI { } /// @brief Abstract base modal component - class IModal : public _u::MonoBehaviour + class CP_SDK_EXPORT IModal : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI", IModal, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(IModal); diff --git a/shared/CP_SDK/UI/IScreen.hpp b/shared/CP_SDK/UI/IScreen.hpp index 901bf7c..f9ca4a4 100644 --- a/shared/CP_SDK/UI/IScreen.hpp +++ b/shared/CP_SDK/UI/IScreen.hpp @@ -26,7 +26,7 @@ namespace CP_SDK::UI { class IViewController; /// @brief Abstract screen - class IScreen : public _u::MonoBehaviour + class CP_SDK_EXPORT IScreen : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI", IScreen, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(IScreen); diff --git a/shared/CP_SDK/UI/IViewController.hpp b/shared/CP_SDK/UI/IViewController.hpp index 710c821..11a1b62 100644 --- a/shared/CP_SDK/UI/IViewController.hpp +++ b/shared/CP_SDK/UI/IViewController.hpp @@ -29,7 +29,7 @@ namespace CP_SDK::UI { using KeyboardCustomKeys = std::vector; /// @brief IViewController interface - class IViewController : public _u::MonoBehaviour + class CP_SDK_EXPORT IViewController : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI", IViewController, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(IViewController); diff --git a/shared/CP_SDK/UI/LoadingProgressBar.hpp b/shared/CP_SDK/UI/LoadingProgressBar.hpp index 189eb98..7744f9a 100644 --- a/shared/CP_SDK/UI/LoadingProgressBar.hpp +++ b/shared/CP_SDK/UI/LoadingProgressBar.hpp @@ -26,7 +26,7 @@ namespace CP_SDK::UI { } /// @brief Loading progress bar - class CP_SDK_EXPORT_VISIBILITY LoadingProgressBar : public _u::MonoBehaviour + class CP_SDK_EXPORT LoadingProgressBar : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI", LoadingProgressBar, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(LoadingProgressBar); diff --git a/shared/CP_SDK/UI/ModButton.hpp b/shared/CP_SDK/UI/ModButton.hpp index 9dad2fb..e6ab506 100644 --- a/shared/CP_SDK/UI/ModButton.hpp +++ b/shared/CP_SDK/UI/ModButton.hpp @@ -14,7 +14,7 @@ namespace CP_SDK::UI { } /// @brief Mod button - class CP_SDK_EXPORT_VISIBILITY ModButton + class CP_SDK_EXPORT ModButton { CP_SDK_NO_DEF_CTORS(ModButton); CP_SDK_PRIV_TAG(); diff --git a/shared/CP_SDK/UI/ModMenu.hpp b/shared/CP_SDK/UI/ModMenu.hpp index 3b15185..5d5323e 100644 --- a/shared/CP_SDK/UI/ModMenu.hpp +++ b/shared/CP_SDK/UI/ModMenu.hpp @@ -19,7 +19,7 @@ namespace CP_SDK::UI { } /// @brief Mod menu - class CP_SDK_EXPORT_VISIBILITY ModMenu : public _u::MonoBehaviour + class CP_SDK_EXPORT ModMenu : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI", ModMenu, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(ModMenu); diff --git a/shared/CP_SDK/UI/Modals/ColorPicker.hpp b/shared/CP_SDK/UI/Modals/ColorPicker.hpp index a72101b..4c6b1f3 100644 --- a/shared/CP_SDK/UI/Modals/ColorPicker.hpp +++ b/shared/CP_SDK/UI/Modals/ColorPicker.hpp @@ -17,7 +17,7 @@ namespace CP_SDK::UI::Modals { } /// @brief ColorPicker modal - class ColorPicker : public IModal + class CP_SDK_EXPORT ColorPicker : public IModal { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Modals", ColorPicker, IModal); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(ColorPicker); diff --git a/shared/CP_SDK/UI/Modals/Confirmation.hpp b/shared/CP_SDK/UI/Modals/Confirmation.hpp index 2c23dd0..35fdc8d 100644 --- a/shared/CP_SDK/UI/Modals/Confirmation.hpp +++ b/shared/CP_SDK/UI/Modals/Confirmation.hpp @@ -17,7 +17,7 @@ namespace CP_SDK::UI::Modals { } /// @brief Confirmation modal - class Confirmation : public IModal + class CP_SDK_EXPORT Confirmation : public IModal { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Modals", Confirmation, IModal); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(Confirmation); diff --git a/shared/CP_SDK/UI/Modals/Dropdown.hpp b/shared/CP_SDK/UI/Modals/Dropdown.hpp index 3845fef..1dac0ed 100644 --- a/shared/CP_SDK/UI/Modals/Dropdown.hpp +++ b/shared/CP_SDK/UI/Modals/Dropdown.hpp @@ -17,7 +17,7 @@ namespace CP_SDK::UI::Modals { } /// @brief Dropdown modal - class Dropdown : public IModal + class CP_SDK_EXPORT Dropdown : public IModal { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Modals", Dropdown, IModal); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(Dropdown); diff --git a/shared/CP_SDK/UI/Modals/Keyboard.hpp b/shared/CP_SDK/UI/Modals/Keyboard.hpp index baad6c3..0341796 100644 --- a/shared/CP_SDK/UI/Modals/Keyboard.hpp +++ b/shared/CP_SDK/UI/Modals/Keyboard.hpp @@ -17,7 +17,7 @@ namespace CP_SDK::UI::Modals { } /// @brief Keyboard modal - class Keyboard : public IModal + class CP_SDK_EXPORT Keyboard : public IModal { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Modals", Keyboard, IModal); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(Keyboard); diff --git a/shared/CP_SDK/UI/Modals/Loading.hpp b/shared/CP_SDK/UI/Modals/Loading.hpp index e64157e..15ba5f2 100644 --- a/shared/CP_SDK/UI/Modals/Loading.hpp +++ b/shared/CP_SDK/UI/Modals/Loading.hpp @@ -17,7 +17,7 @@ namespace CP_SDK::UI::Modals { } /// @brief Loading modal - class Loading : public IModal + class CP_SDK_EXPORT Loading : public IModal { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Modals", Loading, IModal); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(Loading); diff --git a/shared/CP_SDK/UI/Modals/Message.hpp b/shared/CP_SDK/UI/Modals/Message.hpp index 83d8a69..4251e68 100644 --- a/shared/CP_SDK/UI/Modals/Message.hpp +++ b/shared/CP_SDK/UI/Modals/Message.hpp @@ -17,7 +17,7 @@ namespace CP_SDK::UI::Modals { } /// @brief Message modal - class Message : public IModal + class CP_SDK_EXPORT Message : public IModal { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Modals", Message, IModal); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(Message); diff --git a/shared/CP_SDK/UI/ScreenSystem.hpp b/shared/CP_SDK/UI/ScreenSystem.hpp index b755c6a..a74baf3 100644 --- a/shared/CP_SDK/UI/ScreenSystem.hpp +++ b/shared/CP_SDK/UI/ScreenSystem.hpp @@ -16,7 +16,7 @@ namespace CP_SDK::UI { } /// @brief ScreenSystem widget - class CP_SDK_EXPORT_VISIBILITY ScreenSystem : public _u::MonoBehaviour + class CP_SDK_EXPORT ScreenSystem : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI", ScreenSystem, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(ScreenSystem); diff --git a/shared/CP_SDK/UI/Tooltip.hpp b/shared/CP_SDK/UI/Tooltip.hpp index 2108ed6..4320660 100644 --- a/shared/CP_SDK/UI/Tooltip.hpp +++ b/shared/CP_SDK/UI/Tooltip.hpp @@ -22,7 +22,7 @@ namespace CP_SDK::UI { } /// @brief Tooltip widget - class CP_SDK_EXPORT_VISIBILITY Tooltip : public _u::MonoBehaviour + class CP_SDK_EXPORT Tooltip : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI", Tooltip, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(Tooltip); diff --git a/shared/CP_SDK/UI/UISystem.hpp b/shared/CP_SDK/UI/UISystem.hpp index 7ad66ba..1bc8b3f 100644 --- a/shared/CP_SDK/UI/UISystem.hpp +++ b/shared/CP_SDK/UI/UISystem.hpp @@ -44,7 +44,7 @@ namespace CP_SDK::UI { } /// @brief UI system main class - class CP_SDK_EXPORT_VISIBILITY UISystem + class CP_SDK_EXPORT UISystem { CP_SDK_NO_DEF_CTORS(UISystem); diff --git a/shared/CP_SDK/UI/ValueFormatters.hpp b/shared/CP_SDK/UI/ValueFormatters.hpp index c69df7c..a1330a4 100644 --- a/shared/CP_SDK/UI/ValueFormatters.hpp +++ b/shared/CP_SDK/UI/ValueFormatters.hpp @@ -6,12 +6,13 @@ namespace CP_SDK::UI { - class CP_SDK_EXPORT_VISIBILITY ValueFormatters + class CP_SDK_EXPORT ValueFormatters { public: static std::u16string Percentage(float p_Value); static std::u16string Minutes(float p_Value); + static std::u16string Days(float p_Value); static std::u16string TimeShortBaseSeconds(float p_Value); diff --git a/shared/CP_SDK/UI/ViewController.hpp b/shared/CP_SDK/UI/ViewController.hpp index 3befc6d..9a1c17f 100644 --- a/shared/CP_SDK/UI/ViewController.hpp +++ b/shared/CP_SDK/UI/ViewController.hpp @@ -26,7 +26,7 @@ namespace CP_SDK::UI { } /// @brief IViewController interface - class CP_SDK_EXPORT_VISIBILITY ViewController : public IViewController + class CP_SDK_EXPORT ViewController : public IViewController { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI", ViewController, IViewController); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(ViewController); diff --git a/shared/CP_SDK/UI/Views/MainLeftView.hpp b/shared/CP_SDK/UI/Views/MainLeftView.hpp index 3527557..47e5292 100644 --- a/shared/CP_SDK/UI/Views/MainLeftView.hpp +++ b/shared/CP_SDK/UI/Views/MainLeftView.hpp @@ -16,7 +16,7 @@ namespace CP_SDK::UI::Views { } /// @brief Welcome Left View controller - class MainLeftView : public ViewController + class CP_SDK_EXPORT MainLeftView : public ViewController { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Views", MainLeftView, ViewController); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(MainLeftView); diff --git a/shared/CP_SDK/UI/Views/MainMainView.hpp b/shared/CP_SDK/UI/Views/MainMainView.hpp index 2b30730..a84be1f 100644 --- a/shared/CP_SDK/UI/Views/MainMainView.hpp +++ b/shared/CP_SDK/UI/Views/MainMainView.hpp @@ -18,7 +18,7 @@ namespace CP_SDK::UI::Views { } /// @brief Main main view controller - class MainMainView : public ViewController + class CP_SDK_EXPORT MainMainView : public ViewController { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Views", MainMainView, ViewController); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(MainMainView); diff --git a/shared/CP_SDK/UI/Views/MainRightView.hpp b/shared/CP_SDK/UI/Views/MainRightView.hpp index f175c2b..b8dba6d 100644 --- a/shared/CP_SDK/UI/Views/MainRightView.hpp +++ b/shared/CP_SDK/UI/Views/MainRightView.hpp @@ -16,7 +16,7 @@ namespace CP_SDK::UI::Views { } /// @brief Welcome Right View controller - class MainRightView : public ViewController + class CP_SDK_EXPORT MainRightView : public ViewController { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Views", MainRightView, ViewController); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(MainRightView); diff --git a/shared/CP_SDK/UI/Views/ModMenuView.hpp b/shared/CP_SDK/UI/Views/ModMenuView.hpp index 13de57b..f09f0de 100644 --- a/shared/CP_SDK/UI/Views/ModMenuView.hpp +++ b/shared/CP_SDK/UI/Views/ModMenuView.hpp @@ -20,7 +20,7 @@ namespace CP_SDK::UI::Views { } /// @brief Mod menu view controller - class ModMenuView : public ViewController + class CP_SDK_EXPORT ModMenuView : public ViewController { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Views", ModMenuView, ViewController); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(ModMenuView); diff --git a/shared/CP_SDK/UI/Views/SettingsLeftView.hpp b/shared/CP_SDK/UI/Views/SettingsLeftView.hpp index 4ca3cd5..6eb9c7d 100644 --- a/shared/CP_SDK/UI/Views/SettingsLeftView.hpp +++ b/shared/CP_SDK/UI/Views/SettingsLeftView.hpp @@ -16,7 +16,7 @@ namespace CP_SDK::UI::Views { } /// @brief Settings left view controller - class SettingsLeftView : public ViewController + class CP_SDK_EXPORT SettingsLeftView : public ViewController { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Views", SettingsLeftView, ViewController); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(SettingsLeftView); diff --git a/shared/CP_SDK/UI/Views/SettingsMainView.hpp b/shared/CP_SDK/UI/Views/SettingsMainView.hpp index 31349b3..5b43c66 100644 --- a/shared/CP_SDK/UI/Views/SettingsMainView.hpp +++ b/shared/CP_SDK/UI/Views/SettingsMainView.hpp @@ -18,7 +18,7 @@ namespace CP_SDK::UI::Views { } /// @brief Settings main view controller - class SettingsMainView : public ViewController + class CP_SDK_EXPORT SettingsMainView : public ViewController { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Views", SettingsMainView, ViewController); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(SettingsMainView); diff --git a/shared/CP_SDK/UI/Views/SettingsRightView.hpp b/shared/CP_SDK/UI/Views/SettingsRightView.hpp index 657749a..fbd77c1 100644 --- a/shared/CP_SDK/UI/Views/SettingsRightView.hpp +++ b/shared/CP_SDK/UI/Views/SettingsRightView.hpp @@ -16,7 +16,7 @@ namespace CP_SDK::UI::Views { } /// @brief Settings right view controller - class SettingsRightView : public ViewController + class CP_SDK_EXPORT SettingsRightView : public ViewController { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Views", SettingsRightView, ViewController); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(SettingsRightView); diff --git a/shared/CP_SDK/UI/Views/TopNavigationView.hpp b/shared/CP_SDK/UI/Views/TopNavigationView.hpp index fdd8873..7bc562d 100644 --- a/shared/CP_SDK/UI/Views/TopNavigationView.hpp +++ b/shared/CP_SDK/UI/Views/TopNavigationView.hpp @@ -16,7 +16,7 @@ namespace CP_SDK::UI::Views { } /// @brief Top navigation view - class TopNavigationView : public ViewController + class CP_SDK_EXPORT TopNavigationView : public ViewController { CP_SDK_IL2CPP_INHERIT("CP_SDK.UI.Views", TopNavigationView, ViewController); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(TopNavigationView); diff --git a/shared/CP_SDK/Unity/EnhancedImage.hpp b/shared/CP_SDK/Unity/EnhancedImage.hpp index 164633c..6d31367 100644 --- a/shared/CP_SDK/Unity/EnhancedImage.hpp +++ b/shared/CP_SDK/Unity/EnhancedImage.hpp @@ -21,7 +21,7 @@ namespace CP_SDK::Unity { } /// @brief Enhanced image info - class CP_SDK_EXPORT_VISIBILITY EnhancedImage + class CP_SDK_EXPORT EnhancedImage { CP_SDK_NO_COPYMOVE_CTORS(EnhancedImage); CP_SDK_PRIV_TAG(); diff --git a/shared/CP_SDK/Unity/Extensions/ColorU.hpp b/shared/CP_SDK/Unity/Extensions/ColorU.hpp index 644abc6..6688b17 100644 --- a/shared/CP_SDK/Unity/Extensions/ColorU.hpp +++ b/shared/CP_SDK/Unity/Extensions/ColorU.hpp @@ -15,7 +15,7 @@ namespace CP_SDK::Unity::Extensions { } /// @brief Unity Color tools - class CP_SDK_EXPORT_VISIBILITY ColorU + class CP_SDK_EXPORT ColorU { public: /// @brief Get color with alpha diff --git a/shared/CP_SDK/Unity/Extensions/GameObjectU.hpp b/shared/CP_SDK/Unity/Extensions/GameObjectU.hpp index eda4d15..82c57e8 100644 --- a/shared/CP_SDK/Unity/Extensions/GameObjectU.hpp +++ b/shared/CP_SDK/Unity/Extensions/GameObjectU.hpp @@ -17,7 +17,7 @@ namespace CP_SDK::Unity::Extensions { } /// @brief Unity GameObject tools - class CP_SDK_EXPORT_VISIBILITY GameObjectU + class CP_SDK_EXPORT GameObjectU { public: /// @brief Change the layer of a GameObject and all his childs diff --git a/shared/CP_SDK/Unity/FontManager.hpp b/shared/CP_SDK/Unity/FontManager.hpp index 996e3f9..7bbde19 100644 --- a/shared/CP_SDK/Unity/FontManager.hpp +++ b/shared/CP_SDK/Unity/FontManager.hpp @@ -20,7 +20,7 @@ namespace CP_SDK::Unity { } /// @brief Open type to TextMeshPro font manager - class CP_SDK_EXPORT_VISIBILITY FontManager + class CP_SDK_EXPORT FontManager { CP_SDK_NO_DEF_CTORS(FontManager); diff --git a/shared/CP_SDK/Unity/MTCoroutineStarter.hpp b/shared/CP_SDK/Unity/MTCoroutineStarter.hpp index 145513b..75652a8 100644 --- a/shared/CP_SDK/Unity/MTCoroutineStarter.hpp +++ b/shared/CP_SDK/Unity/MTCoroutineStarter.hpp @@ -23,7 +23,7 @@ namespace CP_SDK::Unity { } /// @brief MultiThreading coroutine starter - class CP_SDK_EXPORT_VISIBILITY MTCoroutineStarter : public _u::MonoBehaviour + class CP_SDK_EXPORT MTCoroutineStarter : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.Unity", MTCoroutineStarter, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(MTCoroutineStarter); diff --git a/shared/CP_SDK/Unity/MTMainThreadInvoker.hpp b/shared/CP_SDK/Unity/MTMainThreadInvoker.hpp index c4987a8..2d00d10 100644 --- a/shared/CP_SDK/Unity/MTMainThreadInvoker.hpp +++ b/shared/CP_SDK/Unity/MTMainThreadInvoker.hpp @@ -21,7 +21,7 @@ namespace CP_SDK::Unity { } /// @brief Main thread task system - class CP_SDK_EXPORT_VISIBILITY MTMainThreadInvoker : public _u::MonoBehaviour + class CP_SDK_EXPORT MTMainThreadInvoker : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.Unity", MTMainThreadInvoker, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(MTMainThreadInvoker); diff --git a/shared/CP_SDK/Unity/MTThreadInvoker.hpp b/shared/CP_SDK/Unity/MTThreadInvoker.hpp index 90e7de0..4f471a7 100644 --- a/shared/CP_SDK/Unity/MTThreadInvoker.hpp +++ b/shared/CP_SDK/Unity/MTThreadInvoker.hpp @@ -21,7 +21,7 @@ namespace CP_SDK::Unity { } /// @brief Thread task system - class CP_SDK_EXPORT_VISIBILITY MTThreadInvoker + class CP_SDK_EXPORT MTThreadInvoker { private: /// @brief Queue class diff --git a/shared/CP_SDK/Unity/MonoPtrHolder.hpp b/shared/CP_SDK/Unity/MonoPtrHolder.hpp index c78d701..b0b529e 100644 --- a/shared/CP_SDK/Unity/MonoPtrHolder.hpp +++ b/shared/CP_SDK/Unity/MonoPtrHolder.hpp @@ -21,7 +21,7 @@ namespace CP_SDK::Unity { } /// @brief Il2Cpp pointers holder - class CP_SDK_EXPORT_VISIBILITY MonoPtrHolder : public _u::MonoBehaviour + class CP_SDK_EXPORT MonoPtrHolder : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK.Unity", MonoPtrHolder, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(MonoPtrHolder); diff --git a/shared/CP_SDK/Unity/SpriteU.hpp b/shared/CP_SDK/Unity/SpriteU.hpp index 66eaf7e..c26d0bf 100644 --- a/shared/CP_SDK/Unity/SpriteU.hpp +++ b/shared/CP_SDK/Unity/SpriteU.hpp @@ -20,7 +20,7 @@ namespace CP_SDK::Unity { } /// @brief Sprite helper - class CP_SDK_EXPORT_VISIBILITY SpriteU + class CP_SDK_EXPORT SpriteU { CP_SDK_NO_DEF_CTORS(SpriteU); diff --git a/shared/CP_SDK/Unity/Texture2DU.hpp b/shared/CP_SDK/Unity/Texture2DU.hpp index cfddf95..d68bdc4 100644 --- a/shared/CP_SDK/Unity/Texture2DU.hpp +++ b/shared/CP_SDK/Unity/Texture2DU.hpp @@ -17,7 +17,7 @@ namespace CP_SDK::Unity { } /// @brief Texture2D helper - class CP_SDK_EXPORT_VISIBILITY Texture2DU + class CP_SDK_EXPORT Texture2DU { CP_SDK_NO_DEF_CTORS(Texture2DU); diff --git a/shared/CP_SDK/Unity/TextureRaw.hpp b/shared/CP_SDK/Unity/TextureRaw.hpp index f17eca3..8ec5705 100644 --- a/shared/CP_SDK/Unity/TextureRaw.hpp +++ b/shared/CP_SDK/Unity/TextureRaw.hpp @@ -14,7 +14,7 @@ namespace CP_SDK::Unity { } /// @brief Texture raw utilities - class CP_SDK_EXPORT_VISIBILITY TextureRaw + class CP_SDK_EXPORT TextureRaw { CP_SDK_NO_DEF_CTORS(TextureRaw); diff --git a/shared/CP_SDK/Utils/Il2cpp.hpp b/shared/CP_SDK/Utils/Il2cpp.hpp index f35981f..a148ed4 100644 --- a/shared/CP_SDK/Utils/Il2cpp.hpp +++ b/shared/CP_SDK/Utils/Il2cpp.hpp @@ -5,8 +5,8 @@ #include "../Logging/PaperLogger.hpp" #include "Internals/Il2cpp_enum.hpp" -#include "Internals/il2cpp_customtype.hpp" -#include "Internals/il2cpp_hook.hpp" +#include "Internals/Il2cpp_customtype.hpp" +#include "Internals/Il2cpp_hook.hpp" #include "Internals/Il2cpp_string.hpp" #include @@ -20,8 +20,6 @@ #include #include -#define CP_SDK_EXPORT_VISIBILITY CUSTOM_TYPES_EXPORT_VISIBILITY - //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// @@ -42,7 +40,7 @@ namespace CP_SDK::Utils { /// @brief Hook manager - class CP_SDK_EXPORT_VISIBILITY Hooks + class CP_SDK_EXPORT Hooks { CP_SDK_NO_DEF_CTORS(Hooks); diff --git a/shared/CP_SDK/Utils/Internals/Il2cpp_string.hpp b/shared/CP_SDK/Utils/Internals/Il2cpp_string.hpp index 045af63..c6e7939 100644 --- a/shared/CP_SDK/Utils/Internals/Il2cpp_string.hpp +++ b/shared/CP_SDK/Utils/Internals/Il2cpp_string.hpp @@ -1,14 +1,16 @@ +#include "../../BuildConfig.hpp" + #include #include namespace CP_SDK::Utils { - std::u16string StrToU16Str(std::string_view p_Str); - std::string U16StrToStr(std::u16string_view p_Str); + CP_SDK_EXPORT std::u16string StrToU16Str(std::string_view p_Str); + CP_SDK_EXPORT std::string U16StrToStr(std::u16string_view p_Str); - bool U16EqualsToCaseInsensitive(std::u16string_view p_Left, std::u16string_view p_Right); + CP_SDK_EXPORT bool U16EqualsToCaseInsensitive(std::u16string_view p_Left, std::u16string_view p_Right); - std::u16string U16UrlEncode(std::u16string_view p_Input); + CP_SDK_EXPORT std::u16string U16UrlEncode(std::u16string_view p_Input); } ///< namespace CP_SDK::Utils diff --git a/shared/CP_SDK/Utils/Json.hpp b/shared/CP_SDK/Utils/Json.hpp index b55b508..17ba1b1 100644 --- a/shared/CP_SDK/Utils/Json.hpp +++ b/shared/CP_SDK/Utils/Json.hpp @@ -64,7 +64,7 @@ namespace CP_SDK::Utils { /// @brief Json utils - class CP_SDK_EXPORT_VISIBILITY Json + class CP_SDK_EXPORT Json { CP_SDK_NO_DEF_CTORS(Json); diff --git a/shared/CP_SDK/XUI/Templates.hpp b/shared/CP_SDK/XUI/Templates.hpp index 6e7fba7..0a17771 100644 --- a/shared/CP_SDK/XUI/Templates.hpp +++ b/shared/CP_SDK/XUI/Templates.hpp @@ -5,7 +5,7 @@ namespace CP_SDK::XUI { /// @brief XUI templates - class CP_SDK_EXPORT_VISIBILITY Templates + class CP_SDK_EXPORT Templates { public: /// @brief Modal rect layout diff --git a/shared/CP_SDK_BS/Game/BeatMaps/MapDetail.hpp b/shared/CP_SDK_BS/Game/BeatMaps/MapDetail.hpp index 3bac69e..de4abd8 100644 --- a/shared/CP_SDK_BS/Game/BeatMaps/MapDetail.hpp +++ b/shared/CP_SDK_BS/Game/BeatMaps/MapDetail.hpp @@ -21,7 +21,7 @@ namespace CP_SDK_BS::Game::BeatMaps { using namespace CP_SDK::Utils; } - struct CP_SDK_EXPORT_VISIBILITY MapDetail : public std::enable_shared_from_this + struct CP_SDK_EXPORT MapDetail : public std::enable_shared_from_this { MapDetail() = default; CP_SDK_NO_COPYMOVE_CTORS(MapDetail); diff --git a/shared/CP_SDK_BS/Game/BeatMapsClient.hpp b/shared/CP_SDK_BS/Game/BeatMapsClient.hpp index 7452332..a6449f1 100644 --- a/shared/CP_SDK_BS/Game/BeatMapsClient.hpp +++ b/shared/CP_SDK_BS/Game/BeatMapsClient.hpp @@ -20,7 +20,7 @@ namespace CP_SDK_BS::Game { } /// @brief BeatMaps client - class CP_SDK_EXPORT_VISIBILITY BeatMapsClient + class CP_SDK_EXPORT BeatMapsClient { CP_SDK_NO_DEF_CTORS(BeatMapsClient); diff --git a/shared/CP_SDK_BS/Game/LevelCompletionData.hpp b/shared/CP_SDK_BS/Game/LevelCompletionData.hpp index ef311bd..45b6e55 100644 --- a/shared/CP_SDK_BS/Game/LevelCompletionData.hpp +++ b/shared/CP_SDK_BS/Game/LevelCompletionData.hpp @@ -21,7 +21,7 @@ namespace CP_SDK_BS::Game { } /// @brief Level completion data - class CP_SDK_EXPORT_VISIBILITY LevelCompletionData + class CP_SDK_EXPORT LevelCompletionData { CP_SDK_NO_DEF_CTORS(LevelCompletionData); CP_SDK_PRIV_TAG(); diff --git a/shared/CP_SDK_BS/Game/LevelData.hpp b/shared/CP_SDK_BS/Game/LevelData.hpp index 212f2a9..2bfa31f 100644 --- a/shared/CP_SDK_BS/Game/LevelData.hpp +++ b/shared/CP_SDK_BS/Game/LevelData.hpp @@ -20,7 +20,7 @@ namespace CP_SDK_BS::Game { } /// @brief Level data instance - class CP_SDK_EXPORT_VISIBILITY LevelData + class CP_SDK_EXPORT LevelData { CP_SDK_NO_DEF_CTORS(LevelData); CP_SDK_PRIV_TAG(); diff --git a/shared/CP_SDK_BS/Game/LevelSelection.hpp b/shared/CP_SDK_BS/Game/LevelSelection.hpp index 21985fe..e356872 100644 --- a/shared/CP_SDK_BS/Game/LevelSelection.hpp +++ b/shared/CP_SDK_BS/Game/LevelSelection.hpp @@ -21,7 +21,7 @@ namespace CP_SDK_BS::Game { } /// @brief Level selection filter - class CP_SDK_EXPORT_VISIBILITY LevelSelection + class CP_SDK_EXPORT LevelSelection { CP_SDK_NO_DEF_CTORS(LevelSelection); diff --git a/shared/CP_SDK_BS/Game/Levels.hpp b/shared/CP_SDK_BS/Game/Levels.hpp index 3a33b4c..d16dd35 100644 --- a/shared/CP_SDK_BS/Game/Levels.hpp +++ b/shared/CP_SDK_BS/Game/Levels.hpp @@ -36,7 +36,7 @@ namespace CP_SDK_BS::Game { } /// @brief Level helper - class CP_SDK_EXPORT_VISIBILITY Levels + class CP_SDK_EXPORT Levels { CP_SDK_NO_DEF_CTORS(Levels); diff --git a/shared/CP_SDK_BS/Game/Logic.hpp b/shared/CP_SDK_BS/Game/Logic.hpp index 75b28da..b7aea14 100644 --- a/shared/CP_SDK_BS/Game/Logic.hpp +++ b/shared/CP_SDK_BS/Game/Logic.hpp @@ -5,9 +5,10 @@ #include "LevelData.hpp" #include "LevelCompletionData.hpp" -#include +#include #include #include +#include #include namespace CP_SDK_BS::Game { @@ -24,11 +25,11 @@ namespace CP_SDK_BS::Game { } /// @brief Game helper - class CP_SDK_EXPORT_VISIBILITY Logic + class CP_SDK_EXPORT Logic { CP_SDK_NO_DEF_CTORS(Logic); - using t_Delegate1 = System::Action_2, Zenject::DiContainer*>*; + using t_Delegate1 = System::Action_3<_u::GameScenesManager_SceneTransitionType, UnityW<_u::ScenesTransitionSetupDataSO>, Zenject::DiContainer*>*; public: /// @brief Scenes @@ -69,9 +70,10 @@ namespace CP_SDK_BS::Game { /// @brief On menu scene active static void OnMenuSceneActive(); /// @brief On menu scene loaded + /// @param p_Type Transition type /// @param p_Object Transition object /// @param p_DiContainer Container - static void OnMenuSceneLoadedFresh(_u::ScenesTransitionSetupDataSO* p_Object, Zenject::DiContainer* p_DiContainer); + static void OnMenuSceneLoadedFresh(_u::GameScenesManager_SceneTransitionType p_Type, _u::ScenesTransitionSetupDataSO* p_Object, Zenject::DiContainer* p_DiContainer); /// @brief On game scene active static void OnGameSceneActive(); diff --git a/shared/CP_SDK_BS/Game/Patches/PMissionLevelScenesTransitionSetupDataSO.hpp b/shared/CP_SDK_BS/Game/Patches/PMissionLevelScenesTransitionSetupDataSO.hpp deleted file mode 100644 index 086fb5f..0000000 --- a/shared/CP_SDK_BS/Game/Patches/PMissionLevelScenesTransitionSetupDataSO.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include "../LevelData.hpp" -#include "../../../CP_SDK/Utils/Il2cpp.hpp" - -namespace CP_SDK_BS::Game::Patches { - - /// @brief Level data finder - class PMissionLevelScenesTransitionSetupDataSO - { - CP_SDK_NO_DEF_CTORS(PMissionLevelScenesTransitionSetupDataSO); - - public: - /// @brief Restore the level data (Fix for the new restart mechanic) - /// @param p_LevelData Level data to restore - static void RestoreLevelData(const LevelData::Ptr& p_LevelData); - - }; - -} ///< namespace CP_SDK_BS::Game::Patches diff --git a/shared/CP_SDK_BS/Game/PlayerAvatarPicture.hpp b/shared/CP_SDK_BS/Game/PlayerAvatarPicture.hpp index 5a5bdd7..b317be2 100644 --- a/shared/CP_SDK_BS/Game/PlayerAvatarPicture.hpp +++ b/shared/CP_SDK_BS/Game/PlayerAvatarPicture.hpp @@ -19,7 +19,7 @@ namespace CP_SDK_BS::Game { } /// @brief Player avatar picture provider - class CP_SDK_EXPORT_VISIBILITY PlayerAvatarPicture + class CP_SDK_EXPORT PlayerAvatarPicture { CP_SDK_NO_DEF_CTORS(PlayerAvatarPicture); diff --git a/shared/CP_SDK_BS/Game/Scoring.hpp b/shared/CP_SDK_BS/Game/Scoring.hpp index cfc9c49..ffbb905 100644 --- a/shared/CP_SDK_BS/Game/Scoring.hpp +++ b/shared/CP_SDK_BS/Game/Scoring.hpp @@ -6,7 +6,7 @@ namespace CP_SDK_BS::Game { /// @brief Scoring utils - class CP_SDK_EXPORT_VISIBILITY Scoring + class CP_SDK_EXPORT Scoring { CP_SDK_NO_DEF_CTORS(Scoring); diff --git a/shared/CP_SDK_BS/Game/UserPlatform.hpp b/shared/CP_SDK_BS/Game/UserPlatform.hpp index fac0eaf..4a4eff3 100644 --- a/shared/CP_SDK_BS/Game/UserPlatform.hpp +++ b/shared/CP_SDK_BS/Game/UserPlatform.hpp @@ -7,7 +7,7 @@ namespace CP_SDK_BS::Game { /// UserPlatform helper - class CP_SDK_EXPORT_VISIBILITY UserPlatform + class CP_SDK_EXPORT UserPlatform { CP_SDK_NO_DEF_CTORS(UserPlatform); diff --git a/shared/CP_SDK_BS/UI/DefaultComponentsOverrides/Subs/SubFloatingPanelMover.hpp b/shared/CP_SDK_BS/UI/DefaultComponentsOverrides/Subs/SubFloatingPanelMover.hpp index 382c4bb..30e9a3c 100644 --- a/shared/CP_SDK_BS/UI/DefaultComponentsOverrides/Subs/SubFloatingPanelMover.hpp +++ b/shared/CP_SDK_BS/UI/DefaultComponentsOverrides/Subs/SubFloatingPanelMover.hpp @@ -23,7 +23,7 @@ namespace CP_SDK_BS::UI::DefaultComponentsOverrides::Subs { } /// @brief Floating panel mover - class SubFloatingPanelMover : public _u::MonoBehaviour + class CP_SDK_EXPORT SubFloatingPanelMover : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK_BS.UI.DefaultComponentsOverrides.Subs", SubFloatingPanelMover, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(SubFloatingPanelMover); diff --git a/shared/CP_SDK_BS/UI/DefaultComponentsOverrides/Subs/SubFloatingPanelMoverHandle.hpp b/shared/CP_SDK_BS/UI/DefaultComponentsOverrides/Subs/SubFloatingPanelMoverHandle.hpp index 7da8562..322f86c 100644 --- a/shared/CP_SDK_BS/UI/DefaultComponentsOverrides/Subs/SubFloatingPanelMoverHandle.hpp +++ b/shared/CP_SDK_BS/UI/DefaultComponentsOverrides/Subs/SubFloatingPanelMoverHandle.hpp @@ -17,7 +17,7 @@ namespace CP_SDK_BS::UI::DefaultComponentsOverrides::Subs { } /// @brief Floating panel mover handle - class SubFloatingPanelMoverHandle : public _u::MonoBehaviour + class CP_SDK_EXPORT SubFloatingPanelMoverHandle : public _u::MonoBehaviour { CP_SDK_IL2CPP_INHERIT("CP_SDK_BS.UI.DefaultComponentsOverrides.Subs", SubFloatingPanelMoverHandle, _u::MonoBehaviour); CP_SDK_IL2CPP_DECLARE_CTOR(SubFloatingPanelMoverHandle); diff --git a/shared/CP_SDK_BS/UI/DefaultFactoriesOverrides/BS_FloatingPanelFactory.hpp b/shared/CP_SDK_BS/UI/DefaultFactoriesOverrides/BS_FloatingPanelFactory.hpp index 082cd2b..9fc5ace 100644 --- a/shared/CP_SDK_BS/UI/DefaultFactoriesOverrides/BS_FloatingPanelFactory.hpp +++ b/shared/CP_SDK_BS/UI/DefaultFactoriesOverrides/BS_FloatingPanelFactory.hpp @@ -10,7 +10,7 @@ namespace CP_SDK_BS::UI::DefaultFactoriesOverrides { } /// @brief BeatSaber CFloatingPanel factory - class BS_FloatingPanelFactory : public CP_SDK::UI::FactoryInterfaces::IFloatingPanelFactory + class CP_SDK_EXPORT BS_FloatingPanelFactory : public CP_SDK::UI::FactoryInterfaces::IFloatingPanelFactory { public: /// @brief Create an CFloatingPanel into the parent diff --git a/shared/CP_SDK_BS/UI/GameFont.hpp b/shared/CP_SDK_BS/UI/GameFont.hpp index 2e79fe9..931c5b7 100644 --- a/shared/CP_SDK_BS/UI/GameFont.hpp +++ b/shared/CP_SDK_BS/UI/GameFont.hpp @@ -15,7 +15,7 @@ namespace CP_SDK_BS::UI { } /// @brief Helpers for game font - class CP_SDK_EXPORT_VISIBILITY GameFont + class CP_SDK_EXPORT GameFont { CP_SDK_NO_DEF_CTORS(GameFont); diff --git a/shared/CP_SDK_BS/UI/HMUIIconSegmentedControl.hpp b/shared/CP_SDK_BS/UI/HMUIIconSegmentedControl.hpp index 0c9a8b1..56e47a7 100644 --- a/shared/CP_SDK_BS/UI/HMUIIconSegmentedControl.hpp +++ b/shared/CP_SDK_BS/UI/HMUIIconSegmentedControl.hpp @@ -14,13 +14,18 @@ namespace CP_SDK_BS::UI { } /// @brief Vertical icon segmented control - class CP_SDK_EXPORT_VISIBILITY HMUIIconSegmentedControl + class CP_SDK_EXPORT HMUIIconSegmentedControl { CP_SDK_NO_DEF_CTORS(HMUIIconSegmentedControl); + private: static CP_SDK::Utils::MonoPtr m_Template; + public: + /// @brief When the game is reloaded + static void OnGameSoftReload(); + public: /// @brief Create icon segmented control /// @param p_Parent Parent game object transform diff --git a/shared/CP_SDK_BS/UI/HMUITextSegmentedControl.hpp b/shared/CP_SDK_BS/UI/HMUITextSegmentedControl.hpp index a72c4ea..de4e505 100644 --- a/shared/CP_SDK_BS/UI/HMUITextSegmentedControl.hpp +++ b/shared/CP_SDK_BS/UI/HMUITextSegmentedControl.hpp @@ -14,13 +14,17 @@ namespace CP_SDK_BS::UI { } /// @brief Text segmented control - class CP_SDK_EXPORT_VISIBILITY HMUITextSegmentedControl + class CP_SDK_EXPORT HMUITextSegmentedControl { CP_SDK_NO_DEF_CTORS(HMUITextSegmentedControl); private: static CP_SDK::Utils::MonoPtr m_Template; + public: + /// @brief When the game is reloaded + static void OnGameSoftReload(); + public: /// @brief Create text segmented control /// @param p_Parent Parent game object transform diff --git a/shared/CP_SDK_BS/UI/HMUIUIUtils.hpp b/shared/CP_SDK_BS/UI/HMUIUIUtils.hpp index d566611..07ded64 100644 --- a/shared/CP_SDK_BS/UI/HMUIUIUtils.hpp +++ b/shared/CP_SDK_BS/UI/HMUIUIUtils.hpp @@ -20,7 +20,7 @@ namespace CP_SDK_BS::UI { } /// @brief View controller utils - class CP_SDK_EXPORT_VISIBILITY HMUIUIUtils + class CP_SDK_EXPORT HMUIUIUtils { CP_SDK_NO_DEF_CTORS(HMUIUIUtils); diff --git a/shared/CP_SDK_BS/UI/HMUIViewFlowCoordinator.hpp b/shared/CP_SDK_BS/UI/HMUIViewFlowCoordinator.hpp index f3a39cb..53eeec2 100644 --- a/shared/CP_SDK_BS/UI/HMUIViewFlowCoordinator.hpp +++ b/shared/CP_SDK_BS/UI/HMUIViewFlowCoordinator.hpp @@ -30,7 +30,7 @@ namespace CP_SDK_BS::UI { } /// @brief View flow coordinator base class - class CP_SDK_EXPORT_VISIBILITY HMUIViewFlowCoordinator : public HMUI::FlowCoordinator + class CP_SDK_EXPORT HMUIViewFlowCoordinator : public HMUI::FlowCoordinator { CP_SDK_IL2CPP_INHERIT("CP_SDK_BS.UI", HMUIViewFlowCoordinator, HMUI::FlowCoordinator); CP_SDK_IL2CPP_DECLARE_CTOR(HMUIViewFlowCoordinator); diff --git a/shared/CP_SDK_BS/UI/LevelDetail.hpp b/shared/CP_SDK_BS/UI/LevelDetail.hpp index c437c1b..6f02e77 100644 --- a/shared/CP_SDK_BS/UI/LevelDetail.hpp +++ b/shared/CP_SDK_BS/UI/LevelDetail.hpp @@ -34,13 +34,17 @@ namespace CP_SDK_BS::UI { } /// @brief Song detail widget - class CP_SDK_EXPORT_VISIBILITY LevelDetail + class CP_SDK_EXPORT LevelDetail { CP_SDK_NO_COPYMOVE_CTORS(LevelDetail); private: static _v::MonoPtr<_u::GameObject> m_SongDetailViewTemplate; + public: + /// @brief When the game is reloaded + static void OnGameSoftReload(); + public: /// @brief Init static void Init(); diff --git a/shared/CP_SDK_BS/UI/Patches/PVRPointer.hpp b/shared/CP_SDK_BS/UI/Patches/PVRPointer.hpp index d395e32..2cf058f 100644 --- a/shared/CP_SDK_BS/UI/Patches/PVRPointer.hpp +++ b/shared/CP_SDK_BS/UI/Patches/PVRPointer.hpp @@ -12,7 +12,7 @@ namespace CP_SDK_BS::UI::Patches { using namespace VRUIControls; } - class CP_SDK_EXPORT_VISIBILITY PVRPointer + class CP_SDK_EXPORT PVRPointer { public: static CP_SDK::Utils::Event<_u::VRPointer*> OnActivated; diff --git a/shared/CP_SDK_BS/UI/ViewController.hpp b/shared/CP_SDK_BS/UI/ViewController.hpp index 688ebd4..7fbf6a8 100644 --- a/shared/CP_SDK_BS/UI/ViewController.hpp +++ b/shared/CP_SDK_BS/UI/ViewController.hpp @@ -31,7 +31,7 @@ namespace CP_SDK_BS::UI { } /// @brief View flow coordinator base class - class CP_SDK_EXPORT_VISIBILITY ViewController : public IHMUIViewController + class CP_SDK_EXPORT ViewController : public IHMUIViewController { CP_SDK_IL2CPP_INHERIT("CP_SDK_BS.UI", ViewController, IHMUIViewController); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(ViewController); diff --git a/src/CP_SDK/UI/DefaultComponents/DefaultCFloatingPanel.cpp b/src/CP_SDK/UI/DefaultComponents/DefaultCFloatingPanel.cpp index 832339b..7c344f2 100644 --- a/src/CP_SDK/UI/DefaultComponents/DefaultCFloatingPanel.cpp +++ b/src/CP_SDK/UI/DefaultComponents/DefaultCFloatingPanel.cpp @@ -57,6 +57,8 @@ namespace CP_SDK::UI::DefaultComponents { l_CanvasScaler->set_dynamicPixelsPerUnit (3.44f); l_CanvasScaler->set_referencePixelsPerUnit(10.0f); + get_gameObject()->AddComponent(); + SetBackground(true); SetSize(Vector2(20.0f, 20.0f)); diff --git a/src/CP_SDK/UI/Tooltip.cpp b/src/CP_SDK/UI/Tooltip.cpp index 50adeea..60a3278 100644 --- a/src/CP_SDK/UI/Tooltip.cpp +++ b/src/CP_SDK/UI/Tooltip.cpp @@ -59,7 +59,7 @@ namespace CP_SDK::UI { l_Tooltip->m_Image->set_color (UISystem::TooltipBGColor); l_Tooltip->m_Image->set_maskable (false); - l_Tooltip->m_Border = UISystem::ImageFactory->Create(u"Text", l_Tooltip->m_RTransform.Ptr()); + l_Tooltip->m_Border = UISystem::ImageFactory->Create(u"Border", l_Tooltip->m_RTransform.Ptr()); l_Tooltip->m_Border->SetSprite(UISystem::GetUIRoundSmoothFrameSprite().Ptr()); l_Tooltip->m_Border->SetColor(ColorU::WithAlpha(Color::get_white(), 0.80f)); l_Tooltip->m_Border->SetType(Image::Type::Sliced); @@ -68,11 +68,13 @@ namespace CP_SDK::UI { l_Tooltip->m_Border->RTransform()->set_anchorMax (Vector2::get_one()); l_Tooltip->m_Border->RTransform()->set_anchoredPosition(Vector2::get_zero()); l_Tooltip->m_Border->RTransform()->set_sizeDelta (Vector2::get_zero()); + l_Tooltip->m_Border->ImageC()->set_maskable (false); l_Tooltip->m_Text = UISystem::TextFactory->Create(u"Text", l_Tooltip->m_RTransform.Ptr()); l_Tooltip->m_Text->SetText(u"Tooltip"); l_Tooltip->m_Text->SetFontSize(3.8f); l_Tooltip->m_Text->SetColor(Color::get_white()); + l_Tooltip->m_Text->TMProUGUI()->set_maskable(false); l_Tooltip->get_gameObject()->SetActive(false); diff --git a/src/CP_SDK/UI/ValueFormatters.cpp b/src/CP_SDK/UI/ValueFormatters.cpp index fcf7a38..a66bbef 100644 --- a/src/CP_SDK/UI/ValueFormatters.cpp +++ b/src/CP_SDK/UI/ValueFormatters.cpp @@ -30,6 +30,15 @@ namespace CP_SDK::UI { return Utils::StrToU16Str(l_Builder.str()); } + std::u16string ValueFormatters::Days(float p_Value) + { + auto l_AsInt = static_cast(p_Value); + std::ostringstream l_Builder; + l_Builder << l_AsInt << (l_AsInt > 1 ? " Days" : " Day"); + + return Utils::StrToU16Str(l_Builder.str()); + } + //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// diff --git a/src/CP_SDK_BS/Game/LevelData.cpp b/src/CP_SDK_BS/Game/LevelData.cpp index 3b3350a..25de075 100644 --- a/src/CP_SDK_BS/Game/LevelData.cpp +++ b/src/CP_SDK_BS/Game/LevelData.cpp @@ -5,6 +5,10 @@ #include #include +#include +#include +#include +#include namespace CP_SDK_BS::Game { @@ -13,7 +17,18 @@ namespace CP_SDK_BS::Game { if (!Data || !Data->get_transformedBeatmapData()) return false; - return Data->get_transformedBeatmapData()->get_spawnRotationEventsCount() > 0; + for (auto l_CurrentNode = Data->get_transformedBeatmapData()->allBeatmapDataItems->head; l_CurrentNode != nullptr; l_CurrentNode = l_CurrentNode->Next) + { + auto l_Current = reinterpret_cast<_u::BeatmapDataItem*>(l_CurrentNode->Value); + + if (l_Current->get_type() != _u::BeatmapDataItem_BeatmapDataItemType::BeatmapObject + || reinterpret_cast<_u::BeatmapObjectData*>(l_Current)->get_rotation() == 0) + continue; + + return true; + } + + return false; } bool LevelData::IsNoodle() { diff --git a/src/CP_SDK_BS/Game/LevelSelection.cpp b/src/CP_SDK_BS/Game/LevelSelection.cpp index 02b8c39..72ccf66 100644 --- a/src/CP_SDK_BS/Game/LevelSelection.cpp +++ b/src/CP_SDK_BS/Game/LevelSelection.cpp @@ -1,6 +1,8 @@ #include "CP_SDK_BS/Game/LevelSelection.hpp" #include "CP_SDK_BS/Game/Logic.hpp" #include "CP_SDK/Unity/MTCoroutineStarter.hpp" +#include "GlobalNamespace/zzzz__LevelSelectionFlowCoordinator_def.hpp" +#include "GlobalNamespace/zzzz__PlayerSensitivityFlag_def.hpp" #include #include @@ -30,6 +32,7 @@ namespace CP_SDK_BS::Game { /// @param p_SongToFilter Song to filter bool LevelSelection::FilterToSpecificSong(_u::BeatmapLevel* p_SongToFilter) { + CP_SDK::ChatPlexSDK::Logger()->Info(u"filtering 5"); m_PendingFilterSong = p_SongToFilter; try @@ -64,6 +67,7 @@ namespace CP_SDK_BS::Game { /// @param p_LevelSelectionNavigationController instance void LevelSelection::LevelSelectionNavigationController_didActivateEvent(_u::LevelSelectionNavigationController* p_LevelSelectionNavigationController) { + CP_SDK::ChatPlexSDK::Logger()->Info(u"filtering 4"); CP_SDK::Unity::MTCoroutineStarter::Start(custom_types::Helpers::CoroutineHelper::New( LevelSelection_SelectLevelCategory(p_LevelSelectionNavigationController) )); @@ -73,6 +77,7 @@ namespace CP_SDK_BS::Game { void, _u::LevelSelectionNavigationController* __Instance, bool __a, bool __b, bool __c) { + CP_SDK::ChatPlexSDK::Logger()->Info(u"filtering 3"); //CP_SDK::ChatPlexSDK::Logger()->Error(u"Enter LevelSelectionNavigationController_DidActivate"); LevelSelectionNavigationController_DidActivate(__Instance, __a, __b, __c); @@ -101,6 +106,7 @@ namespace CP_SDK_BS::Game { /// @param p_LevelSelectionNavigationController LevelSelectionNavigationController instance custom_types::Helpers::Coroutine LevelSelection::LevelSelection_SelectLevelCategory(_u::LevelSelectionNavigationController* p_LevelSelectionNavigationController) { + CP_SDK::ChatPlexSDK::Logger()->Info(u"filtering 2"); while (!_v::IsUnityPtrValid(p_LevelSelectionNavigationController) || p_LevelSelectionNavigationController->____isInTransition) { if (!_v::IsUnityPtrValid(p_LevelSelectionNavigationController)) @@ -128,7 +134,6 @@ namespace CP_SDK_BS::Game { auto l_Tags = l_Selector->____levelCategoryInfos; auto l_IndexToSelect = -1; - for (auto l_I = 0; l_I < l_Tags->get_Length(); ++l_I) { if (l_Tags[l_I]->___levelCategory != _u::SelectLevelCategoryViewController::LevelCategory::All) @@ -168,6 +173,7 @@ namespace CP_SDK_BS::Game { /// @param p_Wait Should wait for any transition custom_types::Helpers::Coroutine LevelSelection::LevelSelection_FilterLevel(_u::LevelSearchViewController* p_LevelSearchViewController, bool p_Wait) { + CP_SDK::ChatPlexSDK::Logger()->Info(u"filtering 1"); if (Logic::ActiveScene() != Logic::ESceneType::Menu) co_return; @@ -193,13 +199,25 @@ namespace CP_SDK_BS::Game { try { + CP_SDK::ChatPlexSDK::Logger()->Info(u"filtering "); m_PreventLevelSearchViewController_didStartLoadingEvent = true; p_LevelSearchViewController->ResetAllFilterSettings(false); auto l_Filter = GlobalNamespace::LevelFilter(); + l_Filter.songOwned = false; + l_Filter.songNotOwned = false; + l_Filter.songUnplayed = false; + l_Filter.difficulties = _u::BeatmapDifficultyMask(); + l_Filter.songPacks = _u::SongPackMask(); + l_Filter.characteristicSerializedName = nullptr; + l_Filter.minBpm = 0.0f; + l_Filter.maxBpm = 0.0f; + l_Filter.sensitivity = _u::PlayerSensitivityFlag(); + l_Filter.limitIds = ArrayW({ m_PendingFilterSong->___levelID }); l_Filter.searchText = u""; + p_LevelSearchViewController->ResetAllFilterSettings(false); p_LevelSearchViewController->Refresh( byref(l_Filter) ); @@ -223,7 +241,7 @@ namespace CP_SDK_BS::Game { try { - auto l_Filter = p_LevelSearchViewController->____currentSearchFilter; + const auto& l_Filter = p_LevelSearchViewController->____currentSearchFilter; if (l_Filter.limitIds && l_Filter.limitIds->get_Length() == 1) { p_LevelSearchViewController->ResetAllFilterSettings(false); diff --git a/src/CP_SDK_BS/Game/Levels.cpp b/src/CP_SDK_BS/Game/Levels.cpp index 84e2d0f..0aefa26 100644 --- a/src/CP_SDK_BS/Game/Levels.cpp +++ b/src/CP_SDK_BS/Game/Levels.cpp @@ -186,7 +186,10 @@ namespace CP_SDK_BS::Game { *p_Hash = p_LevelID.substr(13); if (p_Hash->length() == 40) // TODO check for only hex + { + *p_Hash = p_Hash->substr(0, 40); std::transform(p_Hash->begin(), p_Hash->end(), p_Hash->begin(), std::towupper); + } } return true; @@ -660,7 +663,7 @@ namespace CP_SDK_BS::Game { } _v::MonoPtr l_PreviewBeatmapLevel(p_BeatmapLevel); - auto l_Task = p_BeatmapLevel->___previewMediaData->GetCoverSpriteAsync(CancellationToken::get_None()); + auto l_Task = p_BeatmapLevel->___previewMediaData->GetCoverSpriteAsync(); _v::AwaitTaskAsync>( l_Task, @@ -778,7 +781,8 @@ namespace CP_SDK_BS::Game { /* BeatmapLevel beatmapLevel: */ p_Level, /* IBeatmapLevelData beatmapLevelData: */ p_BeatmapLevelData, /* OverrideEnvironmentSettings overrideEnvironmentSettings: */ p_OverrideEnvironmentSettings, - /* ColorScheme overrideColorScheme: */ p_ColorScheme, + /* ColorScheme playerOverrideColorScheme: */ p_ColorScheme, + /* bool playerOverrideLightshowColors*/ false, /* ColorScheme beatmapOverrideColorScheme: */ nullptr, /* GameplayModifiers gameplayModifiers: */ p_GameplayModifiers ? p_GameplayModifiers : GameplayModifiers::New_ctor(), /* PlayerSpecificSettings playerSpecificSettings: */ p_PlayerSettings ? p_PlayerSettings : PlayerSpecificSettings::New_ctor(), @@ -791,7 +795,7 @@ namespace CP_SDK_BS::Game { /* Action afterSceneSwitchCallback: */ nullptr, /* Action levelFinishedCallback: */ l_Delegate, /* Action levelRestartedCallback: */ nullptr, - /* RecordingToolManager.SetupData? recordingToolData: */ System::Nullable_1<__RecordingToolManager__SetupData>() + /* RecordingToolManager.SetupData? recordingToolData: */ System::Nullable_1<_u::RecordingToolManager_SetupData>() ); } catch (const std::exception& l_Exception) @@ -831,15 +835,34 @@ namespace CP_SDK_BS::Game { try { - auto l_Task = m_BeatmapLevelsModel->LoadBeatmapLevelDataAsync(p_LevelID, m_GetLevelCancellationTokenSource->get_Token()); - - _v::AwaitTaskAsync( - l_Task, - [=](_v::MonoPtrRef> p_Task, bool p_Success) { + auto l_VersionTask = m_MenuTransitionsHelper->____beatmapLevelsEntitlementModel->GetLevelDataVersionAsync(p_LevelID, m_GetLevelCancellationTokenSource->get_Token()); + _v::AwaitTaskAsync( + l_VersionTask, + [=](_v::MonoPtrRef> p_VersionTask, bool p_Success) { try { - if (p_Success && !p_Task->get_Result().isError) - p_Callback(p_Task->get_Result().beatmapLevelData); + if (p_Success) + { + auto l_Task = m_BeatmapLevelsModel->LoadBeatmapLevelDataAsync(p_LevelID, p_VersionTask->get_Result(), m_GetLevelCancellationTokenSource->get_Token()); + + _v::AwaitTaskAsync( + l_Task, + [=](_v::MonoPtrRef> p_Task, bool p_Success) { + try + { + if (p_Success && !p_Task->get_Result().isError) + p_Callback(p_Task->get_Result().beatmapLevelData); + else + p_Callback(nullptr); + } + catch (const std::exception& l_Exception) + { + CP_SDK::ChatPlexSDK::Logger()->Error(u"[CP_SDK_BS.Game][Levels.GetLevelFromLevelID] Error:"); + CP_SDK::ChatPlexSDK::Logger()->Error(l_Exception); + } + } + ); + } else p_Callback(nullptr); } diff --git a/src/CP_SDK_BS/Game/Logic.cpp b/src/CP_SDK_BS/Game/Logic.cpp index 2766e40..e73d15a 100644 --- a/src/CP_SDK_BS/Game/Logic.cpp +++ b/src/CP_SDK_BS/Game/Logic.cpp @@ -1,16 +1,17 @@ #include "CP_SDK_BS/Game/Logic.hpp" #include "CP_SDK_BS/Game/Levels.hpp" #include "CP_SDK_BS/Game/Scoring.hpp" -#include "CP_SDK_BS/Game/Patches/PMissionLevelScenesTransitionSetupDataSO.hpp" #include "CP_SDK_BS/Game/Patches/PMultiplayerLevelScenesTransitionSetupDataSO.hpp" #include "CP_SDK_BS/Game/Patches/PStandardLevelScenesTransitionSetupDataSO.hpp" #include "CP_SDK_BS/UI/LevelDetail.hpp" +#include "CP_SDK_BS/UI/HMUIIconSegmentedControl.hpp" +#include "CP_SDK_BS/UI/HMUITextSegmentedControl.hpp" #include "CP_SDK/ChatPlexSDK.hpp" #include #include #include -#include +#include #include static bool m_WasChatPlexUnityInitialized = false; @@ -82,6 +83,10 @@ namespace CP_SDK_BS::Game { l_GameScenesManager->remove_transitionDidFinishEvent(m_Delegate1); l_GameScenesManager->add_transitionDidFinishEvent(m_Delegate1); + + UI::HMUIIconSegmentedControl::OnGameSoftReload(); + UI::HMUITextSegmentedControl::OnGameSoftReload(); + UI::LevelDetail::OnGameSoftReload(); } } @@ -133,9 +138,10 @@ namespace CP_SDK_BS::Game { } } /// @brief On menu scene loaded + /// @param p_Type Transition type /// @param p_Object Transition object /// @param p_DiContainer Container - void Logic::OnMenuSceneLoadedFresh(_u::ScenesTransitionSetupDataSO* p_Object, Zenject::DiContainer* p_DiContainer) + void Logic::OnMenuSceneLoadedFresh(_u::GameScenesManager_SceneTransitionType p_Type, _u::ScenesTransitionSetupDataSO* p_Object,Zenject::DiContainer* p_DiContainer) { #if DEBUG_SCENES CP_SDK::ChatPlexSDK::Logger()->Error(u"====== [CP_SDK_BS.Game][Logic.OnMenuSceneLoadedFresh] ======"); @@ -192,7 +198,6 @@ namespace CP_SDK_BS::Game { { case LevelType::Solo: Patches::PStandardLevelScenesTransitionSetupDataSO::RestoreLevelData(m_LevelData); - Patches::PMissionLevelScenesTransitionSetupDataSO::RestoreLevelData(m_LevelData); break; case LevelType::Multiplayer: diff --git a/src/CP_SDK_BS/Game/Patches/PMissionLevelScenesTransitionSetupDataSO.cpp b/src/CP_SDK_BS/Game/Patches/PMissionLevelScenesTransitionSetupDataSO.cpp deleted file mode 100644 index 489c05b..0000000 --- a/src/CP_SDK_BS/Game/Patches/PMissionLevelScenesTransitionSetupDataSO.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include "CP_SDK_BS/Game/Patches/PMissionLevelScenesTransitionSetupDataSO.hpp" -#include "CP_SDK_BS/Game/Logic.hpp" -#include "CP_SDK_BS/Game/Scoring.hpp" -#include "CP_SDK/Utils/Il2cpp.hpp" - -#include -#include -#include - -using namespace GlobalNamespace; - -namespace CP_SDK_BS::Game::Patches { - - static LevelData::Ptr s_PMissionLevelScenesTransitionSetupDataSO_LevelData; - - //////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////// - - /// @brief Restore the level data (Fix for the new restart mechanic) - /// @param p_LevelData Level data to restore - void PMissionLevelScenesTransitionSetupDataSO::RestoreLevelData(const LevelData::Ptr& p_LevelData) - { - s_PMissionLevelScenesTransitionSetupDataSO_LevelData = p_LevelData; - } - - //////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////// - - CP_SDK_IL2CPP_HOOK_MAKE_AUTO_HOOK_MATCH( - MenuTransitionsHelper_StartMissionLevel, &MenuTransitionsHelper::StartMissionLevel, - void, MenuTransitionsHelper* __Instance, - - StringW __a, - ByRef __b, - BeatmapLevel* __c, - ColorScheme* __d, - GameplayModifiers* __e, - ::ArrayW*> __f, - PlayerSpecificSettings* __g, - EnvironmentsListModel* __h, - System::Action* __i, - System::Action_2, MissionCompletionResults*>* __j, - System::Action_2, MissionCompletionResults*>* __k) - { - //CP_SDK::ChatPlexSDK::Logger()->Error(u"Enter MenuTransitionsHelper_StartMissionLevel"); - Scoring::__SetScoreSaberIsInReplay(false); - MenuTransitionsHelper_StartMissionLevel(__Instance, __a, __b, __c, __d, __e, __f, __g, __h, __i, __j, __k); - - try - { - s_PMissionLevelScenesTransitionSetupDataSO_LevelData = LevelData::Make(); - auto& l_LevelData = s_PMissionLevelScenesTransitionSetupDataSO_LevelData; - l_LevelData->Type = LevelType::Solo; - l_LevelData->Data = __Instance->____missionLevelScenesTransitionSetupData->get_gameplayCoreSceneSetupData(); - - Logic::FireLevelStarted(l_LevelData); - } - catch(const std::exception& l_Exception) - { - CP_SDK::ChatPlexSDK::Logger()->Error(u"[CP_SDK_BS.Game.Patches][MenuTransitionsHelper_StartMissionLevel] Error:"); - CP_SDK::ChatPlexSDK::Logger()->Error(l_Exception); - } - - //CP_SDK::ChatPlexSDK::Logger()->Error(u"Exit MenuTransitionsHelper_StartMissionLevel"); - } - CP_SDK_IL2CPP_HOOK_MAKE_AUTO_HOOK_MATCH( - MissionLevelScenesTransitionSetupDataSO_Finish, &MissionLevelScenesTransitionSetupDataSO::Finish, - void, MissionLevelScenesTransitionSetupDataSO* __Instance, - - MissionCompletionResults* __a) - { - //CP_SDK::ChatPlexSDK::Logger()->Error(u"Enter MissionLevelScenesTransitionSetupDataSO_Finish"); - MissionLevelScenesTransitionSetupDataSO_Finish(__Instance, __a); - - try - { - auto& l_LevelData = s_PMissionLevelScenesTransitionSetupDataSO_LevelData; - if (!l_LevelData) - return; - - auto l_LevelCompletionData = LevelCompletionData::Make(); - l_LevelCompletionData->Type = LevelType::Solo; - l_LevelCompletionData->Data = l_LevelData->Data; - l_LevelCompletionData->Results = __a->___levelCompletionResults; - - Scoring::__SetScoreSaberIsInReplay(false); - - Logic::FireLevelEnded(l_LevelCompletionData); - } - catch (const std::exception& l_Exception) - { - CP_SDK::ChatPlexSDK::Logger()->Error(u"[CP_SDK_BS.Game.Patches][MissionLevelScenesTransitionSetupDataSO_Finish] Error:"); - CP_SDK::ChatPlexSDK::Logger()->Error(l_Exception); - } - - s_PMissionLevelScenesTransitionSetupDataSO_LevelData = nullptr; - - //CP_SDK::ChatPlexSDK::Logger()->Error(u"Exit MissionLevelScenesTransitionSetupDataSO_Finish"); - } - -} ///< namespace CP_SDK_BS::Game::Patches \ No newline at end of file diff --git a/src/CP_SDK_BS/UI/DefaultComponentsOverrides/Subs/SubFloatingPanelMover.cpp b/src/CP_SDK_BS/UI/DefaultComponentsOverrides/Subs/SubFloatingPanelMover.cpp index e300c77..9af3958 100644 --- a/src/CP_SDK_BS/UI/DefaultComponentsOverrides/Subs/SubFloatingPanelMover.cpp +++ b/src/CP_SDK_BS/UI/DefaultComponentsOverrides/Subs/SubFloatingPanelMover.cpp @@ -58,8 +58,8 @@ namespace CP_SDK_BS::UI::DefaultComponentsOverrides::Subs { if (m_GrabbingController) return; - auto l_HitCount = Physics::RaycastNonAlloc( l_VRControllerTransform->get_position(), - l_VRControllerTransform->get_forward(), + auto l_HitCount = Physics::RaycastNonAlloc( l_VRController->____viewAnchorTransform->get_position(), + l_VRController->____viewAnchorTransform->get_forward(), m_RaycastBuffer.Ptr(), MaxLaserDistance, static_cast(1 << CP_SDK::UI::UISystem::UILayer)); diff --git a/src/CP_SDK_BS/UI/HMUIIconSegmentedControl.cpp b/src/CP_SDK_BS/UI/HMUIIconSegmentedControl.cpp index 4507dfc..552e813 100644 --- a/src/CP_SDK_BS/UI/HMUIIconSegmentedControl.cpp +++ b/src/CP_SDK_BS/UI/HMUIIconSegmentedControl.cpp @@ -18,6 +18,15 @@ namespace CP_SDK_BS::UI { //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// + /// @brief When the game is reloaded + void HMUIIconSegmentedControl::OnGameSoftReload() + { + m_Template = nullptr; + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + /// @brief Create icon segmented control /// @param p_Parent Parent game object transform /// @param p_HideCellBackground Should hide cell background diff --git a/src/CP_SDK_BS/UI/HMUITextSegmentedControl.cpp b/src/CP_SDK_BS/UI/HMUITextSegmentedControl.cpp index 7305c1b..b650afa 100644 --- a/src/CP_SDK_BS/UI/HMUITextSegmentedControl.cpp +++ b/src/CP_SDK_BS/UI/HMUITextSegmentedControl.cpp @@ -19,6 +19,15 @@ namespace CP_SDK_BS::UI { //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// + /// @brief When the game is reloaded + void HMUITextSegmentedControl::OnGameSoftReload() + { + m_Template = nullptr; + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + /// @brief Create icon segmented control /// @param p_Parent Parent game object transform /// @param p_HideCellBackground Should hide cell background @@ -59,7 +68,7 @@ namespace CP_SDK_BS::UI { l_List->Add(l_Current); } - l_Control->SetTexts(l_List->AsReadOnly()->i___System__Collections__Generic__IReadOnlyList_1_T_()); + l_Control->SetTexts(l_List->AsReadOnly()->i___System__Collections__Generic__IReadOnlyList_1_T_(), nullptr); return l_Control; } diff --git a/src/CP_SDK_BS/UI/LevelDetail.cpp b/src/CP_SDK_BS/UI/LevelDetail.cpp index 5a9a778..850ebb9 100644 --- a/src/CP_SDK_BS/UI/LevelDetail.cpp +++ b/src/CP_SDK_BS/UI/LevelDetail.cpp @@ -52,6 +52,15 @@ namespace CP_SDK_BS::UI { //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// + /// @brief When the game is reloaded + void LevelDetail::OnGameSoftReload() + { + m_SongDetailViewTemplate = nullptr; + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + /// @brief Init void LevelDetail::Init() { @@ -225,7 +234,7 @@ namespace CP_SDK_BS::UI { l_List->Add(p_Value); m_Difficulty = p_Value; - m_SongDiffSegmentedControl->SetTexts(l_List->AsReadOnly()->i___System__Collections__Generic__IReadOnlyList_1_T_()); + m_SongDiffSegmentedControl->SetTexts(l_List->AsReadOnly()->i___System__Collections__Generic__IReadOnlyList_1_T_(), nullptr); } //////////////////////////////////////////////////////////////////////////// @@ -426,7 +435,7 @@ namespace CP_SDK_BS::UI { } /// Display mode - Characteristic(HMUI::IconSegmentedControl::DataItem::New_ctor(p_Characteristic->____icon, BGLib::Polyglot::Localization::Get(p_Characteristic->____descriptionLocalizationKey))); + Characteristic(HMUI::IconSegmentedControl::DataItem::New_ctor(p_Characteristic->____icon, BGLib::Polyglot::Localization::Get(p_Characteristic->____descriptionLocalizationKey), true)); /// Display difficulty Difficulty(Game::Levels::BeatmapDifficultySerializedNameToDifficultyName(BeatmapDifficultySerializedMethods::SerializedName(p_Difficulty))); @@ -498,7 +507,7 @@ namespace CP_SDK_BS::UI { { auto l_BeatmapCharacteristicSO = (BeatmapCharacteristicSO*)nullptr; if (Game::Levels::TryGetBeatmapCharacteristicSOBySerializedName(l_Current, &l_BeatmapCharacteristicSO)) - l_Characteristics->Add(HMUI::IconSegmentedControl::DataItem::New_ctor(l_BeatmapCharacteristicSO->____icon, BGLib::Polyglot::Localization::Get(l_BeatmapCharacteristicSO->____descriptionLocalizationKey))); + l_Characteristics->Add(HMUI::IconSegmentedControl::DataItem::New_ctor(l_BeatmapCharacteristicSO->____icon, BGLib::Polyglot::Localization::Get(l_BeatmapCharacteristicSO->____descriptionLocalizationKey), true)); } if (l_Characteristics->get_Count() == 0) @@ -660,7 +669,7 @@ namespace CP_SDK_BS::UI { return true; ///< Continue }); - m_SongDiffSegmentedControl->SetTexts(l_Difficulties->AsReadOnly()->i___System__Collections__Generic__IReadOnlyList_1_T_()); + m_SongDiffSegmentedControl->SetTexts(l_Difficulties->AsReadOnly()->i___System__Collections__Generic__IReadOnlyList_1_T_(), nullptr); m_SongDiffSegmentedControl->SelectCellWithNumber(l_Difficulties->get_Count() - 1); OnDifficultyChanged(nullptr, l_Difficulties->get_Count() - 1); } @@ -680,7 +689,7 @@ namespace CP_SDK_BS::UI { for (auto& l_Current : l_Version->GetDifficultiesPerBeatmapCharacteristicSOSerializedName(l_Characs[p_Index])) l_Difficulties->Add(Game::Levels::BeatmapDifficultySerializedNameToDifficultyName(l_Current->difficulty)); - m_SongDiffSegmentedControl->SetTexts(l_Difficulties->AsReadOnly()->i___System__Collections__Generic__IReadOnlyList_1_T_()); + m_SongDiffSegmentedControl->SetTexts(l_Difficulties->AsReadOnly()->i___System__Collections__Generic__IReadOnlyList_1_T_(), nullptr); m_SongDiffSegmentedControl->SelectCellWithNumber(l_Difficulties->get_Count() - 1); OnDifficultyChanged(nullptr, l_Difficulties->get_Count() - 1); } diff --git a/src/main.cpp b/src/main.cpp index 77d4ae1..9450e7d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,3 +1,4 @@ +#include "git_info.h" #include "CP_SDK/ChatPlexSDK.hpp" #include "CP_SDK/ModuleBase.hpp" #include "CP_SDK/Logging/PaperLogger.hpp" @@ -160,6 +161,7 @@ void OnEnable() break; } + l_HasBSPModules = true; if (l_HasBSPModules) { CP_SDK::UI::FlowCoordinators::MainFlowCoordinator::OverrideTitle(u"QBeatSaberPlus"); @@ -178,7 +180,7 @@ void OnEnable() //////////////////////////////////////////////////////////////////////////// // Called at the early stages of game loading -extern "C" void setup(CModInfo* p_ModInfo) +extern "C" __attribute__((visibility("default"))) void setup(CModInfo* p_ModInfo) { p_ModInfo->id = s_ModInfo.id.c_str(); p_ModInfo->version = s_ModInfo.version.c_str(); @@ -216,7 +218,7 @@ extern "C" void setup(CModInfo* p_ModInfo) static bool s_IsLoaded = false; // Called later on in the game loading - a good time to install function hooks -extern "C" void late_load() +extern "C" __attribute__((visibility("default"))) void late_load() { if (s_IsLoaded) return; diff --git a/start-logging.ps1 b/start-logging.ps1 index 9f8ab3a..b779e9b 100644 --- a/start-logging.ps1 +++ b/start-logging.ps1 @@ -62,7 +62,7 @@ if ($all -eq $false) { $pattern += "$custom|" } if ($pattern -eq "(") { - $pattern = "(QuestHook|modloader|scotland2|" + $pattern = "(QuestHook|modloader|scotland2|ChatPlexSDK|" } $pattern += "AndroidRuntime|CRASH)" $command += " | Select-String -pattern `"$pattern`"" From ee0ce3da0b185dee48fc95cb7146727cc55571ac Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 7 May 2025 12:40:14 +0200 Subject: [PATCH 14/35] Work on CI --- .github/workflows/build-ndk.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-ndk.yml b/.github/workflows/build-ndk.yml index 6aca019..ad318d9 100644 --- a/.github/workflows/build-ndk.yml +++ b/.github/workflows/build-ndk.yml @@ -5,6 +5,7 @@ on: push: branches: - 'master' + - 'dev' paths-ignore: - '**.yml' - '!.github/workflows/build-ndk.yml' @@ -79,21 +80,21 @@ jobs: echo "NAME=${files[0]}" >> $GITHUB_OUTPUT - name: Upload non-debug artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: ${{ steps.libname.outputs.NAME }} path: ./build/${{ steps.libname.outputs.NAME }} if-no-files-found: error - name: Upload debug artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: debug_${{ steps.libname.outputs.NAME }} path: ./build/debug/${{ steps.libname.outputs.NAME }} if-no-files-found: error - name: Upload qmod artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: ${{env.qmodName}}.qmod path: ./${{ env.qmodName }}.qmod From de541bcd077bef1eaa33692b5c85ced59fc56058 Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 7 May 2025 12:46:41 +0200 Subject: [PATCH 15/35] CI --- .github/actions/canary-ndk/action.yml | 4 ++-- .github/workflows/build-ndk.yml | 7 +------ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/.github/actions/canary-ndk/action.yml b/.github/actions/canary-ndk/action.yml index 6454ad5..864c63d 100644 --- a/.github/actions/canary-ndk/action.yml +++ b/.github/actions/canary-ndk/action.yml @@ -20,13 +20,13 @@ runs: - name: Download canary ndk if: ${{ !steps.cache.outputs.cache-hit }} env: - CANARY_URL: https://github.com/QuestPackageManager/ndk-canary-archive/releases/download/27.0.1/android-ndk-10883340-linux-x86_64.zip + CANARY_URL: https://dl.google.com/android/repository/android-ndk-r28b-windows.zip run: wget ${CANARY_URL} -O ${HOME}/ndk.zip shell: bash - name: Unzip ndk if: ${{ !steps.cache.outputs.cache-hit }} - run: 7z x "${HOME}/ndk.zip" -o"${HOME}/" + run: 7z -snld x "${HOME}/ndk.zip" -o"${HOME}/" shell: bash - name: Set output diff --git a/.github/workflows/build-ndk.yml b/.github/workflows/build-ndk.yml index ad318d9..37d439f 100644 --- a/.github/workflows/build-ndk.yml +++ b/.github/workflows/build-ndk.yml @@ -39,14 +39,9 @@ jobs: - uses: seanmiddleditch/gha-setup-ninja@v3 - # Use canary NDK to avoid lesser known compile bugs - - name: Setup canary NDK - id: setup-ndk - uses: ./.github/actions/canary-ndk - - name: Create ndkpath.txt run: | - echo ${{ steps.setup-ndk.outputs.ndk-path }} > ${GITHUB_WORKSPACE}/ndkpath.txt + echo $ANDROID_NDK_HOME > ${GITHUB_WORKSPACE}/ndkpath.txt cat ${GITHUB_WORKSPACE}/ndkpath.txt # get version from pushed tag From b1f661ebec75f77f324044b5d3f7806f71494e09 Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 7 May 2025 13:02:57 +0200 Subject: [PATCH 16/35] Thansk windows casing --- .../Internals/{il2cpp_customtype.hpp => _Il2cpp_customtype.hpp} | 0 .../CP_SDK/Utils/Internals/{il2cpp_hook.hpp => _Il2cpp_hook.hpp} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename shared/CP_SDK/Utils/Internals/{il2cpp_customtype.hpp => _Il2cpp_customtype.hpp} (100%) rename shared/CP_SDK/Utils/Internals/{il2cpp_hook.hpp => _Il2cpp_hook.hpp} (100%) diff --git a/shared/CP_SDK/Utils/Internals/il2cpp_customtype.hpp b/shared/CP_SDK/Utils/Internals/_Il2cpp_customtype.hpp similarity index 100% rename from shared/CP_SDK/Utils/Internals/il2cpp_customtype.hpp rename to shared/CP_SDK/Utils/Internals/_Il2cpp_customtype.hpp diff --git a/shared/CP_SDK/Utils/Internals/il2cpp_hook.hpp b/shared/CP_SDK/Utils/Internals/_Il2cpp_hook.hpp similarity index 100% rename from shared/CP_SDK/Utils/Internals/il2cpp_hook.hpp rename to shared/CP_SDK/Utils/Internals/_Il2cpp_hook.hpp From c20158d7fb5c52dc05bfb42a8fdc00e6bec89d57 Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 7 May 2025 13:03:26 +0200 Subject: [PATCH 17/35] Thansk windows casing --- .../Internals/{_Il2cpp_customtype.hpp => Il2cpp_customtype.hpp} | 0 .../CP_SDK/Utils/Internals/{_Il2cpp_hook.hpp => Il2cpp_hook.hpp} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename shared/CP_SDK/Utils/Internals/{_Il2cpp_customtype.hpp => Il2cpp_customtype.hpp} (100%) rename shared/CP_SDK/Utils/Internals/{_Il2cpp_hook.hpp => Il2cpp_hook.hpp} (100%) diff --git a/shared/CP_SDK/Utils/Internals/_Il2cpp_customtype.hpp b/shared/CP_SDK/Utils/Internals/Il2cpp_customtype.hpp similarity index 100% rename from shared/CP_SDK/Utils/Internals/_Il2cpp_customtype.hpp rename to shared/CP_SDK/Utils/Internals/Il2cpp_customtype.hpp diff --git a/shared/CP_SDK/Utils/Internals/_Il2cpp_hook.hpp b/shared/CP_SDK/Utils/Internals/Il2cpp_hook.hpp similarity index 100% rename from shared/CP_SDK/Utils/Internals/_Il2cpp_hook.hpp rename to shared/CP_SDK/Utils/Internals/Il2cpp_hook.hpp From 5285dd4c0a54f5a767c295070d88d571f021dae5 Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 7 May 2025 17:34:52 +0200 Subject: [PATCH 18/35] Version 6.4.0 --- .github/actions/canary-ndk/action.yml | 35 ------------------- .github/workflows/publish.yml | 7 +--- include/git_info.h | 2 +- mod.json | 4 +-- qpm.shared.json | 10 +++--- shared/CP_SDK_BS/Game/BeatMaps/MapVersion.hpp | 2 +- .../UI/CP_SDK_UI_IViewControllerBridge.hpp | 2 +- .../BS_CFloatingPanel.hpp | 2 +- shared/CP_SDK_BS/UI/IHMUIViewController.hpp | 2 +- src/CP_SDK/Logging/PaperLogger.cpp | 21 ++++++----- src/CP_SDK_BS/Game/LevelSelection.cpp | 6 ---- src/CP_SDK_BS/Game/Levels.cpp | 17 +++++---- src/main.cpp | 2 +- 13 files changed, 37 insertions(+), 75 deletions(-) delete mode 100644 .github/actions/canary-ndk/action.yml diff --git a/.github/actions/canary-ndk/action.yml b/.github/actions/canary-ndk/action.yml deleted file mode 100644 index 864c63d..0000000 --- a/.github/actions/canary-ndk/action.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: "Setup canary ndk" -description: "Sets up canary ndk" -outputs: - ndk-path: - value: ${{ steps.path.outputs.path }} - description: "Output path of the ndk" - cache-hit: - value: ${{ steps.cache.outputs.cache-hit }} - description: "Whether a cache hit occurred for the ndk" -runs: - using: "composite" - steps: - - name: NDK cache - id: cache - uses: actions/cache@v3 - with: - path: ${HOME}/android-ndk-r27-canary/ - key: ${{ runner.os }}-ndk-r27-canary - - - name: Download canary ndk - if: ${{ !steps.cache.outputs.cache-hit }} - env: - CANARY_URL: https://dl.google.com/android/repository/android-ndk-r28b-windows.zip - run: wget ${CANARY_URL} -O ${HOME}/ndk.zip - shell: bash - - - name: Unzip ndk - if: ${{ !steps.cache.outputs.cache-hit }} - run: 7z -snld x "${HOME}/ndk.zip" -o"${HOME}/" - shell: bash - - - name: Set output - id: path - shell: bash - run: echo "path=${HOME}/android-ndk-r27-canary" >> ${GITHUB_OUTPUT} \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index eee9da2..8163dde 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -22,14 +22,9 @@ jobs: - uses: seanmiddleditch/gha-setup-ninja@v3 - # Use canary NDK to avoid lesser known compile bugs - - name: Setup canary NDK - id: setup-ndk - uses: ./.github/actions/canary-ndk - - name: Create ndkpath.txt run: | - echo ${{ steps.setup-ndk.outputs.ndk-path }} > ${GITHUB_WORKSPACE}/ndkpath.txt + echo $ANDROID_NDK_HOME > ${GITHUB_WORKSPACE}/ndkpath.txt cat ${GITHUB_WORKSPACE}/ndkpath.txt # get version from pushed tag diff --git a/include/git_info.h b/include/git_info.h index 2297089..5c0b8ca 100644 --- a/include/git_info.h +++ b/include/git_info.h @@ -1,5 +1,5 @@ #pragma once #define GIT_USER "HardCPP" #define GIT_BRANCH "dev" -#define GIT_COMMIT 0xc593a3c +#define GIT_COMMIT 0xc20158d #define GIT_MODIFIED 1 diff --git a/mod.json b/mod.json index 330b8b7..a79e262 100644 --- a/mod.json +++ b/mod.json @@ -5,7 +5,7 @@ "id": "chatplex-sdk-bs", "modloader": "Scotland2", "author": "HardCPP", - "version": "6.4.0", + "version": "6.3.2", "packageId": "com.beatgames.beatsaber", "packageVersion": "1.40.4_5283", "description": "ChatPlex BeatSaber modding SDK (Dependence for other mods)", @@ -34,7 +34,7 @@ { "version": "^4.6.1", "id": "paper2_scotland2", - "downloadIfMissing": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.1/paper2_scotland2.qmod" + "downloadIfMissing": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.2/paper2_scotland2.qmod" } ], "modFiles": [ diff --git a/qpm.shared.json b/qpm.shared.json index cefba26..321cd6e 100644 --- a/qpm.shared.json +++ b/qpm.shared.json @@ -127,12 +127,12 @@ { "dependency": { "id": "paper2_scotland2", - "versionRange": "=4.6.1", + "versionRange": "=4.6.2", "additionalData": { - "soLink": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.1/libpaper2_scotland2.so", + "soLink": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.2/libpaper2_scotland2.so", "overrideSoName": "libpaper2_scotland2.so", - "modLink": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.1/paper2_scotland2.qmod", - "branchName": "version/v4_6_1", + "modLink": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.2/paper2_scotland2.qmod", + "branchName": "version/v4_6_2", "compileOptions": { "systemIncludes": [ "shared/utfcpp/source" @@ -141,7 +141,7 @@ "cmake": false } }, - "version": "4.6.1" + "version": "4.6.2" }, { "dependency": { diff --git a/shared/CP_SDK_BS/Game/BeatMaps/MapVersion.hpp b/shared/CP_SDK_BS/Game/BeatMaps/MapVersion.hpp index 679c529..797bce1 100644 --- a/shared/CP_SDK_BS/Game/BeatMaps/MapVersion.hpp +++ b/shared/CP_SDK_BS/Game/BeatMaps/MapVersion.hpp @@ -40,7 +40,7 @@ namespace CP_SDK_BS::Game::BeatMaps { CP_SDK_IL2CPP_ENUM_UTILS(); }; - struct MapVersion + struct CP_SDK_EXPORT MapVersion { MapVersion() = default; CP_SDK_NO_COPYMOVE_CTORS(MapVersion); diff --git a/shared/CP_SDK_BS/UI/CP_SDK_UI_IViewControllerBridge.hpp b/shared/CP_SDK_BS/UI/CP_SDK_UI_IViewControllerBridge.hpp index c4028c8..5009714 100644 --- a/shared/CP_SDK_BS/UI/CP_SDK_UI_IViewControllerBridge.hpp +++ b/shared/CP_SDK_BS/UI/CP_SDK_UI_IViewControllerBridge.hpp @@ -15,7 +15,7 @@ namespace CP_SDK_BS::UI { class IHMUIViewController; /// @brief CP_SDK.UI.IViewController bridge component - class CP_SDK_UI_IViewControllerBridge : public CP_SDK::UI::IViewController + class CP_SDK_EXPORT CP_SDK_UI_IViewControllerBridge : public CP_SDK::UI::IViewController { CP_SDK_IL2CPP_INHERIT("CP_SDK_BS.UI", CP_SDK_UI_IViewControllerBridge, CP_SDK::UI::IViewController); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(CP_SDK_UI_IViewControllerBridge); diff --git a/shared/CP_SDK_BS/UI/DefaultComponentsOverrides/BS_CFloatingPanel.hpp b/shared/CP_SDK_BS/UI/DefaultComponentsOverrides/BS_CFloatingPanel.hpp index 4642942..9f6e154 100644 --- a/shared/CP_SDK_BS/UI/DefaultComponentsOverrides/BS_CFloatingPanel.hpp +++ b/shared/CP_SDK_BS/UI/DefaultComponentsOverrides/BS_CFloatingPanel.hpp @@ -15,7 +15,7 @@ namespace CP_SDK_BS::UI::DefaultComponentsOverrides { } /// @brief BeatSaber CFloatingPanel component - class BS_CFloatingPanel : public CP_SDK::UI::DefaultComponents::DefaultCFloatingPanel + class CP_SDK_EXPORT BS_CFloatingPanel : public CP_SDK::UI::DefaultComponents::DefaultCFloatingPanel { CP_SDK_IL2CPP_INHERIT("CP_SDK_BS.UI.DefaultComponentsOverrides", BS_CFloatingPanel, CP_SDK::UI::DefaultComponents::DefaultCFloatingPanel); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(BS_CFloatingPanel); diff --git a/shared/CP_SDK_BS/UI/IHMUIViewController.hpp b/shared/CP_SDK_BS/UI/IHMUIViewController.hpp index a823cb7..1469ef2 100644 --- a/shared/CP_SDK_BS/UI/IHMUIViewController.hpp +++ b/shared/CP_SDK_BS/UI/IHMUIViewController.hpp @@ -25,7 +25,7 @@ namespace CP_SDK_BS::UI { } /// @brief IHMUIViewController interface - class IHMUIViewController : public HMUI::ViewController + class CP_SDK_EXPORT IHMUIViewController : public HMUI::ViewController { CP_SDK_IL2CPP_INHERIT("CP_SDK_BS.UI", IHMUIViewController, HMUI::ViewController); CP_SDK_IL2CPP_DECLARE_CTOR_CHILD(IHMUIViewController); diff --git a/src/CP_SDK/Logging/PaperLogger.cpp b/src/CP_SDK/Logging/PaperLogger.cpp index 544ce6e..7a24bec 100644 --- a/src/CP_SDK/Logging/PaperLogger.cpp +++ b/src/CP_SDK/Logging/PaperLogger.cpp @@ -11,7 +11,10 @@ namespace CP_SDK::Logging { PaperLogger::PaperLogger(const std::string& p_Name) : m_PaperLogger(new Paper::LoggerContext(p_Name)) { - + Error(u"Test Error"); + Warning(u"Test Warning"); + Info(u"Test Info"); + Debug(u"Test Debug"); } //////////////////////////////////////////////////////////////////////////// @@ -29,10 +32,10 @@ namespace CP_SDK::Logging { auto l_String = l_UTF8Data.c_str(); switch (p_Type) { - case ELogType::Error: m_PaperLogger->error("{}", l_String); break; - case ELogType::Warning: m_PaperLogger->warn("{}", l_String); break; - case ELogType::Info: m_PaperLogger->info("{}", l_String); break; - case ELogType::Debug: m_PaperLogger->debug("{}", l_String); break; + case ELogType::Error: m_PaperLogger->fmtLog<(Paper::LogLevel)Paper::ffi::paper2_LogLevel::Error>("{}", l_String); break; + case ELogType::Warning: m_PaperLogger->fmtLog<(Paper::LogLevel)Paper::ffi::paper2_LogLevel::Warn>("{}", l_String); break; + case ELogType::Info: m_PaperLogger->fmtLog<(Paper::LogLevel)Paper::ffi::paper2_LogLevel::Info>("{}", l_String); break; + case ELogType::Debug: m_PaperLogger->fmtLog<(Paper::LogLevel)Paper::ffi::paper2_LogLevel::Debug>("{}", l_String); break; } } /// @brief Internal log method @@ -43,10 +46,10 @@ namespace CP_SDK::Logging { auto l_String = p_Data.what(); switch (p_Type) { - case ELogType::Error: m_PaperLogger->error("{}", l_String); break; - case ELogType::Warning: m_PaperLogger->warn("{}", l_String); break; - case ELogType::Info: m_PaperLogger->info("{}", l_String); break; - case ELogType::Debug: m_PaperLogger->debug("{}", l_String); break; + case ELogType::Error: m_PaperLogger->fmtLog<(Paper::LogLevel)Paper::ffi::paper2_LogLevel::Error>("{}", l_String); break; + case ELogType::Warning: m_PaperLogger->fmtLog<(Paper::LogLevel)Paper::ffi::paper2_LogLevel::Warn>("{}", l_String); break; + case ELogType::Info: m_PaperLogger->fmtLog<(Paper::LogLevel)Paper::ffi::paper2_LogLevel::Info>("{}", l_String); break; + case ELogType::Debug: m_PaperLogger->fmtLog<(Paper::LogLevel)Paper::ffi::paper2_LogLevel::Debug>("{}", l_String); break; } } diff --git a/src/CP_SDK_BS/Game/LevelSelection.cpp b/src/CP_SDK_BS/Game/LevelSelection.cpp index 72ccf66..8d36517 100644 --- a/src/CP_SDK_BS/Game/LevelSelection.cpp +++ b/src/CP_SDK_BS/Game/LevelSelection.cpp @@ -32,7 +32,6 @@ namespace CP_SDK_BS::Game { /// @param p_SongToFilter Song to filter bool LevelSelection::FilterToSpecificSong(_u::BeatmapLevel* p_SongToFilter) { - CP_SDK::ChatPlexSDK::Logger()->Info(u"filtering 5"); m_PendingFilterSong = p_SongToFilter; try @@ -67,7 +66,6 @@ namespace CP_SDK_BS::Game { /// @param p_LevelSelectionNavigationController instance void LevelSelection::LevelSelectionNavigationController_didActivateEvent(_u::LevelSelectionNavigationController* p_LevelSelectionNavigationController) { - CP_SDK::ChatPlexSDK::Logger()->Info(u"filtering 4"); CP_SDK::Unity::MTCoroutineStarter::Start(custom_types::Helpers::CoroutineHelper::New( LevelSelection_SelectLevelCategory(p_LevelSelectionNavigationController) )); @@ -77,7 +75,6 @@ namespace CP_SDK_BS::Game { void, _u::LevelSelectionNavigationController* __Instance, bool __a, bool __b, bool __c) { - CP_SDK::ChatPlexSDK::Logger()->Info(u"filtering 3"); //CP_SDK::ChatPlexSDK::Logger()->Error(u"Enter LevelSelectionNavigationController_DidActivate"); LevelSelectionNavigationController_DidActivate(__Instance, __a, __b, __c); @@ -106,7 +103,6 @@ namespace CP_SDK_BS::Game { /// @param p_LevelSelectionNavigationController LevelSelectionNavigationController instance custom_types::Helpers::Coroutine LevelSelection::LevelSelection_SelectLevelCategory(_u::LevelSelectionNavigationController* p_LevelSelectionNavigationController) { - CP_SDK::ChatPlexSDK::Logger()->Info(u"filtering 2"); while (!_v::IsUnityPtrValid(p_LevelSelectionNavigationController) || p_LevelSelectionNavigationController->____isInTransition) { if (!_v::IsUnityPtrValid(p_LevelSelectionNavigationController)) @@ -173,7 +169,6 @@ namespace CP_SDK_BS::Game { /// @param p_Wait Should wait for any transition custom_types::Helpers::Coroutine LevelSelection::LevelSelection_FilterLevel(_u::LevelSearchViewController* p_LevelSearchViewController, bool p_Wait) { - CP_SDK::ChatPlexSDK::Logger()->Info(u"filtering 1"); if (Logic::ActiveScene() != Logic::ESceneType::Menu) co_return; @@ -199,7 +194,6 @@ namespace CP_SDK_BS::Game { try { - CP_SDK::ChatPlexSDK::Logger()->Info(u"filtering "); m_PreventLevelSearchViewController_didStartLoadingEvent = true; p_LevelSearchViewController->ResetAllFilterSettings(false); diff --git a/src/CP_SDK_BS/Game/Levels.cpp b/src/CP_SDK_BS/Game/Levels.cpp index 0aefa26..302be77 100644 --- a/src/CP_SDK_BS/Game/Levels.cpp +++ b/src/CP_SDK_BS/Game/Levels.cpp @@ -826,6 +826,9 @@ namespace CP_SDK_BS::Game { m_BeatmapLevelsModel = l_MainFlowCoordinator->____beatmapLevelsModel; } + if (!m_MenuTransitionsHelper) + m_MenuTransitionsHelper = Resources::FindObjectsOfTypeAll<_u::MenuTransitionsHelper*>()->First(); + if (m_BeatmapLevelsModel) { if (m_GetLevelCancellationTokenSource) @@ -838,19 +841,19 @@ namespace CP_SDK_BS::Game { auto l_VersionTask = m_MenuTransitionsHelper->____beatmapLevelsEntitlementModel->GetLevelDataVersionAsync(p_LevelID, m_GetLevelCancellationTokenSource->get_Token()); _v::AwaitTaskAsync( l_VersionTask, - [=](_v::MonoPtrRef> p_VersionTask, bool p_Success) { + [=](_v::MonoPtrRef> p_VersionTask, bool p_VersionSuccess) { try { - if (p_Success) + if (p_VersionSuccess) { auto l_Task = m_BeatmapLevelsModel->LoadBeatmapLevelDataAsync(p_LevelID, p_VersionTask->get_Result(), m_GetLevelCancellationTokenSource->get_Token()); _v::AwaitTaskAsync( l_Task, - [=](_v::MonoPtrRef> p_Task, bool p_Success) { + [=](_v::MonoPtrRef> p_Task, bool p_Success2) { try { - if (p_Success && !p_Task->get_Result().isError) + if (p_Success2 && !p_Task->get_Result().isError) p_Callback(p_Task->get_Result().beatmapLevelData); else p_Callback(nullptr); @@ -862,15 +865,17 @@ namespace CP_SDK_BS::Game { } } ); + + return; } - else - p_Callback(nullptr); } catch (const std::exception& l_Exception) { CP_SDK::ChatPlexSDK::Logger()->Error(u"[CP_SDK_BS.Game][Levels.GetLevelFromLevelID] Error:"); CP_SDK::ChatPlexSDK::Logger()->Error(l_Exception); } + + p_Callback(nullptr); } ); diff --git a/src/main.cpp b/src/main.cpp index 9450e7d..a68e3c8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -209,7 +209,7 @@ extern "C" __attribute__((visibility("default"))) void setup(CModInfo* p_ModInfo return p_Input; }); - CP_SDK::ChatPlexSDK::Logger()->Error(u"ChatPlexSDK-BS Completed setup!"); + CP_SDK::ChatPlexSDK::Logger()->Info(u"ChatPlexSDK-BS Completed setup!"); } //////////////////////////////////////////////////////////////////////////// From cad9adaecebc85af7c7df420f7b8bd84bd928fc1 Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 7 May 2025 22:31:15 +0200 Subject: [PATCH 19/35] Make the mod late --- mod.json | 4 ++-- mod.template.json | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mod.json b/mod.json index 6dc76ac..3ddfe2e 100644 --- a/mod.json +++ b/mod.json @@ -37,10 +37,10 @@ "downloadIfMissing": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.2/paper2_scotland2.qmod" } ], - "modFiles": [ + "modFiles": [], + "lateModFiles": [ "libchatplex-sdk-bs.so" ], - "lateModFiles": [], "libraryFiles": [], "fileCopies": [], "copyExtensions": [] diff --git a/mod.template.json b/mod.template.json index 6eabf18..63417e4 100644 --- a/mod.template.json +++ b/mod.template.json @@ -10,7 +10,8 @@ "description": "ChatPlex BeatSaber modding SDK (Dependence for other mods)", "coverImage": "cover.png", "dependencies": [], - "modFiles": ["${binary}"], + "modFiles": [], + "lateModFiles": ["${binary}"], "libraryFiles": [], "fileCopies": [], "copyExtensions": [] From 55230040505e6ed40d1c29f033178a7f347a8e55 Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 6 Aug 2025 00:50:12 +0200 Subject: [PATCH 20/35] Improve WebClientUnity & implement full WebClientCore using curl --- shared/CP_SDK/Network/IWebClient.hpp | 68 +-- shared/CP_SDK/Network/WebClientCore.hpp | 183 ++++++++ shared/CP_SDK/Network/WebClientUnity.hpp | 136 +++--- shared/CP_SDK/Network/WebContent.hpp | 8 +- shared/CP_SDK/Network/WebResponse.hpp | 36 +- shared/CP_SDK/Utils/Il2cpp.hpp | 6 - src/CP_SDK/Network/WebClientCore.cpp | 570 +++++++++++++++++++++++ src/CP_SDK/Network/WebClientUnity.cpp | 245 +++++----- src/CP_SDK/Network/WebContent.cpp | 8 + src/CP_SDK/Network/WebResponse.cpp | 46 +- 10 files changed, 1058 insertions(+), 248 deletions(-) create mode 100644 shared/CP_SDK/Network/WebClientCore.hpp create mode 100644 src/CP_SDK/Network/WebClientCore.cpp diff --git a/shared/CP_SDK/Network/IWebClient.hpp b/shared/CP_SDK/Network/IWebClient.hpp index 29a9a28..b7a6e98 100644 --- a/shared/CP_SDK/Network/IWebClient.hpp +++ b/shared/CP_SDK/Network/IWebClient.hpp @@ -24,6 +24,9 @@ namespace CP_SDK::Network { { CP_SDK_NO_COPYMOVE_CTORS(IWebClient); + public: + using IPtr = std::shared_ptr; + protected: /// @brief Constructor IWebClient() = default; @@ -42,39 +45,46 @@ namespace CP_SDK::Network { public: /// @brief Do Async GET query - /// @param p_URL Target URL - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - /// @param p_Progress Progress reporter - virtual void GetAsync(std::u16string_view p_URL, _u::CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry = false, _v::CActionRef p_Progress = nullptr) = 0; + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + virtual void GetAsync(std::u16string_view url, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false, _v::CActionRef progress = nullptr) = 0; /// @brief Do Async GET query - /// @param p_URL Target URL - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - /// @param p_Progress Progress reporter - virtual void DownloadAsync(std::u16string_view p_URL, _u::CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry = false, _v::CActionRef p_Progress = nullptr) = 0; + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + virtual void DownloadAsync(std::u16string_view url, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false, _v::CActionRef progress = nullptr) = 0; /// @brief Do Async POST query - /// @param p_URL Target URL - /// @param p_Content Optional content to post - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - virtual void PostAsync(std::u16string_view p_URL, const WebContent::Ptr& p_Content, _u::CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry = false) = 0; + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void PostAsync(std::u16string_view url, const WebContent::Ptr& content, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) = 0; /// @brief Do Async PATCH query - /// @param p_URL Target URL - /// @param p_Content Optional content to post - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - virtual void PatchAsync(std::u16string_view p_URL, const WebContent::Ptr& p_Content, _u::CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry = false) = 0; + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void PatchAsync(std::u16string_view url, const WebContent::Ptr& content, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) = 0; + /// @brief Do Async PUT query + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void PutAsync(std::u16string_view url, const WebContent::Ptr& content, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) = 0; /// @brief Do Async DELETE query - /// @param p_URL Target URL - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - virtual void DeleteAsync(std::u16string_view p_URL, _u::CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry = false) = 0; + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void DeleteAsync(std::u16string_view url, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) = 0; }; diff --git a/shared/CP_SDK/Network/WebClientCore.hpp b/shared/CP_SDK/Network/WebClientCore.hpp new file mode 100644 index 0000000..bbc2693 --- /dev/null +++ b/shared/CP_SDK/Network/WebClientCore.hpp @@ -0,0 +1,183 @@ +#pragma once + +#include "IWebClient.hpp" + +#include + +#include +#include + +namespace CP_SDK::Network { + + namespace _u + { + using namespace System; + using namespace System::Threading; + } + namespace _v + { + using namespace CP_SDK::Utils; + } + + /// @brief WebClientCore + class CP_SDK_EXPORT WebClientCore : public IWebClient, public std::enable_shared_from_this + { + CP_SDK_NO_COPYMOVE_CTORS(WebClientCore); + CP_SDK_PRIV_TAG(); + + public: + using Ptr = std::shared_ptr; + + private: + static Ptr m_GlobalClient; + + public: + /// @brief Global client instance + static WebClientCore* GlobalClient(); + + private: + std::u16string m_BaseAddress; + int m_TimeOut; + std::map m_Headers; + std::mutex m_HeadersLock; + + public: + /// @brief Maximum retry attempt + int MaxRetry; + /// @brief Delay between each retry + int RetryInterval; + + public: + /// @brief Constructor + /// @param baseAddress Base address + /// @param timeOut Requests timeout + /// @param keepAlive Should try to keep the connection alive + /// @param forceCacheDiscard Should force server cache discard + WebClientCore(CP_SDK_PRIV_TAG_ARG(), std::u16string_view baseAddress, _u::TimeSpan timeOut, bool keepAlive, bool forceCacheDiscard); + + /// @brief Constructor + /// @param baseAddress Base address + /// @param timeOut Requests timeout + /// @param keepAlive Should try to keep the connection alive + /// @param forceCacheDiscard Should force server cache discard + static Ptr Make(std::u16string_view baseAddress, _u::TimeSpan timeOut, bool keepAlive = true, bool forceCacheDiscard = false); + + public: + /// @brief Get header + /// @param p_Name Header name + virtual std::u16string GetHeader(std::u16string_view p_Name) override final; + /// @brief Set header + /// @param p_Name Header name + /// @param p_Value Header value + virtual void SetHeader(std::u16string_view p_Name, std::u16string_view p_Value) override final; + /// @brief Remove header + /// @param p_Name Header name + virtual void RemoveHeader(std::u16string_view p_Name) override final; + + public: + /// @brief Do GET query + /// @param url Target URL + /// @param dontRetry Should not retry + /// @param progress Progress reporter + WebResponse::Ptr Get(std::u16string_view url, bool dontRetry = false, _v::CActionRef progress = nullptr); + /// @brief Do GET query + /// @param url Target URL + /// @param dontRetry Should not retry + /// @param progress Progress reporter + WebResponse::Ptr Download(std::u16string_view url, bool dontRetry = false, _v::CActionRef progress = nullptr); + /// @brief Do POST query + /// @param url Target URL + /// @param content Optional content to post + /// @param dontRetry Should not retry + WebResponse::Ptr Post(std::u16string_view url, const WebContent::Ptr& content, bool dontRetry = false); + /// @brief Do PATCH query + /// @param url Target URL + /// @param content Optional content to post + /// @param dontRetry Should not retry + WebResponse::Ptr Patch(std::u16string_view url, const WebContent::Ptr& content, bool dontRetry = false); + /// @brief Do PUT query + /// @param url Target URL + /// @param content Optional content to post + /// @param dontRetry Should not retry + WebResponse::Ptr Put(std::u16string_view url, const WebContent::Ptr& content, bool dontRetry = false); + /// @brief Do DELETE query + /// @param url Target URL + /// @param dontRetry Should not retry + WebResponse::Ptr Delete(std::u16string_view url, bool dontRetry = false); + + public: + /// @brief Do Async GET query + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + virtual void GetAsync(std::u16string_view url, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false, _v::CActionRef progress = nullptr) override final; + /// @brief Do Async GET query + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + virtual void DownloadAsync(std::u16string_view url, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false, _v::CActionRef progress = nullptr) override final; + /// @brief Do Async POST query + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void PostAsync(std::u16string_view url, const WebContent::Ptr& content, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) override final; + /// @brief Do Async PATCH query + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void PatchAsync(std::u16string_view url, const WebContent::Ptr& content, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) override final; + /// @brief Do Async PUT query + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void PutAsync(std::u16string_view url, const WebContent::Ptr& content, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) override final; + /// @brief Do Async DELETE query + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void DeleteAsync(std::u16string_view url, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) override final; + + private: + /// @brief Get URL + /// @param url Request URL + std::u16string GetURL(std::u16string_view url); + /// @brief Safe URL parsing + /// @param url Source URL + std::u16string SafeURL(std::u16string_view url); + + private: + /// @brief Do request + /// @param debugName Method name for logs + /// @param httpMethod Http method + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + static void DoRequest( + Ptr self, + std::u16string debugName, + std::u16string httpMethod, + std::u16string url, + WebContent::Ptr content, + _u::CancellationToken token, + _v::Action callback, + bool dontRetry, + _v::Action progress + ); + + }; + +} ///< namespace CP_SDK::Network \ No newline at end of file diff --git a/shared/CP_SDK/Network/WebClientUnity.hpp b/shared/CP_SDK/Network/WebClientUnity.hpp index c06bb1e..1029da7 100644 --- a/shared/CP_SDK/Network/WebClientUnity.hpp +++ b/shared/CP_SDK/Network/WebClientUnity.hpp @@ -53,96 +53,96 @@ namespace CP_SDK::Network { public: /// @brief Constructor - /// @param p_BaseAddress Base address - /// @param p_TimeOut Requests timeout - /// @param p_ForceCacheDiscard Should force server cache discard - WebClientUnity(CP_SDK_PRIV_TAG_ARG(), std::u16string_view p_BaseAddress, _u::TimeSpan p_TimeOut, bool p_ForceCacheDiscard); + /// @param baseAddress Base address + /// @param timeOut Requests timeout + /// @param forceCacheDiscard Should force server cache discard + WebClientUnity(CP_SDK_PRIV_TAG_ARG(), std::u16string_view baseAddress, _u::TimeSpan timeOut, bool forceCacheDiscard); /// @brief Constructor - /// @param p_BaseAddress Base address - /// @param p_TimeOut Requests timeout - /// @param p_ForceCacheDiscard Should force server cache discard - static Ptr Make(std::u16string_view p_BaseAddress, _u::TimeSpan p_TimeOut, bool p_ForceCacheDiscard = false); + /// @param baseAddress Base address + /// @param timeOut Requests timeout + /// @param forceCacheDiscard Should force server cache discard + static Ptr Make(std::u16string_view baseAddress, _u::TimeSpan timeOut, bool forceCacheDiscard = false); public: /// @brief Get header - /// @param p_Name Header name - virtual std::u16string GetHeader(std::u16string_view p_Name) override final; + /// @param name Header name + virtual std::u16string GetHeader(std::u16string_view name) override final; /// @brief Set header - /// @param p_Name Header name - /// @param p_Value Header value - virtual void SetHeader(std::u16string_view p_Name, std::u16string_view p_Value) override final; + /// @param name Header name + /// @param value Header value + virtual void SetHeader(std::u16string_view name, std::u16string_view value) override final; /// @brief Remove header - /// @param p_Name Header name - virtual void RemoveHeader(std::u16string_view p_Name) override final; + /// @param name Header name + virtual void RemoveHeader(std::u16string_view name) override final; public: /// @brief Do Async GET query - /// @param p_URL Target URL - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - /// @param p_Progress Progress reporter - virtual void GetAsync(std::u16string_view p_URL, _u::CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry = false, _v::CActionRef p_Progress = nullptr) override final; + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + virtual void GetAsync(std::u16string_view url, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false, _v::CActionRef progress = nullptr) override final; /// @brief Do Async GET query - /// @param p_URL Target URL - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - /// @param p_Progress Progress reporter - virtual void DownloadAsync(std::u16string_view p_URL, _u::CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry = false, _v::CActionRef p_Progress = nullptr) override final; + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + virtual void DownloadAsync(std::u16string_view url, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false, _v::CActionRef progress = nullptr) override final; /// @brief Do Async POST query - /// @param p_URL Target URL - /// @param p_Content Optional content to post - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - virtual void PostAsync(std::u16string_view p_URL, const WebContent::Ptr& p_Content, _u::CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry = false) override final; + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void PostAsync(std::u16string_view url, const WebContent::Ptr& content, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) override final; /// @brief Do Async PATCH query - /// @param p_URL Target URL - /// @param p_Content Optional content to post - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - virtual void PatchAsync(std::u16string_view p_URL, const WebContent::Ptr& p_Content, _u::CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry = false) override final; + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void PatchAsync(std::u16string_view url, const WebContent::Ptr& content, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) override final; /// @brief Do Async DELETE query - /// @param p_URL Target URL - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - virtual void DeleteAsync(std::u16string_view p_URL, _u::CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry = false) override final; + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void DeleteAsync(std::u16string_view url, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) override final; private: /// @brief Get URL - /// @param p_URL Request URL - std::u16string GetURL(std::u16string_view p_URL); + /// @param url Request URL + std::u16string GetURL(std::u16string_view url); /// @brief Safe URL parsing - /// @param p_URL Source URL - std::u16string SafeURL(std::u16string_view p_URL); + /// @param url Source URL + std::u16string SafeURL(std::u16string_view url); private: /// @brief Prepare request - /// @param p_Request Request to prepare - /// @param p_IsDownload Is a download request? - void PrepareRequest(_u::UnityWebRequest* p_Request, bool p_IsDownload); + /// @param request Request to prepare + /// @param isDownload Is a download request? + void PrepareRequest(_u::UnityWebRequest* request, bool isDownload); /// @brief Do request - /// @param p_DebugName Method name for logs - /// @param p_HttpMethod Http method - /// @param p_URL Target URL - /// @param p_Content Optional content to post - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - /// @param p_Progress Progress reporter - static custom_types::Helpers::Coroutine Coroutine_DoRequest(Ptr p_Self, - std::u16string p_DebugName, - std::u16string p_HttpMethod, - std::u16string p_URL, - WebContent::Ptr p_Content, - _u::CancellationToken p_Token, - _v::Action p_Callback, - bool p_DontRetry, - _v::Action p_Progress); + /// @param debugName Method name for logs + /// @param httpMethod Http method + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + static custom_types::Helpers::Coroutine Coroutine_DoRequest(Ptr self, + std::u16string debugName, + std::u16string httpMethod, + std::u16string url, + WebContent::Ptr content, + _u::CancellationToken token, + _v::Action callback, + bool dontRetry, + _v::Action progress); }; diff --git a/shared/CP_SDK/Network/WebContent.hpp b/shared/CP_SDK/Network/WebContent.hpp index 750da47..fb4e6ef 100644 --- a/shared/CP_SDK/Network/WebContent.hpp +++ b/shared/CP_SDK/Network/WebContent.hpp @@ -2,6 +2,7 @@ #include "../Utils/Il2cpp.hpp" #include "../Utils/MonoPtr.hpp" +#include "../Utils/Json.hpp" #include #include @@ -37,8 +38,11 @@ namespace CP_SDK::Network { public: /// @brief Constructor from Json - /// @param p_Content Json content - static Ptr FromJson(std::u16string_view p_Content); + /// @param content Json content + static Ptr FromJson(std::u16string_view content); + /// @brief Constructor from Json + /// @param content Json content + static Ptr FromJson(std::shared_ptr<_v::Json::U16Document>& content); }; diff --git a/shared/CP_SDK/Network/WebResponse.hpp b/shared/CP_SDK/Network/WebResponse.hpp index c89ba58..cc3c140 100644 --- a/shared/CP_SDK/Network/WebResponse.hpp +++ b/shared/CP_SDK/Network/WebResponse.hpp @@ -9,6 +9,7 @@ #include #include +#include namespace CP_SDK::Network { @@ -60,16 +61,21 @@ namespace CP_SDK::Network { using Ptr = std::shared_ptr; /// Constructor - /// @p_Request: Reply status - WebResponse(_u::UnityWebRequest* p_Request); + /// @param request: Reply status + WebResponse(_u::UnityWebRequest* request); + /// @brief Constructor + /// @param curlPerformResult CURL perform result + /// @param curlInstance CURL instance + /// @param data Response data + WebResponse(long curlPerformResult, void* curlInstance, std::vector* data); public: /// @brief Get JObject from serialized JSON - /// @param p_Object Result object + /// @param object Result object /// @return True or false - bool TryAsJObject(std::shared_ptr<_v::Json::U16Document>& p_Object) + bool TryAsJObject(std::shared_ptr<_v::Json::U16Document>& object) { - p_Object = nullptr; + object = nullptr; auto l_New = std::make_shared<_v::Json::U16Document>(); try @@ -77,40 +83,40 @@ namespace CP_SDK::Network { if (!_v::Json::TryFromU16String(BodyString(), *l_New.get())) return false; - p_Object = l_New; + object = l_New; } catch (const std::exception& l_Exception) { - p_Object = nullptr; + object = nullptr; return false; } - return p_Object != nullptr; + return object != nullptr; } /// @brief Get Object from serialized JSON /// @tparam t_Type Object type - /// @param p_Object Result object + /// @param object Result object /// @return True or false template - bool TryGetObject(std::shared_ptr& p_Object) + bool TryGetObject(std::shared_ptr& object) { - p_Object = nullptr; + object = nullptr; try { _v::Json::U16Document l_Document; _v::Json::TryFromU16String(BodyString(), l_Document); - p_Object = std::make_shared(); - p_Object->Unserialize(l_Document); + object = std::make_shared(); + object->Unserialize(l_Document); } catch (const std::exception& l_Exception) { - p_Object = nullptr; + object = nullptr; return false; } - return p_Object != nullptr; + return object != nullptr; } }; diff --git a/shared/CP_SDK/Utils/Il2cpp.hpp b/shared/CP_SDK/Utils/Il2cpp.hpp index a148ed4..54e5ad6 100644 --- a/shared/CP_SDK/Utils/Il2cpp.hpp +++ b/shared/CP_SDK/Utils/Il2cpp.hpp @@ -3,18 +3,12 @@ #define __CP_SDK_U16STR(__mX) u##__mX #define CP_SDK_U16STR(__mX) __CP_SDK_U16STR(#__mX) -#include "../Logging/PaperLogger.hpp" #include "Internals/Il2cpp_enum.hpp" #include "Internals/Il2cpp_customtype.hpp" #include "Internals/Il2cpp_hook.hpp" #include "Internals/Il2cpp_string.hpp" #include -#include -#include -#include -#include -#include #include #include diff --git a/src/CP_SDK/Network/WebClientCore.cpp b/src/CP_SDK/Network/WebClientCore.cpp new file mode 100644 index 0000000..83e8b27 --- /dev/null +++ b/src/CP_SDK/Network/WebClientCore.cpp @@ -0,0 +1,570 @@ +#include "CP_SDK/Network/WebClientCore.hpp" +#include "CP_SDK/Unity/MTThreadInvoker.hpp" +#include "CP_SDK/ChatPlexSDK.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace System; +using namespace System::Net; +using namespace System::Threading; + +struct ScopedCURL +{ + CURL* Instance; + struct curl_slist* Headers = NULL; + std::vector* Data; + + ScopedCURL() + { + Instance = curl_easy_init(); + Data = new std::vector(); + } + ~ScopedCURL() + { + curl_easy_cleanup(Instance); + if (Headers != NULL) + curl_slist_free_all(Headers); + + delete Data; + } +}; + +namespace CP_SDK::Network { + + WebClientCore::Ptr WebClientCore::m_GlobalClient; + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Global client instance + WebClientCore* WebClientCore::GlobalClient() + { + if (!m_GlobalClient) + m_GlobalClient = WebClientCore::Make(u"", TimeSpan::FromSeconds(10), true); + + return m_GlobalClient.get(); + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Constructor + /// @param baseAddress Base address + /// @param timeOut Requests timeout + /// @param forceCacheDiscard Should force server cache discard + WebClientCore::WebClientCore(CP_SDK_PRIV_TAG_ARG(), std::u16string_view baseAddress, TimeSpan timeOut, bool keepAlive, bool forceCacheDiscard) + : m_Headers({}) + { + MaxRetry = 2; + RetryInterval = 5; + + m_BaseAddress = baseAddress; + + m_TimeOut = (int)timeOut.get_TotalSeconds(); + + if (forceCacheDiscard) + m_Headers[u"Cache-Control"] = u"no-cache, must-revalidate, proxy-revalidate, max-age=0, s-maxage=0, max-stale=0"; + } + + /// @brief Constructor + /// @param baseAddress Base address + /// @param timeOut Requests timeout + /// @param forceCacheDiscard Should force server cache discard + WebClientCore::Ptr WebClientCore::Make(std::u16string_view baseAddress, TimeSpan timeOut, bool keepAlive, bool forceCacheDiscard) + { + return std::make_shared(CP_SDK_PRIV_TAG_VAL(), baseAddress, timeOut, keepAlive, forceCacheDiscard); + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Get header + /// @param name Header name + std::u16string WebClientCore::GetHeader(std::u16string_view name) + { + auto l_Name = std::u16string(name); + + std::lock_guard l_Guard(m_HeadersLock); + if (!m_Headers.contains(l_Name)) + return u""; + + return m_Headers[l_Name]; + } + /// @brief Set header + /// @param name Header name + /// @param value Header value + void WebClientCore::SetHeader(std::u16string_view name, std::u16string_view value) + { + auto l_Name = std::u16string(name); + + std::lock_guard l_Guard(m_HeadersLock); + m_Headers[l_Name] = std::u16string(value); + } + /// @brief Remove header + /// @param name Header name + void WebClientCore::RemoveHeader(std::u16string_view name) + { + auto l_Name = std::u16string(name); + + std::lock_guard l_Guard(m_HeadersLock); + auto l_It = m_Headers.find(l_Name); + if (l_It != m_Headers.end()) + m_Headers.erase(l_It); + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Do GET query + /// @param url Target URL + /// @param dontRetry Should not retry + /// @param progress Progress reporter + WebResponse::Ptr WebClientCore::Get(std::u16string_view url, bool dontRetry, _v::CActionRef progress) + { + auto l_Reply = WebResponse::Ptr(nullptr); + + DoRequest( + shared_from_this(), + u"Get", + u"GET", + GetURL(url), + nullptr, + CancellationToken::get_None(), + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + dontRetry, + progress + ); + + return l_Reply; + } + /// @brief Do GET query + /// @param url Target URL + /// @param dontRetry Should not retry + /// @param progress Progress reporter + WebResponse::Ptr WebClientCore::Download(std::u16string_view url, bool dontRetry, _v::CActionRef progress) + { + auto l_Reply = WebResponse::Ptr(nullptr); + + DoRequest( + shared_from_this(), + u"Download", + u"DOWNLOAD", + GetURL(url), + nullptr, + CancellationToken::get_None(), + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + dontRetry, + progress + ); + + return l_Reply; + } + /// @brief Do POST query + /// @param url Target URL + /// @param content Optional content to post + /// @param dontRetry Should not retry + WebResponse::Ptr WebClientCore::Post(std::u16string_view url, const WebContent::Ptr& content, bool dontRetry) + { + auto l_Reply = WebResponse::Ptr(nullptr); + + DoRequest( + shared_from_this(), + u"Post", + u"POST", + GetURL(url), + content, + CancellationToken::get_None(), + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + dontRetry, + nullptr + ); + + return l_Reply; + } + /// @brief Do PATCH query + /// @param url Target URL + /// @param content Optional content to post + /// @param dontRetry Should not retry + WebResponse::Ptr WebClientCore::Patch(std::u16string_view url, const WebContent::Ptr& content, bool dontRetry) + { + auto l_Reply = WebResponse::Ptr(nullptr); + + DoRequest( + shared_from_this(), + u"Patch", + u"PATCH", + GetURL(url), + content, + CancellationToken::get_None(), + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + dontRetry, + nullptr + ); + + return l_Reply; + } + /// @brief Do PUT query + /// @param url Target URL + /// @param content Optional content to post + /// @param dontRetry Should not retry + WebResponse::Ptr WebClientCore::Put(std::u16string_view url, const WebContent::Ptr& content, bool dontRetry) + { + auto l_Reply = WebResponse::Ptr(nullptr); + + DoRequest( + shared_from_this(), + u"Put", + u"PUT", + GetURL(url), + content, + CancellationToken::get_None(), + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + dontRetry, + nullptr + ); + + return l_Reply; + } + /// @brief Do DELETE query + /// @param url Target URL + /// @param dontRetry Should not retry + WebResponse::Ptr WebClientCore::Delete(std::u16string_view url, bool dontRetry) + { + auto l_Reply = WebResponse::Ptr(nullptr); + + DoRequest( + shared_from_this(), + u"Delete", + u"DELETE", + GetURL(url), + nullptr, + CancellationToken::get_None(), + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + dontRetry, + nullptr + ); + + return l_Reply; + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Do Async GET query + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + void WebClientCore::GetAsync(std::u16string_view url, CancellationToken token, _v::CActionRef callback, bool dontRetry, _v::CActionRef progress) + { + il2cpp_utils::il2cpp_aware_thread( + &DoRequest, + shared_from_this(), + u"GetAsync", + u"GET", + GetURL(url), + nullptr, + token, + callback, + dontRetry, + progress + ).detach(); + } + /// @brief Do Async GET query + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + void WebClientCore::DownloadAsync(std::u16string_view url, CancellationToken token, _v::CActionRef callback, bool dontRetry, _v::CActionRef progress) + { + il2cpp_utils::il2cpp_aware_thread( + &DoRequest, + shared_from_this(), + u"DownloadAsync", + u"DOWNLOAD", + GetURL(url), + nullptr, + token, + callback, + dontRetry, + progress + ).detach(); + } + /// @brief Do Async POST query + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + void WebClientCore::PostAsync(std::u16string_view url, const WebContent::Ptr& content, CancellationToken token, _v::CActionRef callback, bool dontRetry) + { + il2cpp_utils::il2cpp_aware_thread( + &DoRequest, + shared_from_this(), + u"PostAsync", + u"POST", + GetURL(url), + content, + token, + callback, + dontRetry, + nullptr + ).detach(); + } + /// @brief Do Async PATCH query + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + void WebClientCore::PatchAsync(std::u16string_view url, const WebContent::Ptr& content, CancellationToken token, _v::CActionRef callback, bool dontRetry) + { + il2cpp_utils::il2cpp_aware_thread( + &DoRequest, + shared_from_this(), + u"PatchAsync", + u"PATCH", + GetURL(url), + content, + token, + callback, + dontRetry, + nullptr + ).detach(); + } + /// @brief Do Async PATCH query + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + void WebClientCore::PutAsync(std::u16string_view url, const WebContent::Ptr& content, CancellationToken token, _v::CActionRef callback, bool dontRetry) + { + il2cpp_utils::il2cpp_aware_thread( + &DoRequest, + shared_from_this(), + u"PutAsync", + u"PUT", + GetURL(url), + content, + token, + callback, + dontRetry, + nullptr + ).detach(); + } + /// @brief Do Async GET query + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + void WebClientCore::DeleteAsync(std::u16string_view url, CancellationToken token, _v::CActionRef callback, bool dontRetry) + { + il2cpp_utils::il2cpp_aware_thread( + &DoRequest, + shared_from_this(), + u"DeleteAsync", + u"DELETE", + GetURL(url), + nullptr, + token, + callback, + dontRetry, + nullptr + ); + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Get URL + /// @param url Request URL + std::u16string WebClientCore::GetURL(std::u16string_view url) + { + if (m_BaseAddress.size() == 0) return std::u16string(url); + if (url.find(u"://") != std::u16string::npos) return std::u16string(url); + if (m_BaseAddress[m_BaseAddress.size() - 1] == '/') return m_BaseAddress + std::u16string(url); + + return m_BaseAddress + u"/" + std::u16string(url); + } + /// @brief Safe URL parsing + /// @param url Source URL + std::u16string WebClientCore::SafeURL(std::u16string_view url) + { + auto l_Position = url.find_first_of('?'); + if (l_Position != std::u16string::npos) + return std::u16string(url).substr(0, l_Position); + + return std::u16string(url); + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Do request + /// @param debugName Method name for logs + /// @param httpMethod Http method + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + void WebClientCore::DoRequest( + Ptr self, + std::u16string debugName, + std::u16string httpMethod, + std::u16string url, + WebContent::Ptr content, + CancellationToken token, + _v::Action callback, + bool dontRetry, + _v::Action progress + ) + { +#if DEBUG + ChatPlexSDK::Logger()->Debug(u"[CP_SDK.Network][WebClientCore." + debugName + u"] " + httpMethod + u" " + url); +#endif + + WebResponse::Ptr l_Reply = nullptr; + for (int l_RetryI = 1; l_RetryI <= self->MaxRetry; l_RetryI++) + { + if (token.get_IsCancellationRequested()) + break; + + ScopedCURL l_ScopedCURL; + l_ScopedCURL.Headers = curl_slist_append(l_ScopedCURL.Headers, "Accept: */*"); + + for (auto const& [l_Header, l_Value] : self->m_Headers) + l_ScopedCURL.Headers = curl_slist_append(l_ScopedCURL.Headers, Utils::U16StrToStr(l_Header + ": " + l_Value).c_str()); + + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_URL, Utils::U16StrToStr(url).c_str()); + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_TIMEOUT, static_cast(self->m_TimeOut)); + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_FOLLOWLOCATION, static_cast(1)); + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_USERAGENT, Utils::U16StrToStr(ChatPlexSDK::NetworkUserAgent()).c_str()); + + if (httpMethod == u"GET" || httpMethod == u"DOWNLOAD") + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_CUSTOMREQUEST, "GET"); + else if (httpMethod == u"POST" || httpMethod == u"PATCH" || httpMethod == u"PUT") + { + if (httpMethod == u"POST") + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_CUSTOMREQUEST, "POST"); + if (httpMethod == u"PATCH") + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_CUSTOMREQUEST, "PATCH"); + else + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_CUSTOMREQUEST, "PUT"); + + if (content) + { + l_ScopedCURL.Headers = curl_slist_append(l_ScopedCURL.Headers, Utils::U16StrToStr(std::u16string(u"Content-Type: ") + content->Type).c_str()); + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_POSTFIELDSIZE, static_cast(content->Bytes->get_Length())); + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_POSTFIELDS, &content->Bytes->_values[0]); + } + } + else if (httpMethod == u"DELETE") + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_CUSTOMREQUEST, "DELETE"); + + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_HTTPHEADER, l_ScopedCURL.Headers); + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_SSL_VERIFYPEER, false); + + if (progress.IsValid()) + { + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_NOPROGRESS, false); + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_XFERINFODATA, (void*)&progress); + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_XFERINFOFUNCTION, + +[] (_v::Action* clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) { + float percentage = (float)dlnow / (float)dltotal * 100.0f; + if(isnan(percentage)) + percentage = 0.0f; + clientp->Invoke(percentage); + return 0; + } + ); + } + + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_WRITEDATA, l_ScopedCURL.Data); + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_WRITEFUNCTION, + +[](void *contents, std::size_t size, std::size_t nmemb, std::vector* clientp) -> size_t + { + size_t l_SizeToWrite = size * nmemb; + + try + { + auto l_WritePos = clientp->size(); + clientp->resize(l_WritePos + l_SizeToWrite); + memcpy(clientp->data() + l_WritePos, contents, l_SizeToWrite); + } + catch(std::bad_alloc &e) + { + ChatPlexSDK::Logger()->Error(u"[CP_SDK.Network][WebClientCore.DoRequest] Failed to read from response stream, allocation error"); + return 0; + } + + return l_SizeToWrite; + }); + + if (token.get_IsCancellationRequested()) + break; + + auto l_CURLResult = curl_easy_perform(l_ScopedCURL.Instance); + + l_Reply = std::make_shared(static_cast(l_CURLResult), l_ScopedCURL.Instance, l_ScopedCURL.Data); + if (!l_Reply->IsSuccessStatusCode() && l_Reply->StatusCode() == (HttpStatusCode)429) + { + /* var l_Limits = RateLimitInfo.Get(l_Request); + if (l_Limits != nullptr) + { + int l_TotalMilliseconds = (int)(l_Limits.Reset - DateTime.Now).TotalMilliseconds; + if (l_TotalMilliseconds > 0) + { + ChatPlexSDK::Logger()->Error(u"[CP_SDK.Network][WebClientCore." + debugName + u"] Request {SafeURL(url)} was rate limited, retrying in {l_TotalMilliseconds}ms..."); + + co_yield WaitForSecondsRealtime::New_ctor(RetryInterval)->i_IEnumerator(); + continue; + } + }*/ + } + + if (!l_Reply->IsSuccessStatusCode()) + { + auto l_LogPrefix = u"[CP_SDK.Network][WebClientCore." + debugName + u"] Request " + self->SafeURL(url) + u" failed with code "; + l_LogPrefix += StringW(std::to_string(l_Reply->StatusCode().value__)); + l_LogPrefix += u":\"" + l_Reply->ReasonPhrase() + "\", "; + + if (!l_Reply->ShouldRetry() || dontRetry) + { + ChatPlexSDK::Logger()->Error(l_LogPrefix + u" not retrying"); + break; + } + + ChatPlexSDK::Logger()->Error(l_LogPrefix + u" next try in " + (std::u16string)StringW(std::to_string(self->RetryInterval)) + u" seconds..."); + + std::this_thread::sleep_for(std::chrono::seconds(self->RetryInterval)); + continue; + } + else + { + if (progress.IsValid()) + try { progress(1.0f); } catch (const std::exception&) { } + + break; + } + } + + if (!token.get_IsCancellationRequested() && callback.IsValid()) + Unity::MTThreadInvoker::EnqueueOnThread([=]() -> void { callback(l_Reply); }); + } + +} ///< namespace CP_SDK::Network \ No newline at end of file diff --git a/src/CP_SDK/Network/WebClientUnity.cpp b/src/CP_SDK/Network/WebClientUnity.cpp index 772c79c..3e6e4b9 100644 --- a/src/CP_SDK/Network/WebClientUnity.cpp +++ b/src/CP_SDK/Network/WebClientUnity.cpp @@ -6,7 +6,6 @@ #include #include #include -//#include #include #include @@ -36,41 +35,41 @@ namespace CP_SDK::Network { //////////////////////////////////////////////////////////////////////////// /// @brief Constructor - /// @param p_BaseAddress Base address - /// @param p_TimeOut Requests timeout - /// @param p_ForceCacheDiscard Should force server cache discard - WebClientUnity::WebClientUnity(CP_SDK_PRIV_TAG_ARG(), std::u16string_view p_BaseAddress, TimeSpan p_TimeOut, bool p_ForceCacheDiscard) + /// @param baseAddress Base address + /// @param timeOut Requests timeout + /// @param forceCacheDiscard Should force server cache discard + WebClientUnity::WebClientUnity(CP_SDK_PRIV_TAG_ARG(), std::u16string_view baseAddress, TimeSpan timeOut, bool forceCacheDiscard) : m_Headers({}) { DownloadTimeout = 2 * 60; MaxRetry = 2; RetryInterval = 5; - m_BaseAddress = p_BaseAddress; + m_BaseAddress = baseAddress; - m_Timeout = (int)p_TimeOut.get_TotalSeconds(); + m_Timeout = (int)timeOut.get_TotalSeconds(); - if (p_ForceCacheDiscard) + if (forceCacheDiscard) m_Headers[u"Cache-Control"] = u"no-cache, must-revalidate, proxy-revalidate, max-age=0, s-maxage=0, max-stale=0"; } /// @brief Constructor - /// @param p_BaseAddress Base address - /// @param p_TimeOut Requests timeout - /// @param p_ForceCacheDiscard Should force server cache discard - WebClientUnity::Ptr WebClientUnity::Make(std::u16string_view p_BaseAddress, TimeSpan p_TimeOut, bool p_ForceCacheDiscard) + /// @param baseAddress Base address + /// @param timeOut Requests timeout + /// @param forceCacheDiscard Should force server cache discard + WebClientUnity::Ptr WebClientUnity::Make(std::u16string_view baseAddress, TimeSpan timeOut, bool forceCacheDiscard) { - return std::make_shared(CP_SDK_PRIV_TAG_VAL(), p_BaseAddress, p_TimeOut, p_ForceCacheDiscard); + return std::make_shared(CP_SDK_PRIV_TAG_VAL(), baseAddress, timeOut, forceCacheDiscard); } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// /// @brief Get header - /// @param p_Name Header name - std::u16string WebClientUnity::GetHeader(std::u16string_view p_Name) + /// @param name Header name + std::u16string WebClientUnity::GetHeader(std::u16string_view name) { - auto l_Name = std::u16string(p_Name); + auto l_Name = std::u16string(name); std::lock_guard l_Guard(m_HeadersLock); if (!m_Headers.contains(l_Name)) @@ -79,20 +78,20 @@ namespace CP_SDK::Network { return m_Headers[l_Name]; } /// @brief Set header - /// @param p_Name Header name - /// @param p_Value Header value - void WebClientUnity::SetHeader(std::u16string_view p_Name, std::u16string_view p_Value) + /// @param name Header name + /// @param value Header value + void WebClientUnity::SetHeader(std::u16string_view name, std::u16string_view value) { - auto l_Name = std::u16string(p_Name); + auto l_Name = std::u16string(name); std::lock_guard l_Guard(m_HeadersLock); - m_Headers[l_Name] = std::u16string(p_Value); + m_Headers[l_Name] = std::u16string(value); } /// @brief Remove header - /// @param p_Name Header name - void WebClientUnity::RemoveHeader(std::u16string_view p_Name) + /// @param name Header name + void WebClientUnity::RemoveHeader(std::u16string_view name) { - auto l_Name = std::u16string(p_Name); + auto l_Name = std::u16string(name); std::lock_guard l_Guard(m_HeadersLock); auto l_It = m_Headers.find(l_Name); @@ -104,153 +103,155 @@ namespace CP_SDK::Network { //////////////////////////////////////////////////////////////////////////// /// @brief Do Async GET query - /// @param p_URL Target URL - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - /// @param p_Progress Progress reporter - void WebClientUnity::GetAsync(std::u16string_view p_URL, CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry, _v::CActionRef p_Progress) + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + void WebClientUnity::GetAsync(std::u16string_view url, CancellationToken token, _v::CActionRef callback, bool dontRetry, _v::CActionRef progress) { - Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"GetAsync", u"GET", GetURL(p_URL), nullptr, p_Token, p_Callback, p_DontRetry, p_Progress))); + Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"GetAsync", u"GET", GetURL(url), nullptr, token, callback, dontRetry, progress))); } /// @brief Do Async GET query - /// @param p_URL Target URL - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - /// @param p_Progress Progress reporter - void WebClientUnity::DownloadAsync(std::u16string_view p_URL, CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry, _v::CActionRef p_Progress) + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + void WebClientUnity::DownloadAsync(std::u16string_view url, CancellationToken token, _v::CActionRef callback, bool dontRetry, _v::CActionRef progress) { - Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"DownloadAsync", u"DOWNLOAD", GetURL(p_URL), nullptr, p_Token, p_Callback, p_DontRetry, p_Progress))); + Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"DownloadAsync", u"DOWNLOAD", GetURL(url), nullptr, token, callback, dontRetry, progress))); } /// @brief Do Async POST query - /// @param p_URL Target URL - /// @param p_Content Optional content to post - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - void WebClientUnity::PostAsync(std::u16string_view p_URL, const WebContent::Ptr& p_Content, CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry) + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + void WebClientUnity::PostAsync(std::u16string_view url, const WebContent::Ptr& content, CancellationToken token, _v::CActionRef callback, bool dontRetry) { - Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"PostAsync", u"POST", GetURL(p_URL), p_Content, p_Token, p_Callback, p_DontRetry, nullptr))); + Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"PostAsync", u"POST", GetURL(url), content, token, callback, dontRetry, nullptr))); } /// @brief Do Async PATCH query - /// @param p_URL Target URL - /// @param p_Content Optional content to post - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - void WebClientUnity::PatchAsync(std::u16string_view p_URL, const WebContent::Ptr& p_Content, CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry) + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + void WebClientUnity::PatchAsync(std::u16string_view url, const WebContent::Ptr& content, CancellationToken token, _v::CActionRef callback, bool dontRetry) { - Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"PatchAsync", u"PATCH", GetURL(p_URL), p_Content, p_Token, p_Callback, p_DontRetry, nullptr))); + Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"PatchAsync", u"PATCH", GetURL(url), content, token, callback, dontRetry, nullptr))); } /// @brief Do Async GET query - /// @param p_URL Target URL - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - /// @param p_Progress Progress reporter - void WebClientUnity::DeleteAsync(std::u16string_view p_URL, CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry) + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + void WebClientUnity::DeleteAsync(std::u16string_view url, CancellationToken token, _v::CActionRef callback, bool dontRetry) { - Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"DownloadAsync", u"DOWNLOAD", GetURL(p_URL), nullptr, p_Token, p_Callback, p_DontRetry, nullptr))); + Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"DownloadAsync", u"DOWNLOAD", GetURL(url), nullptr, token, callback, dontRetry, nullptr))); } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// /// @brief Get URL - /// @param p_URL Request URL - std::u16string WebClientUnity::GetURL(std::u16string_view p_URL) + /// @param url Request URL + std::u16string WebClientUnity::GetURL(std::u16string_view url) { - if (m_BaseAddress.size() == 0) return std::u16string(p_URL); - if (p_URL.find(u"://") != std::u16string::npos) return std::u16string(p_URL); - if (m_BaseAddress[m_BaseAddress.size() - 1] == '/') return m_BaseAddress + std::u16string(p_URL); + if (m_BaseAddress.size() == 0) return std::u16string(url); + if (url.find(u"://") != std::u16string::npos) return std::u16string(url); + if (m_BaseAddress[m_BaseAddress.size() - 1] == '/') return m_BaseAddress + std::u16string(url); - return m_BaseAddress + u"/" + std::u16string(p_URL); + return m_BaseAddress + u"/" + std::u16string(url); } /// @brief Safe URL parsing - /// @param p_URL Source URL - std::u16string WebClientUnity::SafeURL(std::u16string_view p_URL) + /// @param url Source URL + std::u16string WebClientUnity::SafeURL(std::u16string_view url) { - auto l_Position = p_URL.find_first_of('?'); + auto l_Position = url.find_first_of('?'); if (l_Position != std::u16string::npos) - return std::u16string(p_URL).substr(0, l_Position); + return std::u16string(url).substr(0, l_Position); - return std::u16string(p_URL); + return std::u16string(url); } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// /// @brief Prepare request - /// @param p_Request Request to prepare - /// @param p_IsDownload Is a download request? - void WebClientUnity::PrepareRequest(UnityWebRequest* p_Request, bool p_IsDownload) + /// @param request Request to prepare + /// @param isDownload Is a download request? + void WebClientUnity::PrepareRequest(UnityWebRequest* request, bool isDownload) { - if (p_Request->get_downloadHandler() == nullptr) - p_Request->set_downloadHandler(DownloadHandlerBuffer::New_ctor()); + if (request->get_downloadHandler() == nullptr) + request->set_downloadHandler(DownloadHandlerBuffer::New_ctor()); - p_Request->set_timeout(p_IsDownload ? DownloadTimeout : m_Timeout); + request->set_timeout(isDownload ? DownloadTimeout : m_Timeout); std::lock_guard l_Guard(m_HeadersLock); static auto s_UnityWebRequest_InternalSetRequestHeader = il2cpp_utils::resolve_icall("UnityEngine.Networking.UnityWebRequest::InternalSetRequestHeader"); for (auto const& [l_Header, l_Value] : m_Headers) - s_UnityWebRequest_InternalSetRequestHeader(p_Request, l_Header, l_Value); + s_UnityWebRequest_InternalSetRequestHeader(request, l_Header, l_Value); } /// @brief Do request - /// @param p_DebugName Method name for logs - /// @param p_HttpMethod Http method - /// @param p_URL Target URL - /// @param p_Content Optional content to post - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - /// @param p_Progress Progress reporter - custom_types::Helpers::Coroutine WebClientUnity::Coroutine_DoRequest(Ptr p_Self, - std::u16string p_DebugName, - std::u16string p_HttpMethod, - std::u16string p_URL, - WebContent::Ptr p_Content, - CancellationToken p_Token, - _v::Action p_Callback, - bool p_DontRetry, - _v::Action p_Progress) + /// @param debugName Method name for logs + /// @param httpMethod Http method + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + custom_types::Helpers::Coroutine WebClientUnity::Coroutine_DoRequest(Ptr self, + std::u16string debugName, + std::u16string httpMethod, + std::u16string url, + WebContent::Ptr content, + CancellationToken token, + _v::Action callback, + bool dontRetry, + _v::Action progress) { #if DEBUG - ChatPlexSDK::Logger()->Debug(u"[CP_SDK.Network][WebClientUnity." + p_DebugName + u"] " + p_HttpMethod + u" " + p_URL); + ChatPlexSDK::Logger()->Debug(u"[CP_SDK.Network][WebClientUnity." + debugName + u"] " + httpMethod + u" " + url); #endif WebResponse::Ptr l_Reply = nullptr; - for (int l_RetryI = 1; l_RetryI <= p_Self->MaxRetry; l_RetryI++) + for (int l_RetryI = 1; l_RetryI <= self->MaxRetry; l_RetryI++) { - if (p_Token.get_IsCancellationRequested()) + if (token.get_IsCancellationRequested()) break; auto l_Request = _v::MonoPtr(nullptr); - if (p_HttpMethod == u"GET" || p_HttpMethod == u"DOWNLOAD") - l_Request = UnityWebRequest::Get(p_URL); - else if (p_HttpMethod == u"POST" || p_HttpMethod == u"PATCH") + if (httpMethod == u"GET" || httpMethod == u"DOWNLOAD") + l_Request = UnityWebRequest::Get(url); + else if (httpMethod == u"POST" || httpMethod == u"PATCH" || httpMethod == u"PUT") { - ChatPlexSDK::Logger()->Error(u"WebClientUnity POST & PATCH are disabled for now"); + ChatPlexSDK::Logger()->Error(u"WebClientUnity POST & PATCH & PUT are disabled for now"); throw std::runtime_error("WebClientUnity POST & PATCH are disabled for now"); /// TODO Disabled until fixed - /*static auto s_UploadHandler_InternalSetContentType = il2cpp_utils::resolve_icall("UnityEngine.Networking.UploadHandler::InternalSetContentType"); - auto l_UploadHandler = UploadHandlerRaw::New_ctor(p_Content->Bytes.Ptr()); - s_UploadHandler_InternalSetContentType(l_UploadHandler, p_Content->Type); + /*static auto s_UploadHandler_InternalSetContentType + = il2cpp_utils::resolve_icall("UnityEngine.Networking.UploadHandler::InternalSetContentType"); - l_Request = UnityWebRequest::New_ctor(p_URL, p_HttpMethod, DownloadHandlerBuffer::New_ctor(), l_UploadHandler);*/ + auto l_UploadHandler = UploadHandlerRaw::New_ctor(content->Bytes.Ptr()); + s_UploadHandler_InternalSetContentType(l_UploadHandler, content->Type); + + l_Request = UnityWebRequest::New_ctor(url, httpMethod, DownloadHandlerBuffer::New_ctor(), l_UploadHandler);*/ } - else if (p_HttpMethod == u"DELETE") - l_Request = UnityWebRequest::New_ctor(p_URL, p_HttpMethod, nullptr, nullptr); + else if (httpMethod == u"DELETE") + l_Request = UnityWebRequest::New_ctor(url, httpMethod, nullptr, nullptr); - p_Self->PrepareRequest(l_Request.Ptr(), p_HttpMethod == u"DOWNLOAD"); + self->PrepareRequest(l_Request.Ptr(), httpMethod == u"DOWNLOAD"); - if (!p_Progress.IsValid()) + if (!progress.IsValid()) co_yield reinterpret_cast(l_Request->SendWebRequest()); else { - try { p_Progress(0.0f); } catch (const std::exception&) { } + try { progress(0.0f); } catch (const std::exception&) { } l_Request->SendWebRequest(); auto l_Waiter = WaitForSecondsRealtime::New_ctor(0.05f); @@ -262,15 +263,15 @@ namespace CP_SDK::Network { static auto s_UnityWebRequest_GetDownloadProgress = il2cpp_utils::resolve_icall("UnityEngine.Networking.UnityWebRequest::GetDownloadProgress"); auto l_Progress = (!s_UnityWebRequest_IsExecuting(l_Request.Ptr()) && !l_Request->get_isDone()) ? -1.0f : s_UnityWebRequest_GetDownloadProgress(l_Request.Ptr()); - p_Progress(l_Progress); + progress(l_Progress); } catch (const std::exception&) { } - if (p_Token.get_IsCancellationRequested() || l_Request->get_isDone() || l_Request->get_result() == UnityWebRequest::Result::ProtocolError || l_Request->get_result() == UnityWebRequest::Result::ConnectionError) + if (token.get_IsCancellationRequested() || l_Request->get_isDone() || l_Request->get_result() == UnityWebRequest::Result::ProtocolError || l_Request->get_result() == UnityWebRequest::Result::ConnectionError) break; } while (true); } - if (p_Token.get_IsCancellationRequested()) + if (token.get_IsCancellationRequested()) break; l_Reply = std::make_shared(l_Request.Ptr()); @@ -283,7 +284,7 @@ namespace CP_SDK::Network { int l_TotalMilliseconds = (int)(l_Limits.Reset - DateTime.Now).TotalMilliseconds; if (l_TotalMilliseconds > 0) { - ChatPlexSDK::Logger()->Error(u"[CP_SDK.Network][WebClientUnity." + p_DebugName + u"] Request {SafeURL(p_URL)} was rate limited, retrying in {l_TotalMilliseconds}ms..."); + ChatPlexSDK::Logger()->Error(u"[CP_SDK.Network][WebClientUnity." + debugName + u"] Request {SafeURL(url)} was rate limited, retrying in {l_TotalMilliseconds}ms..."); co_yield WaitForSecondsRealtime::New_ctor(RetryInterval)->i_IEnumerator(); continue; @@ -293,32 +294,32 @@ namespace CP_SDK::Network { if (!l_Reply->IsSuccessStatusCode()) { - auto l_LogPrefix = u"[CP_SDK.Network][WebClientUnity." + p_DebugName + u"] Request " + p_Self->SafeURL(p_URL) + u" failed with code "; + auto l_LogPrefix = u"[CP_SDK.Network][WebClientUnity." + debugName + u"] Request " + self->SafeURL(url) + u" failed with code "; l_LogPrefix += StringW(std::to_string(l_Reply->StatusCode().value__)); l_LogPrefix += u":\"" + l_Reply->ReasonPhrase() + "\", "; - if (!l_Reply->ShouldRetry() || p_DontRetry) + if (!l_Reply->ShouldRetry() || dontRetry) { ChatPlexSDK::Logger()->Error(l_LogPrefix + u" not retrying"); break; } - ChatPlexSDK::Logger()->Error(l_LogPrefix + u" next try in " + (std::u16string)StringW(std::to_string(p_Self->RetryInterval)) + u" seconds..."); + ChatPlexSDK::Logger()->Error(l_LogPrefix + u" next try in " + (std::u16string)StringW(std::to_string(self->RetryInterval)) + u" seconds..."); - co_yield WaitForSecondsRealtime::New_ctor(p_Self->RetryInterval)->i___System__Collections__IEnumerator(); + co_yield WaitForSecondsRealtime::New_ctor(self->RetryInterval)->i___System__Collections__IEnumerator(); continue; } else { - if (p_Progress.IsValid()) - try { p_Progress(1.0f); } catch (const std::exception&) { } + if (progress.IsValid()) + try { progress(1.0f); } catch (const std::exception&) { } break; } } - if (!p_Token.get_IsCancellationRequested() && p_Callback.IsValid()) - Unity::MTThreadInvoker::EnqueueOnThread([=]() -> void { p_Callback(l_Reply); }); + if (!token.get_IsCancellationRequested() && callback.IsValid()) + Unity::MTThreadInvoker::EnqueueOnThread([=]() -> void { callback(l_Reply); }); } } ///< namespace CP_SDK::Network \ No newline at end of file diff --git a/src/CP_SDK/Network/WebContent.cpp b/src/CP_SDK/Network/WebContent.cpp index c9ef6b2..f3eb29c 100644 --- a/src/CP_SDK/Network/WebContent.cpp +++ b/src/CP_SDK/Network/WebContent.cpp @@ -1,4 +1,5 @@ #include "CP_SDK/Network/WebContent.hpp" +#include "CP_SDK/Utils/Json.hpp" #include #include @@ -31,5 +32,12 @@ namespace CP_SDK::Network { auto l_Array = Encoding::get_UTF8()->GetBytes(p_Content).operator Array *(); return std::make_shared(CP_SDK_PRIV_TAG_VAL(), l_Array, u"application/json; charset=utf-8"); } + /// @brief Constructor from Json + /// @param content Json content + WebContent::Ptr WebContent::FromJson(std::shared_ptr<_v::Json::U16Document>& content) + { + auto l_Array = Encoding::get_UTF8()->GetBytes(content ? _v::Json::ToU16String(*content, false) : u"").operator Array *(); + return std::make_shared(CP_SDK_PRIV_TAG_VAL(), l_Array, u"application/json; charset=utf-8"); + } } ///< namespace CP_SDK::Network \ No newline at end of file diff --git a/src/CP_SDK/Network/WebResponse.cpp b/src/CP_SDK/Network/WebResponse.cpp index 5ce5aa5..f97e320 100644 --- a/src/CP_SDK/Network/WebResponse.cpp +++ b/src/CP_SDK/Network/WebResponse.cpp @@ -1,6 +1,8 @@ #include "CP_SDK/Network/WebResponse.hpp" -#include "CP_SDK/ChatPlexSDK.hpp" +#include +#include +#include #include #include #include @@ -64,13 +66,10 @@ namespace CP_SDK::Network { //////////////////////////////////////////////////////////////////////////// /// Constructor - /// @p_Request: Reply status + /// @param request: Reply status WebResponse::WebResponse(UnityWebRequest * p_Request) { - m_StatusCode = (HttpStatusCode)p_Request->get_responseCode(); - m_IsSuccessStatusCode = !(p_Request->get_result() == UnityWebRequest::Result::ProtocolError && p_Request->get_result() == UnityWebRequest::Result::ConnectionError); - m_ShouldRetry = IsSuccessStatusCode() ? false : (p_Request->get_responseCode() < 400 || p_Request->get_responseCode() >= 500); - m_BodyBytes = reinterpret_cast<::Array*>(p_Request->get_downloadHandler()->GetData().convert()); + m_StatusCode = (HttpStatusCode)p_Request->get_responseCode(); if (p_Request->get_result() == UnityWebRequest::Result::ConnectionError || p_Request->get_result() == UnityWebRequest::Result::ProtocolError) { @@ -78,7 +77,42 @@ namespace CP_SDK::Network { m_ReasonPhrase = u"HTTP/1.1 " + std::to_string(m_StatusCode.value__) + u" " + p_Request->GetHTTPStatusString(m_StatusCode.value__); else m_ReasonPhrase = p_Request->GetWebErrorString(p_Request->GetError()); + + m_IsSuccessStatusCode = false; } + else + m_IsSuccessStatusCode = ((int)p_Request->get_responseCode() >= 200) && ((int)p_Request->get_responseCode() <= 299); + + m_ShouldRetry = IsSuccessStatusCode() ? false : (p_Request->get_responseCode() < 400 || p_Request->get_responseCode() >= 500); + m_BodyBytes = reinterpret_cast<::Array*>(p_Request->get_downloadHandler()->GetData().convert()); + } + /// @brief Constructor + /// @param curlPerformResult CURL perform result + /// @param curlInstance CURL instance + /// @param data Response data + WebResponse::WebResponse(long curlPerformResult, void* curlInstance, std::vector* data) + { + auto l_CURLInstance = reinterpret_cast(curlInstance); + + if (curlPerformResult != CURLE_OK) + { + m_StatusCode = -curlPerformResult; + m_ReasonPhrase = Utils::StrToU16Str(curl_easy_strerror(static_cast(curlPerformResult))); + m_IsSuccessStatusCode = false; + m_ShouldRetry = false; + } + else + { + long l_HTTPCode(0); + curl_easy_getinfo(l_CURLInstance, CURLINFO_RESPONSE_CODE, &l_HTTPCode); + + m_StatusCode = l_HTTPCode; + m_IsSuccessStatusCode = ((int)l_HTTPCode >= 200) && ((int)l_HTTPCode <= 299); + m_ShouldRetry = IsSuccessStatusCode() ? false : (l_HTTPCode < 400 || l_HTTPCode >= 500); + } + + m_BodyBytes = ::Array::NewLength(data->size()); + memcpy(m_BodyBytes->_values, data->data(), data->size()); } } ///< namespace CP_SDK::Network From f638f574665bf18990d9a6567ef3d90f98409b81 Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 6 Aug 2025 00:50:52 +0200 Subject: [PATCH 21/35] Implement JsonRPCClient --- qpm.json | 5 + qpm.shared.json | 91 +++++++----- shared/CP_SDK/Network/JsonRPCClient.hpp | 90 +++++++++++ shared/CP_SDK/Network/JsonRPCResult.hpp | 53 +++++++ src/CP_SDK/Network/JsonRPCClient.cpp | 190 ++++++++++++++++++++++++ src/CP_SDK/Network/JsonRPCResult.cpp | 49 ++++++ 6 files changed, 444 insertions(+), 34 deletions(-) create mode 100644 shared/CP_SDK/Network/JsonRPCClient.hpp create mode 100644 shared/CP_SDK/Network/JsonRPCResult.hpp create mode 100644 src/CP_SDK/Network/JsonRPCClient.cpp create mode 100644 src/CP_SDK/Network/JsonRPCResult.cpp diff --git a/qpm.json b/qpm.json index 88070e9..e7a6de9 100644 --- a/qpm.json +++ b/qpm.json @@ -103,6 +103,11 @@ "id": "kaleb", "versionRange": "^0.1.9", "additionalData": {} + }, + { + "id": "libcurl", + "versionRange": "=8.5.0", + "additionalData": {} } ] } \ No newline at end of file diff --git a/qpm.shared.json b/qpm.shared.json index 321cd6e..ca32904 100644 --- a/qpm.shared.json +++ b/qpm.shared.json @@ -105,6 +105,11 @@ "id": "kaleb", "versionRange": "^0.1.9", "additionalData": {} + }, + { + "id": "libcurl", + "versionRange": "=8.5.0", + "additionalData": {} } ] }, @@ -127,12 +132,12 @@ { "dependency": { "id": "paper2_scotland2", - "versionRange": "=4.6.2", + "versionRange": "=4.6.4", "additionalData": { - "soLink": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.2/libpaper2_scotland2.so", + "soLink": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.4/libpaper2_scotland2.so", "overrideSoName": "libpaper2_scotland2.so", - "modLink": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.2/paper2_scotland2.qmod", - "branchName": "version/v4_6_2", + "modLink": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.4/paper2_scotland2.qmod", + "branchName": "version/v4_6_4", "compileOptions": { "systemIncludes": [ "shared/utfcpp/source" @@ -141,7 +146,7 @@ "cmake": false } }, - "version": "4.6.2" + "version": "4.6.4" }, { "dependency": { @@ -162,13 +167,13 @@ { "dependency": { "id": "custom-types", - "versionRange": "=0.18.2", + "versionRange": "=0.18.3", "additionalData": { - "soLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.18.2/libcustom-types.so", - "debugSoLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.18.2/debug_libcustom-types.so", + "soLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.18.3/libcustom-types.so", + "debugSoLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.18.3/debug_libcustom-types.so", "overrideSoName": "libcustom-types.so", - "modLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.18.2/CustomTypes.qmod", - "branchName": "version/v0_18_2", + "modLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.18.3/CustomTypes.qmod", + "branchName": "version/v0_18_3", "compileOptions": { "cppFlags": [ "-Wno-invalid-offsetof" @@ -177,7 +182,7 @@ "cmake": true } }, - "version": "0.18.2" + "version": "0.18.3" }, { "dependency": { @@ -232,6 +237,19 @@ }, "version": "0.3.0" }, + { + "dependency": { + "id": "libcurl", + "versionRange": "=8.5.0", + "additionalData": { + "staticLinking": true, + "soLink": "https://github.com/darknight1050/openssl-curl-android/releases/download/v8.5.0/libcurl.a", + "overrideSoName": "libcurl.a", + "branchName": "version-v8.5.0" + } + }, + "version": "8.5.0" + }, { "dependency": { "id": "songcore", @@ -250,36 +268,22 @@ { "dependency": { "id": "beatsaber-hook", - "versionRange": "=6.4.1", + "versionRange": "=6.4.2", "additionalData": { - "soLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.1/libbeatsaber-hook.so", - "debugSoLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.1/debug_libbeatsaber-hook.so", + "soLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.2/libbeatsaber-hook.so", + "debugSoLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.2/debug_libbeatsaber-hook.so", "overrideSoName": "libbeatsaber-hook.so", - "modLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.1/beatsaber-hook.qmod", - "branchName": "version/v6_4_1", - "cmake": true - } - }, - "version": "6.4.1" - }, - { - "dependency": { - "id": "fmt", - "versionRange": "=11.0.2", - "additionalData": { - "headersOnly": true, - "branchName": "version/v11_0_2", + "modLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.2/beatsaber-hook.qmod", + "branchName": "version/v6_4_2", "compileOptions": { - "systemIncludes": [ - "fmt/include/" - ], "cppFlags": [ - "-DFMT_HEADER_ONLY" + "-Wno-extra-qualification" ] - } + }, + "cmake": true } }, - "version": "11.0.2" + "version": "6.4.2" }, { "dependency": { @@ -308,6 +312,25 @@ } }, "version": "10.0.0" + }, + { + "dependency": { + "id": "fmt", + "versionRange": "=11.0.2", + "additionalData": { + "headersOnly": true, + "branchName": "version/v11_0_2", + "compileOptions": { + "systemIncludes": [ + "fmt/include/" + ], + "cppFlags": [ + "-DFMT_HEADER_ONLY" + ] + } + } + }, + "version": "11.0.2" } ] } \ No newline at end of file diff --git a/shared/CP_SDK/Network/JsonRPCClient.hpp b/shared/CP_SDK/Network/JsonRPCClient.hpp new file mode 100644 index 0000000..c247a3b --- /dev/null +++ b/shared/CP_SDK/Network/JsonRPCClient.hpp @@ -0,0 +1,90 @@ +#pragma once + +#include "CP_SDK/Utils/Json.hpp" +#include "JsonRPCResult.hpp" +#include "WebClientCore.hpp" +#include + +namespace CP_SDK::Network { + + namespace _v + { + using namespace CP_SDK::Utils; + } + + /// @brief JsonRPCClient + class CP_SDK_EXPORT JsonRPCClient : public std::enable_shared_from_this + { + CP_SDK_NO_COPYMOVE_CTORS(JsonRPCClient); + CP_SDK_PRIV_TAG(); + + private: + WebClientCore::Ptr m_WebClient; + + public: + using Ptr = std::shared_ptr; + + /// @brief Constructor + /// @param webClient Web client instance + JsonRPCClient(CP_SDK_PRIV_TAG_ARG(), WebClientCore::Ptr& webClient); + /// @brief Destructor + ~JsonRPCClient(); + + public: + /// @brief Create + /// @param webClient Raw web response + static Ptr Create(WebClientCore::Ptr& webClient); + + public: + /// @brief Do a RPC request + /// @param method Target method + /// @param parameters Request parameters + /// @param dontRetry Should not retry? + JsonRPCResult::Ptr Request(std::u16string_view method, std::shared_ptr<_v::Json::U16Value> parameters, bool dontRetry = false); + + public: + /// @brief Do a RPC request + /// @param method Target method + /// @param parameters Request parameters + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry? + void RequestAsync( + std::u16string_view method, + std::shared_ptr<_v::Json::U16Value> parameters, + _u::CancellationToken token, + _v::CActionRef callback, + bool dontRetry = false + ); + + private: + /// @brief Do a RPC request + /// @param method Target method + /// @param content Request content + /// @param dontRetry Should not retry? + JsonRPCResult::Ptr DoRequest( + std::u16string method, + std::shared_ptr<_v::Json::U16Document>& content, + bool dontRetry + ); + /// @brief Do a RPC request + /// @param method Target method + /// @param content Request content + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry? + void DoRequestAsync( + std::u16string method, + std::shared_ptr<_v::Json::U16Document>& content, + _u::CancellationToken token, + _v::CActionRef callback, + bool dontRetry + ); + /// @brief Do a RPC request + /// @param method Target method + /// @param rawResponse Web response + JsonRPCResult::Ptr HandleWebResponse(std::u16string method, WebResponse::Ptr& rawResponse); + + }; + +} ///< namespace CP_SDK::Network \ No newline at end of file diff --git a/shared/CP_SDK/Network/JsonRPCResult.hpp b/shared/CP_SDK/Network/JsonRPCResult.hpp new file mode 100644 index 0000000..190b321 --- /dev/null +++ b/shared/CP_SDK/Network/JsonRPCResult.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include "../Utils/Json.hpp" +#include "WebResponse.hpp" + +namespace CP_SDK::Network { + + namespace _v + { + using namespace CP_SDK::Utils; + } + + /// @brief JsonRPCResult + class CP_SDK_EXPORT JsonRPCResult + { + CP_SDK_NO_COPYMOVE_CTORS(JsonRPCResult); + CP_SDK_PRIV_TAG(); + + public: + WebResponse::Ptr RawResponse; + std::shared_ptr<_v::Json::U16Document> Result; + std::shared_ptr<_v::Json::U16Document> Error; + + public: + using Ptr = std::shared_ptr; + + /// @brief Constructor + /// @param rawResponse Raw web response + /// @param result Result json + /// @param error Json content + JsonRPCResult( + CP_SDK_PRIV_TAG_ARG(), + WebResponse::Ptr& rawResponse, + std::shared_ptr<_v::Json::U16Document> result, + std::shared_ptr<_v::Json::U16Document> error + ); + /// @brief Destructor + ~JsonRPCResult(); + + public: + /// @brief Create + /// @param rawResponse Raw web response + /// @param result Result json + /// @param error Json content + static Ptr Create( + WebResponse::Ptr& rawResponse, + std::shared_ptr<_v::Json::U16Document> result, + std::shared_ptr<_v::Json::U16Document> error + ); + + }; + +} ///< namespace CP_SDK::Network \ No newline at end of file diff --git a/src/CP_SDK/Network/JsonRPCClient.cpp b/src/CP_SDK/Network/JsonRPCClient.cpp new file mode 100644 index 0000000..a3b8813 --- /dev/null +++ b/src/CP_SDK/Network/JsonRPCClient.cpp @@ -0,0 +1,190 @@ +#include "CP_SDK/Network/JsonRPCClient.hpp" +#include "CP_SDK/Utils/Json.hpp" +#include "beatsaber-hook/shared/rapidjson/include/rapidjson/rapidjson.h" + +#include +#include + +using namespace System::Text; + +namespace CP_SDK::Network { + + /// @brief Constructor + /// @param webClient Web client instance + JsonRPCClient::JsonRPCClient(CP_SDK_PRIV_TAG_ARG(), WebClientCore::Ptr& webClient) + { + m_WebClient = webClient; + } + /// @brief Destructor + JsonRPCClient::~JsonRPCClient() + { + m_WebClient = nullptr; + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Create + /// @param webClient Web client instance + JsonRPCClient::Ptr JsonRPCClient::Create(WebClientCore::Ptr& webClient) + { + return std::make_shared(CP_SDK_PRIV_TAG_VAL(), webClient); + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Do a RPC request + /// @param method Target method + /// @param parameters Request parameters + /// @param dontRetry Should not retry? + JsonRPCResult::Ptr JsonRPCClient::Request(std::u16string_view method, std::shared_ptr<_v::Json::U16Value> parameters, bool dontRetry) + { + auto l_Method = std::u16string(method); + + std::shared_ptr<_v::Json::U16Document> l_Content(new _v::Json::U16Document()); + l_Content->SetObject(); + l_Content->AddMember(u"id", _v::Json::U16Value(1), l_Content->GetAllocator()); + l_Content->AddMember(u"jsonrpc", _v::Json::U16Value(u"2.0", l_Content->GetAllocator()), l_Content->GetAllocator()); + l_Content->AddMember(u"method", _v::Json::U16Value(l_Method.c_str(), l_Method.length(), l_Content->GetAllocator()), l_Content->GetAllocator()); + + if (parameters) + { + _v::Json::U16Value l_Copy; + l_Copy.CopyFrom(*parameters, l_Content->GetAllocator()); + + l_Content->AddMember(u"params", l_Copy, l_Content->GetAllocator()); + } + else + l_Content->AddMember(u"params", _v::Json::U16Value(rapidjson::kNullType), l_Content->GetAllocator()); + + return DoRequest(l_Method, l_Content, dontRetry); + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Do a RPC request + /// @param method Target method + /// @param parameters Request parameters + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry? + void JsonRPCClient::RequestAsync( + std::u16string_view method, + std::shared_ptr<_v::Json::U16Value> parameters, + _u::CancellationToken token, + _v::CActionRef callback, + bool dontRetry + ) + { + auto l_Method = std::u16string(method); + + std::shared_ptr<_v::Json::U16Document> l_Content(new _v::Json::U16Document()); + l_Content->SetObject(); + l_Content->AddMember(u"id", _v::Json::U16Value(1), l_Content->GetAllocator()); + l_Content->AddMember(u"jsonrpc", _v::Json::U16Value(u"2.0", l_Content->GetAllocator()), l_Content->GetAllocator()); + l_Content->AddMember(u"method", _v::Json::U16Value(l_Method.c_str(), l_Method.length(), l_Content->GetAllocator()), l_Content->GetAllocator()); + + if (parameters) + { + _v::Json::U16Value l_Copy; + l_Copy.CopyFrom(*parameters, l_Content->GetAllocator()); + + l_Content->AddMember(u"params", l_Copy, l_Content->GetAllocator()); + } + else + l_Content->AddMember(u"params", _v::Json::U16Value(rapidjson::kNullType), l_Content->GetAllocator()); + + DoRequestAsync(l_Method, l_Content, token, callback, dontRetry); + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Do a RPC request + /// @param method Target method + /// @param parameters Request content + /// @param dontRetry Should not retry? + JsonRPCResult::Ptr JsonRPCClient::DoRequest( + std::u16string method, + std::shared_ptr<_v::Json::U16Document>& content, + bool dontRetry + ) + { + auto l_Response = m_WebClient->Post( + u"", + WebContent::FromJson(content), + dontRetry + ); + return HandleWebResponse(method, l_Response); + } + /// @brief Do a RPC request + /// @param method Target method + /// @param content Request content + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry? + void JsonRPCClient::DoRequestAsync( + std::u16string method, + std::shared_ptr<_v::Json::U16Document>& content, + _u::CancellationToken token, + _v::CActionRef callback, + bool dontRetry + ) + { + auto l_Self = shared_from_this(); + m_WebClient->PostAsync( + u"", + WebContent::FromJson(content), + token, + [=](CP_SDK::Network::WebResponse::Ptr webResponse) -> void { + callback(l_Self->HandleWebResponse(method, webResponse)); + }, + dontRetry + ); + } + /// @brief Do a RPC request + /// @param method Target method + /// @param rawResponse Web response + JsonRPCResult::Ptr JsonRPCClient::HandleWebResponse(std::u16string method, WebResponse::Ptr& rawResponse) + { + if (!rawResponse) + return JsonRPCResult::Create(rawResponse, nullptr, nullptr); + + try + { + auto l_JsonResult = std::make_shared<_v::Json::U16Document>(); + if (!_v::Json::TryFromU16String(rawResponse->BodyString(), *l_JsonResult.get())) + return nullptr; + + auto l_ResultDocument = std::shared_ptr<_v::Json::U16Document>(nullptr); + if (l_JsonResult->HasMember(u"result")) + { + l_ResultDocument = std::make_shared<_v::Json::U16Document>(); + l_ResultDocument->CopyFrom(l_JsonResult->FindMember(u"result")->value, l_ResultDocument->GetAllocator()); + } + + auto l_ErrorDocument = std::shared_ptr<_v::Json::U16Document>(nullptr); + if (l_JsonResult->HasMember(u"error")) + { + l_ErrorDocument = std::make_shared<_v::Json::U16Document>(); + l_ErrorDocument->CopyFrom(l_JsonResult->FindMember(u"error")->value, l_ErrorDocument->GetAllocator()); + } + + return JsonRPCResult::Create( + rawResponse, + l_ResultDocument, + l_ErrorDocument + ); + } + catch (std::exception& l_Exception) + { + ChatPlexSDK::Logger()->Error(u"[CP_API_SDK.Network][JsonRPCClient.HandleResponse] Request " + method + u" failed parsing response:"); + ChatPlexSDK::Logger()->Error(l_Exception); + } + + return nullptr; + } + +} ///< namespace CP_SDK::Network \ No newline at end of file diff --git a/src/CP_SDK/Network/JsonRPCResult.cpp b/src/CP_SDK/Network/JsonRPCResult.cpp new file mode 100644 index 0000000..16c4656 --- /dev/null +++ b/src/CP_SDK/Network/JsonRPCResult.cpp @@ -0,0 +1,49 @@ +#include "CP_SDK/Network/JsonRPCResult.hpp" + +#include +#include + +using namespace System::Text; + +namespace CP_SDK::Network { + + /// @brief Constructor + /// @param rawResponse Raw web response + /// @param result Result json + /// @param error Json content + JsonRPCResult::JsonRPCResult( + CP_SDK_PRIV_TAG_ARG(), + WebResponse::Ptr& rawResponse, + std::shared_ptr<_v::Json::U16Document> result, + std::shared_ptr<_v::Json::U16Document> error + ) + { + RawResponse = rawResponse; + Result = result; + Error = error; + } + /// @brief Destructor + JsonRPCResult::~JsonRPCResult() + { + RawResponse = nullptr; + Result = nullptr; + Error = nullptr; + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Create + /// @param rawResponse Raw web response + /// @param result Result json + /// @param error Json content + JsonRPCResult::Ptr JsonRPCResult::Create( + WebResponse::Ptr& rawResponse, + std::shared_ptr<_v::Json::U16Document> result, + std::shared_ptr<_v::Json::U16Document> error + ) + { + return std::make_shared(CP_SDK_PRIV_TAG_VAL(), rawResponse, result, error); + } + +} ///< namespace CP_SDK::Network \ No newline at end of file From 1a0d58dd796ae7db7763a68dd3949991f0a33a53 Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 6 Aug 2025 01:07:24 +0200 Subject: [PATCH 22/35] Fix build with the WebClientC/U changes --- shared/CP_SDK/Network/IWebClient.hpp | 14 +++++++------- shared/CP_SDK/Network/WebClientUnity.hpp | 7 +++++++ src/CP_SDK/Utils/Il2cpp.cpp | 2 ++ 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/shared/CP_SDK/Network/IWebClient.hpp b/shared/CP_SDK/Network/IWebClient.hpp index b7a6e98..67f7767 100644 --- a/shared/CP_SDK/Network/IWebClient.hpp +++ b/shared/CP_SDK/Network/IWebClient.hpp @@ -33,15 +33,15 @@ namespace CP_SDK::Network { public: /// @brief Get header - /// @param p_Name Header name - virtual std::u16string GetHeader(std::u16string_view p_Name) = 0; + /// @param name Header name + virtual std::u16string GetHeader(std::u16string_view name) = 0; /// @brief Set header - /// @param p_Name Header name - /// @param p_Value Header value - virtual void SetHeader(std::u16string_view p_Name, std::u16string_view p_Value) = 0; + /// @param name Header name + /// @param value Header value + virtual void SetHeader(std::u16string_view name, std::u16string_view value) = 0; /// @brief Remove header - /// @param p_Name Header name - virtual void RemoveHeader(std::u16string_view p_Name) = 0; + /// @param name Header name + virtual void RemoveHeader(std::u16string_view name) = 0; public: /// @brief Do Async GET query diff --git a/shared/CP_SDK/Network/WebClientUnity.hpp b/shared/CP_SDK/Network/WebClientUnity.hpp index 1029da7..fa1f7ab 100644 --- a/shared/CP_SDK/Network/WebClientUnity.hpp +++ b/shared/CP_SDK/Network/WebClientUnity.hpp @@ -105,6 +105,13 @@ namespace CP_SDK::Network { /// @param callback Callback /// @param dontRetry Should not retry virtual void PatchAsync(std::u16string_view url, const WebContent::Ptr& content, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) override final; + /// @brief Do Async PUT query + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void PutAsync(std::u16string_view url, const WebContent::Ptr& content, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) override final; /// @brief Do Async DELETE query /// @param url Target URL /// @param token Cancellation token diff --git a/src/CP_SDK/Utils/Il2cpp.cpp b/src/CP_SDK/Utils/Il2cpp.cpp index 7af7769..bf5e22a 100644 --- a/src/CP_SDK/Utils/Il2cpp.cpp +++ b/src/CP_SDK/Utils/Il2cpp.cpp @@ -1,6 +1,8 @@ #include "CP_SDK/Utils/Il2cpp.hpp" #include "CP_SDK/ChatPlexSDK.hpp" +#include "CP_SDK/Logging/PaperLogger.hpp" + namespace CP_SDK::Utils { std::vector Hooks::m_InstalledFuncs; From 1d4abc78ce15f4483204f7afb9b360ecfa3b9777 Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 6 Aug 2025 01:15:27 +0200 Subject: [PATCH 23/35] Add ChatPlex web service --- shared/CP_SDK/CPConfig.hpp | 6 +- shared/CP_SDK/ChatPlexService.hpp | 118 ++++++++++ shared/CP_SDK/Utils/Json.hpp | 3 +- src/CP_SDK/CPConfig.cpp | 2 + src/CP_SDK/ChatPlexSDK.cpp | 6 +- src/CP_SDK/ChatPlexService.cpp | 318 ++++++++++++++++++++++++++ src/CP_SDK/Network/WebClientUnity.cpp | 10 + 7 files changed, 459 insertions(+), 4 deletions(-) create mode 100644 shared/CP_SDK/ChatPlexService.hpp create mode 100644 src/CP_SDK/ChatPlexService.cpp diff --git a/shared/CP_SDK/CPConfig.hpp b/shared/CP_SDK/CPConfig.hpp index 1cfd370..e1cf727 100644 --- a/shared/CP_SDK/CPConfig.hpp +++ b/shared/CP_SDK/CPConfig.hpp @@ -1,6 +1,7 @@ #pragma once #include "Config/JsonConfig.hpp" +#include namespace CP_SDK { @@ -10,8 +11,9 @@ namespace CP_SDK { CP_SDK_CONFIG_JSONCONFIG_INSTANCE_DECL(CPConfig); public: - bool FirstRun = true; - bool FirstChatServiceRun = true; + bool FirstRun = true; + bool FirstChatServiceRun = true; + std::u16string ChatPlexServiceToken = u""; protected: /// @brief Reset config to default diff --git a/shared/CP_SDK/ChatPlexService.hpp b/shared/CP_SDK/ChatPlexService.hpp new file mode 100644 index 0000000..913f5fa --- /dev/null +++ b/shared/CP_SDK/ChatPlexService.hpp @@ -0,0 +1,118 @@ +#pragma once + +#include "Network/JsonRPCResult.hpp" +#include "Network/JsonRPCClient.hpp" +#include "Utils/Event.hpp" +#include "Utils/Il2cpp.hpp" +#include "Utils/Delegate.hpp" + +#include +#include +#include + +namespace CP_SDK { + + namespace _u + { + using namespace il2cpp_utils; + using namespace System; + using namespace UnityEngine; + } + + namespace _v + { + using namespace CP_SDK::Network; + using namespace CP_SDK::Utils; + } + + /// @brief ChatPlexService + class CP_SDK_EXPORT ChatPlexService + { + CP_SDK_NO_DEF_CTORS(ChatPlexService); + + public: + enum class EState + { + Disconnected, + LinkRequest, + LinkWait, + Connecting, + + Connected, + + Error + }; + + private: + static bool m_ThreadCondition; + static _u::il2cpp_aware_thread* m_Thread; + static EState m_State; + static _v::WebClientCore::Ptr m_WebClientCore; + static _v::JsonRPCClient::Ptr m_JsonRPCClient; + static std::u16string m_LinkRequestID; + static std::u16string m_LinkCode; + static std::u16string m_LastError; + static std::u16string m_ActiveSubscription; + static std::vector m_UnlockedFeatures; + static std::queue<_v::Action<>> m_OnTokenReadyQueue; + static std::mutex m_OnTokenReadyQueueMutex; + static std::u16string m_DeviceName; + + public: + static const EState State(); + static const std::u16string_view Token(); + static const std::u16string_view LinkCode(); + static const std::u16string_view LastError(); + static const std::u16string_view ActiveSubscription(); + static const std::vector& UnlockedFeatures(); + + static _v::Event StateChanged; + + public: + /// @brief Init the service + static void Init(); + /// @brief Release the service + static void Release(); + + public: + /// @brief Add a callback to be called when the token is ready (call immediatly if ready) + /// @param action Callback to be caled + static void OnTokenReady(_v::CActionRef<> action); + + public: + /// @brief Start linking procedure + static void StartLinking(); + /// @brief Stop linking procedure + static void StopLinking(); + /// @brief Refresh the session + static void Refresh(); + /// @brief Disconnect and erase the saved connected application token + static void Disconnect(); + + private: + /// @brief Change state and notify listenners + static void ChangeState(const EState newState); + /// @brief Fire on token ready actions + static void FireOnTokenReady(); + + private: + /// @brief Thread function + static void ThreadRunner(); + + private: + /// @brief Is RPC call result a success result? + /// @param rpcResult Result of the RPC command + /// @return True if success + static bool IsRPCSuccess(_v::JsonRPCResult::Ptr& rpcResult); + + private: + /// @brief When we are Authed + /// @param rpcResult Result of the RPC command + static void OnAuthed(_v::JsonRPCResult::Ptr& rpcResult); + /// @brief On error received + /// @param rpcResult Result of the RPC command + static void OnError(_v::JsonRPCResult::Ptr& rpcResult); + + }; + +} ///< namespace CP_SDK \ No newline at end of file diff --git a/shared/CP_SDK/Utils/Json.hpp b/shared/CP_SDK/Utils/Json.hpp index 17ba1b1..bbea0d8 100644 --- a/shared/CP_SDK/Utils/Json.hpp +++ b/shared/CP_SDK/Utils/Json.hpp @@ -1,6 +1,8 @@ #pragma once #include "Il2cpp.hpp" +#include +#include "beatsaber-hook/shared/rapidjson/include/rapidjson/document.h" #include #include @@ -8,7 +10,6 @@ #include #include -#include #include #include #include diff --git a/src/CP_SDK/CPConfig.cpp b/src/CP_SDK/CPConfig.cpp index 7b46702..7eb208f 100644 --- a/src/CP_SDK/CPConfig.cpp +++ b/src/CP_SDK/CPConfig.cpp @@ -23,6 +23,7 @@ namespace CP_SDK { { CP_SDK_JSON_SERIALIZE_BOOL(FirstRun); CP_SDK_JSON_SERIALIZE_BOOL(FirstChatServiceRun); + CP_SDK_JSON_SERIALIZE_STRING(ChatPlexServiceToken); } /// @brief Read the document /// @param p_Document Source @@ -30,6 +31,7 @@ namespace CP_SDK { { CP_SDK_JSON_UNSERIALIZE_BOOL(FirstRun); CP_SDK_JSON_UNSERIALIZE_BOOL(FirstChatServiceRun); + CP_SDK_JSON_UNSERIALIZE_STRING(ChatPlexServiceToken); } //////////////////////////////////////////////////////////////////////////// diff --git a/src/CP_SDK/ChatPlexSDK.cpp b/src/CP_SDK/ChatPlexSDK.cpp index 6baed2f..ba55df2 100644 --- a/src/CP_SDK/ChatPlexSDK.cpp +++ b/src/CP_SDK/ChatPlexSDK.cpp @@ -9,6 +9,7 @@ #include "CP_SDK/Unity/MTMainThreadInvoker.hpp" #include "CP_SDK/Unity/MTThreadInvoker.hpp" #include "CP_SDK/ModuleBase.hpp" +#include "CP_SDK/ChatPlexService.hpp" #include @@ -51,7 +52,6 @@ namespace CP_SDK { { InstallWEBPCodecs(); - /// Init config Chat::Service::Init(); } /// @brief On assembly exit @@ -87,6 +87,8 @@ namespace CP_SDK { /// Init UI UI::UISystem::Init(); + + ChatPlexService::Init(); } catch (const std::exception& p_Exception) { @@ -102,6 +104,8 @@ namespace CP_SDK { OnGenericSceneChange.Clear(); OnGenericMenuSceneLoaded.Clear(); + ChatPlexService::Release(); + UI::UISystem::Destroy(); UI::LoadingProgressBar::Destroy(); diff --git a/src/CP_SDK/ChatPlexService.cpp b/src/CP_SDK/ChatPlexService.cpp new file mode 100644 index 0000000..f3191a9 --- /dev/null +++ b/src/CP_SDK/ChatPlexService.cpp @@ -0,0 +1,318 @@ +#include "CP_SDK/Unity/MTThreadInvoker.hpp" +#include "CP_SDK/ChatPlexService.hpp" +#include "CP_SDK/CPConfig.hpp" + +#include +#include +#include +#include +#include + +static std::u16string s_EmptyU16String = u""; + +namespace CP_SDK { + + bool ChatPlexService::m_ThreadCondition = true; + _u::il2cpp_aware_thread* ChatPlexService::m_Thread = nullptr; + ChatPlexService::EState ChatPlexService::m_State = ChatPlexService::EState::Disconnected; + _v::WebClientCore::Ptr ChatPlexService::m_WebClientCore = nullptr; + _v::JsonRPCClient::Ptr ChatPlexService::m_JsonRPCClient = nullptr; + std::u16string ChatPlexService::m_LinkRequestID = u""; + std::u16string ChatPlexService::m_LinkCode = u""; + std::u16string ChatPlexService::m_LastError = u""; + std::u16string ChatPlexService::m_ActiveSubscription = u""; + std::vector ChatPlexService::m_UnlockedFeatures; + std::queue<_v::Action<>> ChatPlexService::m_OnTokenReadyQueue; + std::mutex ChatPlexService::m_OnTokenReadyQueueMutex; + std::u16string ChatPlexService::m_DeviceName = u""; + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + const ChatPlexService::EState ChatPlexService::State() + { + return m_State; + } + const std::u16string_view ChatPlexService::Token() + { + return CPConfig::Instance()->ChatPlexServiceToken; + } + const std::u16string_view ChatPlexService::LinkCode() + { + return m_LinkCode; + } + const std::u16string_view ChatPlexService::LastError() + { + return m_LastError; + } + const std::u16string_view ChatPlexService::ActiveSubscription() + { + return m_State == EState::Connected ? m_ActiveSubscription : s_EmptyU16String; + } + const std::vector& ChatPlexService::UnlockedFeatures() + { + return *reinterpret_cast*>(&m_UnlockedFeatures); + } + + _v::Event ChatPlexService::StateChanged; + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Init the service + void ChatPlexService::Init() + { + m_WebClientCore = _v::WebClientCore::Make(u"https://api.chatplex.org/", _u::TimeSpan::FromSeconds(10), false, true); + m_JsonRPCClient = _v::JsonRPCClient::Create(m_WebClientCore); + + m_Thread = new _u::il2cpp_aware_thread(&ThreadRunner); + + m_DeviceName = _u::SystemInfo::GetDeviceName(); + } + /// @brief Release the service + void ChatPlexService::Release() + { + m_ThreadCondition = false; + m_Thread->join(); + + delete m_Thread; + m_Thread = nullptr; + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Add a callback to be called when the token is ready (call immediatly if ready) + /// @param action Callback to be caled + void ChatPlexService::OnTokenReady(_v::CActionRef<> action) + { + if (m_State == EState::Connected) + action(); + else + { + std::lock_guard l_Lock(m_OnTokenReadyQueueMutex); + m_OnTokenReadyQueue.push(action); + } + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Start linking procedure + void ChatPlexService::StartLinking() + { + if (m_State != EState::Disconnected) + return; + + ChangeState(EState::LinkRequest); + } + /// @brief Stop linking procedure + void ChatPlexService::StopLinking() + { + if (m_State != EState::LinkRequest && m_State != EState::LinkWait) + return; + + ChangeState(EState::Disconnected); + } + /// @brief Refresh the session + void ChatPlexService::Refresh() + { + ChangeState(EState::Disconnected); + } + /// @brief Disconnect and erase the saved connected application token + void ChatPlexService::Disconnect() + { + CPConfig::Instance()->ChatPlexServiceToken = u""; + CPConfig::Instance()->Save(); + + ChangeState(EState::Disconnected); + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Change state and notify listenners + void ChatPlexService::ChangeState(const EState newState) + { + auto l_OldState = m_State; + m_State = newState; + + Unity::MTThreadInvoker::EnqueueOnThread([=]() -> void { StateChanged(l_OldState, newState); }); + } + /// @brief Fire on token ready actions + void ChatPlexService::FireOnTokenReady() + { + m_OnTokenReadyQueueMutex.lock(); + while (!m_OnTokenReadyQueue.empty()) + { + auto l_Action = m_OnTokenReadyQueue.front(); + m_OnTokenReadyQueue.pop(); + m_OnTokenReadyQueueMutex.unlock(); + try + { + l_Action(); + } + catch (std::exception l_Exception) + { + ChatPlexSDK::Logger()->Error(u"[CP_SDK][ChatPlexService.FireOnTokenReady] Error:"); + ChatPlexSDK::Logger()->Error(l_Exception); + } + m_OnTokenReadyQueueMutex.lock(); + } + + m_OnTokenReadyQueueMutex.unlock(); + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Thread function + void ChatPlexService::ThreadRunner() + { + while (m_ThreadCondition) + { + if (m_State == EState::Disconnected && !CPConfig::Instance()->ChatPlexServiceToken.empty()) + { + m_WebClientCore->RemoveHeader(u"Authorization"); + + ChangeState(EState::Connecting); + + std::shared_ptr<_v::Json::U16Document> l_Content(new _v::Json::U16Document()); + l_Content->SetObject(); + l_Content->AddMember(u"ConnectedApplicationToken", _v::Json::U16Value(CPConfig::Instance()->ChatPlexServiceToken, l_Content->GetAllocator()), l_Content->GetAllocator()); + + auto l_Result = m_JsonRPCClient->Request( + u"Account_AuthByConnectedApplicationToken", + l_Content + ); + + if (IsRPCSuccess(l_Result)) + OnAuthed(l_Result); + else + { + if (l_Result->Result != nullptr && l_Result->Result->HasMember(u"Result") && (*l_Result->Result)[u"Result"].GetBool() == false) + { + CPConfig::Instance()->ChatPlexServiceToken = u""; + CPConfig::Instance()->Save(); + + ChangeState(EState::Disconnected); + } + else + OnError(l_Result); + } + } + else if (m_State == EState::LinkRequest) + { + std::shared_ptr<_v::Json::U16Document> l_Content(new _v::Json::U16Document()); + l_Content->SetObject(); + l_Content->AddMember(u"ApplicationIdentifier", _v::Json::U16Value(ChatPlexSDK::ProductName().data(), l_Content->GetAllocator()), l_Content->GetAllocator()); + l_Content->AddMember(u"ApplicationDeviceName", _v::Json::U16Value(m_DeviceName, l_Content->GetAllocator()), l_Content->GetAllocator()); + + auto l_Result = m_JsonRPCClient->Request( + u"ConnectedApplication_CreateLinkRequest", + l_Content + ); + + if (IsRPCSuccess(l_Result)) + { + auto& l_ResultR = *l_Result->Result.get(); + m_LinkRequestID = l_ResultR[u"RequestID"].GetString(); + m_LinkCode = l_ResultR[u"Code"].GetString(); + + ChangeState(EState::LinkWait); + } + else + OnError(l_Result); + } + else if (m_State == EState::LinkWait) + { + std::shared_ptr<_v::Json::U16Document> l_Content(new _v::Json::U16Document()); + l_Content->SetObject(); + l_Content->AddMember(u"RequestID", _v::Json::U16Value(m_LinkRequestID, l_Content->GetAllocator()), l_Content->GetAllocator()); + + auto l_Result = m_JsonRPCClient->Request( + u"ConnectedApplication_GetLinkRequestStatus", + l_Content + ); + + if (IsRPCSuccess(l_Result)) + { + auto& l_ResultR = *l_Result->Result.get(); + if (l_ResultR[u"ResultToken"].IsString()) + { + CPConfig::Instance()->ChatPlexServiceToken = l_ResultR[u"ResultToken"].GetString(); + CPConfig::Instance()->Save(); + + ChangeState(EState::Disconnected); + } + } + else + OnError(l_Result); + } + + if (m_State == EState::LinkWait) + std::this_thread::sleep_for(std::chrono::milliseconds(1500)); + else + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Is RPC call result a success result? + /// @param rpcResult Result of the RPC command + /// @return True if success + bool ChatPlexService::IsRPCSuccess(_v::JsonRPCResult::Ptr& rpcResult) + { + if (rpcResult->Result == nullptr) + return false; + + auto& l_ResultR = *rpcResult->Result.get(); + return l_ResultR.HasMember(u"Result") && l_ResultR[u"Result"].GetBool() == true; + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief When we are Authed + /// @param rpcResult Result of the RPC command + void ChatPlexService::OnAuthed(_v::JsonRPCResult::Ptr& rpcResult) + { + auto& l_ResultR = *rpcResult->Result.get(); + m_ActiveSubscription = l_ResultR.HasMember(u"ActiveSubscription") ? l_ResultR[u"ActiveSubscription"].GetString() : u""; + + m_UnlockedFeatures.clear(); + if (l_ResultR.HasMember(u"UnlockedFeatures") && l_ResultR[u"UnlockedFeatures"].IsArray()) + { + auto l_Array = l_ResultR[u"UnlockedFeatures"].GetArray(); + for (auto& l_CurrentValue : l_Array) + { + if (!l_CurrentValue.IsString()) + continue; + + m_UnlockedFeatures.push_back(l_CurrentValue.GetString()); + } + } + + m_WebClientCore->SetHeader(u"Authorization", std::u16string(u"ConnectedApplicationToken ") + CPConfig::Instance()->ChatPlexServiceToken); + + ChangeState(EState::Connected); + FireOnTokenReady(); + } + /// @brief On error received + /// @param rpcResult Result of the RPC command + void ChatPlexService::OnError(_v::JsonRPCResult::Ptr& rpcResult) + { + std::u16string l_Error = u"Unknow server error!"; + if (rpcResult->Result != nullptr && rpcResult->Result->HasMember(u"Error")) + { + auto& l_ResultR = *rpcResult->Result.get(); + l_Error = l_ResultR[u"Error"].GetString(); + } + + m_LastError = l_Error; + ChangeState(EState::Error); + } + +} ///< namespace CP_SDK \ No newline at end of file diff --git a/src/CP_SDK/Network/WebClientUnity.cpp b/src/CP_SDK/Network/WebClientUnity.cpp index 3e6e4b9..0498722 100644 --- a/src/CP_SDK/Network/WebClientUnity.cpp +++ b/src/CP_SDK/Network/WebClientUnity.cpp @@ -142,6 +142,16 @@ namespace CP_SDK::Network { { Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"PatchAsync", u"PATCH", GetURL(url), content, token, callback, dontRetry, nullptr))); } + /// @brief Do Async PUT query + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + void WebClientUnity::PutAsync(std::u16string_view url, const WebContent::Ptr& content, CancellationToken token, _v::CActionRef callback, bool dontRetry) + { + Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"PutAsync", u"PUT", GetURL(url), content, token, callback, dontRetry, nullptr))); + } /// @brief Do Async GET query /// @param url Target URL /// @param token Cancellation token From 19735f0db8d719ba28b005cafa96315e61885d3f Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 6 Aug 2025 01:16:09 +0200 Subject: [PATCH 24/35] Add ChatPlex connection screen --- shared/CP_SDK/UI/Views/SettingsLeftView.hpp | 28 ++- src/CP_SDK/UI/Views/SettingsLeftView.cpp | 184 +++++++++++++++++++- 2 files changed, 205 insertions(+), 7 deletions(-) diff --git a/shared/CP_SDK/UI/Views/SettingsLeftView.hpp b/shared/CP_SDK/UI/Views/SettingsLeftView.hpp index 6eb9c7d..0a16836 100644 --- a/shared/CP_SDK/UI/Views/SettingsLeftView.hpp +++ b/shared/CP_SDK/UI/Views/SettingsLeftView.hpp @@ -1,7 +1,8 @@ #pragma once -#include "../ViewController.hpp" +#include "../../ChatPlexService.hpp" #include "../../XUI/XUI.hpp" +#include "../ViewController.hpp" namespace CP_SDK::UI::Views { @@ -23,9 +24,34 @@ namespace CP_SDK::UI::Views { CP_SDK_IL2CPP_DECLARE_DTOR_MONOBEHAVIOUR_CHILD(SettingsLeftView); CP_SDK_UI_VIEW_CONTROLLER_INSTANCE(); + private: + _v::XUIText::Ptr m_StatusText; + _v::XUIText::Ptr m_SubscriptionText; + _v::XUIPrimaryButton::Ptr m_PrimaryButton; + _v::XUISecondaryButton::Ptr m_SecondaryButton; + + private: + bool m_IsLinking = false; + private: /// @brief On view creation void OnViewCreation_Impl(); + /// @brief On view deactivation + void OnViewDeactivation_Impl(); + + private: + /// @brief On primary button pressed + void OnPrimaryButtonPressed(); + /// @brief On secondary button pressed + void OnSecondaryButtonPressed(); + /// @brief On Loading cancel + void OnLoadingCancel(); + + private: + /// @brief On ChatPlex service state change + /// @param oldState Old state + /// @param newState New state + void ChatPlexService_StateChanged(ChatPlexService::EState oldState, ChatPlexService::EState newState); }; diff --git a/src/CP_SDK/UI/Views/SettingsLeftView.cpp b/src/CP_SDK/UI/Views/SettingsLeftView.cpp index 3169108..f83b50f 100644 --- a/src/CP_SDK/UI/Views/SettingsLeftView.cpp +++ b/src/CP_SDK/UI/Views/SettingsLeftView.cpp @@ -1,9 +1,14 @@ #include "CP_SDK/UI/Views/SettingsLeftView.hpp" #include "CP_SDK/Unity/SpriteU.hpp" +#include "CP_SDK/Unity/MTMainThreadInvoker.hpp" +#include +#include using namespace CP_SDK::XUI; using namespace UnityEngine; +#include "assets.hpp" + namespace CP_SDK::UI::Views { CP_SDK_IL2CPP_INHERIT_INIT(SettingsLeftView); @@ -14,7 +19,8 @@ namespace CP_SDK::UI::Views { /// @brief Constructor CP_SDK_IL2CPP_DECLARE_CTOR_IMPL(SettingsLeftView) { - OnViewCreation = {this, &SettingsLeftView::OnViewCreation_Impl}; + OnViewCreation = {this, &SettingsLeftView::OnViewCreation_Impl}; + OnViewDeactivation = {this, &SettingsLeftView::OnViewDeactivation_Impl}; } /// @brief Destructor CP_SDK_IL2CPP_DECLARE_DTOR_MONOBEHAVIOUR_IMPL(SettingsLeftView) @@ -28,13 +34,179 @@ namespace CP_SDK::UI::Views { /// @brief On view creation void SettingsLeftView::OnViewCreation_Impl() { + auto l_Sprite = Unity::SpriteU::CreateFromRaw(Assets::ChatPlexLogoTransparent_png); + Templates::FullRectLayout({ - Templates::TitleBar(u"Tools"), + Templates::TitleBar(u"ChatPlex Account"), + + XUIPrimaryButton::Make(u"") + ->SetBackgroundSprite(nullptr) + ->SetIconSprite(l_Sprite) + ->SetWidth(52) + ->SetHeight(52) + ->AsShared(), + + XUIText::Make(u"Not connected") + ->Bind(&m_StatusText) + ->AsShared(), + + XUIText::Make(u" ") + ->Bind(&m_SubscriptionText) + ->AsShared(), + + XUIVLayout::Make({ + XUIPrimaryButton::Make(u"Connect", {this, &SettingsLeftView::OnPrimaryButtonPressed}) + ->Bind(&m_PrimaryButton) + ->AsShared(), + XUISecondaryButton::Make(u"Disconnect", {this, &SettingsLeftView::OnSecondaryButtonPressed}) + ->Bind(&m_SecondaryButton) + ->AsShared() + }) + ->SetWidth(60.0f) + ->SetPadding(0) + ->ForEachDirect([](XUIPrimaryButton* y) -> void + { + y->SetHeight(8.0f); + y->OnReady([](Components::CPrimaryButton* x) -> void + { + x->CSizeFitter()->horizontalFit = ContentSizeFitter::FitMode::Unconstrained; + }); + }) + ->ForEachDirect([](XUISecondaryButton* y ) -> void + { + y->SetHeight(8.0f); + y->OnReady([](Components::CSecondaryButton* x) -> void + { + x->CSizeFitter()->horizontalFit = ContentSizeFitter::FitMode::Unconstrained; + }); + }) + ->AsShared() + }) + ->SetBackground(true, std::nullopt, true) + ->BuildUI(get_transform()); + + ChatPlexService::StateChanged += {this, &SettingsLeftView::ChatPlexService_StateChanged}; + + ChatPlexService_StateChanged(ChatPlexService::State(), ChatPlexService::State()); + } + /// @brief On view deactivation + void SettingsLeftView::OnViewDeactivation_Impl() + { + ChatPlexService::StateChanged -= {this, &SettingsLeftView::ChatPlexService_StateChanged}; + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief On primary button pressed + void SettingsLeftView::OnPrimaryButtonPressed() + { + if (ChatPlexService::State() == ChatPlexService::EState::Disconnected) + { + m_IsLinking = true; + ChatPlexService::StartLinking(); + ShowLoadingModal(u"Loading...", true, {this, &SettingsLeftView::OnLoadingCancel}); + } + else if (ChatPlexService::State() == ChatPlexService::EState::Error || ChatPlexService::State() == ChatPlexService::EState::Connected) + { + ChatPlexService::Refresh(); + } + } + /// @brief On secondary button pressed + void SettingsLeftView::OnSecondaryButtonPressed() + { + ChatPlexService::Disconnect(); + } + /// @brief On Loading cancel + void SettingsLeftView::OnLoadingCancel() + { + if (ChatPlexService::State() == ChatPlexService::EState::LinkRequest || ChatPlexService::State() == ChatPlexService::EState::LinkWait) + { + m_IsLinking = false; + ChatPlexService::StopLinking(); + } + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief On ChatPlex service state change + /// @param oldState Old state + /// @param newState New state + void SettingsLeftView::ChatPlexService_StateChanged(ChatPlexService::EState oldState, ChatPlexService::EState newState) + { + Unity::MTMainThreadInvoker::Enqueue([this, oldState, newState]() -> void + { + if (m_IsLinking) + { + if (newState == ChatPlexService::EState::LinkRequest) + ShowLoadingModal(u"Creating link request...", true, {this, &SettingsLeftView::OnLoadingCancel}); + else if (newState == ChatPlexService::EState::LinkWait) + ShowLoadingModal( + std::u16string(u"Go to https://chatplex.org/link and the input following code\n") + ChatPlexService::LinkCode(), + true, + {this, &SettingsLeftView::OnLoadingCancel} + ); + else if (newState == ChatPlexService::EState::Error) + { + m_IsLinking = false; + + CloseLoadingModal(); + ShowMessageModal(u"Error: " + ChatPlexService::LastError()); + } + else + { + m_IsLinking = false; + CloseLoadingModal(); + } + } + + switch (newState) + { + case ChatPlexService::EState::Disconnected: + m_StatusText->SetColor(Color::get_red()); + m_StatusText->SetText(u"Disconected!"); + m_PrimaryButton->SetInteractable(true); + m_PrimaryButton->SetText(u"Connect"); + m_SecondaryButton->SetInteractable(false); + break; + + case ChatPlexService::EState::Error: + m_StatusText->SetColor(Color::get_red()); + m_StatusText->SetText(u"Disconected, error!"); + m_PrimaryButton->SetInteractable(true); + m_PrimaryButton->SetText(u"Connect"); + m_SecondaryButton->SetInteractable(false); + break; + + case ChatPlexService::EState::Connecting: + m_StatusText->SetColor(Color::get_blue()); + m_StatusText->SetText(u"Connecting..."); + m_PrimaryButton->SetInteractable(false); + m_PrimaryButton->SetText(u"Connect"); + m_SecondaryButton->SetInteractable(false); + break; + + case ChatPlexService::EState::LinkRequest: + case ChatPlexService::EState::LinkWait: + m_StatusText->SetColor(Color::get_blue()); + m_StatusText->SetText(u"Linking account..."); + m_PrimaryButton->SetInteractable(false); + m_PrimaryButton->SetText(u"Connect"); + m_SecondaryButton->SetInteractable(false); + break; + + case ChatPlexService::EState::Connected: + m_StatusText->SetColor(Color::get_green()); + m_StatusText->SetText(u"Connected!"); + m_PrimaryButton->SetInteractable(true); + m_PrimaryButton->SetText(u"Refresh"); + m_SecondaryButton->SetInteractable(true); + break; + } - XUIText::Make(u"No available tools at the moment!")->AsShared() - }) - ->SetBackground(true, std::nullopt, true) - ->BuildUI(get_transform()); + m_SubscriptionText->Element()->SetText(ChatPlexService::ActiveSubscription()); + }); } } ///< namespace CP_SDK::UI::Views \ No newline at end of file From eca090fd756fc01240c024dd797604de632a9ff1 Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 6 Aug 2025 20:36:26 +0200 Subject: [PATCH 25/35] Add missing include --- shared/CP_SDK/ChatPlexService.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/shared/CP_SDK/ChatPlexService.hpp b/shared/CP_SDK/ChatPlexService.hpp index 913f5fa..cb6d11d 100644 --- a/shared/CP_SDK/ChatPlexService.hpp +++ b/shared/CP_SDK/ChatPlexService.hpp @@ -7,6 +7,7 @@ #include "Utils/Delegate.hpp" #include +#include #include #include From 11661632d6cdfeee8448384c5a095f3886df9fbb Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 6 Aug 2025 22:34:07 +0200 Subject: [PATCH 26/35] Version 6.4.1 for BS 1.40.8 --- include/git_info.h | 2 +- mod.json | 24 ++++---- mod.template.json | 2 +- qpm.json | 19 +++--- qpm.shared.json | 87 +++++++++++++-------------- src/CP_SDK/Network/WebClientCore.cpp | 38 +++++++++--- src/CP_SDK_BS/Game/LevelSelection.cpp | 12 ++-- 7 files changed, 99 insertions(+), 85 deletions(-) diff --git a/include/git_info.h b/include/git_info.h index 5c0b8ca..3d19d83 100644 --- a/include/git_info.h +++ b/include/git_info.h @@ -1,5 +1,5 @@ #pragma once #define GIT_USER "HardCPP" #define GIT_BRANCH "dev" -#define GIT_COMMIT 0xc20158d +#define GIT_COMMIT 0xeca090f #define GIT_MODIFIED 1 diff --git a/mod.json b/mod.json index 3ddfe2e..5b4d3dd 100644 --- a/mod.json +++ b/mod.json @@ -5,36 +5,36 @@ "id": "chatplex-sdk-bs", "modloader": "Scotland2", "author": "HardCPP", - "version": "6.4.0", + "version": "6.4.1", "packageId": "com.beatgames.beatsaber", - "packageVersion": "1.40.4_5283", + "packageVersion": "1.40.8_7379", "description": "ChatPlex BeatSaber modding SDK (Dependence for other mods)", "coverImage": "cover.png", "dependencies": [ { - "version": "^6.4.1", + "version": "^6.4.2", "id": "beatsaber-hook", - "downloadIfMissing": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.1/beatsaber-hook.qmod" + "downloadIfMissing": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.2/beatsaber-hook.qmod" }, { - "version": "^0.18.2", + "version": "^0.18.3", "id": "custom-types", - "downloadIfMissing": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.18.2/CustomTypes.qmod" + "downloadIfMissing": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.18.3/CustomTypes.qmod" }, { - "version": "^0.4.51", + "version": "^0.4.55", "id": "bsml", - "downloadIfMissing": "https://github.com/bsq-ports/Quest-BSML/releases/download/v0.4.51/BSML.qmod" + "downloadIfMissing": "https://github.com/bsq-ports/Quest-BSML/releases/download/v0.4.55/BSML.qmod" }, { - "version": "^1.1.20", + "version": "^1.1.24", "id": "songcore", - "downloadIfMissing": "https://github.com/raineaeternal/Quest-SongCore/releases/download/v1.1.20/SongCore.qmod" + "downloadIfMissing": "https://github.com/raineaeternal/Quest-SongCore/releases/download/v1.1.24/SongCore.qmod" }, { - "version": "^4.6.1", + "version": "^4.6.4", "id": "paper2_scotland2", - "downloadIfMissing": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.2/paper2_scotland2.qmod" + "downloadIfMissing": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.4/paper2_scotland2.qmod" } ], "modFiles": [], diff --git a/mod.template.json b/mod.template.json index 63417e4..a4e3f1a 100644 --- a/mod.template.json +++ b/mod.template.json @@ -6,7 +6,7 @@ "author": "HardCPP", "version": "${version}", "packageId": "com.beatgames.beatsaber", - "packageVersion": "1.40.4_5283", + "packageVersion": "1.40.8_7379", "description": "ChatPlex BeatSaber modding SDK (Dependence for other mods)", "coverImage": "cover.png", "dependencies": [], diff --git a/qpm.json b/qpm.json index e7a6de9..4b98143 100644 --- a/qpm.json +++ b/qpm.json @@ -5,7 +5,7 @@ "info": { "name": "ChatPlexSDK-BS", "id": "chatplex-sdk-bs", - "version": "6.4.0", + "version": "6.4.1", "url": "https://github.com/hardcpp/QuestChatPlexSDK-BS", "additionalData": { "overrideSoName": "libchatplex-sdk-bs.so", @@ -47,17 +47,17 @@ "dependencies": [ { "id": "beatsaber-hook", - "versionRange": "^6.4.1", + "versionRange": "^6.4.2", "additionalData": {} }, { "id": "bs-cordl", - "versionRange": "^4004.0.0", + "versionRange": "^4008.*", "additionalData": {} }, { "id": "custom-types", - "versionRange": "^0.18.2", + "versionRange": "^0.18.3", "additionalData": {} }, { @@ -70,19 +70,14 @@ }, { "id": "bsml", - "versionRange": "^0.4.51", + "versionRange": "^0.4.55", "additionalData": { "private": true } }, - { - "id": "libil2cpp", - "versionRange": "^0.4.0", - "additionalData": {} - }, { "id": "songcore", - "versionRange": "^1.1.20", + "versionRange": "^1.1.24", "additionalData": { "private": true } @@ -96,7 +91,7 @@ }, { "id": "paper2_scotland2", - "versionRange": "^4.6.1", + "versionRange": "^4.6.4", "additionalData": {} }, { diff --git a/qpm.shared.json b/qpm.shared.json index ca32904..81aebe6 100644 --- a/qpm.shared.json +++ b/qpm.shared.json @@ -7,7 +7,7 @@ "info": { "name": "ChatPlexSDK-BS", "id": "chatplex-sdk-bs", - "version": "6.4.0", + "version": "6.4.1", "url": "https://github.com/hardcpp/QuestChatPlexSDK-BS", "additionalData": { "overrideSoName": "libchatplex-sdk-bs.so", @@ -49,17 +49,17 @@ "dependencies": [ { "id": "beatsaber-hook", - "versionRange": "^6.4.1", + "versionRange": "^6.4.2", "additionalData": {} }, { "id": "bs-cordl", - "versionRange": "^4004.0.0", + "versionRange": "4008.*", "additionalData": {} }, { "id": "custom-types", - "versionRange": "^0.18.2", + "versionRange": "^0.18.3", "additionalData": {} }, { @@ -72,19 +72,14 @@ }, { "id": "bsml", - "versionRange": "^0.4.51", + "versionRange": "^0.4.55", "additionalData": { "private": true } }, - { - "id": "libil2cpp", - "versionRange": "^0.4.0", - "additionalData": {} - }, { "id": "songcore", - "versionRange": "^1.1.20", + "versionRange": "^1.1.24", "additionalData": { "private": true } @@ -98,7 +93,7 @@ }, { "id": "paper2_scotland2", - "versionRange": "^4.6.1", + "versionRange": "^4.6.4", "additionalData": {} }, { @@ -117,17 +112,17 @@ { "dependency": { "id": "bsml", - "versionRange": "=0.4.51", + "versionRange": "=0.4.55", "additionalData": { - "soLink": "https://github.com/bsq-ports/Quest-BSML/releases/download/v0.4.51/libbsml.so", - "debugSoLink": "https://github.com/bsq-ports/Quest-BSML/releases/download/v0.4.51/debug_libbsml.so", + "soLink": "https://github.com/bsq-ports/Quest-BSML/releases/download/v0.4.55/libbsml.so", + "debugSoLink": "https://github.com/bsq-ports/Quest-BSML/releases/download/v0.4.55/debug_libbsml.so", "overrideSoName": "libbsml.so", - "modLink": "https://github.com/bsq-ports/Quest-BSML/releases/download/v0.4.51/BSML.qmod", - "branchName": "version/v0_4_51", + "modLink": "https://github.com/bsq-ports/Quest-BSML/releases/download/v0.4.55/BSML.qmod", + "branchName": "version/v0_4_55", "cmake": true } }, - "version": "0.4.51" + "version": "0.4.55" }, { "dependency": { @@ -204,10 +199,10 @@ { "dependency": { "id": "bs-cordl", - "versionRange": "=4004.0.0", + "versionRange": "=4008.0.0", "additionalData": { "headersOnly": true, - "branchName": "version/v4004_0_0", + "branchName": "version/v4008_0_0", "compileOptions": { "includePaths": [ "include" @@ -223,7 +218,7 @@ } } }, - "version": "4004.0.0" + "version": "4008.0.0" }, { "dependency": { @@ -253,17 +248,17 @@ { "dependency": { "id": "songcore", - "versionRange": "=1.1.20", + "versionRange": "=1.1.24", "additionalData": { - "soLink": "https://github.com/raineaeternal/Quest-SongCore/releases/download/v1.1.20/libsongcore.so", - "debugSoLink": "https://github.com/raineaeternal/Quest-SongCore/releases/download/v1.1.20/debug_libsongcore.so", + "soLink": "https://github.com/raineaeternal/Quest-SongCore/releases/download/v1.1.24/libsongcore.so", + "debugSoLink": "https://github.com/raineaeternal/Quest-SongCore/releases/download/v1.1.24/debug_libsongcore.so", "overrideSoName": "libsongcore.so", - "modLink": "https://github.com/raineaeternal/Quest-SongCore/releases/download/v1.1.20/SongCore.qmod", - "branchName": "version/v1_1_20", + "modLink": "https://github.com/raineaeternal/Quest-SongCore/releases/download/v1.1.24/SongCore.qmod", + "branchName": "version/v1_1_24", "cmake": true } }, - "version": "1.1.20" + "version": "1.1.24" }, { "dependency": { @@ -285,6 +280,25 @@ }, "version": "6.4.2" }, + { + "dependency": { + "id": "fmt", + "versionRange": "=11.0.2", + "additionalData": { + "headersOnly": true, + "branchName": "version/v11_0_2", + "compileOptions": { + "systemIncludes": [ + "fmt/include/" + ], + "cppFlags": [ + "-DFMT_HEADER_ONLY" + ] + } + } + }, + "version": "11.0.2" + }, { "dependency": { "id": "scotland2", @@ -312,25 +326,6 @@ } }, "version": "10.0.0" - }, - { - "dependency": { - "id": "fmt", - "versionRange": "=11.0.2", - "additionalData": { - "headersOnly": true, - "branchName": "version/v11_0_2", - "compileOptions": { - "systemIncludes": [ - "fmt/include/" - ], - "cppFlags": [ - "-DFMT_HEADER_ONLY" - ] - } - } - }, - "version": "11.0.2" } ] } \ No newline at end of file diff --git a/src/CP_SDK/Network/WebClientCore.cpp b/src/CP_SDK/Network/WebClientCore.cpp index 83e8b27..d5eb88b 100644 --- a/src/CP_SDK/Network/WebClientCore.cpp +++ b/src/CP_SDK/Network/WebClientCore.cpp @@ -130,6 +130,7 @@ namespace CP_SDK::Network { /// @param progress Progress reporter WebResponse::Ptr WebClientCore::Get(std::u16string_view url, bool dontRetry, _v::CActionRef progress) { + auto l_IsDone = false; auto l_Reply = WebResponse::Ptr(nullptr); DoRequest( @@ -139,11 +140,14 @@ namespace CP_SDK::Network { GetURL(url), nullptr, CancellationToken::get_None(), - [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; l_IsDone = true; }, dontRetry, progress ); + while (!l_IsDone) + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + return l_Reply; } /// @brief Do GET query @@ -152,6 +156,7 @@ namespace CP_SDK::Network { /// @param progress Progress reporter WebResponse::Ptr WebClientCore::Download(std::u16string_view url, bool dontRetry, _v::CActionRef progress) { + auto l_IsDone = false; auto l_Reply = WebResponse::Ptr(nullptr); DoRequest( @@ -161,11 +166,14 @@ namespace CP_SDK::Network { GetURL(url), nullptr, CancellationToken::get_None(), - [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; l_IsDone = true; }, dontRetry, progress ); + while (!l_IsDone) + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + return l_Reply; } /// @brief Do POST query @@ -174,6 +182,7 @@ namespace CP_SDK::Network { /// @param dontRetry Should not retry WebResponse::Ptr WebClientCore::Post(std::u16string_view url, const WebContent::Ptr& content, bool dontRetry) { + auto l_IsDone = false; auto l_Reply = WebResponse::Ptr(nullptr); DoRequest( @@ -183,11 +192,14 @@ namespace CP_SDK::Network { GetURL(url), content, CancellationToken::get_None(), - [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; l_IsDone = true; }, dontRetry, nullptr ); + while (!l_IsDone) + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + return l_Reply; } /// @brief Do PATCH query @@ -196,6 +208,7 @@ namespace CP_SDK::Network { /// @param dontRetry Should not retry WebResponse::Ptr WebClientCore::Patch(std::u16string_view url, const WebContent::Ptr& content, bool dontRetry) { + auto l_IsDone = false; auto l_Reply = WebResponse::Ptr(nullptr); DoRequest( @@ -205,11 +218,14 @@ namespace CP_SDK::Network { GetURL(url), content, CancellationToken::get_None(), - [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; l_IsDone = true; }, dontRetry, nullptr ); + while (!l_IsDone) + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + return l_Reply; } /// @brief Do PUT query @@ -218,6 +234,7 @@ namespace CP_SDK::Network { /// @param dontRetry Should not retry WebResponse::Ptr WebClientCore::Put(std::u16string_view url, const WebContent::Ptr& content, bool dontRetry) { + auto l_IsDone = false; auto l_Reply = WebResponse::Ptr(nullptr); DoRequest( @@ -227,11 +244,14 @@ namespace CP_SDK::Network { GetURL(url), content, CancellationToken::get_None(), - [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; l_IsDone = true; }, dontRetry, nullptr ); + while (!l_IsDone) + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + return l_Reply; } /// @brief Do DELETE query @@ -239,6 +259,7 @@ namespace CP_SDK::Network { /// @param dontRetry Should not retry WebResponse::Ptr WebClientCore::Delete(std::u16string_view url, bool dontRetry) { + auto l_IsDone = false; auto l_Reply = WebResponse::Ptr(nullptr); DoRequest( @@ -248,11 +269,14 @@ namespace CP_SDK::Network { GetURL(url), nullptr, CancellationToken::get_None(), - [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; l_IsDone = true; }, dontRetry, nullptr ); + while (!l_IsDone) + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + return l_Reply; } @@ -461,7 +485,7 @@ namespace CP_SDK::Network { { if (httpMethod == u"POST") curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_CUSTOMREQUEST, "POST"); - if (httpMethod == u"PATCH") + else if (httpMethod == u"PATCH") curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_CUSTOMREQUEST, "PATCH"); else curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_CUSTOMREQUEST, "PUT"); diff --git a/src/CP_SDK_BS/Game/LevelSelection.cpp b/src/CP_SDK_BS/Game/LevelSelection.cpp index 8d36517..d925926 100644 --- a/src/CP_SDK_BS/Game/LevelSelection.cpp +++ b/src/CP_SDK_BS/Game/LevelSelection.cpp @@ -195,23 +195,23 @@ namespace CP_SDK_BS::Game { try { m_PreventLevelSearchViewController_didStartLoadingEvent = true; - p_LevelSearchViewController->ResetAllFilterSettings(false); + //p_LevelSearchViewController->ResetAllFilterSettings(false); auto l_Filter = GlobalNamespace::LevelFilter(); - l_Filter.songOwned = false; + l_Filter.songOwned = true; l_Filter.songNotOwned = false; l_Filter.songUnplayed = false; - l_Filter.difficulties = _u::BeatmapDifficultyMask(); - l_Filter.songPacks = _u::SongPackMask(); + l_Filter.difficulties = _u::BeatmapDifficultyMask(0); + l_Filter.songPacks = _u::SongPackMask::get_all(); l_Filter.characteristicSerializedName = nullptr; l_Filter.minBpm = 0.0f; l_Filter.maxBpm = 0.0f; - l_Filter.sensitivity = _u::PlayerSensitivityFlag(); + l_Filter.sensitivity = _u::PlayerSensitivityFlag::Unknown; l_Filter.limitIds = ArrayW({ m_PendingFilterSong->___levelID }); l_Filter.searchText = u""; - p_LevelSearchViewController->ResetAllFilterSettings(false); + //p_LevelSearchViewController->ResetAllFilterSettings(false); p_LevelSearchViewController->Refresh( byref(l_Filter) ); From fd760a2ebec09b9179ddb497146bf19aa8b6e14a Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 7 May 2025 22:31:15 +0200 Subject: [PATCH 27/35] Make the mod late --- mod.json | 4 ++-- mod.template.json | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mod.json b/mod.json index a79e262..2b2eee2 100644 --- a/mod.json +++ b/mod.json @@ -37,10 +37,10 @@ "downloadIfMissing": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.2/paper2_scotland2.qmod" } ], - "modFiles": [ + "modFiles": [], + "lateModFiles": [ "libchatplex-sdk-bs.so" ], - "lateModFiles": [], "libraryFiles": [], "fileCopies": [], "copyExtensions": [] diff --git a/mod.template.json b/mod.template.json index 6eabf18..63417e4 100644 --- a/mod.template.json +++ b/mod.template.json @@ -10,7 +10,8 @@ "description": "ChatPlex BeatSaber modding SDK (Dependence for other mods)", "coverImage": "cover.png", "dependencies": [], - "modFiles": ["${binary}"], + "modFiles": [], + "lateModFiles": ["${binary}"], "libraryFiles": [], "fileCopies": [], "copyExtensions": [] From a280b24583d4631b21a48a2de239284e7af79568 Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 6 Aug 2025 00:50:12 +0200 Subject: [PATCH 28/35] Improve WebClientUnity & implement full WebClientCore using curl --- shared/CP_SDK/Network/IWebClient.hpp | 68 +-- shared/CP_SDK/Network/WebClientCore.hpp | 183 ++++++++ shared/CP_SDK/Network/WebClientUnity.hpp | 136 +++--- shared/CP_SDK/Network/WebContent.hpp | 8 +- shared/CP_SDK/Network/WebResponse.hpp | 36 +- shared/CP_SDK/Utils/Il2cpp.hpp | 6 - src/CP_SDK/Network/WebClientCore.cpp | 570 +++++++++++++++++++++++ src/CP_SDK/Network/WebClientUnity.cpp | 245 +++++----- src/CP_SDK/Network/WebContent.cpp | 8 + src/CP_SDK/Network/WebResponse.cpp | 46 +- 10 files changed, 1058 insertions(+), 248 deletions(-) create mode 100644 shared/CP_SDK/Network/WebClientCore.hpp create mode 100644 src/CP_SDK/Network/WebClientCore.cpp diff --git a/shared/CP_SDK/Network/IWebClient.hpp b/shared/CP_SDK/Network/IWebClient.hpp index 29a9a28..b7a6e98 100644 --- a/shared/CP_SDK/Network/IWebClient.hpp +++ b/shared/CP_SDK/Network/IWebClient.hpp @@ -24,6 +24,9 @@ namespace CP_SDK::Network { { CP_SDK_NO_COPYMOVE_CTORS(IWebClient); + public: + using IPtr = std::shared_ptr; + protected: /// @brief Constructor IWebClient() = default; @@ -42,39 +45,46 @@ namespace CP_SDK::Network { public: /// @brief Do Async GET query - /// @param p_URL Target URL - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - /// @param p_Progress Progress reporter - virtual void GetAsync(std::u16string_view p_URL, _u::CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry = false, _v::CActionRef p_Progress = nullptr) = 0; + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + virtual void GetAsync(std::u16string_view url, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false, _v::CActionRef progress = nullptr) = 0; /// @brief Do Async GET query - /// @param p_URL Target URL - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - /// @param p_Progress Progress reporter - virtual void DownloadAsync(std::u16string_view p_URL, _u::CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry = false, _v::CActionRef p_Progress = nullptr) = 0; + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + virtual void DownloadAsync(std::u16string_view url, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false, _v::CActionRef progress = nullptr) = 0; /// @brief Do Async POST query - /// @param p_URL Target URL - /// @param p_Content Optional content to post - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - virtual void PostAsync(std::u16string_view p_URL, const WebContent::Ptr& p_Content, _u::CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry = false) = 0; + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void PostAsync(std::u16string_view url, const WebContent::Ptr& content, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) = 0; /// @brief Do Async PATCH query - /// @param p_URL Target URL - /// @param p_Content Optional content to post - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - virtual void PatchAsync(std::u16string_view p_URL, const WebContent::Ptr& p_Content, _u::CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry = false) = 0; + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void PatchAsync(std::u16string_view url, const WebContent::Ptr& content, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) = 0; + /// @brief Do Async PUT query + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void PutAsync(std::u16string_view url, const WebContent::Ptr& content, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) = 0; /// @brief Do Async DELETE query - /// @param p_URL Target URL - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - virtual void DeleteAsync(std::u16string_view p_URL, _u::CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry = false) = 0; + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void DeleteAsync(std::u16string_view url, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) = 0; }; diff --git a/shared/CP_SDK/Network/WebClientCore.hpp b/shared/CP_SDK/Network/WebClientCore.hpp new file mode 100644 index 0000000..bbc2693 --- /dev/null +++ b/shared/CP_SDK/Network/WebClientCore.hpp @@ -0,0 +1,183 @@ +#pragma once + +#include "IWebClient.hpp" + +#include + +#include +#include + +namespace CP_SDK::Network { + + namespace _u + { + using namespace System; + using namespace System::Threading; + } + namespace _v + { + using namespace CP_SDK::Utils; + } + + /// @brief WebClientCore + class CP_SDK_EXPORT WebClientCore : public IWebClient, public std::enable_shared_from_this + { + CP_SDK_NO_COPYMOVE_CTORS(WebClientCore); + CP_SDK_PRIV_TAG(); + + public: + using Ptr = std::shared_ptr; + + private: + static Ptr m_GlobalClient; + + public: + /// @brief Global client instance + static WebClientCore* GlobalClient(); + + private: + std::u16string m_BaseAddress; + int m_TimeOut; + std::map m_Headers; + std::mutex m_HeadersLock; + + public: + /// @brief Maximum retry attempt + int MaxRetry; + /// @brief Delay between each retry + int RetryInterval; + + public: + /// @brief Constructor + /// @param baseAddress Base address + /// @param timeOut Requests timeout + /// @param keepAlive Should try to keep the connection alive + /// @param forceCacheDiscard Should force server cache discard + WebClientCore(CP_SDK_PRIV_TAG_ARG(), std::u16string_view baseAddress, _u::TimeSpan timeOut, bool keepAlive, bool forceCacheDiscard); + + /// @brief Constructor + /// @param baseAddress Base address + /// @param timeOut Requests timeout + /// @param keepAlive Should try to keep the connection alive + /// @param forceCacheDiscard Should force server cache discard + static Ptr Make(std::u16string_view baseAddress, _u::TimeSpan timeOut, bool keepAlive = true, bool forceCacheDiscard = false); + + public: + /// @brief Get header + /// @param p_Name Header name + virtual std::u16string GetHeader(std::u16string_view p_Name) override final; + /// @brief Set header + /// @param p_Name Header name + /// @param p_Value Header value + virtual void SetHeader(std::u16string_view p_Name, std::u16string_view p_Value) override final; + /// @brief Remove header + /// @param p_Name Header name + virtual void RemoveHeader(std::u16string_view p_Name) override final; + + public: + /// @brief Do GET query + /// @param url Target URL + /// @param dontRetry Should not retry + /// @param progress Progress reporter + WebResponse::Ptr Get(std::u16string_view url, bool dontRetry = false, _v::CActionRef progress = nullptr); + /// @brief Do GET query + /// @param url Target URL + /// @param dontRetry Should not retry + /// @param progress Progress reporter + WebResponse::Ptr Download(std::u16string_view url, bool dontRetry = false, _v::CActionRef progress = nullptr); + /// @brief Do POST query + /// @param url Target URL + /// @param content Optional content to post + /// @param dontRetry Should not retry + WebResponse::Ptr Post(std::u16string_view url, const WebContent::Ptr& content, bool dontRetry = false); + /// @brief Do PATCH query + /// @param url Target URL + /// @param content Optional content to post + /// @param dontRetry Should not retry + WebResponse::Ptr Patch(std::u16string_view url, const WebContent::Ptr& content, bool dontRetry = false); + /// @brief Do PUT query + /// @param url Target URL + /// @param content Optional content to post + /// @param dontRetry Should not retry + WebResponse::Ptr Put(std::u16string_view url, const WebContent::Ptr& content, bool dontRetry = false); + /// @brief Do DELETE query + /// @param url Target URL + /// @param dontRetry Should not retry + WebResponse::Ptr Delete(std::u16string_view url, bool dontRetry = false); + + public: + /// @brief Do Async GET query + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + virtual void GetAsync(std::u16string_view url, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false, _v::CActionRef progress = nullptr) override final; + /// @brief Do Async GET query + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + virtual void DownloadAsync(std::u16string_view url, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false, _v::CActionRef progress = nullptr) override final; + /// @brief Do Async POST query + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void PostAsync(std::u16string_view url, const WebContent::Ptr& content, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) override final; + /// @brief Do Async PATCH query + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void PatchAsync(std::u16string_view url, const WebContent::Ptr& content, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) override final; + /// @brief Do Async PUT query + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void PutAsync(std::u16string_view url, const WebContent::Ptr& content, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) override final; + /// @brief Do Async DELETE query + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void DeleteAsync(std::u16string_view url, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) override final; + + private: + /// @brief Get URL + /// @param url Request URL + std::u16string GetURL(std::u16string_view url); + /// @brief Safe URL parsing + /// @param url Source URL + std::u16string SafeURL(std::u16string_view url); + + private: + /// @brief Do request + /// @param debugName Method name for logs + /// @param httpMethod Http method + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + static void DoRequest( + Ptr self, + std::u16string debugName, + std::u16string httpMethod, + std::u16string url, + WebContent::Ptr content, + _u::CancellationToken token, + _v::Action callback, + bool dontRetry, + _v::Action progress + ); + + }; + +} ///< namespace CP_SDK::Network \ No newline at end of file diff --git a/shared/CP_SDK/Network/WebClientUnity.hpp b/shared/CP_SDK/Network/WebClientUnity.hpp index c06bb1e..1029da7 100644 --- a/shared/CP_SDK/Network/WebClientUnity.hpp +++ b/shared/CP_SDK/Network/WebClientUnity.hpp @@ -53,96 +53,96 @@ namespace CP_SDK::Network { public: /// @brief Constructor - /// @param p_BaseAddress Base address - /// @param p_TimeOut Requests timeout - /// @param p_ForceCacheDiscard Should force server cache discard - WebClientUnity(CP_SDK_PRIV_TAG_ARG(), std::u16string_view p_BaseAddress, _u::TimeSpan p_TimeOut, bool p_ForceCacheDiscard); + /// @param baseAddress Base address + /// @param timeOut Requests timeout + /// @param forceCacheDiscard Should force server cache discard + WebClientUnity(CP_SDK_PRIV_TAG_ARG(), std::u16string_view baseAddress, _u::TimeSpan timeOut, bool forceCacheDiscard); /// @brief Constructor - /// @param p_BaseAddress Base address - /// @param p_TimeOut Requests timeout - /// @param p_ForceCacheDiscard Should force server cache discard - static Ptr Make(std::u16string_view p_BaseAddress, _u::TimeSpan p_TimeOut, bool p_ForceCacheDiscard = false); + /// @param baseAddress Base address + /// @param timeOut Requests timeout + /// @param forceCacheDiscard Should force server cache discard + static Ptr Make(std::u16string_view baseAddress, _u::TimeSpan timeOut, bool forceCacheDiscard = false); public: /// @brief Get header - /// @param p_Name Header name - virtual std::u16string GetHeader(std::u16string_view p_Name) override final; + /// @param name Header name + virtual std::u16string GetHeader(std::u16string_view name) override final; /// @brief Set header - /// @param p_Name Header name - /// @param p_Value Header value - virtual void SetHeader(std::u16string_view p_Name, std::u16string_view p_Value) override final; + /// @param name Header name + /// @param value Header value + virtual void SetHeader(std::u16string_view name, std::u16string_view value) override final; /// @brief Remove header - /// @param p_Name Header name - virtual void RemoveHeader(std::u16string_view p_Name) override final; + /// @param name Header name + virtual void RemoveHeader(std::u16string_view name) override final; public: /// @brief Do Async GET query - /// @param p_URL Target URL - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - /// @param p_Progress Progress reporter - virtual void GetAsync(std::u16string_view p_URL, _u::CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry = false, _v::CActionRef p_Progress = nullptr) override final; + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + virtual void GetAsync(std::u16string_view url, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false, _v::CActionRef progress = nullptr) override final; /// @brief Do Async GET query - /// @param p_URL Target URL - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - /// @param p_Progress Progress reporter - virtual void DownloadAsync(std::u16string_view p_URL, _u::CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry = false, _v::CActionRef p_Progress = nullptr) override final; + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + virtual void DownloadAsync(std::u16string_view url, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false, _v::CActionRef progress = nullptr) override final; /// @brief Do Async POST query - /// @param p_URL Target URL - /// @param p_Content Optional content to post - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - virtual void PostAsync(std::u16string_view p_URL, const WebContent::Ptr& p_Content, _u::CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry = false) override final; + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void PostAsync(std::u16string_view url, const WebContent::Ptr& content, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) override final; /// @brief Do Async PATCH query - /// @param p_URL Target URL - /// @param p_Content Optional content to post - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - virtual void PatchAsync(std::u16string_view p_URL, const WebContent::Ptr& p_Content, _u::CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry = false) override final; + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void PatchAsync(std::u16string_view url, const WebContent::Ptr& content, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) override final; /// @brief Do Async DELETE query - /// @param p_URL Target URL - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - virtual void DeleteAsync(std::u16string_view p_URL, _u::CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry = false) override final; + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void DeleteAsync(std::u16string_view url, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) override final; private: /// @brief Get URL - /// @param p_URL Request URL - std::u16string GetURL(std::u16string_view p_URL); + /// @param url Request URL + std::u16string GetURL(std::u16string_view url); /// @brief Safe URL parsing - /// @param p_URL Source URL - std::u16string SafeURL(std::u16string_view p_URL); + /// @param url Source URL + std::u16string SafeURL(std::u16string_view url); private: /// @brief Prepare request - /// @param p_Request Request to prepare - /// @param p_IsDownload Is a download request? - void PrepareRequest(_u::UnityWebRequest* p_Request, bool p_IsDownload); + /// @param request Request to prepare + /// @param isDownload Is a download request? + void PrepareRequest(_u::UnityWebRequest* request, bool isDownload); /// @brief Do request - /// @param p_DebugName Method name for logs - /// @param p_HttpMethod Http method - /// @param p_URL Target URL - /// @param p_Content Optional content to post - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - /// @param p_Progress Progress reporter - static custom_types::Helpers::Coroutine Coroutine_DoRequest(Ptr p_Self, - std::u16string p_DebugName, - std::u16string p_HttpMethod, - std::u16string p_URL, - WebContent::Ptr p_Content, - _u::CancellationToken p_Token, - _v::Action p_Callback, - bool p_DontRetry, - _v::Action p_Progress); + /// @param debugName Method name for logs + /// @param httpMethod Http method + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + static custom_types::Helpers::Coroutine Coroutine_DoRequest(Ptr self, + std::u16string debugName, + std::u16string httpMethod, + std::u16string url, + WebContent::Ptr content, + _u::CancellationToken token, + _v::Action callback, + bool dontRetry, + _v::Action progress); }; diff --git a/shared/CP_SDK/Network/WebContent.hpp b/shared/CP_SDK/Network/WebContent.hpp index 750da47..fb4e6ef 100644 --- a/shared/CP_SDK/Network/WebContent.hpp +++ b/shared/CP_SDK/Network/WebContent.hpp @@ -2,6 +2,7 @@ #include "../Utils/Il2cpp.hpp" #include "../Utils/MonoPtr.hpp" +#include "../Utils/Json.hpp" #include #include @@ -37,8 +38,11 @@ namespace CP_SDK::Network { public: /// @brief Constructor from Json - /// @param p_Content Json content - static Ptr FromJson(std::u16string_view p_Content); + /// @param content Json content + static Ptr FromJson(std::u16string_view content); + /// @brief Constructor from Json + /// @param content Json content + static Ptr FromJson(std::shared_ptr<_v::Json::U16Document>& content); }; diff --git a/shared/CP_SDK/Network/WebResponse.hpp b/shared/CP_SDK/Network/WebResponse.hpp index c89ba58..cc3c140 100644 --- a/shared/CP_SDK/Network/WebResponse.hpp +++ b/shared/CP_SDK/Network/WebResponse.hpp @@ -9,6 +9,7 @@ #include #include +#include namespace CP_SDK::Network { @@ -60,16 +61,21 @@ namespace CP_SDK::Network { using Ptr = std::shared_ptr; /// Constructor - /// @p_Request: Reply status - WebResponse(_u::UnityWebRequest* p_Request); + /// @param request: Reply status + WebResponse(_u::UnityWebRequest* request); + /// @brief Constructor + /// @param curlPerformResult CURL perform result + /// @param curlInstance CURL instance + /// @param data Response data + WebResponse(long curlPerformResult, void* curlInstance, std::vector* data); public: /// @brief Get JObject from serialized JSON - /// @param p_Object Result object + /// @param object Result object /// @return True or false - bool TryAsJObject(std::shared_ptr<_v::Json::U16Document>& p_Object) + bool TryAsJObject(std::shared_ptr<_v::Json::U16Document>& object) { - p_Object = nullptr; + object = nullptr; auto l_New = std::make_shared<_v::Json::U16Document>(); try @@ -77,40 +83,40 @@ namespace CP_SDK::Network { if (!_v::Json::TryFromU16String(BodyString(), *l_New.get())) return false; - p_Object = l_New; + object = l_New; } catch (const std::exception& l_Exception) { - p_Object = nullptr; + object = nullptr; return false; } - return p_Object != nullptr; + return object != nullptr; } /// @brief Get Object from serialized JSON /// @tparam t_Type Object type - /// @param p_Object Result object + /// @param object Result object /// @return True or false template - bool TryGetObject(std::shared_ptr& p_Object) + bool TryGetObject(std::shared_ptr& object) { - p_Object = nullptr; + object = nullptr; try { _v::Json::U16Document l_Document; _v::Json::TryFromU16String(BodyString(), l_Document); - p_Object = std::make_shared(); - p_Object->Unserialize(l_Document); + object = std::make_shared(); + object->Unserialize(l_Document); } catch (const std::exception& l_Exception) { - p_Object = nullptr; + object = nullptr; return false; } - return p_Object != nullptr; + return object != nullptr; } }; diff --git a/shared/CP_SDK/Utils/Il2cpp.hpp b/shared/CP_SDK/Utils/Il2cpp.hpp index a148ed4..54e5ad6 100644 --- a/shared/CP_SDK/Utils/Il2cpp.hpp +++ b/shared/CP_SDK/Utils/Il2cpp.hpp @@ -3,18 +3,12 @@ #define __CP_SDK_U16STR(__mX) u##__mX #define CP_SDK_U16STR(__mX) __CP_SDK_U16STR(#__mX) -#include "../Logging/PaperLogger.hpp" #include "Internals/Il2cpp_enum.hpp" #include "Internals/Il2cpp_customtype.hpp" #include "Internals/Il2cpp_hook.hpp" #include "Internals/Il2cpp_string.hpp" #include -#include -#include -#include -#include -#include #include #include diff --git a/src/CP_SDK/Network/WebClientCore.cpp b/src/CP_SDK/Network/WebClientCore.cpp new file mode 100644 index 0000000..83e8b27 --- /dev/null +++ b/src/CP_SDK/Network/WebClientCore.cpp @@ -0,0 +1,570 @@ +#include "CP_SDK/Network/WebClientCore.hpp" +#include "CP_SDK/Unity/MTThreadInvoker.hpp" +#include "CP_SDK/ChatPlexSDK.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace System; +using namespace System::Net; +using namespace System::Threading; + +struct ScopedCURL +{ + CURL* Instance; + struct curl_slist* Headers = NULL; + std::vector* Data; + + ScopedCURL() + { + Instance = curl_easy_init(); + Data = new std::vector(); + } + ~ScopedCURL() + { + curl_easy_cleanup(Instance); + if (Headers != NULL) + curl_slist_free_all(Headers); + + delete Data; + } +}; + +namespace CP_SDK::Network { + + WebClientCore::Ptr WebClientCore::m_GlobalClient; + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Global client instance + WebClientCore* WebClientCore::GlobalClient() + { + if (!m_GlobalClient) + m_GlobalClient = WebClientCore::Make(u"", TimeSpan::FromSeconds(10), true); + + return m_GlobalClient.get(); + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Constructor + /// @param baseAddress Base address + /// @param timeOut Requests timeout + /// @param forceCacheDiscard Should force server cache discard + WebClientCore::WebClientCore(CP_SDK_PRIV_TAG_ARG(), std::u16string_view baseAddress, TimeSpan timeOut, bool keepAlive, bool forceCacheDiscard) + : m_Headers({}) + { + MaxRetry = 2; + RetryInterval = 5; + + m_BaseAddress = baseAddress; + + m_TimeOut = (int)timeOut.get_TotalSeconds(); + + if (forceCacheDiscard) + m_Headers[u"Cache-Control"] = u"no-cache, must-revalidate, proxy-revalidate, max-age=0, s-maxage=0, max-stale=0"; + } + + /// @brief Constructor + /// @param baseAddress Base address + /// @param timeOut Requests timeout + /// @param forceCacheDiscard Should force server cache discard + WebClientCore::Ptr WebClientCore::Make(std::u16string_view baseAddress, TimeSpan timeOut, bool keepAlive, bool forceCacheDiscard) + { + return std::make_shared(CP_SDK_PRIV_TAG_VAL(), baseAddress, timeOut, keepAlive, forceCacheDiscard); + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Get header + /// @param name Header name + std::u16string WebClientCore::GetHeader(std::u16string_view name) + { + auto l_Name = std::u16string(name); + + std::lock_guard l_Guard(m_HeadersLock); + if (!m_Headers.contains(l_Name)) + return u""; + + return m_Headers[l_Name]; + } + /// @brief Set header + /// @param name Header name + /// @param value Header value + void WebClientCore::SetHeader(std::u16string_view name, std::u16string_view value) + { + auto l_Name = std::u16string(name); + + std::lock_guard l_Guard(m_HeadersLock); + m_Headers[l_Name] = std::u16string(value); + } + /// @brief Remove header + /// @param name Header name + void WebClientCore::RemoveHeader(std::u16string_view name) + { + auto l_Name = std::u16string(name); + + std::lock_guard l_Guard(m_HeadersLock); + auto l_It = m_Headers.find(l_Name); + if (l_It != m_Headers.end()) + m_Headers.erase(l_It); + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Do GET query + /// @param url Target URL + /// @param dontRetry Should not retry + /// @param progress Progress reporter + WebResponse::Ptr WebClientCore::Get(std::u16string_view url, bool dontRetry, _v::CActionRef progress) + { + auto l_Reply = WebResponse::Ptr(nullptr); + + DoRequest( + shared_from_this(), + u"Get", + u"GET", + GetURL(url), + nullptr, + CancellationToken::get_None(), + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + dontRetry, + progress + ); + + return l_Reply; + } + /// @brief Do GET query + /// @param url Target URL + /// @param dontRetry Should not retry + /// @param progress Progress reporter + WebResponse::Ptr WebClientCore::Download(std::u16string_view url, bool dontRetry, _v::CActionRef progress) + { + auto l_Reply = WebResponse::Ptr(nullptr); + + DoRequest( + shared_from_this(), + u"Download", + u"DOWNLOAD", + GetURL(url), + nullptr, + CancellationToken::get_None(), + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + dontRetry, + progress + ); + + return l_Reply; + } + /// @brief Do POST query + /// @param url Target URL + /// @param content Optional content to post + /// @param dontRetry Should not retry + WebResponse::Ptr WebClientCore::Post(std::u16string_view url, const WebContent::Ptr& content, bool dontRetry) + { + auto l_Reply = WebResponse::Ptr(nullptr); + + DoRequest( + shared_from_this(), + u"Post", + u"POST", + GetURL(url), + content, + CancellationToken::get_None(), + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + dontRetry, + nullptr + ); + + return l_Reply; + } + /// @brief Do PATCH query + /// @param url Target URL + /// @param content Optional content to post + /// @param dontRetry Should not retry + WebResponse::Ptr WebClientCore::Patch(std::u16string_view url, const WebContent::Ptr& content, bool dontRetry) + { + auto l_Reply = WebResponse::Ptr(nullptr); + + DoRequest( + shared_from_this(), + u"Patch", + u"PATCH", + GetURL(url), + content, + CancellationToken::get_None(), + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + dontRetry, + nullptr + ); + + return l_Reply; + } + /// @brief Do PUT query + /// @param url Target URL + /// @param content Optional content to post + /// @param dontRetry Should not retry + WebResponse::Ptr WebClientCore::Put(std::u16string_view url, const WebContent::Ptr& content, bool dontRetry) + { + auto l_Reply = WebResponse::Ptr(nullptr); + + DoRequest( + shared_from_this(), + u"Put", + u"PUT", + GetURL(url), + content, + CancellationToken::get_None(), + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + dontRetry, + nullptr + ); + + return l_Reply; + } + /// @brief Do DELETE query + /// @param url Target URL + /// @param dontRetry Should not retry + WebResponse::Ptr WebClientCore::Delete(std::u16string_view url, bool dontRetry) + { + auto l_Reply = WebResponse::Ptr(nullptr); + + DoRequest( + shared_from_this(), + u"Delete", + u"DELETE", + GetURL(url), + nullptr, + CancellationToken::get_None(), + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + dontRetry, + nullptr + ); + + return l_Reply; + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Do Async GET query + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + void WebClientCore::GetAsync(std::u16string_view url, CancellationToken token, _v::CActionRef callback, bool dontRetry, _v::CActionRef progress) + { + il2cpp_utils::il2cpp_aware_thread( + &DoRequest, + shared_from_this(), + u"GetAsync", + u"GET", + GetURL(url), + nullptr, + token, + callback, + dontRetry, + progress + ).detach(); + } + /// @brief Do Async GET query + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + void WebClientCore::DownloadAsync(std::u16string_view url, CancellationToken token, _v::CActionRef callback, bool dontRetry, _v::CActionRef progress) + { + il2cpp_utils::il2cpp_aware_thread( + &DoRequest, + shared_from_this(), + u"DownloadAsync", + u"DOWNLOAD", + GetURL(url), + nullptr, + token, + callback, + dontRetry, + progress + ).detach(); + } + /// @brief Do Async POST query + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + void WebClientCore::PostAsync(std::u16string_view url, const WebContent::Ptr& content, CancellationToken token, _v::CActionRef callback, bool dontRetry) + { + il2cpp_utils::il2cpp_aware_thread( + &DoRequest, + shared_from_this(), + u"PostAsync", + u"POST", + GetURL(url), + content, + token, + callback, + dontRetry, + nullptr + ).detach(); + } + /// @brief Do Async PATCH query + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + void WebClientCore::PatchAsync(std::u16string_view url, const WebContent::Ptr& content, CancellationToken token, _v::CActionRef callback, bool dontRetry) + { + il2cpp_utils::il2cpp_aware_thread( + &DoRequest, + shared_from_this(), + u"PatchAsync", + u"PATCH", + GetURL(url), + content, + token, + callback, + dontRetry, + nullptr + ).detach(); + } + /// @brief Do Async PATCH query + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + void WebClientCore::PutAsync(std::u16string_view url, const WebContent::Ptr& content, CancellationToken token, _v::CActionRef callback, bool dontRetry) + { + il2cpp_utils::il2cpp_aware_thread( + &DoRequest, + shared_from_this(), + u"PutAsync", + u"PUT", + GetURL(url), + content, + token, + callback, + dontRetry, + nullptr + ).detach(); + } + /// @brief Do Async GET query + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + void WebClientCore::DeleteAsync(std::u16string_view url, CancellationToken token, _v::CActionRef callback, bool dontRetry) + { + il2cpp_utils::il2cpp_aware_thread( + &DoRequest, + shared_from_this(), + u"DeleteAsync", + u"DELETE", + GetURL(url), + nullptr, + token, + callback, + dontRetry, + nullptr + ); + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Get URL + /// @param url Request URL + std::u16string WebClientCore::GetURL(std::u16string_view url) + { + if (m_BaseAddress.size() == 0) return std::u16string(url); + if (url.find(u"://") != std::u16string::npos) return std::u16string(url); + if (m_BaseAddress[m_BaseAddress.size() - 1] == '/') return m_BaseAddress + std::u16string(url); + + return m_BaseAddress + u"/" + std::u16string(url); + } + /// @brief Safe URL parsing + /// @param url Source URL + std::u16string WebClientCore::SafeURL(std::u16string_view url) + { + auto l_Position = url.find_first_of('?'); + if (l_Position != std::u16string::npos) + return std::u16string(url).substr(0, l_Position); + + return std::u16string(url); + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Do request + /// @param debugName Method name for logs + /// @param httpMethod Http method + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + void WebClientCore::DoRequest( + Ptr self, + std::u16string debugName, + std::u16string httpMethod, + std::u16string url, + WebContent::Ptr content, + CancellationToken token, + _v::Action callback, + bool dontRetry, + _v::Action progress + ) + { +#if DEBUG + ChatPlexSDK::Logger()->Debug(u"[CP_SDK.Network][WebClientCore." + debugName + u"] " + httpMethod + u" " + url); +#endif + + WebResponse::Ptr l_Reply = nullptr; + for (int l_RetryI = 1; l_RetryI <= self->MaxRetry; l_RetryI++) + { + if (token.get_IsCancellationRequested()) + break; + + ScopedCURL l_ScopedCURL; + l_ScopedCURL.Headers = curl_slist_append(l_ScopedCURL.Headers, "Accept: */*"); + + for (auto const& [l_Header, l_Value] : self->m_Headers) + l_ScopedCURL.Headers = curl_slist_append(l_ScopedCURL.Headers, Utils::U16StrToStr(l_Header + ": " + l_Value).c_str()); + + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_URL, Utils::U16StrToStr(url).c_str()); + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_TIMEOUT, static_cast(self->m_TimeOut)); + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_FOLLOWLOCATION, static_cast(1)); + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_USERAGENT, Utils::U16StrToStr(ChatPlexSDK::NetworkUserAgent()).c_str()); + + if (httpMethod == u"GET" || httpMethod == u"DOWNLOAD") + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_CUSTOMREQUEST, "GET"); + else if (httpMethod == u"POST" || httpMethod == u"PATCH" || httpMethod == u"PUT") + { + if (httpMethod == u"POST") + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_CUSTOMREQUEST, "POST"); + if (httpMethod == u"PATCH") + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_CUSTOMREQUEST, "PATCH"); + else + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_CUSTOMREQUEST, "PUT"); + + if (content) + { + l_ScopedCURL.Headers = curl_slist_append(l_ScopedCURL.Headers, Utils::U16StrToStr(std::u16string(u"Content-Type: ") + content->Type).c_str()); + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_POSTFIELDSIZE, static_cast(content->Bytes->get_Length())); + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_POSTFIELDS, &content->Bytes->_values[0]); + } + } + else if (httpMethod == u"DELETE") + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_CUSTOMREQUEST, "DELETE"); + + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_HTTPHEADER, l_ScopedCURL.Headers); + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_SSL_VERIFYPEER, false); + + if (progress.IsValid()) + { + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_NOPROGRESS, false); + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_XFERINFODATA, (void*)&progress); + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_XFERINFOFUNCTION, + +[] (_v::Action* clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) { + float percentage = (float)dlnow / (float)dltotal * 100.0f; + if(isnan(percentage)) + percentage = 0.0f; + clientp->Invoke(percentage); + return 0; + } + ); + } + + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_WRITEDATA, l_ScopedCURL.Data); + curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_WRITEFUNCTION, + +[](void *contents, std::size_t size, std::size_t nmemb, std::vector* clientp) -> size_t + { + size_t l_SizeToWrite = size * nmemb; + + try + { + auto l_WritePos = clientp->size(); + clientp->resize(l_WritePos + l_SizeToWrite); + memcpy(clientp->data() + l_WritePos, contents, l_SizeToWrite); + } + catch(std::bad_alloc &e) + { + ChatPlexSDK::Logger()->Error(u"[CP_SDK.Network][WebClientCore.DoRequest] Failed to read from response stream, allocation error"); + return 0; + } + + return l_SizeToWrite; + }); + + if (token.get_IsCancellationRequested()) + break; + + auto l_CURLResult = curl_easy_perform(l_ScopedCURL.Instance); + + l_Reply = std::make_shared(static_cast(l_CURLResult), l_ScopedCURL.Instance, l_ScopedCURL.Data); + if (!l_Reply->IsSuccessStatusCode() && l_Reply->StatusCode() == (HttpStatusCode)429) + { + /* var l_Limits = RateLimitInfo.Get(l_Request); + if (l_Limits != nullptr) + { + int l_TotalMilliseconds = (int)(l_Limits.Reset - DateTime.Now).TotalMilliseconds; + if (l_TotalMilliseconds > 0) + { + ChatPlexSDK::Logger()->Error(u"[CP_SDK.Network][WebClientCore." + debugName + u"] Request {SafeURL(url)} was rate limited, retrying in {l_TotalMilliseconds}ms..."); + + co_yield WaitForSecondsRealtime::New_ctor(RetryInterval)->i_IEnumerator(); + continue; + } + }*/ + } + + if (!l_Reply->IsSuccessStatusCode()) + { + auto l_LogPrefix = u"[CP_SDK.Network][WebClientCore." + debugName + u"] Request " + self->SafeURL(url) + u" failed with code "; + l_LogPrefix += StringW(std::to_string(l_Reply->StatusCode().value__)); + l_LogPrefix += u":\"" + l_Reply->ReasonPhrase() + "\", "; + + if (!l_Reply->ShouldRetry() || dontRetry) + { + ChatPlexSDK::Logger()->Error(l_LogPrefix + u" not retrying"); + break; + } + + ChatPlexSDK::Logger()->Error(l_LogPrefix + u" next try in " + (std::u16string)StringW(std::to_string(self->RetryInterval)) + u" seconds..."); + + std::this_thread::sleep_for(std::chrono::seconds(self->RetryInterval)); + continue; + } + else + { + if (progress.IsValid()) + try { progress(1.0f); } catch (const std::exception&) { } + + break; + } + } + + if (!token.get_IsCancellationRequested() && callback.IsValid()) + Unity::MTThreadInvoker::EnqueueOnThread([=]() -> void { callback(l_Reply); }); + } + +} ///< namespace CP_SDK::Network \ No newline at end of file diff --git a/src/CP_SDK/Network/WebClientUnity.cpp b/src/CP_SDK/Network/WebClientUnity.cpp index 772c79c..3e6e4b9 100644 --- a/src/CP_SDK/Network/WebClientUnity.cpp +++ b/src/CP_SDK/Network/WebClientUnity.cpp @@ -6,7 +6,6 @@ #include #include #include -//#include #include #include @@ -36,41 +35,41 @@ namespace CP_SDK::Network { //////////////////////////////////////////////////////////////////////////// /// @brief Constructor - /// @param p_BaseAddress Base address - /// @param p_TimeOut Requests timeout - /// @param p_ForceCacheDiscard Should force server cache discard - WebClientUnity::WebClientUnity(CP_SDK_PRIV_TAG_ARG(), std::u16string_view p_BaseAddress, TimeSpan p_TimeOut, bool p_ForceCacheDiscard) + /// @param baseAddress Base address + /// @param timeOut Requests timeout + /// @param forceCacheDiscard Should force server cache discard + WebClientUnity::WebClientUnity(CP_SDK_PRIV_TAG_ARG(), std::u16string_view baseAddress, TimeSpan timeOut, bool forceCacheDiscard) : m_Headers({}) { DownloadTimeout = 2 * 60; MaxRetry = 2; RetryInterval = 5; - m_BaseAddress = p_BaseAddress; + m_BaseAddress = baseAddress; - m_Timeout = (int)p_TimeOut.get_TotalSeconds(); + m_Timeout = (int)timeOut.get_TotalSeconds(); - if (p_ForceCacheDiscard) + if (forceCacheDiscard) m_Headers[u"Cache-Control"] = u"no-cache, must-revalidate, proxy-revalidate, max-age=0, s-maxage=0, max-stale=0"; } /// @brief Constructor - /// @param p_BaseAddress Base address - /// @param p_TimeOut Requests timeout - /// @param p_ForceCacheDiscard Should force server cache discard - WebClientUnity::Ptr WebClientUnity::Make(std::u16string_view p_BaseAddress, TimeSpan p_TimeOut, bool p_ForceCacheDiscard) + /// @param baseAddress Base address + /// @param timeOut Requests timeout + /// @param forceCacheDiscard Should force server cache discard + WebClientUnity::Ptr WebClientUnity::Make(std::u16string_view baseAddress, TimeSpan timeOut, bool forceCacheDiscard) { - return std::make_shared(CP_SDK_PRIV_TAG_VAL(), p_BaseAddress, p_TimeOut, p_ForceCacheDiscard); + return std::make_shared(CP_SDK_PRIV_TAG_VAL(), baseAddress, timeOut, forceCacheDiscard); } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// /// @brief Get header - /// @param p_Name Header name - std::u16string WebClientUnity::GetHeader(std::u16string_view p_Name) + /// @param name Header name + std::u16string WebClientUnity::GetHeader(std::u16string_view name) { - auto l_Name = std::u16string(p_Name); + auto l_Name = std::u16string(name); std::lock_guard l_Guard(m_HeadersLock); if (!m_Headers.contains(l_Name)) @@ -79,20 +78,20 @@ namespace CP_SDK::Network { return m_Headers[l_Name]; } /// @brief Set header - /// @param p_Name Header name - /// @param p_Value Header value - void WebClientUnity::SetHeader(std::u16string_view p_Name, std::u16string_view p_Value) + /// @param name Header name + /// @param value Header value + void WebClientUnity::SetHeader(std::u16string_view name, std::u16string_view value) { - auto l_Name = std::u16string(p_Name); + auto l_Name = std::u16string(name); std::lock_guard l_Guard(m_HeadersLock); - m_Headers[l_Name] = std::u16string(p_Value); + m_Headers[l_Name] = std::u16string(value); } /// @brief Remove header - /// @param p_Name Header name - void WebClientUnity::RemoveHeader(std::u16string_view p_Name) + /// @param name Header name + void WebClientUnity::RemoveHeader(std::u16string_view name) { - auto l_Name = std::u16string(p_Name); + auto l_Name = std::u16string(name); std::lock_guard l_Guard(m_HeadersLock); auto l_It = m_Headers.find(l_Name); @@ -104,153 +103,155 @@ namespace CP_SDK::Network { //////////////////////////////////////////////////////////////////////////// /// @brief Do Async GET query - /// @param p_URL Target URL - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - /// @param p_Progress Progress reporter - void WebClientUnity::GetAsync(std::u16string_view p_URL, CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry, _v::CActionRef p_Progress) + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + void WebClientUnity::GetAsync(std::u16string_view url, CancellationToken token, _v::CActionRef callback, bool dontRetry, _v::CActionRef progress) { - Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"GetAsync", u"GET", GetURL(p_URL), nullptr, p_Token, p_Callback, p_DontRetry, p_Progress))); + Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"GetAsync", u"GET", GetURL(url), nullptr, token, callback, dontRetry, progress))); } /// @brief Do Async GET query - /// @param p_URL Target URL - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - /// @param p_Progress Progress reporter - void WebClientUnity::DownloadAsync(std::u16string_view p_URL, CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry, _v::CActionRef p_Progress) + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + void WebClientUnity::DownloadAsync(std::u16string_view url, CancellationToken token, _v::CActionRef callback, bool dontRetry, _v::CActionRef progress) { - Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"DownloadAsync", u"DOWNLOAD", GetURL(p_URL), nullptr, p_Token, p_Callback, p_DontRetry, p_Progress))); + Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"DownloadAsync", u"DOWNLOAD", GetURL(url), nullptr, token, callback, dontRetry, progress))); } /// @brief Do Async POST query - /// @param p_URL Target URL - /// @param p_Content Optional content to post - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - void WebClientUnity::PostAsync(std::u16string_view p_URL, const WebContent::Ptr& p_Content, CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry) + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + void WebClientUnity::PostAsync(std::u16string_view url, const WebContent::Ptr& content, CancellationToken token, _v::CActionRef callback, bool dontRetry) { - Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"PostAsync", u"POST", GetURL(p_URL), p_Content, p_Token, p_Callback, p_DontRetry, nullptr))); + Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"PostAsync", u"POST", GetURL(url), content, token, callback, dontRetry, nullptr))); } /// @brief Do Async PATCH query - /// @param p_URL Target URL - /// @param p_Content Optional content to post - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - void WebClientUnity::PatchAsync(std::u16string_view p_URL, const WebContent::Ptr& p_Content, CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry) + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + void WebClientUnity::PatchAsync(std::u16string_view url, const WebContent::Ptr& content, CancellationToken token, _v::CActionRef callback, bool dontRetry) { - Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"PatchAsync", u"PATCH", GetURL(p_URL), p_Content, p_Token, p_Callback, p_DontRetry, nullptr))); + Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"PatchAsync", u"PATCH", GetURL(url), content, token, callback, dontRetry, nullptr))); } /// @brief Do Async GET query - /// @param p_URL Target URL - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - /// @param p_Progress Progress reporter - void WebClientUnity::DeleteAsync(std::u16string_view p_URL, CancellationToken p_Token, _v::CActionRef p_Callback, bool p_DontRetry) + /// @param url Target URL + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + void WebClientUnity::DeleteAsync(std::u16string_view url, CancellationToken token, _v::CActionRef callback, bool dontRetry) { - Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"DownloadAsync", u"DOWNLOAD", GetURL(p_URL), nullptr, p_Token, p_Callback, p_DontRetry, nullptr))); + Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"DownloadAsync", u"DOWNLOAD", GetURL(url), nullptr, token, callback, dontRetry, nullptr))); } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// /// @brief Get URL - /// @param p_URL Request URL - std::u16string WebClientUnity::GetURL(std::u16string_view p_URL) + /// @param url Request URL + std::u16string WebClientUnity::GetURL(std::u16string_view url) { - if (m_BaseAddress.size() == 0) return std::u16string(p_URL); - if (p_URL.find(u"://") != std::u16string::npos) return std::u16string(p_URL); - if (m_BaseAddress[m_BaseAddress.size() - 1] == '/') return m_BaseAddress + std::u16string(p_URL); + if (m_BaseAddress.size() == 0) return std::u16string(url); + if (url.find(u"://") != std::u16string::npos) return std::u16string(url); + if (m_BaseAddress[m_BaseAddress.size() - 1] == '/') return m_BaseAddress + std::u16string(url); - return m_BaseAddress + u"/" + std::u16string(p_URL); + return m_BaseAddress + u"/" + std::u16string(url); } /// @brief Safe URL parsing - /// @param p_URL Source URL - std::u16string WebClientUnity::SafeURL(std::u16string_view p_URL) + /// @param url Source URL + std::u16string WebClientUnity::SafeURL(std::u16string_view url) { - auto l_Position = p_URL.find_first_of('?'); + auto l_Position = url.find_first_of('?'); if (l_Position != std::u16string::npos) - return std::u16string(p_URL).substr(0, l_Position); + return std::u16string(url).substr(0, l_Position); - return std::u16string(p_URL); + return std::u16string(url); } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// /// @brief Prepare request - /// @param p_Request Request to prepare - /// @param p_IsDownload Is a download request? - void WebClientUnity::PrepareRequest(UnityWebRequest* p_Request, bool p_IsDownload) + /// @param request Request to prepare + /// @param isDownload Is a download request? + void WebClientUnity::PrepareRequest(UnityWebRequest* request, bool isDownload) { - if (p_Request->get_downloadHandler() == nullptr) - p_Request->set_downloadHandler(DownloadHandlerBuffer::New_ctor()); + if (request->get_downloadHandler() == nullptr) + request->set_downloadHandler(DownloadHandlerBuffer::New_ctor()); - p_Request->set_timeout(p_IsDownload ? DownloadTimeout : m_Timeout); + request->set_timeout(isDownload ? DownloadTimeout : m_Timeout); std::lock_guard l_Guard(m_HeadersLock); static auto s_UnityWebRequest_InternalSetRequestHeader = il2cpp_utils::resolve_icall("UnityEngine.Networking.UnityWebRequest::InternalSetRequestHeader"); for (auto const& [l_Header, l_Value] : m_Headers) - s_UnityWebRequest_InternalSetRequestHeader(p_Request, l_Header, l_Value); + s_UnityWebRequest_InternalSetRequestHeader(request, l_Header, l_Value); } /// @brief Do request - /// @param p_DebugName Method name for logs - /// @param p_HttpMethod Http method - /// @param p_URL Target URL - /// @param p_Content Optional content to post - /// @param p_Token Cancellation token - /// @param p_Callback Callback - /// @param p_DontRetry Should not retry - /// @param p_Progress Progress reporter - custom_types::Helpers::Coroutine WebClientUnity::Coroutine_DoRequest(Ptr p_Self, - std::u16string p_DebugName, - std::u16string p_HttpMethod, - std::u16string p_URL, - WebContent::Ptr p_Content, - CancellationToken p_Token, - _v::Action p_Callback, - bool p_DontRetry, - _v::Action p_Progress) + /// @param debugName Method name for logs + /// @param httpMethod Http method + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + /// @param progress Progress reporter + custom_types::Helpers::Coroutine WebClientUnity::Coroutine_DoRequest(Ptr self, + std::u16string debugName, + std::u16string httpMethod, + std::u16string url, + WebContent::Ptr content, + CancellationToken token, + _v::Action callback, + bool dontRetry, + _v::Action progress) { #if DEBUG - ChatPlexSDK::Logger()->Debug(u"[CP_SDK.Network][WebClientUnity." + p_DebugName + u"] " + p_HttpMethod + u" " + p_URL); + ChatPlexSDK::Logger()->Debug(u"[CP_SDK.Network][WebClientUnity." + debugName + u"] " + httpMethod + u" " + url); #endif WebResponse::Ptr l_Reply = nullptr; - for (int l_RetryI = 1; l_RetryI <= p_Self->MaxRetry; l_RetryI++) + for (int l_RetryI = 1; l_RetryI <= self->MaxRetry; l_RetryI++) { - if (p_Token.get_IsCancellationRequested()) + if (token.get_IsCancellationRequested()) break; auto l_Request = _v::MonoPtr(nullptr); - if (p_HttpMethod == u"GET" || p_HttpMethod == u"DOWNLOAD") - l_Request = UnityWebRequest::Get(p_URL); - else if (p_HttpMethod == u"POST" || p_HttpMethod == u"PATCH") + if (httpMethod == u"GET" || httpMethod == u"DOWNLOAD") + l_Request = UnityWebRequest::Get(url); + else if (httpMethod == u"POST" || httpMethod == u"PATCH" || httpMethod == u"PUT") { - ChatPlexSDK::Logger()->Error(u"WebClientUnity POST & PATCH are disabled for now"); + ChatPlexSDK::Logger()->Error(u"WebClientUnity POST & PATCH & PUT are disabled for now"); throw std::runtime_error("WebClientUnity POST & PATCH are disabled for now"); /// TODO Disabled until fixed - /*static auto s_UploadHandler_InternalSetContentType = il2cpp_utils::resolve_icall("UnityEngine.Networking.UploadHandler::InternalSetContentType"); - auto l_UploadHandler = UploadHandlerRaw::New_ctor(p_Content->Bytes.Ptr()); - s_UploadHandler_InternalSetContentType(l_UploadHandler, p_Content->Type); + /*static auto s_UploadHandler_InternalSetContentType + = il2cpp_utils::resolve_icall("UnityEngine.Networking.UploadHandler::InternalSetContentType"); - l_Request = UnityWebRequest::New_ctor(p_URL, p_HttpMethod, DownloadHandlerBuffer::New_ctor(), l_UploadHandler);*/ + auto l_UploadHandler = UploadHandlerRaw::New_ctor(content->Bytes.Ptr()); + s_UploadHandler_InternalSetContentType(l_UploadHandler, content->Type); + + l_Request = UnityWebRequest::New_ctor(url, httpMethod, DownloadHandlerBuffer::New_ctor(), l_UploadHandler);*/ } - else if (p_HttpMethod == u"DELETE") - l_Request = UnityWebRequest::New_ctor(p_URL, p_HttpMethod, nullptr, nullptr); + else if (httpMethod == u"DELETE") + l_Request = UnityWebRequest::New_ctor(url, httpMethod, nullptr, nullptr); - p_Self->PrepareRequest(l_Request.Ptr(), p_HttpMethod == u"DOWNLOAD"); + self->PrepareRequest(l_Request.Ptr(), httpMethod == u"DOWNLOAD"); - if (!p_Progress.IsValid()) + if (!progress.IsValid()) co_yield reinterpret_cast(l_Request->SendWebRequest()); else { - try { p_Progress(0.0f); } catch (const std::exception&) { } + try { progress(0.0f); } catch (const std::exception&) { } l_Request->SendWebRequest(); auto l_Waiter = WaitForSecondsRealtime::New_ctor(0.05f); @@ -262,15 +263,15 @@ namespace CP_SDK::Network { static auto s_UnityWebRequest_GetDownloadProgress = il2cpp_utils::resolve_icall("UnityEngine.Networking.UnityWebRequest::GetDownloadProgress"); auto l_Progress = (!s_UnityWebRequest_IsExecuting(l_Request.Ptr()) && !l_Request->get_isDone()) ? -1.0f : s_UnityWebRequest_GetDownloadProgress(l_Request.Ptr()); - p_Progress(l_Progress); + progress(l_Progress); } catch (const std::exception&) { } - if (p_Token.get_IsCancellationRequested() || l_Request->get_isDone() || l_Request->get_result() == UnityWebRequest::Result::ProtocolError || l_Request->get_result() == UnityWebRequest::Result::ConnectionError) + if (token.get_IsCancellationRequested() || l_Request->get_isDone() || l_Request->get_result() == UnityWebRequest::Result::ProtocolError || l_Request->get_result() == UnityWebRequest::Result::ConnectionError) break; } while (true); } - if (p_Token.get_IsCancellationRequested()) + if (token.get_IsCancellationRequested()) break; l_Reply = std::make_shared(l_Request.Ptr()); @@ -283,7 +284,7 @@ namespace CP_SDK::Network { int l_TotalMilliseconds = (int)(l_Limits.Reset - DateTime.Now).TotalMilliseconds; if (l_TotalMilliseconds > 0) { - ChatPlexSDK::Logger()->Error(u"[CP_SDK.Network][WebClientUnity." + p_DebugName + u"] Request {SafeURL(p_URL)} was rate limited, retrying in {l_TotalMilliseconds}ms..."); + ChatPlexSDK::Logger()->Error(u"[CP_SDK.Network][WebClientUnity." + debugName + u"] Request {SafeURL(url)} was rate limited, retrying in {l_TotalMilliseconds}ms..."); co_yield WaitForSecondsRealtime::New_ctor(RetryInterval)->i_IEnumerator(); continue; @@ -293,32 +294,32 @@ namespace CP_SDK::Network { if (!l_Reply->IsSuccessStatusCode()) { - auto l_LogPrefix = u"[CP_SDK.Network][WebClientUnity." + p_DebugName + u"] Request " + p_Self->SafeURL(p_URL) + u" failed with code "; + auto l_LogPrefix = u"[CP_SDK.Network][WebClientUnity." + debugName + u"] Request " + self->SafeURL(url) + u" failed with code "; l_LogPrefix += StringW(std::to_string(l_Reply->StatusCode().value__)); l_LogPrefix += u":\"" + l_Reply->ReasonPhrase() + "\", "; - if (!l_Reply->ShouldRetry() || p_DontRetry) + if (!l_Reply->ShouldRetry() || dontRetry) { ChatPlexSDK::Logger()->Error(l_LogPrefix + u" not retrying"); break; } - ChatPlexSDK::Logger()->Error(l_LogPrefix + u" next try in " + (std::u16string)StringW(std::to_string(p_Self->RetryInterval)) + u" seconds..."); + ChatPlexSDK::Logger()->Error(l_LogPrefix + u" next try in " + (std::u16string)StringW(std::to_string(self->RetryInterval)) + u" seconds..."); - co_yield WaitForSecondsRealtime::New_ctor(p_Self->RetryInterval)->i___System__Collections__IEnumerator(); + co_yield WaitForSecondsRealtime::New_ctor(self->RetryInterval)->i___System__Collections__IEnumerator(); continue; } else { - if (p_Progress.IsValid()) - try { p_Progress(1.0f); } catch (const std::exception&) { } + if (progress.IsValid()) + try { progress(1.0f); } catch (const std::exception&) { } break; } } - if (!p_Token.get_IsCancellationRequested() && p_Callback.IsValid()) - Unity::MTThreadInvoker::EnqueueOnThread([=]() -> void { p_Callback(l_Reply); }); + if (!token.get_IsCancellationRequested() && callback.IsValid()) + Unity::MTThreadInvoker::EnqueueOnThread([=]() -> void { callback(l_Reply); }); } } ///< namespace CP_SDK::Network \ No newline at end of file diff --git a/src/CP_SDK/Network/WebContent.cpp b/src/CP_SDK/Network/WebContent.cpp index c9ef6b2..f3eb29c 100644 --- a/src/CP_SDK/Network/WebContent.cpp +++ b/src/CP_SDK/Network/WebContent.cpp @@ -1,4 +1,5 @@ #include "CP_SDK/Network/WebContent.hpp" +#include "CP_SDK/Utils/Json.hpp" #include #include @@ -31,5 +32,12 @@ namespace CP_SDK::Network { auto l_Array = Encoding::get_UTF8()->GetBytes(p_Content).operator Array *(); return std::make_shared(CP_SDK_PRIV_TAG_VAL(), l_Array, u"application/json; charset=utf-8"); } + /// @brief Constructor from Json + /// @param content Json content + WebContent::Ptr WebContent::FromJson(std::shared_ptr<_v::Json::U16Document>& content) + { + auto l_Array = Encoding::get_UTF8()->GetBytes(content ? _v::Json::ToU16String(*content, false) : u"").operator Array *(); + return std::make_shared(CP_SDK_PRIV_TAG_VAL(), l_Array, u"application/json; charset=utf-8"); + } } ///< namespace CP_SDK::Network \ No newline at end of file diff --git a/src/CP_SDK/Network/WebResponse.cpp b/src/CP_SDK/Network/WebResponse.cpp index 5ce5aa5..f97e320 100644 --- a/src/CP_SDK/Network/WebResponse.cpp +++ b/src/CP_SDK/Network/WebResponse.cpp @@ -1,6 +1,8 @@ #include "CP_SDK/Network/WebResponse.hpp" -#include "CP_SDK/ChatPlexSDK.hpp" +#include +#include +#include #include #include #include @@ -64,13 +66,10 @@ namespace CP_SDK::Network { //////////////////////////////////////////////////////////////////////////// /// Constructor - /// @p_Request: Reply status + /// @param request: Reply status WebResponse::WebResponse(UnityWebRequest * p_Request) { - m_StatusCode = (HttpStatusCode)p_Request->get_responseCode(); - m_IsSuccessStatusCode = !(p_Request->get_result() == UnityWebRequest::Result::ProtocolError && p_Request->get_result() == UnityWebRequest::Result::ConnectionError); - m_ShouldRetry = IsSuccessStatusCode() ? false : (p_Request->get_responseCode() < 400 || p_Request->get_responseCode() >= 500); - m_BodyBytes = reinterpret_cast<::Array*>(p_Request->get_downloadHandler()->GetData().convert()); + m_StatusCode = (HttpStatusCode)p_Request->get_responseCode(); if (p_Request->get_result() == UnityWebRequest::Result::ConnectionError || p_Request->get_result() == UnityWebRequest::Result::ProtocolError) { @@ -78,7 +77,42 @@ namespace CP_SDK::Network { m_ReasonPhrase = u"HTTP/1.1 " + std::to_string(m_StatusCode.value__) + u" " + p_Request->GetHTTPStatusString(m_StatusCode.value__); else m_ReasonPhrase = p_Request->GetWebErrorString(p_Request->GetError()); + + m_IsSuccessStatusCode = false; } + else + m_IsSuccessStatusCode = ((int)p_Request->get_responseCode() >= 200) && ((int)p_Request->get_responseCode() <= 299); + + m_ShouldRetry = IsSuccessStatusCode() ? false : (p_Request->get_responseCode() < 400 || p_Request->get_responseCode() >= 500); + m_BodyBytes = reinterpret_cast<::Array*>(p_Request->get_downloadHandler()->GetData().convert()); + } + /// @brief Constructor + /// @param curlPerformResult CURL perform result + /// @param curlInstance CURL instance + /// @param data Response data + WebResponse::WebResponse(long curlPerformResult, void* curlInstance, std::vector* data) + { + auto l_CURLInstance = reinterpret_cast(curlInstance); + + if (curlPerformResult != CURLE_OK) + { + m_StatusCode = -curlPerformResult; + m_ReasonPhrase = Utils::StrToU16Str(curl_easy_strerror(static_cast(curlPerformResult))); + m_IsSuccessStatusCode = false; + m_ShouldRetry = false; + } + else + { + long l_HTTPCode(0); + curl_easy_getinfo(l_CURLInstance, CURLINFO_RESPONSE_CODE, &l_HTTPCode); + + m_StatusCode = l_HTTPCode; + m_IsSuccessStatusCode = ((int)l_HTTPCode >= 200) && ((int)l_HTTPCode <= 299); + m_ShouldRetry = IsSuccessStatusCode() ? false : (l_HTTPCode < 400 || l_HTTPCode >= 500); + } + + m_BodyBytes = ::Array::NewLength(data->size()); + memcpy(m_BodyBytes->_values, data->data(), data->size()); } } ///< namespace CP_SDK::Network From 2e2edba8fdbbcced04bf3d8773dd7e1ef2f8c582 Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 6 Aug 2025 00:50:52 +0200 Subject: [PATCH 29/35] Implement JsonRPCClient --- qpm.json | 5 + qpm.shared.json | 91 +++++++----- shared/CP_SDK/Network/JsonRPCClient.hpp | 90 +++++++++++ shared/CP_SDK/Network/JsonRPCResult.hpp | 53 +++++++ src/CP_SDK/Network/JsonRPCClient.cpp | 190 ++++++++++++++++++++++++ src/CP_SDK/Network/JsonRPCResult.cpp | 49 ++++++ 6 files changed, 444 insertions(+), 34 deletions(-) create mode 100644 shared/CP_SDK/Network/JsonRPCClient.hpp create mode 100644 shared/CP_SDK/Network/JsonRPCResult.hpp create mode 100644 src/CP_SDK/Network/JsonRPCClient.cpp create mode 100644 src/CP_SDK/Network/JsonRPCResult.cpp diff --git a/qpm.json b/qpm.json index 88070e9..e7a6de9 100644 --- a/qpm.json +++ b/qpm.json @@ -103,6 +103,11 @@ "id": "kaleb", "versionRange": "^0.1.9", "additionalData": {} + }, + { + "id": "libcurl", + "versionRange": "=8.5.0", + "additionalData": {} } ] } \ No newline at end of file diff --git a/qpm.shared.json b/qpm.shared.json index 321cd6e..ca32904 100644 --- a/qpm.shared.json +++ b/qpm.shared.json @@ -105,6 +105,11 @@ "id": "kaleb", "versionRange": "^0.1.9", "additionalData": {} + }, + { + "id": "libcurl", + "versionRange": "=8.5.0", + "additionalData": {} } ] }, @@ -127,12 +132,12 @@ { "dependency": { "id": "paper2_scotland2", - "versionRange": "=4.6.2", + "versionRange": "=4.6.4", "additionalData": { - "soLink": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.2/libpaper2_scotland2.so", + "soLink": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.4/libpaper2_scotland2.so", "overrideSoName": "libpaper2_scotland2.so", - "modLink": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.2/paper2_scotland2.qmod", - "branchName": "version/v4_6_2", + "modLink": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.4/paper2_scotland2.qmod", + "branchName": "version/v4_6_4", "compileOptions": { "systemIncludes": [ "shared/utfcpp/source" @@ -141,7 +146,7 @@ "cmake": false } }, - "version": "4.6.2" + "version": "4.6.4" }, { "dependency": { @@ -162,13 +167,13 @@ { "dependency": { "id": "custom-types", - "versionRange": "=0.18.2", + "versionRange": "=0.18.3", "additionalData": { - "soLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.18.2/libcustom-types.so", - "debugSoLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.18.2/debug_libcustom-types.so", + "soLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.18.3/libcustom-types.so", + "debugSoLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.18.3/debug_libcustom-types.so", "overrideSoName": "libcustom-types.so", - "modLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.18.2/CustomTypes.qmod", - "branchName": "version/v0_18_2", + "modLink": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.18.3/CustomTypes.qmod", + "branchName": "version/v0_18_3", "compileOptions": { "cppFlags": [ "-Wno-invalid-offsetof" @@ -177,7 +182,7 @@ "cmake": true } }, - "version": "0.18.2" + "version": "0.18.3" }, { "dependency": { @@ -232,6 +237,19 @@ }, "version": "0.3.0" }, + { + "dependency": { + "id": "libcurl", + "versionRange": "=8.5.0", + "additionalData": { + "staticLinking": true, + "soLink": "https://github.com/darknight1050/openssl-curl-android/releases/download/v8.5.0/libcurl.a", + "overrideSoName": "libcurl.a", + "branchName": "version-v8.5.0" + } + }, + "version": "8.5.0" + }, { "dependency": { "id": "songcore", @@ -250,36 +268,22 @@ { "dependency": { "id": "beatsaber-hook", - "versionRange": "=6.4.1", + "versionRange": "=6.4.2", "additionalData": { - "soLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.1/libbeatsaber-hook.so", - "debugSoLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.1/debug_libbeatsaber-hook.so", + "soLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.2/libbeatsaber-hook.so", + "debugSoLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.2/debug_libbeatsaber-hook.so", "overrideSoName": "libbeatsaber-hook.so", - "modLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.1/beatsaber-hook.qmod", - "branchName": "version/v6_4_1", - "cmake": true - } - }, - "version": "6.4.1" - }, - { - "dependency": { - "id": "fmt", - "versionRange": "=11.0.2", - "additionalData": { - "headersOnly": true, - "branchName": "version/v11_0_2", + "modLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.2/beatsaber-hook.qmod", + "branchName": "version/v6_4_2", "compileOptions": { - "systemIncludes": [ - "fmt/include/" - ], "cppFlags": [ - "-DFMT_HEADER_ONLY" + "-Wno-extra-qualification" ] - } + }, + "cmake": true } }, - "version": "11.0.2" + "version": "6.4.2" }, { "dependency": { @@ -308,6 +312,25 @@ } }, "version": "10.0.0" + }, + { + "dependency": { + "id": "fmt", + "versionRange": "=11.0.2", + "additionalData": { + "headersOnly": true, + "branchName": "version/v11_0_2", + "compileOptions": { + "systemIncludes": [ + "fmt/include/" + ], + "cppFlags": [ + "-DFMT_HEADER_ONLY" + ] + } + } + }, + "version": "11.0.2" } ] } \ No newline at end of file diff --git a/shared/CP_SDK/Network/JsonRPCClient.hpp b/shared/CP_SDK/Network/JsonRPCClient.hpp new file mode 100644 index 0000000..c247a3b --- /dev/null +++ b/shared/CP_SDK/Network/JsonRPCClient.hpp @@ -0,0 +1,90 @@ +#pragma once + +#include "CP_SDK/Utils/Json.hpp" +#include "JsonRPCResult.hpp" +#include "WebClientCore.hpp" +#include + +namespace CP_SDK::Network { + + namespace _v + { + using namespace CP_SDK::Utils; + } + + /// @brief JsonRPCClient + class CP_SDK_EXPORT JsonRPCClient : public std::enable_shared_from_this + { + CP_SDK_NO_COPYMOVE_CTORS(JsonRPCClient); + CP_SDK_PRIV_TAG(); + + private: + WebClientCore::Ptr m_WebClient; + + public: + using Ptr = std::shared_ptr; + + /// @brief Constructor + /// @param webClient Web client instance + JsonRPCClient(CP_SDK_PRIV_TAG_ARG(), WebClientCore::Ptr& webClient); + /// @brief Destructor + ~JsonRPCClient(); + + public: + /// @brief Create + /// @param webClient Raw web response + static Ptr Create(WebClientCore::Ptr& webClient); + + public: + /// @brief Do a RPC request + /// @param method Target method + /// @param parameters Request parameters + /// @param dontRetry Should not retry? + JsonRPCResult::Ptr Request(std::u16string_view method, std::shared_ptr<_v::Json::U16Value> parameters, bool dontRetry = false); + + public: + /// @brief Do a RPC request + /// @param method Target method + /// @param parameters Request parameters + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry? + void RequestAsync( + std::u16string_view method, + std::shared_ptr<_v::Json::U16Value> parameters, + _u::CancellationToken token, + _v::CActionRef callback, + bool dontRetry = false + ); + + private: + /// @brief Do a RPC request + /// @param method Target method + /// @param content Request content + /// @param dontRetry Should not retry? + JsonRPCResult::Ptr DoRequest( + std::u16string method, + std::shared_ptr<_v::Json::U16Document>& content, + bool dontRetry + ); + /// @brief Do a RPC request + /// @param method Target method + /// @param content Request content + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry? + void DoRequestAsync( + std::u16string method, + std::shared_ptr<_v::Json::U16Document>& content, + _u::CancellationToken token, + _v::CActionRef callback, + bool dontRetry + ); + /// @brief Do a RPC request + /// @param method Target method + /// @param rawResponse Web response + JsonRPCResult::Ptr HandleWebResponse(std::u16string method, WebResponse::Ptr& rawResponse); + + }; + +} ///< namespace CP_SDK::Network \ No newline at end of file diff --git a/shared/CP_SDK/Network/JsonRPCResult.hpp b/shared/CP_SDK/Network/JsonRPCResult.hpp new file mode 100644 index 0000000..190b321 --- /dev/null +++ b/shared/CP_SDK/Network/JsonRPCResult.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include "../Utils/Json.hpp" +#include "WebResponse.hpp" + +namespace CP_SDK::Network { + + namespace _v + { + using namespace CP_SDK::Utils; + } + + /// @brief JsonRPCResult + class CP_SDK_EXPORT JsonRPCResult + { + CP_SDK_NO_COPYMOVE_CTORS(JsonRPCResult); + CP_SDK_PRIV_TAG(); + + public: + WebResponse::Ptr RawResponse; + std::shared_ptr<_v::Json::U16Document> Result; + std::shared_ptr<_v::Json::U16Document> Error; + + public: + using Ptr = std::shared_ptr; + + /// @brief Constructor + /// @param rawResponse Raw web response + /// @param result Result json + /// @param error Json content + JsonRPCResult( + CP_SDK_PRIV_TAG_ARG(), + WebResponse::Ptr& rawResponse, + std::shared_ptr<_v::Json::U16Document> result, + std::shared_ptr<_v::Json::U16Document> error + ); + /// @brief Destructor + ~JsonRPCResult(); + + public: + /// @brief Create + /// @param rawResponse Raw web response + /// @param result Result json + /// @param error Json content + static Ptr Create( + WebResponse::Ptr& rawResponse, + std::shared_ptr<_v::Json::U16Document> result, + std::shared_ptr<_v::Json::U16Document> error + ); + + }; + +} ///< namespace CP_SDK::Network \ No newline at end of file diff --git a/src/CP_SDK/Network/JsonRPCClient.cpp b/src/CP_SDK/Network/JsonRPCClient.cpp new file mode 100644 index 0000000..a3b8813 --- /dev/null +++ b/src/CP_SDK/Network/JsonRPCClient.cpp @@ -0,0 +1,190 @@ +#include "CP_SDK/Network/JsonRPCClient.hpp" +#include "CP_SDK/Utils/Json.hpp" +#include "beatsaber-hook/shared/rapidjson/include/rapidjson/rapidjson.h" + +#include +#include + +using namespace System::Text; + +namespace CP_SDK::Network { + + /// @brief Constructor + /// @param webClient Web client instance + JsonRPCClient::JsonRPCClient(CP_SDK_PRIV_TAG_ARG(), WebClientCore::Ptr& webClient) + { + m_WebClient = webClient; + } + /// @brief Destructor + JsonRPCClient::~JsonRPCClient() + { + m_WebClient = nullptr; + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Create + /// @param webClient Web client instance + JsonRPCClient::Ptr JsonRPCClient::Create(WebClientCore::Ptr& webClient) + { + return std::make_shared(CP_SDK_PRIV_TAG_VAL(), webClient); + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Do a RPC request + /// @param method Target method + /// @param parameters Request parameters + /// @param dontRetry Should not retry? + JsonRPCResult::Ptr JsonRPCClient::Request(std::u16string_view method, std::shared_ptr<_v::Json::U16Value> parameters, bool dontRetry) + { + auto l_Method = std::u16string(method); + + std::shared_ptr<_v::Json::U16Document> l_Content(new _v::Json::U16Document()); + l_Content->SetObject(); + l_Content->AddMember(u"id", _v::Json::U16Value(1), l_Content->GetAllocator()); + l_Content->AddMember(u"jsonrpc", _v::Json::U16Value(u"2.0", l_Content->GetAllocator()), l_Content->GetAllocator()); + l_Content->AddMember(u"method", _v::Json::U16Value(l_Method.c_str(), l_Method.length(), l_Content->GetAllocator()), l_Content->GetAllocator()); + + if (parameters) + { + _v::Json::U16Value l_Copy; + l_Copy.CopyFrom(*parameters, l_Content->GetAllocator()); + + l_Content->AddMember(u"params", l_Copy, l_Content->GetAllocator()); + } + else + l_Content->AddMember(u"params", _v::Json::U16Value(rapidjson::kNullType), l_Content->GetAllocator()); + + return DoRequest(l_Method, l_Content, dontRetry); + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Do a RPC request + /// @param method Target method + /// @param parameters Request parameters + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry? + void JsonRPCClient::RequestAsync( + std::u16string_view method, + std::shared_ptr<_v::Json::U16Value> parameters, + _u::CancellationToken token, + _v::CActionRef callback, + bool dontRetry + ) + { + auto l_Method = std::u16string(method); + + std::shared_ptr<_v::Json::U16Document> l_Content(new _v::Json::U16Document()); + l_Content->SetObject(); + l_Content->AddMember(u"id", _v::Json::U16Value(1), l_Content->GetAllocator()); + l_Content->AddMember(u"jsonrpc", _v::Json::U16Value(u"2.0", l_Content->GetAllocator()), l_Content->GetAllocator()); + l_Content->AddMember(u"method", _v::Json::U16Value(l_Method.c_str(), l_Method.length(), l_Content->GetAllocator()), l_Content->GetAllocator()); + + if (parameters) + { + _v::Json::U16Value l_Copy; + l_Copy.CopyFrom(*parameters, l_Content->GetAllocator()); + + l_Content->AddMember(u"params", l_Copy, l_Content->GetAllocator()); + } + else + l_Content->AddMember(u"params", _v::Json::U16Value(rapidjson::kNullType), l_Content->GetAllocator()); + + DoRequestAsync(l_Method, l_Content, token, callback, dontRetry); + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Do a RPC request + /// @param method Target method + /// @param parameters Request content + /// @param dontRetry Should not retry? + JsonRPCResult::Ptr JsonRPCClient::DoRequest( + std::u16string method, + std::shared_ptr<_v::Json::U16Document>& content, + bool dontRetry + ) + { + auto l_Response = m_WebClient->Post( + u"", + WebContent::FromJson(content), + dontRetry + ); + return HandleWebResponse(method, l_Response); + } + /// @brief Do a RPC request + /// @param method Target method + /// @param content Request content + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry? + void JsonRPCClient::DoRequestAsync( + std::u16string method, + std::shared_ptr<_v::Json::U16Document>& content, + _u::CancellationToken token, + _v::CActionRef callback, + bool dontRetry + ) + { + auto l_Self = shared_from_this(); + m_WebClient->PostAsync( + u"", + WebContent::FromJson(content), + token, + [=](CP_SDK::Network::WebResponse::Ptr webResponse) -> void { + callback(l_Self->HandleWebResponse(method, webResponse)); + }, + dontRetry + ); + } + /// @brief Do a RPC request + /// @param method Target method + /// @param rawResponse Web response + JsonRPCResult::Ptr JsonRPCClient::HandleWebResponse(std::u16string method, WebResponse::Ptr& rawResponse) + { + if (!rawResponse) + return JsonRPCResult::Create(rawResponse, nullptr, nullptr); + + try + { + auto l_JsonResult = std::make_shared<_v::Json::U16Document>(); + if (!_v::Json::TryFromU16String(rawResponse->BodyString(), *l_JsonResult.get())) + return nullptr; + + auto l_ResultDocument = std::shared_ptr<_v::Json::U16Document>(nullptr); + if (l_JsonResult->HasMember(u"result")) + { + l_ResultDocument = std::make_shared<_v::Json::U16Document>(); + l_ResultDocument->CopyFrom(l_JsonResult->FindMember(u"result")->value, l_ResultDocument->GetAllocator()); + } + + auto l_ErrorDocument = std::shared_ptr<_v::Json::U16Document>(nullptr); + if (l_JsonResult->HasMember(u"error")) + { + l_ErrorDocument = std::make_shared<_v::Json::U16Document>(); + l_ErrorDocument->CopyFrom(l_JsonResult->FindMember(u"error")->value, l_ErrorDocument->GetAllocator()); + } + + return JsonRPCResult::Create( + rawResponse, + l_ResultDocument, + l_ErrorDocument + ); + } + catch (std::exception& l_Exception) + { + ChatPlexSDK::Logger()->Error(u"[CP_API_SDK.Network][JsonRPCClient.HandleResponse] Request " + method + u" failed parsing response:"); + ChatPlexSDK::Logger()->Error(l_Exception); + } + + return nullptr; + } + +} ///< namespace CP_SDK::Network \ No newline at end of file diff --git a/src/CP_SDK/Network/JsonRPCResult.cpp b/src/CP_SDK/Network/JsonRPCResult.cpp new file mode 100644 index 0000000..16c4656 --- /dev/null +++ b/src/CP_SDK/Network/JsonRPCResult.cpp @@ -0,0 +1,49 @@ +#include "CP_SDK/Network/JsonRPCResult.hpp" + +#include +#include + +using namespace System::Text; + +namespace CP_SDK::Network { + + /// @brief Constructor + /// @param rawResponse Raw web response + /// @param result Result json + /// @param error Json content + JsonRPCResult::JsonRPCResult( + CP_SDK_PRIV_TAG_ARG(), + WebResponse::Ptr& rawResponse, + std::shared_ptr<_v::Json::U16Document> result, + std::shared_ptr<_v::Json::U16Document> error + ) + { + RawResponse = rawResponse; + Result = result; + Error = error; + } + /// @brief Destructor + JsonRPCResult::~JsonRPCResult() + { + RawResponse = nullptr; + Result = nullptr; + Error = nullptr; + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Create + /// @param rawResponse Raw web response + /// @param result Result json + /// @param error Json content + JsonRPCResult::Ptr JsonRPCResult::Create( + WebResponse::Ptr& rawResponse, + std::shared_ptr<_v::Json::U16Document> result, + std::shared_ptr<_v::Json::U16Document> error + ) + { + return std::make_shared(CP_SDK_PRIV_TAG_VAL(), rawResponse, result, error); + } + +} ///< namespace CP_SDK::Network \ No newline at end of file From 8110b838dee458cec46cb8fc0bbb97232c591ed0 Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 6 Aug 2025 01:07:24 +0200 Subject: [PATCH 30/35] Fix build with the WebClientC/U changes --- shared/CP_SDK/Network/IWebClient.hpp | 14 +++++++------- shared/CP_SDK/Network/WebClientUnity.hpp | 7 +++++++ src/CP_SDK/Utils/Il2cpp.cpp | 2 ++ 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/shared/CP_SDK/Network/IWebClient.hpp b/shared/CP_SDK/Network/IWebClient.hpp index b7a6e98..67f7767 100644 --- a/shared/CP_SDK/Network/IWebClient.hpp +++ b/shared/CP_SDK/Network/IWebClient.hpp @@ -33,15 +33,15 @@ namespace CP_SDK::Network { public: /// @brief Get header - /// @param p_Name Header name - virtual std::u16string GetHeader(std::u16string_view p_Name) = 0; + /// @param name Header name + virtual std::u16string GetHeader(std::u16string_view name) = 0; /// @brief Set header - /// @param p_Name Header name - /// @param p_Value Header value - virtual void SetHeader(std::u16string_view p_Name, std::u16string_view p_Value) = 0; + /// @param name Header name + /// @param value Header value + virtual void SetHeader(std::u16string_view name, std::u16string_view value) = 0; /// @brief Remove header - /// @param p_Name Header name - virtual void RemoveHeader(std::u16string_view p_Name) = 0; + /// @param name Header name + virtual void RemoveHeader(std::u16string_view name) = 0; public: /// @brief Do Async GET query diff --git a/shared/CP_SDK/Network/WebClientUnity.hpp b/shared/CP_SDK/Network/WebClientUnity.hpp index 1029da7..fa1f7ab 100644 --- a/shared/CP_SDK/Network/WebClientUnity.hpp +++ b/shared/CP_SDK/Network/WebClientUnity.hpp @@ -105,6 +105,13 @@ namespace CP_SDK::Network { /// @param callback Callback /// @param dontRetry Should not retry virtual void PatchAsync(std::u16string_view url, const WebContent::Ptr& content, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) override final; + /// @brief Do Async PUT query + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + virtual void PutAsync(std::u16string_view url, const WebContent::Ptr& content, _u::CancellationToken token, _v::CActionRef callback, bool dontRetry = false) override final; /// @brief Do Async DELETE query /// @param url Target URL /// @param token Cancellation token diff --git a/src/CP_SDK/Utils/Il2cpp.cpp b/src/CP_SDK/Utils/Il2cpp.cpp index 7af7769..bf5e22a 100644 --- a/src/CP_SDK/Utils/Il2cpp.cpp +++ b/src/CP_SDK/Utils/Il2cpp.cpp @@ -1,6 +1,8 @@ #include "CP_SDK/Utils/Il2cpp.hpp" #include "CP_SDK/ChatPlexSDK.hpp" +#include "CP_SDK/Logging/PaperLogger.hpp" + namespace CP_SDK::Utils { std::vector Hooks::m_InstalledFuncs; From 854fe7965e46ba77cb0f2770fa2e6ce30d6fedcc Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 6 Aug 2025 01:15:27 +0200 Subject: [PATCH 31/35] Add ChatPlex web service --- shared/CP_SDK/CPConfig.hpp | 6 +- shared/CP_SDK/ChatPlexService.hpp | 118 ++++++++++ shared/CP_SDK/Utils/Json.hpp | 3 +- src/CP_SDK/CPConfig.cpp | 2 + src/CP_SDK/ChatPlexSDK.cpp | 6 +- src/CP_SDK/ChatPlexService.cpp | 318 ++++++++++++++++++++++++++ src/CP_SDK/Network/WebClientUnity.cpp | 10 + 7 files changed, 459 insertions(+), 4 deletions(-) create mode 100644 shared/CP_SDK/ChatPlexService.hpp create mode 100644 src/CP_SDK/ChatPlexService.cpp diff --git a/shared/CP_SDK/CPConfig.hpp b/shared/CP_SDK/CPConfig.hpp index 1cfd370..e1cf727 100644 --- a/shared/CP_SDK/CPConfig.hpp +++ b/shared/CP_SDK/CPConfig.hpp @@ -1,6 +1,7 @@ #pragma once #include "Config/JsonConfig.hpp" +#include namespace CP_SDK { @@ -10,8 +11,9 @@ namespace CP_SDK { CP_SDK_CONFIG_JSONCONFIG_INSTANCE_DECL(CPConfig); public: - bool FirstRun = true; - bool FirstChatServiceRun = true; + bool FirstRun = true; + bool FirstChatServiceRun = true; + std::u16string ChatPlexServiceToken = u""; protected: /// @brief Reset config to default diff --git a/shared/CP_SDK/ChatPlexService.hpp b/shared/CP_SDK/ChatPlexService.hpp new file mode 100644 index 0000000..913f5fa --- /dev/null +++ b/shared/CP_SDK/ChatPlexService.hpp @@ -0,0 +1,118 @@ +#pragma once + +#include "Network/JsonRPCResult.hpp" +#include "Network/JsonRPCClient.hpp" +#include "Utils/Event.hpp" +#include "Utils/Il2cpp.hpp" +#include "Utils/Delegate.hpp" + +#include +#include +#include + +namespace CP_SDK { + + namespace _u + { + using namespace il2cpp_utils; + using namespace System; + using namespace UnityEngine; + } + + namespace _v + { + using namespace CP_SDK::Network; + using namespace CP_SDK::Utils; + } + + /// @brief ChatPlexService + class CP_SDK_EXPORT ChatPlexService + { + CP_SDK_NO_DEF_CTORS(ChatPlexService); + + public: + enum class EState + { + Disconnected, + LinkRequest, + LinkWait, + Connecting, + + Connected, + + Error + }; + + private: + static bool m_ThreadCondition; + static _u::il2cpp_aware_thread* m_Thread; + static EState m_State; + static _v::WebClientCore::Ptr m_WebClientCore; + static _v::JsonRPCClient::Ptr m_JsonRPCClient; + static std::u16string m_LinkRequestID; + static std::u16string m_LinkCode; + static std::u16string m_LastError; + static std::u16string m_ActiveSubscription; + static std::vector m_UnlockedFeatures; + static std::queue<_v::Action<>> m_OnTokenReadyQueue; + static std::mutex m_OnTokenReadyQueueMutex; + static std::u16string m_DeviceName; + + public: + static const EState State(); + static const std::u16string_view Token(); + static const std::u16string_view LinkCode(); + static const std::u16string_view LastError(); + static const std::u16string_view ActiveSubscription(); + static const std::vector& UnlockedFeatures(); + + static _v::Event StateChanged; + + public: + /// @brief Init the service + static void Init(); + /// @brief Release the service + static void Release(); + + public: + /// @brief Add a callback to be called when the token is ready (call immediatly if ready) + /// @param action Callback to be caled + static void OnTokenReady(_v::CActionRef<> action); + + public: + /// @brief Start linking procedure + static void StartLinking(); + /// @brief Stop linking procedure + static void StopLinking(); + /// @brief Refresh the session + static void Refresh(); + /// @brief Disconnect and erase the saved connected application token + static void Disconnect(); + + private: + /// @brief Change state and notify listenners + static void ChangeState(const EState newState); + /// @brief Fire on token ready actions + static void FireOnTokenReady(); + + private: + /// @brief Thread function + static void ThreadRunner(); + + private: + /// @brief Is RPC call result a success result? + /// @param rpcResult Result of the RPC command + /// @return True if success + static bool IsRPCSuccess(_v::JsonRPCResult::Ptr& rpcResult); + + private: + /// @brief When we are Authed + /// @param rpcResult Result of the RPC command + static void OnAuthed(_v::JsonRPCResult::Ptr& rpcResult); + /// @brief On error received + /// @param rpcResult Result of the RPC command + static void OnError(_v::JsonRPCResult::Ptr& rpcResult); + + }; + +} ///< namespace CP_SDK \ No newline at end of file diff --git a/shared/CP_SDK/Utils/Json.hpp b/shared/CP_SDK/Utils/Json.hpp index 17ba1b1..bbea0d8 100644 --- a/shared/CP_SDK/Utils/Json.hpp +++ b/shared/CP_SDK/Utils/Json.hpp @@ -1,6 +1,8 @@ #pragma once #include "Il2cpp.hpp" +#include +#include "beatsaber-hook/shared/rapidjson/include/rapidjson/document.h" #include #include @@ -8,7 +10,6 @@ #include #include -#include #include #include #include diff --git a/src/CP_SDK/CPConfig.cpp b/src/CP_SDK/CPConfig.cpp index 7b46702..7eb208f 100644 --- a/src/CP_SDK/CPConfig.cpp +++ b/src/CP_SDK/CPConfig.cpp @@ -23,6 +23,7 @@ namespace CP_SDK { { CP_SDK_JSON_SERIALIZE_BOOL(FirstRun); CP_SDK_JSON_SERIALIZE_BOOL(FirstChatServiceRun); + CP_SDK_JSON_SERIALIZE_STRING(ChatPlexServiceToken); } /// @brief Read the document /// @param p_Document Source @@ -30,6 +31,7 @@ namespace CP_SDK { { CP_SDK_JSON_UNSERIALIZE_BOOL(FirstRun); CP_SDK_JSON_UNSERIALIZE_BOOL(FirstChatServiceRun); + CP_SDK_JSON_UNSERIALIZE_STRING(ChatPlexServiceToken); } //////////////////////////////////////////////////////////////////////////// diff --git a/src/CP_SDK/ChatPlexSDK.cpp b/src/CP_SDK/ChatPlexSDK.cpp index 6baed2f..ba55df2 100644 --- a/src/CP_SDK/ChatPlexSDK.cpp +++ b/src/CP_SDK/ChatPlexSDK.cpp @@ -9,6 +9,7 @@ #include "CP_SDK/Unity/MTMainThreadInvoker.hpp" #include "CP_SDK/Unity/MTThreadInvoker.hpp" #include "CP_SDK/ModuleBase.hpp" +#include "CP_SDK/ChatPlexService.hpp" #include @@ -51,7 +52,6 @@ namespace CP_SDK { { InstallWEBPCodecs(); - /// Init config Chat::Service::Init(); } /// @brief On assembly exit @@ -87,6 +87,8 @@ namespace CP_SDK { /// Init UI UI::UISystem::Init(); + + ChatPlexService::Init(); } catch (const std::exception& p_Exception) { @@ -102,6 +104,8 @@ namespace CP_SDK { OnGenericSceneChange.Clear(); OnGenericMenuSceneLoaded.Clear(); + ChatPlexService::Release(); + UI::UISystem::Destroy(); UI::LoadingProgressBar::Destroy(); diff --git a/src/CP_SDK/ChatPlexService.cpp b/src/CP_SDK/ChatPlexService.cpp new file mode 100644 index 0000000..f3191a9 --- /dev/null +++ b/src/CP_SDK/ChatPlexService.cpp @@ -0,0 +1,318 @@ +#include "CP_SDK/Unity/MTThreadInvoker.hpp" +#include "CP_SDK/ChatPlexService.hpp" +#include "CP_SDK/CPConfig.hpp" + +#include +#include +#include +#include +#include + +static std::u16string s_EmptyU16String = u""; + +namespace CP_SDK { + + bool ChatPlexService::m_ThreadCondition = true; + _u::il2cpp_aware_thread* ChatPlexService::m_Thread = nullptr; + ChatPlexService::EState ChatPlexService::m_State = ChatPlexService::EState::Disconnected; + _v::WebClientCore::Ptr ChatPlexService::m_WebClientCore = nullptr; + _v::JsonRPCClient::Ptr ChatPlexService::m_JsonRPCClient = nullptr; + std::u16string ChatPlexService::m_LinkRequestID = u""; + std::u16string ChatPlexService::m_LinkCode = u""; + std::u16string ChatPlexService::m_LastError = u""; + std::u16string ChatPlexService::m_ActiveSubscription = u""; + std::vector ChatPlexService::m_UnlockedFeatures; + std::queue<_v::Action<>> ChatPlexService::m_OnTokenReadyQueue; + std::mutex ChatPlexService::m_OnTokenReadyQueueMutex; + std::u16string ChatPlexService::m_DeviceName = u""; + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + const ChatPlexService::EState ChatPlexService::State() + { + return m_State; + } + const std::u16string_view ChatPlexService::Token() + { + return CPConfig::Instance()->ChatPlexServiceToken; + } + const std::u16string_view ChatPlexService::LinkCode() + { + return m_LinkCode; + } + const std::u16string_view ChatPlexService::LastError() + { + return m_LastError; + } + const std::u16string_view ChatPlexService::ActiveSubscription() + { + return m_State == EState::Connected ? m_ActiveSubscription : s_EmptyU16String; + } + const std::vector& ChatPlexService::UnlockedFeatures() + { + return *reinterpret_cast*>(&m_UnlockedFeatures); + } + + _v::Event ChatPlexService::StateChanged; + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Init the service + void ChatPlexService::Init() + { + m_WebClientCore = _v::WebClientCore::Make(u"https://api.chatplex.org/", _u::TimeSpan::FromSeconds(10), false, true); + m_JsonRPCClient = _v::JsonRPCClient::Create(m_WebClientCore); + + m_Thread = new _u::il2cpp_aware_thread(&ThreadRunner); + + m_DeviceName = _u::SystemInfo::GetDeviceName(); + } + /// @brief Release the service + void ChatPlexService::Release() + { + m_ThreadCondition = false; + m_Thread->join(); + + delete m_Thread; + m_Thread = nullptr; + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Add a callback to be called when the token is ready (call immediatly if ready) + /// @param action Callback to be caled + void ChatPlexService::OnTokenReady(_v::CActionRef<> action) + { + if (m_State == EState::Connected) + action(); + else + { + std::lock_guard l_Lock(m_OnTokenReadyQueueMutex); + m_OnTokenReadyQueue.push(action); + } + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Start linking procedure + void ChatPlexService::StartLinking() + { + if (m_State != EState::Disconnected) + return; + + ChangeState(EState::LinkRequest); + } + /// @brief Stop linking procedure + void ChatPlexService::StopLinking() + { + if (m_State != EState::LinkRequest && m_State != EState::LinkWait) + return; + + ChangeState(EState::Disconnected); + } + /// @brief Refresh the session + void ChatPlexService::Refresh() + { + ChangeState(EState::Disconnected); + } + /// @brief Disconnect and erase the saved connected application token + void ChatPlexService::Disconnect() + { + CPConfig::Instance()->ChatPlexServiceToken = u""; + CPConfig::Instance()->Save(); + + ChangeState(EState::Disconnected); + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Change state and notify listenners + void ChatPlexService::ChangeState(const EState newState) + { + auto l_OldState = m_State; + m_State = newState; + + Unity::MTThreadInvoker::EnqueueOnThread([=]() -> void { StateChanged(l_OldState, newState); }); + } + /// @brief Fire on token ready actions + void ChatPlexService::FireOnTokenReady() + { + m_OnTokenReadyQueueMutex.lock(); + while (!m_OnTokenReadyQueue.empty()) + { + auto l_Action = m_OnTokenReadyQueue.front(); + m_OnTokenReadyQueue.pop(); + m_OnTokenReadyQueueMutex.unlock(); + try + { + l_Action(); + } + catch (std::exception l_Exception) + { + ChatPlexSDK::Logger()->Error(u"[CP_SDK][ChatPlexService.FireOnTokenReady] Error:"); + ChatPlexSDK::Logger()->Error(l_Exception); + } + m_OnTokenReadyQueueMutex.lock(); + } + + m_OnTokenReadyQueueMutex.unlock(); + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Thread function + void ChatPlexService::ThreadRunner() + { + while (m_ThreadCondition) + { + if (m_State == EState::Disconnected && !CPConfig::Instance()->ChatPlexServiceToken.empty()) + { + m_WebClientCore->RemoveHeader(u"Authorization"); + + ChangeState(EState::Connecting); + + std::shared_ptr<_v::Json::U16Document> l_Content(new _v::Json::U16Document()); + l_Content->SetObject(); + l_Content->AddMember(u"ConnectedApplicationToken", _v::Json::U16Value(CPConfig::Instance()->ChatPlexServiceToken, l_Content->GetAllocator()), l_Content->GetAllocator()); + + auto l_Result = m_JsonRPCClient->Request( + u"Account_AuthByConnectedApplicationToken", + l_Content + ); + + if (IsRPCSuccess(l_Result)) + OnAuthed(l_Result); + else + { + if (l_Result->Result != nullptr && l_Result->Result->HasMember(u"Result") && (*l_Result->Result)[u"Result"].GetBool() == false) + { + CPConfig::Instance()->ChatPlexServiceToken = u""; + CPConfig::Instance()->Save(); + + ChangeState(EState::Disconnected); + } + else + OnError(l_Result); + } + } + else if (m_State == EState::LinkRequest) + { + std::shared_ptr<_v::Json::U16Document> l_Content(new _v::Json::U16Document()); + l_Content->SetObject(); + l_Content->AddMember(u"ApplicationIdentifier", _v::Json::U16Value(ChatPlexSDK::ProductName().data(), l_Content->GetAllocator()), l_Content->GetAllocator()); + l_Content->AddMember(u"ApplicationDeviceName", _v::Json::U16Value(m_DeviceName, l_Content->GetAllocator()), l_Content->GetAllocator()); + + auto l_Result = m_JsonRPCClient->Request( + u"ConnectedApplication_CreateLinkRequest", + l_Content + ); + + if (IsRPCSuccess(l_Result)) + { + auto& l_ResultR = *l_Result->Result.get(); + m_LinkRequestID = l_ResultR[u"RequestID"].GetString(); + m_LinkCode = l_ResultR[u"Code"].GetString(); + + ChangeState(EState::LinkWait); + } + else + OnError(l_Result); + } + else if (m_State == EState::LinkWait) + { + std::shared_ptr<_v::Json::U16Document> l_Content(new _v::Json::U16Document()); + l_Content->SetObject(); + l_Content->AddMember(u"RequestID", _v::Json::U16Value(m_LinkRequestID, l_Content->GetAllocator()), l_Content->GetAllocator()); + + auto l_Result = m_JsonRPCClient->Request( + u"ConnectedApplication_GetLinkRequestStatus", + l_Content + ); + + if (IsRPCSuccess(l_Result)) + { + auto& l_ResultR = *l_Result->Result.get(); + if (l_ResultR[u"ResultToken"].IsString()) + { + CPConfig::Instance()->ChatPlexServiceToken = l_ResultR[u"ResultToken"].GetString(); + CPConfig::Instance()->Save(); + + ChangeState(EState::Disconnected); + } + } + else + OnError(l_Result); + } + + if (m_State == EState::LinkWait) + std::this_thread::sleep_for(std::chrono::milliseconds(1500)); + else + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief Is RPC call result a success result? + /// @param rpcResult Result of the RPC command + /// @return True if success + bool ChatPlexService::IsRPCSuccess(_v::JsonRPCResult::Ptr& rpcResult) + { + if (rpcResult->Result == nullptr) + return false; + + auto& l_ResultR = *rpcResult->Result.get(); + return l_ResultR.HasMember(u"Result") && l_ResultR[u"Result"].GetBool() == true; + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief When we are Authed + /// @param rpcResult Result of the RPC command + void ChatPlexService::OnAuthed(_v::JsonRPCResult::Ptr& rpcResult) + { + auto& l_ResultR = *rpcResult->Result.get(); + m_ActiveSubscription = l_ResultR.HasMember(u"ActiveSubscription") ? l_ResultR[u"ActiveSubscription"].GetString() : u""; + + m_UnlockedFeatures.clear(); + if (l_ResultR.HasMember(u"UnlockedFeatures") && l_ResultR[u"UnlockedFeatures"].IsArray()) + { + auto l_Array = l_ResultR[u"UnlockedFeatures"].GetArray(); + for (auto& l_CurrentValue : l_Array) + { + if (!l_CurrentValue.IsString()) + continue; + + m_UnlockedFeatures.push_back(l_CurrentValue.GetString()); + } + } + + m_WebClientCore->SetHeader(u"Authorization", std::u16string(u"ConnectedApplicationToken ") + CPConfig::Instance()->ChatPlexServiceToken); + + ChangeState(EState::Connected); + FireOnTokenReady(); + } + /// @brief On error received + /// @param rpcResult Result of the RPC command + void ChatPlexService::OnError(_v::JsonRPCResult::Ptr& rpcResult) + { + std::u16string l_Error = u"Unknow server error!"; + if (rpcResult->Result != nullptr && rpcResult->Result->HasMember(u"Error")) + { + auto& l_ResultR = *rpcResult->Result.get(); + l_Error = l_ResultR[u"Error"].GetString(); + } + + m_LastError = l_Error; + ChangeState(EState::Error); + } + +} ///< namespace CP_SDK \ No newline at end of file diff --git a/src/CP_SDK/Network/WebClientUnity.cpp b/src/CP_SDK/Network/WebClientUnity.cpp index 3e6e4b9..0498722 100644 --- a/src/CP_SDK/Network/WebClientUnity.cpp +++ b/src/CP_SDK/Network/WebClientUnity.cpp @@ -142,6 +142,16 @@ namespace CP_SDK::Network { { Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"PatchAsync", u"PATCH", GetURL(url), content, token, callback, dontRetry, nullptr))); } + /// @brief Do Async PUT query + /// @param url Target URL + /// @param content Optional content to post + /// @param token Cancellation token + /// @param callback Callback + /// @param dontRetry Should not retry + void WebClientUnity::PutAsync(std::u16string_view url, const WebContent::Ptr& content, CancellationToken token, _v::CActionRef callback, bool dontRetry) + { + Unity::MTCoroutineStarter::EnqueueFromThread(custom_types::Helpers::CoroutineHelper::New(Coroutine_DoRequest(shared_from_this(), u"PutAsync", u"PUT", GetURL(url), content, token, callback, dontRetry, nullptr))); + } /// @brief Do Async GET query /// @param url Target URL /// @param token Cancellation token From ce7974b6ce91303503cac8278fab6e60d9a521c8 Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 6 Aug 2025 01:16:09 +0200 Subject: [PATCH 32/35] Add ChatPlex connection screen --- shared/CP_SDK/UI/Views/SettingsLeftView.hpp | 28 ++- src/CP_SDK/UI/Views/SettingsLeftView.cpp | 184 +++++++++++++++++++- 2 files changed, 205 insertions(+), 7 deletions(-) diff --git a/shared/CP_SDK/UI/Views/SettingsLeftView.hpp b/shared/CP_SDK/UI/Views/SettingsLeftView.hpp index 6eb9c7d..0a16836 100644 --- a/shared/CP_SDK/UI/Views/SettingsLeftView.hpp +++ b/shared/CP_SDK/UI/Views/SettingsLeftView.hpp @@ -1,7 +1,8 @@ #pragma once -#include "../ViewController.hpp" +#include "../../ChatPlexService.hpp" #include "../../XUI/XUI.hpp" +#include "../ViewController.hpp" namespace CP_SDK::UI::Views { @@ -23,9 +24,34 @@ namespace CP_SDK::UI::Views { CP_SDK_IL2CPP_DECLARE_DTOR_MONOBEHAVIOUR_CHILD(SettingsLeftView); CP_SDK_UI_VIEW_CONTROLLER_INSTANCE(); + private: + _v::XUIText::Ptr m_StatusText; + _v::XUIText::Ptr m_SubscriptionText; + _v::XUIPrimaryButton::Ptr m_PrimaryButton; + _v::XUISecondaryButton::Ptr m_SecondaryButton; + + private: + bool m_IsLinking = false; + private: /// @brief On view creation void OnViewCreation_Impl(); + /// @brief On view deactivation + void OnViewDeactivation_Impl(); + + private: + /// @brief On primary button pressed + void OnPrimaryButtonPressed(); + /// @brief On secondary button pressed + void OnSecondaryButtonPressed(); + /// @brief On Loading cancel + void OnLoadingCancel(); + + private: + /// @brief On ChatPlex service state change + /// @param oldState Old state + /// @param newState New state + void ChatPlexService_StateChanged(ChatPlexService::EState oldState, ChatPlexService::EState newState); }; diff --git a/src/CP_SDK/UI/Views/SettingsLeftView.cpp b/src/CP_SDK/UI/Views/SettingsLeftView.cpp index 3169108..f83b50f 100644 --- a/src/CP_SDK/UI/Views/SettingsLeftView.cpp +++ b/src/CP_SDK/UI/Views/SettingsLeftView.cpp @@ -1,9 +1,14 @@ #include "CP_SDK/UI/Views/SettingsLeftView.hpp" #include "CP_SDK/Unity/SpriteU.hpp" +#include "CP_SDK/Unity/MTMainThreadInvoker.hpp" +#include +#include using namespace CP_SDK::XUI; using namespace UnityEngine; +#include "assets.hpp" + namespace CP_SDK::UI::Views { CP_SDK_IL2CPP_INHERIT_INIT(SettingsLeftView); @@ -14,7 +19,8 @@ namespace CP_SDK::UI::Views { /// @brief Constructor CP_SDK_IL2CPP_DECLARE_CTOR_IMPL(SettingsLeftView) { - OnViewCreation = {this, &SettingsLeftView::OnViewCreation_Impl}; + OnViewCreation = {this, &SettingsLeftView::OnViewCreation_Impl}; + OnViewDeactivation = {this, &SettingsLeftView::OnViewDeactivation_Impl}; } /// @brief Destructor CP_SDK_IL2CPP_DECLARE_DTOR_MONOBEHAVIOUR_IMPL(SettingsLeftView) @@ -28,13 +34,179 @@ namespace CP_SDK::UI::Views { /// @brief On view creation void SettingsLeftView::OnViewCreation_Impl() { + auto l_Sprite = Unity::SpriteU::CreateFromRaw(Assets::ChatPlexLogoTransparent_png); + Templates::FullRectLayout({ - Templates::TitleBar(u"Tools"), + Templates::TitleBar(u"ChatPlex Account"), + + XUIPrimaryButton::Make(u"") + ->SetBackgroundSprite(nullptr) + ->SetIconSprite(l_Sprite) + ->SetWidth(52) + ->SetHeight(52) + ->AsShared(), + + XUIText::Make(u"Not connected") + ->Bind(&m_StatusText) + ->AsShared(), + + XUIText::Make(u" ") + ->Bind(&m_SubscriptionText) + ->AsShared(), + + XUIVLayout::Make({ + XUIPrimaryButton::Make(u"Connect", {this, &SettingsLeftView::OnPrimaryButtonPressed}) + ->Bind(&m_PrimaryButton) + ->AsShared(), + XUISecondaryButton::Make(u"Disconnect", {this, &SettingsLeftView::OnSecondaryButtonPressed}) + ->Bind(&m_SecondaryButton) + ->AsShared() + }) + ->SetWidth(60.0f) + ->SetPadding(0) + ->ForEachDirect([](XUIPrimaryButton* y) -> void + { + y->SetHeight(8.0f); + y->OnReady([](Components::CPrimaryButton* x) -> void + { + x->CSizeFitter()->horizontalFit = ContentSizeFitter::FitMode::Unconstrained; + }); + }) + ->ForEachDirect([](XUISecondaryButton* y ) -> void + { + y->SetHeight(8.0f); + y->OnReady([](Components::CSecondaryButton* x) -> void + { + x->CSizeFitter()->horizontalFit = ContentSizeFitter::FitMode::Unconstrained; + }); + }) + ->AsShared() + }) + ->SetBackground(true, std::nullopt, true) + ->BuildUI(get_transform()); + + ChatPlexService::StateChanged += {this, &SettingsLeftView::ChatPlexService_StateChanged}; + + ChatPlexService_StateChanged(ChatPlexService::State(), ChatPlexService::State()); + } + /// @brief On view deactivation + void SettingsLeftView::OnViewDeactivation_Impl() + { + ChatPlexService::StateChanged -= {this, &SettingsLeftView::ChatPlexService_StateChanged}; + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief On primary button pressed + void SettingsLeftView::OnPrimaryButtonPressed() + { + if (ChatPlexService::State() == ChatPlexService::EState::Disconnected) + { + m_IsLinking = true; + ChatPlexService::StartLinking(); + ShowLoadingModal(u"Loading...", true, {this, &SettingsLeftView::OnLoadingCancel}); + } + else if (ChatPlexService::State() == ChatPlexService::EState::Error || ChatPlexService::State() == ChatPlexService::EState::Connected) + { + ChatPlexService::Refresh(); + } + } + /// @brief On secondary button pressed + void SettingsLeftView::OnSecondaryButtonPressed() + { + ChatPlexService::Disconnect(); + } + /// @brief On Loading cancel + void SettingsLeftView::OnLoadingCancel() + { + if (ChatPlexService::State() == ChatPlexService::EState::LinkRequest || ChatPlexService::State() == ChatPlexService::EState::LinkWait) + { + m_IsLinking = false; + ChatPlexService::StopLinking(); + } + } + + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + /// @brief On ChatPlex service state change + /// @param oldState Old state + /// @param newState New state + void SettingsLeftView::ChatPlexService_StateChanged(ChatPlexService::EState oldState, ChatPlexService::EState newState) + { + Unity::MTMainThreadInvoker::Enqueue([this, oldState, newState]() -> void + { + if (m_IsLinking) + { + if (newState == ChatPlexService::EState::LinkRequest) + ShowLoadingModal(u"Creating link request...", true, {this, &SettingsLeftView::OnLoadingCancel}); + else if (newState == ChatPlexService::EState::LinkWait) + ShowLoadingModal( + std::u16string(u"Go to https://chatplex.org/link and the input following code\n") + ChatPlexService::LinkCode(), + true, + {this, &SettingsLeftView::OnLoadingCancel} + ); + else if (newState == ChatPlexService::EState::Error) + { + m_IsLinking = false; + + CloseLoadingModal(); + ShowMessageModal(u"Error: " + ChatPlexService::LastError()); + } + else + { + m_IsLinking = false; + CloseLoadingModal(); + } + } + + switch (newState) + { + case ChatPlexService::EState::Disconnected: + m_StatusText->SetColor(Color::get_red()); + m_StatusText->SetText(u"Disconected!"); + m_PrimaryButton->SetInteractable(true); + m_PrimaryButton->SetText(u"Connect"); + m_SecondaryButton->SetInteractable(false); + break; + + case ChatPlexService::EState::Error: + m_StatusText->SetColor(Color::get_red()); + m_StatusText->SetText(u"Disconected, error!"); + m_PrimaryButton->SetInteractable(true); + m_PrimaryButton->SetText(u"Connect"); + m_SecondaryButton->SetInteractable(false); + break; + + case ChatPlexService::EState::Connecting: + m_StatusText->SetColor(Color::get_blue()); + m_StatusText->SetText(u"Connecting..."); + m_PrimaryButton->SetInteractable(false); + m_PrimaryButton->SetText(u"Connect"); + m_SecondaryButton->SetInteractable(false); + break; + + case ChatPlexService::EState::LinkRequest: + case ChatPlexService::EState::LinkWait: + m_StatusText->SetColor(Color::get_blue()); + m_StatusText->SetText(u"Linking account..."); + m_PrimaryButton->SetInteractable(false); + m_PrimaryButton->SetText(u"Connect"); + m_SecondaryButton->SetInteractable(false); + break; + + case ChatPlexService::EState::Connected: + m_StatusText->SetColor(Color::get_green()); + m_StatusText->SetText(u"Connected!"); + m_PrimaryButton->SetInteractable(true); + m_PrimaryButton->SetText(u"Refresh"); + m_SecondaryButton->SetInteractable(true); + break; + } - XUIText::Make(u"No available tools at the moment!")->AsShared() - }) - ->SetBackground(true, std::nullopt, true) - ->BuildUI(get_transform()); + m_SubscriptionText->Element()->SetText(ChatPlexService::ActiveSubscription()); + }); } } ///< namespace CP_SDK::UI::Views \ No newline at end of file From 3cd4e387e3211a13250b15c003acc93976c18a91 Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 6 Aug 2025 20:36:26 +0200 Subject: [PATCH 33/35] Add missing include --- shared/CP_SDK/ChatPlexService.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/shared/CP_SDK/ChatPlexService.hpp b/shared/CP_SDK/ChatPlexService.hpp index 913f5fa..cb6d11d 100644 --- a/shared/CP_SDK/ChatPlexService.hpp +++ b/shared/CP_SDK/ChatPlexService.hpp @@ -7,6 +7,7 @@ #include "Utils/Delegate.hpp" #include +#include #include #include From 9ccd325626b4ec219aaf26a68e7192090e4bfb9a Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 6 Aug 2025 22:34:07 +0200 Subject: [PATCH 34/35] Version 6.4.1 for BS 1.40.8 --- include/git_info.h | 2 +- mod.json | 24 ++++---- mod.template.json | 2 +- qpm.json | 19 +++--- qpm.shared.json | 87 +++++++++++++-------------- src/CP_SDK/Network/WebClientCore.cpp | 38 +++++++++--- src/CP_SDK_BS/Game/LevelSelection.cpp | 12 ++-- 7 files changed, 99 insertions(+), 85 deletions(-) diff --git a/include/git_info.h b/include/git_info.h index 5c0b8ca..3d19d83 100644 --- a/include/git_info.h +++ b/include/git_info.h @@ -1,5 +1,5 @@ #pragma once #define GIT_USER "HardCPP" #define GIT_BRANCH "dev" -#define GIT_COMMIT 0xc20158d +#define GIT_COMMIT 0xeca090f #define GIT_MODIFIED 1 diff --git a/mod.json b/mod.json index 2b2eee2..5b4d3dd 100644 --- a/mod.json +++ b/mod.json @@ -5,36 +5,36 @@ "id": "chatplex-sdk-bs", "modloader": "Scotland2", "author": "HardCPP", - "version": "6.3.2", + "version": "6.4.1", "packageId": "com.beatgames.beatsaber", - "packageVersion": "1.40.4_5283", + "packageVersion": "1.40.8_7379", "description": "ChatPlex BeatSaber modding SDK (Dependence for other mods)", "coverImage": "cover.png", "dependencies": [ { - "version": "^6.4.1", + "version": "^6.4.2", "id": "beatsaber-hook", - "downloadIfMissing": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.1/beatsaber-hook.qmod" + "downloadIfMissing": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.2/beatsaber-hook.qmod" }, { - "version": "^0.18.2", + "version": "^0.18.3", "id": "custom-types", - "downloadIfMissing": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.18.2/CustomTypes.qmod" + "downloadIfMissing": "https://github.com/QuestPackageManager/Il2CppQuestTypePatching/releases/download/v0.18.3/CustomTypes.qmod" }, { - "version": "^0.4.51", + "version": "^0.4.55", "id": "bsml", - "downloadIfMissing": "https://github.com/bsq-ports/Quest-BSML/releases/download/v0.4.51/BSML.qmod" + "downloadIfMissing": "https://github.com/bsq-ports/Quest-BSML/releases/download/v0.4.55/BSML.qmod" }, { - "version": "^1.1.20", + "version": "^1.1.24", "id": "songcore", - "downloadIfMissing": "https://github.com/raineaeternal/Quest-SongCore/releases/download/v1.1.20/SongCore.qmod" + "downloadIfMissing": "https://github.com/raineaeternal/Quest-SongCore/releases/download/v1.1.24/SongCore.qmod" }, { - "version": "^4.6.1", + "version": "^4.6.4", "id": "paper2_scotland2", - "downloadIfMissing": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.2/paper2_scotland2.qmod" + "downloadIfMissing": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.4/paper2_scotland2.qmod" } ], "modFiles": [], diff --git a/mod.template.json b/mod.template.json index 63417e4..a4e3f1a 100644 --- a/mod.template.json +++ b/mod.template.json @@ -6,7 +6,7 @@ "author": "HardCPP", "version": "${version}", "packageId": "com.beatgames.beatsaber", - "packageVersion": "1.40.4_5283", + "packageVersion": "1.40.8_7379", "description": "ChatPlex BeatSaber modding SDK (Dependence for other mods)", "coverImage": "cover.png", "dependencies": [], diff --git a/qpm.json b/qpm.json index e7a6de9..4b98143 100644 --- a/qpm.json +++ b/qpm.json @@ -5,7 +5,7 @@ "info": { "name": "ChatPlexSDK-BS", "id": "chatplex-sdk-bs", - "version": "6.4.0", + "version": "6.4.1", "url": "https://github.com/hardcpp/QuestChatPlexSDK-BS", "additionalData": { "overrideSoName": "libchatplex-sdk-bs.so", @@ -47,17 +47,17 @@ "dependencies": [ { "id": "beatsaber-hook", - "versionRange": "^6.4.1", + "versionRange": "^6.4.2", "additionalData": {} }, { "id": "bs-cordl", - "versionRange": "^4004.0.0", + "versionRange": "^4008.*", "additionalData": {} }, { "id": "custom-types", - "versionRange": "^0.18.2", + "versionRange": "^0.18.3", "additionalData": {} }, { @@ -70,19 +70,14 @@ }, { "id": "bsml", - "versionRange": "^0.4.51", + "versionRange": "^0.4.55", "additionalData": { "private": true } }, - { - "id": "libil2cpp", - "versionRange": "^0.4.0", - "additionalData": {} - }, { "id": "songcore", - "versionRange": "^1.1.20", + "versionRange": "^1.1.24", "additionalData": { "private": true } @@ -96,7 +91,7 @@ }, { "id": "paper2_scotland2", - "versionRange": "^4.6.1", + "versionRange": "^4.6.4", "additionalData": {} }, { diff --git a/qpm.shared.json b/qpm.shared.json index ca32904..81aebe6 100644 --- a/qpm.shared.json +++ b/qpm.shared.json @@ -7,7 +7,7 @@ "info": { "name": "ChatPlexSDK-BS", "id": "chatplex-sdk-bs", - "version": "6.4.0", + "version": "6.4.1", "url": "https://github.com/hardcpp/QuestChatPlexSDK-BS", "additionalData": { "overrideSoName": "libchatplex-sdk-bs.so", @@ -49,17 +49,17 @@ "dependencies": [ { "id": "beatsaber-hook", - "versionRange": "^6.4.1", + "versionRange": "^6.4.2", "additionalData": {} }, { "id": "bs-cordl", - "versionRange": "^4004.0.0", + "versionRange": "4008.*", "additionalData": {} }, { "id": "custom-types", - "versionRange": "^0.18.2", + "versionRange": "^0.18.3", "additionalData": {} }, { @@ -72,19 +72,14 @@ }, { "id": "bsml", - "versionRange": "^0.4.51", + "versionRange": "^0.4.55", "additionalData": { "private": true } }, - { - "id": "libil2cpp", - "versionRange": "^0.4.0", - "additionalData": {} - }, { "id": "songcore", - "versionRange": "^1.1.20", + "versionRange": "^1.1.24", "additionalData": { "private": true } @@ -98,7 +93,7 @@ }, { "id": "paper2_scotland2", - "versionRange": "^4.6.1", + "versionRange": "^4.6.4", "additionalData": {} }, { @@ -117,17 +112,17 @@ { "dependency": { "id": "bsml", - "versionRange": "=0.4.51", + "versionRange": "=0.4.55", "additionalData": { - "soLink": "https://github.com/bsq-ports/Quest-BSML/releases/download/v0.4.51/libbsml.so", - "debugSoLink": "https://github.com/bsq-ports/Quest-BSML/releases/download/v0.4.51/debug_libbsml.so", + "soLink": "https://github.com/bsq-ports/Quest-BSML/releases/download/v0.4.55/libbsml.so", + "debugSoLink": "https://github.com/bsq-ports/Quest-BSML/releases/download/v0.4.55/debug_libbsml.so", "overrideSoName": "libbsml.so", - "modLink": "https://github.com/bsq-ports/Quest-BSML/releases/download/v0.4.51/BSML.qmod", - "branchName": "version/v0_4_51", + "modLink": "https://github.com/bsq-ports/Quest-BSML/releases/download/v0.4.55/BSML.qmod", + "branchName": "version/v0_4_55", "cmake": true } }, - "version": "0.4.51" + "version": "0.4.55" }, { "dependency": { @@ -204,10 +199,10 @@ { "dependency": { "id": "bs-cordl", - "versionRange": "=4004.0.0", + "versionRange": "=4008.0.0", "additionalData": { "headersOnly": true, - "branchName": "version/v4004_0_0", + "branchName": "version/v4008_0_0", "compileOptions": { "includePaths": [ "include" @@ -223,7 +218,7 @@ } } }, - "version": "4004.0.0" + "version": "4008.0.0" }, { "dependency": { @@ -253,17 +248,17 @@ { "dependency": { "id": "songcore", - "versionRange": "=1.1.20", + "versionRange": "=1.1.24", "additionalData": { - "soLink": "https://github.com/raineaeternal/Quest-SongCore/releases/download/v1.1.20/libsongcore.so", - "debugSoLink": "https://github.com/raineaeternal/Quest-SongCore/releases/download/v1.1.20/debug_libsongcore.so", + "soLink": "https://github.com/raineaeternal/Quest-SongCore/releases/download/v1.1.24/libsongcore.so", + "debugSoLink": "https://github.com/raineaeternal/Quest-SongCore/releases/download/v1.1.24/debug_libsongcore.so", "overrideSoName": "libsongcore.so", - "modLink": "https://github.com/raineaeternal/Quest-SongCore/releases/download/v1.1.20/SongCore.qmod", - "branchName": "version/v1_1_20", + "modLink": "https://github.com/raineaeternal/Quest-SongCore/releases/download/v1.1.24/SongCore.qmod", + "branchName": "version/v1_1_24", "cmake": true } }, - "version": "1.1.20" + "version": "1.1.24" }, { "dependency": { @@ -285,6 +280,25 @@ }, "version": "6.4.2" }, + { + "dependency": { + "id": "fmt", + "versionRange": "=11.0.2", + "additionalData": { + "headersOnly": true, + "branchName": "version/v11_0_2", + "compileOptions": { + "systemIncludes": [ + "fmt/include/" + ], + "cppFlags": [ + "-DFMT_HEADER_ONLY" + ] + } + } + }, + "version": "11.0.2" + }, { "dependency": { "id": "scotland2", @@ -312,25 +326,6 @@ } }, "version": "10.0.0" - }, - { - "dependency": { - "id": "fmt", - "versionRange": "=11.0.2", - "additionalData": { - "headersOnly": true, - "branchName": "version/v11_0_2", - "compileOptions": { - "systemIncludes": [ - "fmt/include/" - ], - "cppFlags": [ - "-DFMT_HEADER_ONLY" - ] - } - } - }, - "version": "11.0.2" } ] } \ No newline at end of file diff --git a/src/CP_SDK/Network/WebClientCore.cpp b/src/CP_SDK/Network/WebClientCore.cpp index 83e8b27..d5eb88b 100644 --- a/src/CP_SDK/Network/WebClientCore.cpp +++ b/src/CP_SDK/Network/WebClientCore.cpp @@ -130,6 +130,7 @@ namespace CP_SDK::Network { /// @param progress Progress reporter WebResponse::Ptr WebClientCore::Get(std::u16string_view url, bool dontRetry, _v::CActionRef progress) { + auto l_IsDone = false; auto l_Reply = WebResponse::Ptr(nullptr); DoRequest( @@ -139,11 +140,14 @@ namespace CP_SDK::Network { GetURL(url), nullptr, CancellationToken::get_None(), - [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; l_IsDone = true; }, dontRetry, progress ); + while (!l_IsDone) + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + return l_Reply; } /// @brief Do GET query @@ -152,6 +156,7 @@ namespace CP_SDK::Network { /// @param progress Progress reporter WebResponse::Ptr WebClientCore::Download(std::u16string_view url, bool dontRetry, _v::CActionRef progress) { + auto l_IsDone = false; auto l_Reply = WebResponse::Ptr(nullptr); DoRequest( @@ -161,11 +166,14 @@ namespace CP_SDK::Network { GetURL(url), nullptr, CancellationToken::get_None(), - [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; l_IsDone = true; }, dontRetry, progress ); + while (!l_IsDone) + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + return l_Reply; } /// @brief Do POST query @@ -174,6 +182,7 @@ namespace CP_SDK::Network { /// @param dontRetry Should not retry WebResponse::Ptr WebClientCore::Post(std::u16string_view url, const WebContent::Ptr& content, bool dontRetry) { + auto l_IsDone = false; auto l_Reply = WebResponse::Ptr(nullptr); DoRequest( @@ -183,11 +192,14 @@ namespace CP_SDK::Network { GetURL(url), content, CancellationToken::get_None(), - [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; l_IsDone = true; }, dontRetry, nullptr ); + while (!l_IsDone) + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + return l_Reply; } /// @brief Do PATCH query @@ -196,6 +208,7 @@ namespace CP_SDK::Network { /// @param dontRetry Should not retry WebResponse::Ptr WebClientCore::Patch(std::u16string_view url, const WebContent::Ptr& content, bool dontRetry) { + auto l_IsDone = false; auto l_Reply = WebResponse::Ptr(nullptr); DoRequest( @@ -205,11 +218,14 @@ namespace CP_SDK::Network { GetURL(url), content, CancellationToken::get_None(), - [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; l_IsDone = true; }, dontRetry, nullptr ); + while (!l_IsDone) + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + return l_Reply; } /// @brief Do PUT query @@ -218,6 +234,7 @@ namespace CP_SDK::Network { /// @param dontRetry Should not retry WebResponse::Ptr WebClientCore::Put(std::u16string_view url, const WebContent::Ptr& content, bool dontRetry) { + auto l_IsDone = false; auto l_Reply = WebResponse::Ptr(nullptr); DoRequest( @@ -227,11 +244,14 @@ namespace CP_SDK::Network { GetURL(url), content, CancellationToken::get_None(), - [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; l_IsDone = true; }, dontRetry, nullptr ); + while (!l_IsDone) + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + return l_Reply; } /// @brief Do DELETE query @@ -239,6 +259,7 @@ namespace CP_SDK::Network { /// @param dontRetry Should not retry WebResponse::Ptr WebClientCore::Delete(std::u16string_view url, bool dontRetry) { + auto l_IsDone = false; auto l_Reply = WebResponse::Ptr(nullptr); DoRequest( @@ -248,11 +269,14 @@ namespace CP_SDK::Network { GetURL(url), nullptr, CancellationToken::get_None(), - [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; }, + [&](WebResponse::Ptr p_Result) -> void { l_Reply = p_Result; l_IsDone = true; }, dontRetry, nullptr ); + while (!l_IsDone) + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + return l_Reply; } @@ -461,7 +485,7 @@ namespace CP_SDK::Network { { if (httpMethod == u"POST") curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_CUSTOMREQUEST, "POST"); - if (httpMethod == u"PATCH") + else if (httpMethod == u"PATCH") curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_CUSTOMREQUEST, "PATCH"); else curl_easy_setopt(l_ScopedCURL.Instance, CURLOPT_CUSTOMREQUEST, "PUT"); diff --git a/src/CP_SDK_BS/Game/LevelSelection.cpp b/src/CP_SDK_BS/Game/LevelSelection.cpp index 8d36517..d925926 100644 --- a/src/CP_SDK_BS/Game/LevelSelection.cpp +++ b/src/CP_SDK_BS/Game/LevelSelection.cpp @@ -195,23 +195,23 @@ namespace CP_SDK_BS::Game { try { m_PreventLevelSearchViewController_didStartLoadingEvent = true; - p_LevelSearchViewController->ResetAllFilterSettings(false); + //p_LevelSearchViewController->ResetAllFilterSettings(false); auto l_Filter = GlobalNamespace::LevelFilter(); - l_Filter.songOwned = false; + l_Filter.songOwned = true; l_Filter.songNotOwned = false; l_Filter.songUnplayed = false; - l_Filter.difficulties = _u::BeatmapDifficultyMask(); - l_Filter.songPacks = _u::SongPackMask(); + l_Filter.difficulties = _u::BeatmapDifficultyMask(0); + l_Filter.songPacks = _u::SongPackMask::get_all(); l_Filter.characteristicSerializedName = nullptr; l_Filter.minBpm = 0.0f; l_Filter.maxBpm = 0.0f; - l_Filter.sensitivity = _u::PlayerSensitivityFlag(); + l_Filter.sensitivity = _u::PlayerSensitivityFlag::Unknown; l_Filter.limitIds = ArrayW({ m_PendingFilterSong->___levelID }); l_Filter.searchText = u""; - p_LevelSearchViewController->ResetAllFilterSettings(false); + //p_LevelSearchViewController->ResetAllFilterSettings(false); p_LevelSearchViewController->Refresh( byref(l_Filter) ); From 06fa39e8842bb0497366004953edeed75d594b9b Mon Sep 17 00:00:00 2001 From: HardCPP Date: Wed, 6 Aug 2025 22:46:09 +0200 Subject: [PATCH 35/35] Sanaity check --- mod.json | 3 ++- src/CP_SDK_BS/Game/LevelSelection.cpp | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mod.json b/mod.json index f31175e..5b4d3dd 100644 --- a/mod.json +++ b/mod.json @@ -37,7 +37,8 @@ "downloadIfMissing": "https://github.com/Fernthedev/paperlog/releases/download/v4.6.4/paper2_scotland2.qmod" } ], - "modFiles": [ + "modFiles": [], + "lateModFiles": [ "libchatplex-sdk-bs.so" ], "libraryFiles": [], diff --git a/src/CP_SDK_BS/Game/LevelSelection.cpp b/src/CP_SDK_BS/Game/LevelSelection.cpp index 06065e4..d925926 100644 --- a/src/CP_SDK_BS/Game/LevelSelection.cpp +++ b/src/CP_SDK_BS/Game/LevelSelection.cpp @@ -198,7 +198,6 @@ namespace CP_SDK_BS::Game { //p_LevelSearchViewController->ResetAllFilterSettings(false); auto l_Filter = GlobalNamespace::LevelFilter(); - l_Filter.songOwned = true; l_Filter.songNotOwned = false; l_Filter.songUnplayed = false; @@ -213,7 +212,6 @@ namespace CP_SDK_BS::Game { l_Filter.searchText = u""; //p_LevelSearchViewController->ResetAllFilterSettings(false); - p_LevelSearchViewController->Refresh( byref(l_Filter) );