From 7ea5df3b84a338fad70ab527b6384dd3a44df349 Mon Sep 17 00:00:00 2001 From: kkEngine <78795688+kkEngine@users.noreply.github.com> Date: Sun, 28 Jul 2024 18:46:04 +0300 Subject: [PATCH] - Released version 1.0 - Modified README --- CMakeLists.txt | 8 +- README.md | 95 ++++++++++++++++++- .../Controllers/PublicAPIController.h | 2 +- src/UIPlatform/NirnLabUIPlatformAPI/API.h | 6 +- src/UIPlatform/NirnLabUIPlatformAPI/Version.h | 16 ++-- src/UIPlatform/Utils/PathUtils.h | 4 +- src/UIPlatform/main.cpp | 6 +- src/UIPlatformTest/NirnLabUIPlatformAPI/API.h | 6 +- .../NirnLabUIPlatformAPI/Version.h | 16 ++-- src/UIPlatformTest/main.cpp | 28 +++--- src/UIPlugin/main.cpp | 4 +- src/Version.h.in | 4 +- 12 files changed, 140 insertions(+), 55 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 959a45c..6b9e007 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,10 +3,10 @@ cmake_minimum_required(VERSION 3.23) option(BUILD_AS_SHARED "Build as dll skse plugin else build as static lib" ON) # Version -set(LIB_MAJOR_VERSION 0) -set(LIB_MINOR_VERSION 1) -set(API_MAJOR_VERSION 0) -set(API_MINOR_VERSION 1) +set(LIB_MAJOR_VERSION 1) +set(LIB_MINOR_VERSION 0) +set(API_MAJOR_VERSION 1) +set(API_MINOR_VERSION 0) # VCPKG config string(REPLACE "\\" "/" ENV_VCPKG_ROOT "$ENV{VCPKG_ROOT}") diff --git a/README.md b/README.md index 721e085..42734f5 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,86 @@ UI platform for Skyrim with CEF (Chromium Embedded Framework) integration and more. You can create interface based on html5, css, javascript. This project is a part of NirnLab project. -## NirnLab +## Features +- Chromium browser is rendered in Skyrim's native menu (can take screenshots, using native cursor) +- Creating multiple browsers +- Changing keyboard layout out of the box (SHIFT-CTRL or SHIFT-ALT) including console +- Binding js to cpp function callbacks +- Auto closing CEF processes in case of the game crash -NirnLab is a competitive MMO-like mod for Skyrim which will be announced after the main part is completed. -If you want to follow the progress and news, subscribe to [![Discord](https://img.shields.io/discord/1004071212361711678?label=Discord&logo=Discord)](https://discord.gg/3YDR4pDJYy). +## Usage as skse plugin (preferred) +You can find all public APIs in this [folder](https://github.com/kkEngine/NirnLabUIPlatform/tree/main/src/UIPlatform/NirnLabUIPlatformAPI). Copy and include the folder in your project (included in release). +Test [examples](https://github.com/kkEngine/NirnLabUIPlatform/tree/main/src/UIPlatformTest) + +# Get API (CommonLibSSE example) +First of all we need to check the API version. If major versions are defferent i don't recommend continuing (may crash). + +Send request version message when all plugin loaded (kPostPostLoad) +```cpp +SKSE::GetMessagingInterface()->Dispatch(NL::UI::APIMessageType::RequestVersion, nullptr, 0, LibVersion::PROJECT_NAME); +``` +Response message will contain API and Lib versions +```cpp +SKSE::GetMessagingInterface()->RegisterListener(LibVersion::PROJECT_NAME, [](SKSE::MessagingInterface::Message* a_msg) { + switch (a_msg->type) + { + case NL::UI::APIMessageType::ResponseVersion: + // API and Lib versions + const auto versionInfo = reinterpret_cast(a_msg->data); + break; + } +}); +``` + +Check the API version and if it's ok, request API +```cpp +SKSE::GetMessagingInterface()->Dispatch(NL::UI::APIMessageType::RequestAPI, nullptr, 0, NL::UI::LibVersion::PROJECT_NAME); +``` +When a first plugin requests API, library and CEF will initialize +Response message will contain API struct. You can save the API pointer and use it in the future. +```cpp +SKSE::GetMessagingInterface()->RegisterListener(LibVersion::PROJECT_NAME, [](SKSE::MessagingInterface::Message* a_msg) { + switch (a_msg->type) + { + case NL::UI::APIMessageType::ResponseAPI: + auto api = reinterpret_cast(a_msg->data)->API; + break; + } +}); +``` + +# Create browser +```cpp +NL::CEF::IBrowser* g_browser = nullptr; +NL::UI::IUIPlatformAPI::BrowserRefHandle g_browserHandle = NL::UI::IUIPlatformAPI::InvalidBrowserRefHandle; + +void CreateBrowser(NL::UI::IUIPlatformAPI* a_api) +{ + g_browserHandle = a_api->AddOrGetBrowser("MyPluginCEF", nullptr, 0, "https://www.youtube.com", g_browser); + if (g_browserHandle == NL::UI::IUIPlatformAPI::InvalidBrowserRefHandle) + { + spdlog::error("browser handle is invalid"); + return; + } -## Examples -todo + // Keep "g_browserHandle" util you need a browser + // When the browser is no longer needed, release it using a_api->ReleaseBrowserHandle(); + // If this was the last browser handle, the browser will be deleted + + // Check NL::CEF::IBrowser interface for more features + m_browser->ToggleBrowserFocusByKeys(RE::BSKeyboardDevice::Keys::kF6, 0); + g_browser->ToggleBrowserVisibleByKeys(RE::BSKeyboardDevice::Keys::kF7, 0); + g_browser->SetBrowserFocused(true); + g_browser->ExecuteJavaScript("window.myString = 'Hello CEF'"); +} + +void ReleaseBrowser(NL::UI::IUIPlatformAPI::BrowserRefHandle a_handle) +{ + g_browser = nullptr; + a_api->ReleaseBrowserHandle(g_browserHandle); + g_browserHandle = NL::UI::IUIPlatformAPI::InvalidBrowserRefHandle; +} +``` ## Dev and build requirements - CMake 3.23+ @@ -21,5 +94,17 @@ todo - Address library (https://www.nexusmods.com/skyrimspecialedition/mods/32444) - SKSE (https://skse.silverlock.org/) +## NirnLab + +NirnLab is a competitive MMO-like mod for Skyrim which will be announced after the main part is completed. +If you want to follow the progress and news, subscribe to [![Discord](https://img.shields.io/discord/1004071212361711678?label=Discord&logo=Discord)](https://discord.gg/3YDR4pDJYy). + +### Thanks to +[@Pospelove](https://github.com/Pospelove) +[Skymp](https://github.com/skyrim-multiplayer/skymp) +[CommonLibSSE](https://github.com/Ryan-rsm-McKenzie/CommonLibSSE) +[CommonLibSSE-NG](https://github.com/CharmedBaryon/CommonLibSSE-NG) +Chromium Embedded Framework ([CEF](https://bitbucket.org/chromiumembedded/cef)) + ### License MIT diff --git a/src/UIPlatform/Controllers/PublicAPIController.h b/src/UIPlatform/Controllers/PublicAPIController.h index 48978aa..1b651c2 100644 --- a/src/UIPlatform/Controllers/PublicAPIController.h +++ b/src/UIPlatform/Controllers/PublicAPIController.h @@ -19,7 +19,7 @@ namespace NL::Controllers }; protected: - NL::UI::ResponseVersionMessage m_rvMessage{LibVersion::AS_INT, APIVersion::AS_INT}; + NL::UI::ResponseVersionMessage m_rvMessage{NL::UI::LibVersion::AS_INT, NL::UI::APIVersion::AS_INT}; NL::UI::ResponseAPIMessage m_rAPIMessage{this}; std::atomic m_currentRefHandle{1}; diff --git a/src/UIPlatform/NirnLabUIPlatformAPI/API.h b/src/UIPlatform/NirnLabUIPlatformAPI/API.h index 7d05021..6239d2b 100644 --- a/src/UIPlatform/NirnLabUIPlatformAPI/API.h +++ b/src/UIPlatform/NirnLabUIPlatformAPI/API.h @@ -47,7 +47,7 @@ namespace NL::UI /// /// Response with version info. See ResponseVersionMessage struct. - /// You should check current API version (APIVersion::AS_INT) and version in response. + /// You should check current API version (NL::UI::APIVersion::AS_INT) and version in response. /// It is not guaranteed that the major versions are compatible. In this case, I recommend not using the library. /// ResponseVersion, @@ -69,12 +69,12 @@ namespace NL::UI /// /// NirnLabUIPlatform version /// - std::uint32_t libVersion = LibVersion::AS_INT; + std::uint32_t libVersion = NL::UI::LibVersion::AS_INT; /// /// NirnLabUIPlatform API version /// - std::uint32_t apiVersion = APIVersion::AS_INT; + std::uint32_t apiVersion = NL::UI::APIVersion::AS_INT; }; struct ResponseAPIMessage diff --git a/src/UIPlatform/NirnLabUIPlatformAPI/Version.h b/src/UIPlatform/NirnLabUIPlatformAPI/Version.h index 6dffa95..2c6c4ca 100644 --- a/src/UIPlatform/NirnLabUIPlatformAPI/Version.h +++ b/src/UIPlatform/NirnLabUIPlatformAPI/Version.h @@ -2,14 +2,14 @@ #include -namespace LibVersion +namespace NL::UI::LibVersion { - inline constexpr std::uint32_t MAJOR = 0; - inline constexpr std::uint32_t MINOR = 1; + inline constexpr std::uint32_t MAJOR = 1; + inline constexpr std::uint32_t MINOR = 0; inline constexpr auto PROJECT_NAME = "NirnLabUIPlatform"; inline constexpr auto MAJOR_MULT = 100000; - inline constexpr auto AS_STRING = "0.1"; + inline constexpr auto AS_STRING = "1.0"; inline constexpr std::uint32_t AS_INT = (static_cast(MAJOR * MAJOR_MULT + MINOR)); inline std::uint32_t GetMajorVersion(std::uint32_t a_version) @@ -23,13 +23,13 @@ namespace LibVersion } } -namespace APIVersion +namespace NL::UI::APIVersion { - inline constexpr std::uint32_t MAJOR = 0; - inline constexpr std::uint32_t MINOR = 1; + inline constexpr std::uint32_t MAJOR = 1; + inline constexpr std::uint32_t MINOR = 0; inline constexpr auto MAJOR_MULT = 100000; - inline constexpr auto AS_STRING = "0.1"; + inline constexpr auto AS_STRING = "1.0"; inline constexpr std::uint32_t AS_INT = (static_cast(MAJOR * MAJOR_MULT + MINOR)); inline std::uint32_t GetMajorVersion(std::uint32_t a_version) diff --git a/src/UIPlatform/Utils/PathUtils.h b/src/UIPlatform/Utils/PathUtils.h index 0cf5bf8..5e39d6c 100644 --- a/src/UIPlatform/Utils/PathUtils.h +++ b/src/UIPlatform/Utils/PathUtils.h @@ -9,7 +9,7 @@ namespace NL::Utils { static inline std::filesystem::path GetTempAppDataPath() { - auto appPath = std::filesystem::temp_directory_path() / LibVersion::PROJECT_NAME; + auto appPath = std::filesystem::temp_directory_path() / NL::UI::LibVersion::PROJECT_NAME; CreateDirectoryW(appPath.wstring().c_str(), 0); return appPath; } @@ -21,7 +21,7 @@ namespace NL::Utils if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &pwStr))) { - fsPath = std::filesystem::path(pwStr) / LibVersion::PROJECT_NAME; + fsPath = std::filesystem::path(pwStr) / NL::UI::LibVersion::PROJECT_NAME; } CoTaskMemFree(pwStr); return fsPath; diff --git a/src/UIPlatform/main.cpp b/src/UIPlatform/main.cpp index 8c506fe..7786f75 100644 --- a/src/UIPlatform/main.cpp +++ b/src/UIPlatform/main.cpp @@ -19,7 +19,7 @@ void InitDefaultLog() SKSE::stl::report_and_fail("Failed to find standard logging directory"sv); } - *path /= fmt::format("{}.log"sv, LibVersion::PROJECT_NAME); + *path /= fmt::format("{}.log"sv, NL::UI::LibVersion::PROJECT_NAME); auto sink = std::make_shared(path->string(), true); #endif @@ -58,8 +58,8 @@ void InitCefSubprocessLog() extern "C" DLLEXPORT constinit auto SKSEPlugin_Version = []() { SKSE::PluginVersionData v{}; - v.pluginVersion = LibVersion::AS_INT; - v.PluginName(LibVersion::PROJECT_NAME); + v.pluginVersion = NL::UI::LibVersion::AS_INT; + v.PluginName(NL::UI::LibVersion::PROJECT_NAME); v.AuthorName("kkEngine"sv); v.CompatibleVersions({SKSE::RUNTIME_SSE_1_6_640, REL::Version(1, 6, 1170, 0)}); v.UsesAddressLibrary(true); diff --git a/src/UIPlatformTest/NirnLabUIPlatformAPI/API.h b/src/UIPlatformTest/NirnLabUIPlatformAPI/API.h index 7d05021..6239d2b 100644 --- a/src/UIPlatformTest/NirnLabUIPlatformAPI/API.h +++ b/src/UIPlatformTest/NirnLabUIPlatformAPI/API.h @@ -47,7 +47,7 @@ namespace NL::UI /// /// Response with version info. See ResponseVersionMessage struct. - /// You should check current API version (APIVersion::AS_INT) and version in response. + /// You should check current API version (NL::UI::APIVersion::AS_INT) and version in response. /// It is not guaranteed that the major versions are compatible. In this case, I recommend not using the library. /// ResponseVersion, @@ -69,12 +69,12 @@ namespace NL::UI /// /// NirnLabUIPlatform version /// - std::uint32_t libVersion = LibVersion::AS_INT; + std::uint32_t libVersion = NL::UI::LibVersion::AS_INT; /// /// NirnLabUIPlatform API version /// - std::uint32_t apiVersion = APIVersion::AS_INT; + std::uint32_t apiVersion = NL::UI::APIVersion::AS_INT; }; struct ResponseAPIMessage diff --git a/src/UIPlatformTest/NirnLabUIPlatformAPI/Version.h b/src/UIPlatformTest/NirnLabUIPlatformAPI/Version.h index 6dffa95..2c6c4ca 100644 --- a/src/UIPlatformTest/NirnLabUIPlatformAPI/Version.h +++ b/src/UIPlatformTest/NirnLabUIPlatformAPI/Version.h @@ -2,14 +2,14 @@ #include -namespace LibVersion +namespace NL::UI::LibVersion { - inline constexpr std::uint32_t MAJOR = 0; - inline constexpr std::uint32_t MINOR = 1; + inline constexpr std::uint32_t MAJOR = 1; + inline constexpr std::uint32_t MINOR = 0; inline constexpr auto PROJECT_NAME = "NirnLabUIPlatform"; inline constexpr auto MAJOR_MULT = 100000; - inline constexpr auto AS_STRING = "0.1"; + inline constexpr auto AS_STRING = "1.0"; inline constexpr std::uint32_t AS_INT = (static_cast(MAJOR * MAJOR_MULT + MINOR)); inline std::uint32_t GetMajorVersion(std::uint32_t a_version) @@ -23,13 +23,13 @@ namespace LibVersion } } -namespace APIVersion +namespace NL::UI::APIVersion { - inline constexpr std::uint32_t MAJOR = 0; - inline constexpr std::uint32_t MINOR = 1; + inline constexpr std::uint32_t MAJOR = 1; + inline constexpr std::uint32_t MINOR = 0; inline constexpr auto MAJOR_MULT = 100000; - inline constexpr auto AS_STRING = "0.1"; + inline constexpr auto AS_STRING = "1.0"; inline constexpr std::uint32_t AS_INT = (static_cast(MAJOR * MAJOR_MULT + MINOR)); inline std::uint32_t GetMajorVersion(std::uint32_t a_version) diff --git a/src/UIPlatformTest/main.cpp b/src/UIPlatformTest/main.cpp index 6e3e2be..b6d7826 100644 --- a/src/UIPlatformTest/main.cpp +++ b/src/UIPlatformTest/main.cpp @@ -55,46 +55,46 @@ SKSEPluginLoad(const SKSE::LoadInterface* a_skse) { case SKSE::MessagingInterface::kPostPostLoad: // All plugins are loaded. Request lib version. - SKSE::GetMessagingInterface()->Dispatch(NL::UI::APIMessageType::RequestVersion, nullptr, 0, LibVersion::PROJECT_NAME); + SKSE::GetMessagingInterface()->Dispatch(NL::UI::APIMessageType::RequestVersion, nullptr, 0, NL::UI::LibVersion::PROJECT_NAME); break; case SKSE::MessagingInterface::kInputLoaded: if (g_canUseAPI) { // API version is ok. Request interface. - SKSE::GetMessagingInterface()->Dispatch(NL::UI::APIMessageType::RequestAPI, nullptr, 0, LibVersion::PROJECT_NAME); + SKSE::GetMessagingInterface()->Dispatch(NL::UI::APIMessageType::RequestAPI, nullptr, 0, NL::UI::LibVersion::PROJECT_NAME); } break; default: break; } }); - SKSE::GetMessagingInterface()->RegisterListener(nullptr, [](SKSE::MessagingInterface::Message* a_msg) { + SKSE::GetMessagingInterface()->RegisterListener(NL::UI::LibVersion::PROJECT_NAME, [](SKSE::MessagingInterface::Message* a_msg) { spdlog::info("Received message({}) from \"{}\"", a_msg->type, a_msg->sender ? a_msg->sender : "nullptr"); switch (a_msg->type) { case NL::UI::APIMessageType::ResponseVersion: { const auto versionInfo = reinterpret_cast(a_msg->data); - spdlog::info("NirnLabUIPlatform version: {}.{}", LibVersion::GetMajorVersion(versionInfo->libVersion), LibVersion::GetMinorVersion(versionInfo->libVersion)); + spdlog::info("NirnLabUIPlatform version: {}.{}", NL::UI::LibVersion::GetMajorVersion(versionInfo->libVersion), NL::UI::LibVersion::GetMinorVersion(versionInfo->libVersion)); - const auto majorAPIVersion = APIVersion::GetMajorVersion(versionInfo->apiVersion); + const auto majorAPIVersion = NL::UI::APIVersion::GetMajorVersion(versionInfo->apiVersion); // If the major version is different from ours, then using the API may cause problems - if (majorAPIVersion != APIVersion::MAJOR) + if (majorAPIVersion != NL::UI::APIVersion::MAJOR) { g_canUseAPI = false; spdlog::error("Can't using this API version of NirnLabUIPlatform. We have {}.{} and installed is {}.{}", - APIVersion::MAJOR, - APIVersion::MINOR, - APIVersion::GetMajorVersion(versionInfo->apiVersion), - APIVersion::GetMinorVersion(versionInfo->apiVersion)); + NL::UI::APIVersion::MAJOR, + NL::UI::APIVersion::MINOR, + NL::UI::APIVersion::GetMajorVersion(versionInfo->apiVersion), + NL::UI::APIVersion::GetMinorVersion(versionInfo->apiVersion)); } else { g_canUseAPI = true; spdlog::info("API version is ok. We have {}.{} and installed is {}.{}", - APIVersion::MAJOR, - APIVersion::MINOR, - APIVersion::GetMajorVersion(versionInfo->apiVersion), - APIVersion::GetMinorVersion(versionInfo->apiVersion)); + NL::UI::APIVersion::MAJOR, + NL::UI::APIVersion::MINOR, + NL::UI::APIVersion::GetMajorVersion(versionInfo->apiVersion), + NL::UI::APIVersion::GetMinorVersion(versionInfo->apiVersion)); } break; } diff --git a/src/UIPlugin/main.cpp b/src/UIPlugin/main.cpp index 1071892..2f9ceeb 100644 --- a/src/UIPlugin/main.cpp +++ b/src/UIPlugin/main.cpp @@ -153,8 +153,8 @@ static inline TFunc ExecLibFunc(const char* a_funcName) extern "C" DLLEXPORT constinit auto SKSEPlugin_Version = []() { SKSE::PluginVersionData v{}; - v.pluginVersion = LibVersion::AS_INT; - v.PluginName(LibVersion::PROJECT_NAME); + v.pluginVersion = NL::UI::LibVersion::AS_INT; + v.PluginName(NL::UI::LibVersion::PROJECT_NAME); v.AuthorName("kkEngine"sv); v.CompatibleVersions({SKSE::RUNTIME_SSE_1_6_640, REL::Version(1, 6, 1170, 0)}); v.UsesAddressLibrary(true); diff --git a/src/Version.h.in b/src/Version.h.in index d25eae8..1b88ae4 100644 --- a/src/Version.h.in +++ b/src/Version.h.in @@ -2,7 +2,7 @@ #include -namespace LibVersion +namespace NL::UI::LibVersion { inline constexpr std::uint32_t MAJOR = @PROJECT_VERSION_MAJOR@; inline constexpr std::uint32_t MINOR = @PROJECT_VERSION_MINOR@; @@ -23,7 +23,7 @@ namespace LibVersion } } -namespace APIVersion +namespace NL::UI::APIVersion { inline constexpr std::uint32_t MAJOR = @API_MAJOR_VERSION@; inline constexpr std::uint32_t MINOR = @API_MINOR_VERSION@;