You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
340 lines
11 KiB
340 lines
11 KiB
4 years ago
|
/**
|
||
|
* Acedia's class for storing player's ID.
|
||
|
* This class is inherently linked to steam and it's SteamIDs, since
|
||
|
* Killing Floor 1 is all but guaranteed to be steam-exclusive.
|
||
|
* Still, if you wish to use it in a portable manner, limit yourself to
|
||
|
* `Initialize()`, `IsInitialized()`, `IsEqual()` and `GetUniqueID()`.
|
||
|
* Copyright 2020 Anton Tarasenko
|
||
|
*------------------------------------------------------------------------------
|
||
|
* This file is part of Acedia.
|
||
|
*
|
||
|
* Acedia is free software: you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation, version 3 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* Acedia is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with Acedia. If not, see <https://www.gnu.org/licenses/>.
|
||
|
*/
|
||
4 years ago
|
class UserID extends AcediaObject;
|
||
4 years ago
|
|
||
|
/**
|
||
4 years ago
|
* Stead data corresponding to a SteamID that relevant `UserID` was
|
||
4 years ago
|
* initialized with.
|
||
|
*
|
||
|
* For more info read: https://developer.valvesoftware.com/wiki/SteamID
|
||
|
*/
|
||
4 years ago
|
struct SteamID
|
||
4 years ago
|
{
|
||
|
var public byte accountType;
|
||
|
var public byte universe;
|
||
|
var public int instance;
|
||
|
// 32 lowest bits of SteadID64.
|
||
|
// Corresponds to a combination of "Y" and "Z" in "STEAM_X:Y:Z".
|
||
|
var public int steamID32;
|
||
4 years ago
|
// Other 4 fields fully define a SteamID and `steamID64` can be
|
||
|
// generated from them, but it is easier to simply cache it in
|
||
|
// a separate variable.
|
||
4 years ago
|
// `SteamID` is considered valid iff `steamID64` is equal to
|
||
4 years ago
|
// Steam64 ID that can be generated from other variables.
|
||
4 years ago
|
var string steamID64;
|
||
|
};
|
||
4 years ago
|
var protected SteamID initializedData;
|
||
|
// To make it safe to pass `UserID` to users, prevent any modifications
|
||
4 years ago
|
// after `initialized` is set to `true`.
|
||
|
var protected bool initialized;
|
||
|
|
||
|
// Given a number in form of array (`digits`) of it's digits
|
||
|
// (425327 <-> [4, 2, 5, 3, 2, 7])
|
||
|
// return given number mod 2 and
|
||
|
// divide that number by two (record result in that same array)
|
||
4 years ago
|
private static final function int DivideDigitArrayByTwo(out array<int> digits)
|
||
4 years ago
|
{
|
||
|
local int i;
|
||
|
local int wasOdd;
|
||
|
if (digits[digits.length - 1] % 2 == 1)
|
||
|
{
|
||
|
wasOdd = 1;
|
||
|
digits[digits.length - 1] -= 1;
|
||
|
}
|
||
|
for (i = digits.length - 1; i >= 0; i -= 1)
|
||
|
{
|
||
|
if (digits[i] % 2 == 1)
|
||
|
{
|
||
|
digits[i] -= 1;
|
||
|
// `digits[digits.length - 1]` was guaranteed to be even before
|
||
|
// this cycle, so it is safe to add 1 to the index here
|
||
|
digits[i + 1] += 5;
|
||
|
}
|
||
|
digits[i] = digits[i] / 2;
|
||
|
}
|
||
|
return wasOdd;
|
||
|
}
|
||
|
|
||
|
// Given a number in form of array (`digits`) of it's digits
|
||
|
// (425327 <-> [4, 2, 5, 3, 2, 7])
|
||
|
// extracts `bitsToRead` of lower bits from it and returns them as an `int`.
|
||
4 years ago
|
private static final function int ReadBitsFromDigitArray(
|
||
4 years ago
|
out array<int> digits,
|
||
|
int bitsToRead)
|
||
|
{
|
||
|
local int i;
|
||
|
local int result;
|
||
|
local int binaryPadding;
|
||
|
result = 0;
|
||
|
binaryPadding = 1;
|
||
|
for (i = 0; i < bitsToRead; i += 1) {
|
||
|
result += DivideDigitArrayByTwo(digits) * binaryPadding;
|
||
|
binaryPadding *= 2;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
// Explanation of what that is:
|
||
|
// https://developer.valvesoftware.com/wiki/SteamID#Types_of_Steam_Accounts
|
||
|
private final function string GetSteamAccountTypeCharacter()
|
||
|
{
|
||
|
// Individual
|
||
|
if (initializedData.accountType == 1) return "U";
|
||
|
// Multiseat
|
||
|
if (initializedData.accountType == 2) return "M";
|
||
|
// GameServer
|
||
|
if (initializedData.accountType == 3) return "G";
|
||
|
// AnonGameServer
|
||
|
if (initializedData.accountType == 4) return "A";
|
||
|
// Pending
|
||
|
if (initializedData.accountType == 5) return "P";
|
||
|
// ContentServer
|
||
|
if (initializedData.accountType == 6) return "C";
|
||
|
// Clan
|
||
|
if (initializedData.accountType == 7) return "g";
|
||
|
// Chat
|
||
|
if (initializedData.accountType == 8) return "c";
|
||
|
// P2P SuperSeeder
|
||
|
if (initializedData.accountType == 9) return "";
|
||
|
// AnonUser
|
||
|
if (initializedData.accountType == 10) return "a";
|
||
|
// Invalid
|
||
|
return "I";
|
||
|
}
|
||
|
|
||
|
/**
|
||
4 years ago
|
* Helper function that generates `SteamID` structure from
|
||
4 years ago
|
* a given Steam64 ID.
|
||
4 years ago
|
*
|
||
4 years ago
|
* In case invalid ID is given this method will not raise any warning and
|
||
|
* returned value should be considered undefined.
|
||
4 years ago
|
*
|
||
4 years ago
|
* @param steamID64 Steam64 ID's decimal representation in a plain string.
|
||
4 years ago
|
* @return `SteamID` generated from a given Steam64 ID `steamID64`.
|
||
4 years ago
|
*/
|
||
4 years ago
|
public static final function SteamID GetSteamIDFromSteamID64(
|
||
4 years ago
|
string steamID64)
|
||
4 years ago
|
{
|
||
|
local int i;
|
||
4 years ago
|
local SteamID newSteamID;
|
||
4 years ago
|
local array<Text.Character> characters;
|
||
|
local array<int> digits;
|
||
|
|
||
|
characters = _().text.StringToRaw(steamID64);
|
||
|
for (i = 0; i < characters.length; i += 1) {
|
||
|
digits[digits.length] = _().text.CharacterToInt(characters[i]);
|
||
|
}
|
||
4 years ago
|
newSteamID.steamID64 = steamID64;
|
||
4 years ago
|
// Refer to https://developer.valvesoftware.com/wiki/SteamID
|
||
|
// The lowest bit represents Y.
|
||
|
// The next 31 bits represents the account number.
|
||
|
// ^ these two can be combined into a "SteamID32".
|
||
4 years ago
|
newSteamID.steamID32 = ReadBitsFromDigitArray(digits, 32);
|
||
4 years ago
|
// The next 20 bits represents the instance of the account.
|
||
4 years ago
|
newSteamID.instance = ReadBitsFromDigitArray(digits, 20);
|
||
4 years ago
|
// The next 4 bits represents the type of account.
|
||
4 years ago
|
newSteamID.accountType = ReadBitsFromDigitArray(digits, 4);
|
||
4 years ago
|
// The next 8 bits represents the "Universe" the steam account belongs to.
|
||
4 years ago
|
newSteamID.universe = ReadBitsFromDigitArray(digits, 8);
|
||
|
return newSteamID;
|
||
4 years ago
|
}
|
||
|
|
||
|
/**
|
||
4 years ago
|
* Initializes caller `UserID` from a given `string` ID.
|
||
4 years ago
|
*
|
||
4 years ago
|
* Each `UserID` can only be initialized once and becomes immutable
|
||
4 years ago
|
* afterwards.
|
||
|
*
|
||
|
* @param steamID64 `string` with unique ID, provided by the game
|
||
|
* (Steam64 ID used in profile permalink,
|
||
|
* like http://steamcommunity.com/profiles/76561198025127722)
|
||
|
*
|
||
|
* @return `true` if initialization was successful and `false` otherwise
|
||
4 years ago
|
* (can only happen if caller `UserID` was already initialized).
|
||
4 years ago
|
*/
|
||
|
public final function bool Initialize(string steamID64)
|
||
|
{
|
||
|
if (initialized) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
4 years ago
|
initializedData = GetSteamIDFromSteamID64(steamID64);
|
||
4 years ago
|
initialized = true;
|
||
4 years ago
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
4 years ago
|
* Checks if caller `UserID` was already initialized
|
||
4 years ago
|
* (and is, therefore, immutable).
|
||
|
*
|
||
|
* @return `true` if it was initialized and `false` otherwise.
|
||
|
*/
|
||
|
public final function bool IsInitialized()
|
||
|
{
|
||
|
return initialized;
|
||
|
}
|
||
|
|
||
|
/**
|
||
4 years ago
|
* Returns steam data (see `UserID.SteamID`) of the caller `APlayerData`.
|
||
4 years ago
|
*
|
||
|
* Only returns a valid value if caller `APLayerData` was already initialized.
|
||
|
*
|
||
4 years ago
|
* @return `UserID.SteamID` of a caller `UserID`;
|
||
|
* structure will be filled with default values if caller `UserID`
|
||
4 years ago
|
* was not initialized.
|
||
|
*/
|
||
4 years ago
|
public final function SteamID GetSteamID()
|
||
4 years ago
|
{
|
||
|
return initializedData;
|
||
|
}
|
||
|
|
||
|
/**
|
||
4 years ago
|
* Checks if two `UserID`s are the same.
|
||
4 years ago
|
*
|
||
4 years ago
|
* @param otherID `UserID` to compare caller object to.
|
||
|
* @return `true` if caller `UserID` is identical to `otherID` and
|
||
|
* `false` otherwise. If at least one of the `UserID`s being compared is
|
||
4 years ago
|
* uninitialized, the result will be `false`.
|
||
|
*/
|
||
4 years ago
|
public final function bool IsEqual(UserID otherID)
|
||
4 years ago
|
{
|
||
|
if (!IsInitialized()) return false;
|
||
|
if (!otherID.IsInitialized()) return false;
|
||
|
return (initializedData.steamID32 == otherID.initializedData.steamID32);
|
||
|
}
|
||
|
|
||
4 years ago
|
/**
|
||
4 years ago
|
* Checks if caller `UserID`s is the same as what's described by
|
||
|
* given `SteamID`.
|
||
4 years ago
|
*
|
||
4 years ago
|
* NOTE: only part of the `otherSteamID` might be used for comparison.
|
||
|
* It is up to user to ensure that given `otherSteamID` is valid.
|
||
4 years ago
|
*
|
||
4 years ago
|
* @param otherSteamID `SteamID` to compare caller `UserID` to.
|
||
|
* @return `true` if caller `UserID` is identical to ID described by
|
||
|
* `otherSteamID` and `false` otherwise.
|
||
|
* If caller `UserID` is uninitialized, the result will be `false`.
|
||
4 years ago
|
*/
|
||
4 years ago
|
public final function bool IsEqualToSteamID(SteamID otherSteamID)
|
||
4 years ago
|
{
|
||
|
if (!IsInitialized()) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
4 years ago
|
return (initializedData.steamID32 == otherSteamID.steamID32);
|
||
4 years ago
|
}
|
||
|
|
||
4 years ago
|
/**
|
||
|
* Returns unique string representation of the caller `APlayerData`.
|
||
|
*
|
||
|
* Only returns a valid value if caller `APLayerData` was already initialized.
|
||
|
*
|
||
|
* @return Unique string representation of the caller `APlayerData`
|
||
|
* if it was initialized and `false` otherwise.
|
||
|
*/
|
||
|
public final function string GetUniqueID()
|
||
|
{
|
||
|
if (!IsInitialized()) return "";
|
||
|
return initializedData.steamID64;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns string representation of the caller `APlayerData` in
|
||
|
* following format: "STEAM_X:Y:Z".
|
||
|
*
|
||
|
* Only returns a valid value if caller `APLayerData` was already initialized.
|
||
|
*
|
||
|
* @return String representation of the caller `APlayerData` in
|
||
|
* form "STEAM_X:Y:Z" if it was initialized and empty `string` otherwise.
|
||
|
*/
|
||
|
public final function string GetSteamID()
|
||
|
{
|
||
|
local int Y, Z;
|
||
|
Y = 0;
|
||
|
Z = initializedData.steamID32;
|
||
|
if (Z % 2 == 1)
|
||
|
{
|
||
|
Y = 1;
|
||
|
Z -= 1;
|
||
|
}
|
||
|
Z = Z / 2;
|
||
|
return ("STEAM_" $ initializedData.universe $ ":" $ Y $ ":" $ Z);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns string representation of the caller `APlayerData` in
|
||
|
* following format: "C:U:A", where
|
||
|
* C is character representation of Account Type;
|
||
|
* U is "Universe" steam account belongs to;
|
||
|
* A is account ID.
|
||
|
*
|
||
|
* Only returns a valid value if caller `APLayerData` was already initialized.
|
||
|
*
|
||
|
* @return String representation of the caller `APlayerData` in
|
||
|
* form "C:U:A" if it was initialized and empty `string` otherwise.
|
||
|
*/
|
||
|
public final function string GetSteamID3()
|
||
|
{
|
||
|
return (GetSteamAccountTypeCharacter()
|
||
|
$ ":" $ initializedData.universe
|
||
|
$ ":" $ initializedData.steamID32);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns Steam32 ID for the caller `APlayerData`. It is a lowest 32 bits of
|
||
|
* the full Steam64 ID.
|
||
|
*
|
||
|
* Only returns a valid value if caller `APLayerData` was already initialized.
|
||
|
*
|
||
|
* @return Unique `int` representation of the caller `APlayerData`
|
||
|
* if it was initialized and `-1` otherwise.
|
||
|
*/
|
||
|
public final function int GetSteamID32()
|
||
|
{
|
||
|
if (!IsInitialized()) return -1;
|
||
|
return initializedData.steamID32;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns Steam64 ID for the caller `APlayerData`.
|
||
|
*
|
||
|
* Only returns a valid value if caller `APLayerData` was already initialized.
|
||
|
*
|
||
|
* Since UnrealEngine 2 does not support 64-bit integer values, it is returned
|
||
|
* simply as a decimal representation of a whole Steam64 ID
|
||
|
* (Steam64 ID used in profile permalink,
|
||
|
* like http://steamcommunity.com/profiles/76561198025127722).
|
||
|
*
|
||
|
* @return String representation of the Steam64 ID of the caller `APlayerData`
|
||
|
* if it was initialized and empty `string` otherwise.
|
||
|
*/
|
||
|
public final function string GetSteamID64()
|
||
|
{
|
||
|
if (!IsInitialized()) return "";
|
||
|
return initializedData.steamID64;
|
||
|
}
|
||
|
|
||
|
defaultproperties
|
||
|
{
|
||
|
}
|