From b67e2679918e8a6be5699af80d7852dd088e5f10 Mon Sep 17 00:00:00 2001 From: OwnProx Date: Sun, 26 Jul 2020 04:58:58 +0100 Subject: [PATCH] Permissions 1.7 Cache Added Default permission added to Default group Fixed admin detection when using AllowedCheaterSteamIDs.txt --- .../Permissions/Permissions.vcxproj.filters | 6 + Permissions/Permissions/Private/Cache/Cache.h | 109 ++++++++++++++++++ .../Permissions/Private/Database/MysqlDB.h | 4 +- .../Permissions/Private/Database/SqlLiteDB.h | 4 +- Permissions/Permissions/Private/Hooks.cpp | 39 +++++-- Permissions/Permissions/Private/Main.cpp | 2 + Permissions/Permissions/Private/Main.h | 3 + .../Permissions/Private/Permissions.cpp | 52 ++++++++- 8 files changed, 206 insertions(+), 13 deletions(-) create mode 100644 Permissions/Permissions/Private/Cache/Cache.h diff --git a/Permissions/Permissions/Permissions.vcxproj.filters b/Permissions/Permissions/Permissions.vcxproj.filters index 4cdf5300..838e9c24 100644 --- a/Permissions/Permissions/Permissions.vcxproj.filters +++ b/Permissions/Permissions/Permissions.vcxproj.filters @@ -13,6 +13,9 @@ {b090c175-c079-441f-bf0c-01d206683d33} + + {c048ee96-81a8-4d9f-846e-4fbea9158926} + @@ -45,6 +48,9 @@ Public + + Private\Cache + diff --git a/Permissions/Permissions/Private/Cache/Cache.h b/Permissions/Permissions/Private/Cache/Cache.h new file mode 100644 index 00000000..5539e91b --- /dev/null +++ b/Permissions/Permissions/Private/Cache/Cache.h @@ -0,0 +1,109 @@ +#pragma once + +namespace Permissions::Cache +{ + struct permissions_cache_player_permissions + { + size_t permission_hash; + bool active; + + permissions_cache_player_permissions(size_t _permission_hash, bool _active) + { + permission_hash = _permission_hash; + active = _active; + } + }; + + struct permission_cache_player_groups + { + size_t group_hash; + bool active; + + permission_cache_player_groups(size_t _group_hash, bool _active) + { + group_hash = _group_hash; + active = _active; + } + }; + + struct permission_cache_player + { + std::vector groups; + std::vector permissions; + + permission_cache_player(permission_cache_player_groups group) + { + groups.push_back(group); + } + + permission_cache_player(permissions_cache_player_permissions permission) + { + permissions.push_back(permission); + } + }; + + inline std::hash hasher; + inline std::unordered_map> player_cache; + + inline void AddPlayerToGroup(const uint64& steam_id, const FString& group, const bool active) + { + const size_t group_hash = hasher(group.ToString()); + + auto cache_info = std::find_if(player_cache.begin(), player_cache.end(), [&steam_id](const auto& perm_info) { return perm_info.first == steam_id; }); + if (cache_info != player_cache.end()) + cache_info->second->groups.push_back(permission_cache_player_groups(group_hash, active)); + else + player_cache[steam_id] = std::make_unique(permission_cache_player(permission_cache_player_groups(group_hash, active))); + } + + inline void AddPlayerToPermission(const uint64& steam_id, const FString& permission, const bool active) + { + const size_t permission_hash = hasher(permission.ToString()); + + auto cache_info = std::find_if(player_cache.begin(), player_cache.end(), [&steam_id](const auto& perm_info) { return perm_info.first == steam_id; }); + if (cache_info != player_cache.end()) + cache_info->second->permissions.push_back(permissions_cache_player_permissions(permission_hash, active)); + else + player_cache[steam_id] = std::make_unique(permission_cache_player(permissions_cache_player_permissions(permission_hash, active))); + } + + inline void RemovePlayer(const uint64& steam_id) + { + player_cache.erase(steam_id); + } + + inline void ClearAll() + { + player_cache.clear(); + } + + inline const int IsPlayerInGroup(const uint64& steam_id, const FString& group) + { + const auto& cache_info = std::find_if(player_cache.begin(), player_cache.end(), [&steam_id](const auto& perm_info) { return perm_info.first == steam_id; }); + if (cache_info == player_cache.end()) + return -1; + + const size_t group_hash = hasher(group.ToString()); + + const auto& cache_group_perm = std::find_if(cache_info->second->groups.begin(), cache_info->second->groups.end(), [&group_hash](const auto& group_info) { return group_info.group_hash == group_hash; }); + if (cache_group_perm != cache_info->second->groups.end()) + return cache_group_perm->active ? 1 : 0; + + return -1; + } + + inline const int IsPlayerHasPermission(const uint64& steam_id, const FString& permission) + { + const auto& cache_info = std::find_if(player_cache.begin(), player_cache.end(), [&steam_id](const auto& perm_info) { return perm_info.first == steam_id; }); + if (cache_info == player_cache.end()) + return -1; + + const size_t permission_hash = hasher(permission.ToString()); + + const auto& cache_perm = std::find_if(cache_info->second->permissions.begin(), cache_info->second->permissions.end(), [&permission_hash](const auto& perm_info) { return perm_info.permission_hash == permission_hash; }); + if (cache_perm != cache_info->second->permissions.end()) + return cache_perm->active ? 1 : 0; + + return -1; + } +} \ No newline at end of file diff --git a/Permissions/Permissions/Private/Database/MysqlDB.h b/Permissions/Permissions/Private/Database/MysqlDB.h index 2e03eeaf..2d4f00c7 100644 --- a/Permissions/Permissions/Private/Database/MysqlDB.h +++ b/Permissions/Permissions/Private/Database/MysqlDB.h @@ -51,8 +51,8 @@ class MySql : public IDatabase "WHERE NOT EXISTS(SELECT 1 FROM {} WHERE GroupName = 'Admins');", table_groups_, table_groups_)); - result |= db_.query(fmt::format("INSERT INTO {} (GroupName)" - "SELECT 'Default'" + result |= db_.query(fmt::format("INSERT INTO {} (GroupName, Permissions)" + "SELECT 'Default', 'Default,'" "WHERE NOT EXISTS(SELECT 1 FROM {} WHERE GroupName = 'Default');", table_groups_, table_groups_)); diff --git a/Permissions/Permissions/Private/Database/SqlLiteDB.h b/Permissions/Permissions/Private/Database/SqlLiteDB.h index f82a9b28..14c8a50f 100644 --- a/Permissions/Permissions/Private/Database/SqlLiteDB.h +++ b/Permissions/Permissions/Private/Database/SqlLiteDB.h @@ -33,8 +33,8 @@ class SqlLite : public IDatabase db_.exec("INSERT INTO Groups(GroupName, Permissions)" "SELECT 'Admins', '*,'" "WHERE NOT EXISTS(SELECT 1 FROM Groups WHERE GroupName = 'Admins');"); - db_.exec("INSERT INTO Groups(GroupName)" - "SELECT 'Default'" + db_.exec("INSERT INTO Groups(GroupName, Permissions)" + "SELECT 'Default', 'Default,'" "WHERE NOT EXISTS(SELECT 1 FROM Groups WHERE GroupName = 'Default');"); } catch (const std::exception& exception) diff --git a/Permissions/Permissions/Private/Hooks.cpp b/Permissions/Permissions/Private/Hooks.cpp index 0573dc38..ff0b2253 100644 --- a/Permissions/Permissions/Private/Hooks.cpp +++ b/Permissions/Permissions/Private/Hooks.cpp @@ -7,12 +7,20 @@ namespace Permissions::Hooks DECLARE_HOOK(AShooterGameMode_HandleNewPlayer, bool, AShooterGameMode*, AShooterPlayerController*, UPrimalPlayerData*, AShooterCharacter*, bool); DECLARE_HOOK(AShooterPlayerController_ClientNotifyAdmin, void, AShooterPlayerController*); + DECLARE_HOOK(AShooterGameMode_Logout, void, AShooterGameMode*, AController*); - bool Hook_AShooterGameMode_HandleNewPlayer(AShooterGameMode* _this, AShooterPlayerController* new_player, + + void CheckAdmin(const uint64 steam_id) + { + if (!IsPlayerInGroup(steam_id, "Admins")) + database->AddPlayerToGroup(steam_id, "Admins"); + } + + bool Hook_AShooterGameMode_HandleNewPlayer(AShooterGameMode* _this, AShooterPlayerController* player_controller, UPrimalPlayerData* player_data, AShooterCharacter* player_character, bool is_from_login) { - const uint64 steam_id = ArkApi::IApiUtils::GetSteamIdFromController(new_player); + const uint64 steam_id = ArkApi::IApiUtils::GetSteamIdFromController(player_controller); if (!database->IsPlayerExists(steam_id)) { @@ -21,21 +29,33 @@ namespace Permissions::Hooks { Log::GetLog()->error("({} {}) Couldn't add player", __FILE__, __FUNCTION__); } + + CheckAdmin(steam_id); } - return AShooterGameMode_HandleNewPlayer_original(_this, new_player, player_data, player_character, + return AShooterGameMode_HandleNewPlayer_original(_this, player_controller, player_data, player_character, is_from_login); } void Hook_AShooterPlayerController_ClientNotifyAdmin(AShooterPlayerController* player_controller) - { + { const uint64 steam_id = ArkApi::IApiUtils::GetSteamIdFromController(player_controller); - - if (!IsPlayerInGroup(steam_id, "Admins")) - database->AddPlayerToGroup(steam_id, "Admins"); + + CheckAdmin(steam_id); AShooterPlayerController_ClientNotifyAdmin_original(player_controller); } + + void _cdecl Hook_AShooterGameMode_Logout(AShooterGameMode* _this, AController* controller) + { + if (use_cache && controller && controller->IsA(AShooterPlayerController::StaticClass())) + { + AShooterPlayerController* player_controller = static_cast(controller); + const uint64 steam_id = ArkApi::IApiUtils::GetSteamIdFromController(player_controller); + Cache::RemovePlayer(steam_id); + } + AShooterGameMode_Logout_original(_this, controller); + } void Init() { @@ -46,5 +66,10 @@ namespace Permissions::Hooks ArkApi::GetHooks().SetHook("AShooterPlayerController.ClientNotifyAdmin", &Hook_AShooterPlayerController_ClientNotifyAdmin, &AShooterPlayerController_ClientNotifyAdmin_original); + + ArkApi::GetHooks().SetHook("AShooterGameMode.Logout", + &Hook_AShooterGameMode_Logout, + &AShooterGameMode_Logout_original); + } } diff --git a/Permissions/Permissions/Private/Main.cpp b/Permissions/Permissions/Private/Main.cpp index 67e441dd..2cc05734 100644 --- a/Permissions/Permissions/Private/Main.cpp +++ b/Permissions/Permissions/Private/Main.cpp @@ -460,6 +460,8 @@ namespace Permissions database = std::make_unique(config.value("DbPathOverride", "")); } + use_cache = config.value("UseCache", true); + Hooks::Init(); ArkApi::GetCommands().AddConsoleCommand("Permissions.Add", &AddPlayerToGroupCmd); diff --git a/Permissions/Permissions/Private/Main.h b/Permissions/Permissions/Private/Main.h index 7be38a40..df277f33 100644 --- a/Permissions/Permissions/Private/Main.h +++ b/Permissions/Permissions/Private/Main.h @@ -1,10 +1,13 @@ #pragma once #include "Database/IDatabase.h" +#include "Cache/Cache.h" namespace Permissions { inline std::unique_ptr database; std::string GetDbPath(); + + inline bool use_cache = true; } diff --git a/Permissions/Permissions/Private/Permissions.cpp b/Permissions/Permissions/Private/Permissions.cpp index 5d62dada..bcd19e16 100644 --- a/Permissions/Permissions/Private/Permissions.cpp +++ b/Permissions/Permissions/Private/Permissions.cpp @@ -30,7 +30,7 @@ namespace Permissions return database->GetGroupMembers(group); } - bool IsPlayerInGroup(uint64 steam_id, const FString& group) + bool _IsPlayerInGroup(uint64 steam_id, const FString& group) { TArray groups = GetPlayerGroups(steam_id); @@ -43,23 +43,50 @@ namespace Permissions return false; } + bool IsPlayerInGroup(uint64 steam_id, const FString& group) + { + if (use_cache) + { + const int cache_player_in_group = Cache::IsPlayerInGroup(steam_id, group); + + if (cache_player_in_group == -1) + Cache::AddPlayerToGroup(steam_id, group, _IsPlayerInGroup(steam_id, group)); + + return cache_player_in_group == 1; + } + + return _IsPlayerInGroup(steam_id, group); + } + std::optional AddPlayerToGroup(uint64 steam_id, const FString& group) { + if(use_cache) + Cache::RemovePlayer(steam_id); + return database->AddPlayerToGroup(steam_id, group); } std::optional RemovePlayerFromGroup(uint64 steam_id, const FString& group) { + if (use_cache) + Cache::RemovePlayer(steam_id); + return database->RemovePlayerFromGroup(steam_id, group); } std::optional AddGroup(const FString& group) { + if (use_cache) + Cache::ClearAll(); + return database->AddGroup(group); } std::optional RemoveGroup(const FString& group) { + if (use_cache) + Cache::ClearAll(); + return database->RemoveGroup(group); } @@ -79,7 +106,7 @@ namespace Permissions return false; } - bool IsPlayerHasPermission(uint64 steam_id, const FString& permission) + bool _IsPlayerHasPermission(uint64 steam_id, const FString& permission) { TArray groups = GetPlayerGroups(steam_id); @@ -92,13 +119,34 @@ namespace Permissions return false; } + bool IsPlayerHasPermission(uint64 steam_id, const FString& permission) + { + if (use_cache) + { + const int cache_player_in_group = Cache::IsPlayerHasPermission(steam_id, permission); + + if (cache_player_in_group == -1) + Cache::AddPlayerToPermission(steam_id, permission, _IsPlayerHasPermission(steam_id, permission)); + + return cache_player_in_group == 1; + } + + return _IsPlayerHasPermission(steam_id, permission); + } + std::optional GroupGrantPermission(const FString& group, const FString& permission) { + if (use_cache) + Cache::ClearAll(); + return database->GroupGrantPermission(group, permission); } std::optional GroupRevokePermission(const FString& group, const FString& permission) { + if (use_cache) + Cache::ClearAll(); + return database->GroupRevokePermission(group, permission); } }