|
|
|
@ -26,6 +26,19 @@ var private /*config*/ bool useDatabase;
|
|
|
|
|
var private /*config*/ string databaseLink; |
|
|
|
|
var private /*config*/ array<string> availableUserGroups; |
|
|
|
|
|
|
|
|
|
var private bool diskSaveScheduled; |
|
|
|
|
|
|
|
|
|
struct AnnotatedUserID |
|
|
|
|
{ |
|
|
|
|
var public UserID id; |
|
|
|
|
var public Text annotation; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct IDAnnotationPair |
|
|
|
|
{ |
|
|
|
|
var Text id, annotation; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// List of all available user groups for current config |
|
|
|
|
var private array<Text> loadedUserGroups; |
|
|
|
|
// `HashTable` (with group name keys) that stores `HashTable`s used as |
|
|
|
@ -106,9 +119,10 @@ private final function LoadLocalGroup(
|
|
|
|
|
optional bool localGroupIsExpected) |
|
|
|
|
{ |
|
|
|
|
local int i; |
|
|
|
|
local Text newSteamID, lowerCaseGroupName; |
|
|
|
|
local Text lowerCaseGroupName; |
|
|
|
|
local HashTable newPlayerSet; |
|
|
|
|
local UserGroup groupConfig; |
|
|
|
|
local IDAnnotationPair nextUserPair; |
|
|
|
|
local array<string> groupUserArray; |
|
|
|
|
|
|
|
|
|
if (groupName == none) { |
|
|
|
@ -129,9 +143,10 @@ private final function LoadLocalGroup(
|
|
|
|
|
groupUserArray = groupConfig.user; |
|
|
|
|
for (i = 0; i < groupUserArray.length; i += 1) |
|
|
|
|
{ |
|
|
|
|
newSteamID = _.text.FromString(groupUserArray[i]); |
|
|
|
|
newPlayerSet.SetItem(newSteamID, none); |
|
|
|
|
newSteamID.FreeSelf(); |
|
|
|
|
nextUserPair = ParseConfigUserName(groupUserArray[i]); |
|
|
|
|
newPlayerSet.SetItem(nextUserPair.id, nextUserPair.annotation); |
|
|
|
|
_.memory.Free(nextUserPair.id); |
|
|
|
|
_.memory.Free(nextUserPair.annotation); |
|
|
|
|
} |
|
|
|
|
lowerCaseGroupName = groupName.LowerCopy(); |
|
|
|
|
loadedGroupToUsersMap.SetItem(lowerCaseGroupName, newPlayerSet); |
|
|
|
@ -140,6 +155,29 @@ private final function LoadLocalGroup(
|
|
|
|
|
groupConfig.FreeSelf(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private final function IDAnnotationPair ParseConfigUserName( |
|
|
|
|
string configUserName) |
|
|
|
|
{ |
|
|
|
|
local Parser parser; |
|
|
|
|
local MutableText parsingResult; |
|
|
|
|
local IDAnnotationPair result; |
|
|
|
|
local Text.Character slashSeparator; |
|
|
|
|
|
|
|
|
|
parser = _.text.ParseString(configUserName); |
|
|
|
|
slashSeparator = _.text.GetCharacter("/"); |
|
|
|
|
if (parser.MUntil(parsingResult, slashSeparator).Match(P("/")).Ok()) { |
|
|
|
|
result.annotation = parser.GetRemainderM().IntoText(); |
|
|
|
|
} |
|
|
|
|
result.id = parsingResult.IntoText(); |
|
|
|
|
if (result.annotation != none && result.annotation.IsEmpty()) |
|
|
|
|
{ |
|
|
|
|
result.annotation.FreeSelf(); |
|
|
|
|
result.annotation = none; |
|
|
|
|
} |
|
|
|
|
parser.FreeSelf(); |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private final function SaveLocalData() |
|
|
|
|
{ |
|
|
|
|
local Text nextGroup, activeConfigName; |
|
|
|
@ -178,6 +216,15 @@ private final function SaveLocalData()
|
|
|
|
|
_.memory.Free(activeConfigName); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private final function ScheduleConfigSave() |
|
|
|
|
{ |
|
|
|
|
if (diskSaveScheduled) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
_.scheduler.RequestDiskAccess(self).connect = SaveLocalData; |
|
|
|
|
diskSaveScheduled = true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns names of all available groups that users can belong to. |
|
|
|
|
* |
|
|
|
@ -237,6 +284,7 @@ public final function bool AddGroup(BaseText groupName)
|
|
|
|
|
loadedUserGroups[loadedUserGroups.length] = lowerCaseGroupName; |
|
|
|
|
// Try loading local `UserGroup`? |
|
|
|
|
LoadLocalGroup(lowerCaseGroupName); |
|
|
|
|
ScheduleConfigSave(); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -284,6 +332,7 @@ public final function bool RemoveGroup(BaseText groupName)
|
|
|
|
|
// Try loading local `UserGroup`? |
|
|
|
|
loadedGroupToUsersMap.RemoveItem(lowerCaseGroupName); |
|
|
|
|
lowerCaseGroupName.FreeSelf(); |
|
|
|
|
ScheduleConfigSave(); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -347,6 +396,7 @@ public final function bool AddSteamIDToGroup(
|
|
|
|
|
} |
|
|
|
|
groupUsers.SetItem(steamID, none); |
|
|
|
|
groupUsers.FreeSelf(); |
|
|
|
|
ScheduleConfigSave(); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -402,7 +452,7 @@ public final function bool AddUserIDToGroup(
|
|
|
|
|
|
|
|
|
|
if (groupName == none) return false; |
|
|
|
|
if (id == none) return false; |
|
|
|
|
steamID = id.GetSteamID64String(); |
|
|
|
|
steamID = id.GetUniqueID(); |
|
|
|
|
if (steamID == none) return false; |
|
|
|
|
|
|
|
|
|
result = AddSteamIDToGroup(steamID, groupName); |
|
|
|
@ -472,6 +522,7 @@ public final function bool RemoveSteamIDFromGroup(
|
|
|
|
|
hadUser = groupUsers.HasKey(steamID); |
|
|
|
|
groupUsers.RemoveItem(steamID); |
|
|
|
|
groupUsers.FreeSelf(); |
|
|
|
|
ScheduleConfigSave(); |
|
|
|
|
return hadUser; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -527,7 +578,7 @@ public final function bool RemoveUserIDFromGroup(
|
|
|
|
|
|
|
|
|
|
if (groupName == none) return false; |
|
|
|
|
if (id == none) return false; |
|
|
|
|
steamID = id.GetSteamID64String(); |
|
|
|
|
steamID = id.GetUniqueID(); |
|
|
|
|
if (steamID == none) return false; |
|
|
|
|
|
|
|
|
|
result = RemoveSteamIDFromGroup(steamID, groupName); |
|
|
|
@ -666,7 +717,7 @@ public final function array<Text> GetGroupsForUserID(UserID id)
|
|
|
|
|
local array<Text> result; |
|
|
|
|
|
|
|
|
|
if (id == none) return result; |
|
|
|
|
steamID = id.GetSteamID64String(); |
|
|
|
|
steamID = id.GetUniqueID(); |
|
|
|
|
if (steamID == none) return result; |
|
|
|
|
|
|
|
|
|
result = GetGroupsForSteamID(steamID); |
|
|
|
@ -709,6 +760,9 @@ public final function array<Text> GetGroupsForUser(User user)
|
|
|
|
|
/** |
|
|
|
|
* Returns `UserID`s of all users that belong into the group named `groupName`. |
|
|
|
|
* |
|
|
|
|
* @see For more information alongside `UserID`s use |
|
|
|
|
* `GetAnnotatedGroupMembers()`. |
|
|
|
|
* |
|
|
|
|
* In case this feature is configured to load user groups from a database |
|
|
|
|
* (either local or remote), the returned value is a locally cached one. |
|
|
|
|
* This helps us avoid having to query database each time we want to check |
|
|
|
@ -755,6 +809,63 @@ public final function array<UserID> GetGroupMembers(BaseText groupName)
|
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns annotated `UserID`s of all users that belong into the group named |
|
|
|
|
* `groupName`. `UserID`s aren't necessarily human-readable (e.g. SteamID) |
|
|
|
|
* and to help organize configs they can be annotated with a `Text` name. |
|
|
|
|
* This method returns `UserID` alongside such annotation, if it exists. |
|
|
|
|
* |
|
|
|
|
* @see For just `UserID`s use `GetGroupMembers()`. |
|
|
|
|
* |
|
|
|
|
* In case this feature is configured to load user groups from a database |
|
|
|
|
* (either local or remote), the returned value is a locally cached one. |
|
|
|
|
* This helps us avoid having to query database each time we want to check |
|
|
|
|
* something about user groups, but it also means we might have an outdated |
|
|
|
|
* information. |
|
|
|
|
* |
|
|
|
|
* @param groupName Name of the group. Case-insensitive. |
|
|
|
|
* @return Array with `UserID`s for every user in the user group named |
|
|
|
|
* `groupName`. All array elements are guaranteed to be not-`none` and |
|
|
|
|
* correspond to unique players. |
|
|
|
|
* If data wasn't yet loaded - returns empty array. |
|
|
|
|
*/ |
|
|
|
|
public final function array<AnnotatedUserID> GetAnnotatedGroupMembers( |
|
|
|
|
BaseText groupName) |
|
|
|
|
{ |
|
|
|
|
local int i; |
|
|
|
|
local Text lowerCaseGroupName; |
|
|
|
|
local HashTable groupUsers; |
|
|
|
|
local array<Text> groupUsersNames; |
|
|
|
|
local AnnotatedUserID nextRecord; |
|
|
|
|
local array<AnnotatedUserID> result; |
|
|
|
|
|
|
|
|
|
if (loadedGroupToUsersMap == none) return result; |
|
|
|
|
if (groupName == none) return result; |
|
|
|
|
|
|
|
|
|
lowerCaseGroupName = groupName.LowerCopy(); |
|
|
|
|
groupUsers = loadedGroupToUsersMap.GetHashTable(lowerCaseGroupName); |
|
|
|
|
lowerCaseGroupName.FreeSelf(); |
|
|
|
|
if (groupUsers == none) { |
|
|
|
|
groupUsersNames = groupUsers.GetTextKeys(); |
|
|
|
|
} |
|
|
|
|
for (i = 0; i < groupUsersNames.length; i += 1) |
|
|
|
|
{ |
|
|
|
|
nextRecord.id = UserID(_.memory.Allocate(class'UserID')); |
|
|
|
|
nextRecord.id.Initialize(groupUsersNames[i]); |
|
|
|
|
if (nextRecord.id.IsInitialized()) |
|
|
|
|
{ |
|
|
|
|
nextRecord.annotation = groupUsers.GetText(groupUsersNames[i]); |
|
|
|
|
result[result.length] = nextRecord; |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
nextRecord.id.FreeSelf(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
_.memory.FreeMany(groupUsersNames); |
|
|
|
|
_.memory.Free(groupUsers); |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Checks whether user given by `UserID` belongs to the group named |
|
|
|
|
* `groupName`. |
|
|
|
@ -781,7 +892,7 @@ public final function bool IsUserIDInGroup(UserID id, Text groupName)
|
|
|
|
|
if (loadedGroupToUsersMap == none) return false; |
|
|
|
|
if (groupName == none) return false; |
|
|
|
|
if (id == none) return false; |
|
|
|
|
steamID = id.GetSteamID64String(); |
|
|
|
|
steamID = id.GetUniqueID(); |
|
|
|
|
if (steamID == none) return false; |
|
|
|
|
|
|
|
|
|
lowerGroupName = groupName.LowerCopy(); |
|
|
|
|