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);
}
}