diff --git a/sources/Users/User.uc b/sources/Users/User.uc index 18ecc36..73fa259 100644 --- a/sources/Users/User.uc +++ b/sources/Users/User.uc @@ -31,7 +31,15 @@ var private int key; var private Database persistentDatabase; // Pointer to this user's "settings" data in particular var private JSONPointer persistentSettingsPointer; - +// Groups to which caller `User` belongs to. +// Every user always belongs to group "everyone", so it is never listed +// here. +// Local user groups are not available for modification and are only loaded +// from configs, so `userGroups` might duplicate groups from `localUserGroup`, +// allowing to add them to editable sources (database). +// Group names are stored in the lower register. +var private array userGroups; // user groups loaded from database +var private array localUserGroups; // user groups loaded from local files var private LoggerAPI.Definition errNoUserDataDatabase; protected function Finalizer() @@ -52,6 +60,7 @@ protected function Finalizer() * Initialization should (and can) only be done once. * Before a `Initialize()` call, any other method calls on such `User` * must be considerate to have undefined behavior. + * DO NOT CALL THIS METHOD MANUALLY. */ public final function Initialize(UserID initID, int initKey) { @@ -60,6 +69,7 @@ public final function Initialize(UserID initID, int initKey) if (initID != none) { initID.NewRef(); } + LoadLocalGroups(); } /** @@ -85,6 +95,150 @@ public final function int GetKey() return key; } +// Loads locally defined groups from the "AcediaUserGroups.ini" config +private final function LoadLocalGroups() +{ + local int i, j; + local string mySteamID; + local UserGroup nextGroupConfig; + local array nextUserArray; + local array availableGroups; + + if (id == none) { + return; + } + class'UserGroup'.static.Initialize(); + mySteamID = _.text.IntoString(id.GetSteamID64String()); + availableGroups = class'UserGroup'.static.AvailableConfigs(); + // Go over every group + for (i = 0; i < availableGroups.length; i += 1) + { + nextGroupConfig = UserGroup( + class'UserGroup'.static.GetConfigInstance(availableGroups[i])); + // Add group as local if it has our ID recorded + nextUserArray = nextGroupConfig.user; + for (j = 0; j < nextUserArray.length; j += 1) + { + if (nextUserArray[j] == mySteamID) + { + localUserGroups[localUserGroups.length] = + availableGroups[i].LowerCopy(); + } + } + _.memory.Free(nextGroupConfig); + } + _.memory.FreeMany(availableGroups); +} + +/** + * Adds caller user into new group, specified by `newGroup`. + * This group must exist for the method to succeed. + * + * @param newGroup Name of the group to add caller `User` into. + */ +public final function AddGroup(Text newGroup) +{ + local int i; + + if (newGroup == none) return; + if (class'UserGroup'.static.Exists(newGroup)) return; + + for (i = 0; i < userGroups.length; i += 1) + { + if (newGroup.Compare(userGroups[i], SCASE_INSENSITIVE)) { + return; + } + } + userGroups[userGroups.length] = newGroup.LowerCopy(); +} + +/** + * Removes caller user from the given group `groupToRemove`. + * + * @param groupToRemove Name of the group to remove caller `User` from. + * @return `true` if user was actually removed from the group and `false` + * otherwise (group doesn't exist or user didn't belong to it). + */ +public final function bool RemoveGroup(Text groupToRemove) +{ + local int i; + + if (groupToRemove == none) { + return false; + } + for (i = 0; i < userGroups.length; i += 1) + { + if (groupToRemove.Compare(userGroups[i], SCASE_INSENSITIVE)) + { + userGroups[i].FreeSelf(); + userGroups.Remove(i, 1); + return true; + } + } + return false; +} + +/** + * Checks whether caller `User` belongs to the group specified by + * `groupToCheck`. + * + * @param groupToCheck Name of the group to check for whether caller `User` + * belongs to it. + * @return `true` if caller `User` belongs to the group `groupToCheck` and + * `false` otherwise. + */ +public final function bool IsInGroup(Text groupToCheck) +{ + local int i; + + if (groupToCheck == none) { + return false; + } + for (i = 0; i < userGroups.length; i += 1) + { + if (groupToCheck.Compare(userGroups[i], SCASE_INSENSITIVE)) { + return true; + } + } + return false; +} + +/** + * Returns array with names of all groups to which caller user belongs to. + * + * @return Array of names of the groups that caller user belongs to. + * Guaranteed to not contain duplicates or `none` values. + */ +public final function array GetGroups() +{ + local int i, j; + local bool duplicate; + local array result; + + for (i = 0; i < localUserGroups.length; i += 1) { + result[result.length] = localUserGroups[i].Copy(); + } + for (i = 0; i < userGroups.length; i += 1) + { + duplicate = false; + // Check `userGroups[i]` for being a duplicate from `localUserGroups` + for (j = 0; j < localUserGroups.length; j += 1) + { + // No need for `SCASE_INSENSITIVE`, since user group names + // are stored in lower case + if (userGroups[i].Compare(localUserGroups[j])) + { + duplicate = true; + break; + } + } + if (!duplicate) { + result[result.length] = userGroups[i].Copy(); + } + } + return result; +} + /** * Reads user's persistent data saved inside group `groupName`, saving it into * a collection using mutable data types.