From c6d1d8b085d272ddc64882fabe476cbba59fb00c Mon Sep 17 00:00:00 2001 From: Space V <40030799+ahcenezdh@users.noreply.github.com> Date: Tue, 1 Oct 2024 19:26:22 +0200 Subject: [PATCH] feat(gameinput): new sorting algo and new native * Added a native to be able to hide all resource names from the FiveM key page * Removed specific handling for txAdmin * Improved sorting algorithm to sort by resource names and then alphabetically within each resource (including lowercase) --- .../src/GameInputFunctions.cpp | 11 +++ .../gta-core-five/include/GameInput.h | 2 + .../gta-core-five/src/GameInput.cpp | 79 ++++++++++++++----- .../SetKeyMappingHideResources.md | 14 ++++ 4 files changed, 86 insertions(+), 20 deletions(-) create mode 100644 ext/native-decls/SetKeyMappingHideResources.md diff --git a/code/components/citizen-resources-gta/src/GameInputFunctions.cpp b/code/components/citizen-resources-gta/src/GameInputFunctions.cpp index 6e17a2c85d..ee82a51cf9 100644 --- a/code/components/citizen-resources-gta/src/GameInputFunctions.cpp +++ b/code/components/citizen-resources-gta/src/GameInputFunctions.cpp @@ -27,6 +27,17 @@ static InitFunction initFunction([]() } }); + fx::ScriptEngine::RegisterNativeHandler("SET_KEY_MAPPING_HIDE_RESOURCES", [](fx::ScriptContext& context) + { + bool hide = context.GetArgument(0); + + fx::OMPtr runtime; + if (FX_SUCCEEDED(fx::GetCurrentScriptRuntime(&runtime))) + { + game::SetKeyMappingHideResources(hide); + } + }); + fx::Resource::OnInitializeInstance.Connect([](fx::Resource* resource) { resource->OnStart.Connect([resource]() diff --git a/code/components/gta-core-five/include/GameInput.h b/code/components/gta-core-five/include/GameInput.h index 1790650132..8bd5b05249 100644 --- a/code/components/gta-core-five/include/GameInput.h +++ b/code/components/gta-core-five/include/GameInput.h @@ -13,4 +13,6 @@ namespace game GAMEINPUT_EXPORT void RegisterBindingForTag(const std::string& tag, const std::string& command, const std::string& languageDesc, const std::string& ioms, const std::string& ioParam); GAMEINPUT_EXPORT bool IsControlKeyDown(int control); + + GAMEINPUT_EXPORT void SetKeyMappingHideResources(bool hide); } diff --git a/code/components/gta-core-five/src/GameInput.cpp b/code/components/gta-core-five/src/GameInput.cpp index 664f8e556e..7916d85a10 100644 --- a/code/components/gta-core-five/src/GameInput.cpp +++ b/code/components/gta-core-five/src/GameInput.cpp @@ -1033,9 +1033,15 @@ static void* GetFunc() } static std::map> g_registeredBindings; +static bool g_hideAllResourceNames = false; namespace game { + GAMEINPUT_EXPORT void SetKeyMappingHideResources(bool hide) + { + g_hideAllResourceNames = hide; + } + void SetBindingTagActive(const std::string& tag, bool active) { if (active) @@ -1172,22 +1178,45 @@ static void(*g_origGetMappingCategoryInputs)(uint32_t* categoryId, atArray& controlIds) { - g_origGetMappingCategoryInputs(categoryId, controlIds); - - if (*categoryId == HashString("PM_PANE_CFX")) - { - std::vector>> sortedBindings(g_registeredBindings.begin(), g_registeredBindings.end()); - std::sort(sortedBindings.begin(), sortedBindings.end(), [](const auto& left, const auto& right) - { - // #TODO: Unicode-aware comparison - return std::get<1>(left.second) < std::get<1>(right.second); - }); - - for (auto& binding : sortedBindings) - { - controlIds.Set(controlIds.GetCount(), HashBinding(binding.first)); - } - } + g_origGetMappingCategoryInputs(categoryId, controlIds); + + if (*categoryId == HashString("PM_PANE_CFX")) + { + auto caseInsensitiveCompare = [](const std::string& a, const std::string& b) + { + return std::lexicographical_compare( + a.begin(), a.end(), + b.begin(), b.end(), + [](char a, char b) { + return std::tolower(static_cast(a)) < std::tolower(static_cast(b)); + } + ); + }; + + std::map>>, decltype(caseInsensitiveCompare)> groupedBindings(caseInsensitiveCompare); + + for (const auto& [command, info] : g_registeredBindings) + { + const auto& [tag, desc] = info; + groupedBindings[tag].push_back({command, info}); + } + + std::vector>>>> sortedGroups(groupedBindings.begin(), groupedBindings.end()); + + + for (auto& [tag, bindings] : sortedGroups) + { + std::sort(bindings.begin(), bindings.end(), + [&caseInsensitiveCompare](const auto& a, const auto& b) { + return caseInsensitiveCompare(std::get<1>(a.second), std::get<1>(b.second)); + }); + + for (const auto& [command, info] : bindings) + { + controlIds.Set(controlIds.GetCount(), HashBinding(command)); + } + } + } } static void*(*g_origGetBindingForControl)(void* control, rage::ioInputSource* outBinding, uint32_t controlId, int source, uint8_t subIdx, bool unk); @@ -1232,16 +1261,26 @@ static const char* GetNameForControl(uint32_t controlId) static std::string str; str = fmt::sprintf("INPUT_%08X", HashString(pair.first.c_str())); - // #TODO: replace once GH-1111 is done auto resourceName = std::get<0>(pair.second); + auto actionName = std::get<1>(pair.second); if (resourceName == "monitor") { resourceName = "txAdmin"; } - - // lame hack - game::AddCustomText(HashString(str.c_str()), fmt::sprintf("~HC_3~(%s)~s~ %s", resourceName, std::get<1>(pair.second))); + + std::string displayName; + + if (g_hideAllResourceNames) + { + displayName = fmt::sprintf("%s", actionName); + } + else + { + displayName = fmt::sprintf("~HC_3~(%s)~s~ %s", resourceName, actionName); + } + + game::AddCustomText(HashString(str.c_str()), displayName); return str.c_str(); } diff --git a/ext/native-decls/SetKeyMappingHideResources.md b/ext/native-decls/SetKeyMappingHideResources.md new file mode 100644 index 0000000000..59e4680079 --- /dev/null +++ b/ext/native-decls/SetKeyMappingHideResources.md @@ -0,0 +1,14 @@ +--- +ns: CFX +apiset: client +--- +## SET_KEY_MAPPING_HIDE_RESOURCES + +```c +void SET_KEY_MAPPING_HIDE_RESOURCES(bool hide); +``` + +Toggles the visibility of resource names in the FiveM key mapping page. + +## Parameters +* **hide**: `true` will disable the display of resource names, and `false` will enable it. \ No newline at end of file