diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..27ed978 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "tools"] + path = tools + url = https://github.com/GenZmeY/KF2-BuildTools diff --git a/AAL/Classes/AAL.uc b/AAL/Classes/AAL.uc new file mode 100644 index 0000000..7703ed9 --- /dev/null +++ b/AAL/Classes/AAL.uc @@ -0,0 +1,156 @@ +class AAL extends Info + config(AAL); + +const LatestVersion = 1; + +const CfgAdminList = class'AdminList'; + +var private config int Version; +var private config E_LogLevel LogLevel; + +var private OnlineSubsystem OS; +var private Array AdminUIDList; + +public simulated function bool SafeDestroy() +{ + `Log_Trace(); + + return (bPendingDelete || bDeleteMe || Destroy()); +} + +public event PreBeginPlay() +{ + `Log_Trace(); + + if (WorldInfo.NetMode == NM_Client) + { + `Log_Fatal("Wrong NetMode:" @ WorldInfo.NetMode); + SafeDestroy(); + return; + } + + Super.PreBeginPlay(); + + PreInit(); +} + +public event PostBeginPlay() +{ + `Log_Trace(); + + if (bPendingDelete || bDeleteMe) return; + + Super.PostBeginPlay(); + + PostInit(); +} + +private function PreInit() +{ + `Log_Trace(); + + if (Version == `NO_CONFIG) + { + LogLevel = LL_Info; + SaveConfig(); + } + + CfgAdminList.static.InitConfig(Version, LatestVersion, LogLevel); + + switch (Version) + { + case `NO_CONFIG: + `Log_Info("Config created"); + + case MaxInt: + `Log_Info("Config updated to version" @ LatestVersion); + break; + + case LatestVersion: + `Log_Info("Config is up-to-date"); + break; + + default: + `Log_Warn("The config version is higher than the current version (are you using an old mutator?)"); + `Log_Warn("Config version is" @ Version @ "but current version is" @ LatestVersion); + `Log_Warn("The config version will be changed to" @ LatestVersion); + break; + } + + if (LatestVersion != Version) + { + Version = LatestVersion; + SaveConfig(); + } + + if (LogLevel == LL_WrongLevel) + { + LogLevel = LL_Info; + + `Log_Warn("Wrong 'LogLevel', return to default value"); + + SaveConfig(); + } + `Log_Base("LogLevel:" @ LogLevel); + + OS = class'GameEngine'.static.GetOnlineSubsystem(); + if (OS != None) + { + AdminUIDList = CfgAdminList.static.Load(OS, LogLevel); + } + else + { + `Log_Fatal("Can't get online subsystem!"); + SafeDestroy(); + } +} + +private function PostInit() +{ + `Log_Trace(); +} + +public function NotifyLogin(Controller C) +{ + local PlayerController PC; + local PlayerReplicationInfo PRI; + local String UniqueID; + local String SteamID; + local String Profile; + + `Log_Trace(); + + if (C == None || C.PlayerReplicationInfo == None) return; + + PRI = C.PlayerReplicationInfo; + + if (AdminUIDList.Find('Uid', PRI.UniqueId.Uid) != INDEX_NONE) + { + PRI.bAdmin = true; + + UniqueID = OS.UniqueNetIdToString(PRI.UniqueId); + + PC = PlayerController(C); + if (PC != None && !PC.bIsEosPlayer) + { + SteamID = OS.UniqueNetIdToInt64(PRI.UniqueId); + Profile = "https://steamcommunity.com/profiles/" $ SteamID; + + `Log_Info("Admin login:" @ PRI.PlayerName @ "(" $ UniqueID $ "," @ SteamID $ "," @ Profile $ ")"); + } + else + { + `Log_Info("Admin login:" @ PRI.PlayerName @ "(" $ UniqueID $ ")"); + } + } +} + +public function NotifyLogout(Controller C) +{ + `Log_Trace(); +} + +defaultproperties +{ + +} \ No newline at end of file diff --git a/AAL/Classes/AAL.upkg b/AAL/Classes/AAL.upkg new file mode 100644 index 0000000..7d148dd --- /dev/null +++ b/AAL/Classes/AAL.upkg @@ -0,0 +1,4 @@ +[Flags] +AllowDownload=False +ClientOptional=False +ServerSideOnly=True diff --git a/AAL/Classes/AALMut.uc b/AAL/Classes/AALMut.uc new file mode 100644 index 0000000..942fda5 --- /dev/null +++ b/AAL/Classes/AALMut.uc @@ -0,0 +1,60 @@ +class AALMut extends KFMutator; + +var private AAL AAL; + +public simulated function bool SafeDestroy() +{ + return (bPendingDelete || bDeleteMe || Destroy()); +} + +public event PreBeginPlay() +{ + Super.PreBeginPlay(); + + if (WorldInfo.NetMode == NM_Client) return; + + foreach WorldInfo.DynamicActors(class'AAL', AAL) + { + break; + } + + if (AAL == None) + { + AAL = WorldInfo.Spawn(class'AAL'); + } + + if (AAL == None) + { + `Log_Base("FATAL: Can't Spawn 'AAL'"); + SafeDestroy(); + } +} + +public function AddMutator(Mutator Mut) +{ + if (Mut == Self) return; + + if (Mut.Class == Class) + Mut.Destroy(); + else + Super.AddMutator(Mut); +} + +public function NotifyLogin(Controller C) +{ + Super.NotifyLogin(C); + + AAL.NotifyLogin(C); +} + +public function NotifyLogout(Controller C) +{ + Super.NotifyLogout(C); + + AAL.NotifyLogout(C); +} + +DefaultProperties +{ + +} \ No newline at end of file diff --git a/AAL/Classes/AdminList.uc b/AAL/Classes/AdminList.uc new file mode 100644 index 0000000..198232f --- /dev/null +++ b/AAL/Classes/AdminList.uc @@ -0,0 +1,84 @@ +class AdminList extends Object + config(AAL) + abstract; + +var private config Array AdminId; + +public static function InitConfig(int Version, int LatestVersion, E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + switch (Version) + { + case `NO_CONFIG: + ApplyDefault(LogLevel); + + default: break; + } + + if (LatestVersion != Version) + { + StaticSaveConfig(); + } +} + +public static function Array Load(OnlineSubsystem OS, E_LogLevel LogLevel) +{ + local Array UIDs; + local UniqueNetId UID; + local String ID; + + `Log_TraceStatic(); + + foreach default.AdminId(ID) + { + if (AnyToUID(OS, ID, UID, LogLevel)) + { + UIDs.AddItem(UID); + `Log_Debug("Loaded:" @ ID); + } + else + { + `Log_Warn("Can't load AdminId:" @ ID); + } + } + + if (default.AdminId.Length == UIDs.Length) + { + `Log_Info("Loaded" @ UIDs.Length @ "entries"); + } + else + { + `Log_Info("Loaded" @ UIDs.Length @ "of" @ default.AdminId.Length @ "entries"); + } + + return UIDs; +} + +private static function ApplyDefault(E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + default.AdminId.Length = 0; + default.AdminId.AddItem("76561190000000000"); + default.AdminId.AddItem("0x0000000000000000"); +} + +private static function bool IsUID(String ID, E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + return (Locs(Left(ID, 2)) ~= "0x"); +} + +private static function bool AnyToUID(OnlineSubsystem OS, String ID, out UniqueNetId UID, E_LogLevel LogLevel) +{ + `Log_TraceStatic(); + + return IsUID(ID, LogLevel) ? OS.StringToUniqueNetId(ID, UID) : OS.Int64ToUniqueNetId(ID, UID); +} + +defaultproperties +{ + +} diff --git a/AAL/Classes/_Logger.uc b/AAL/Classes/_Logger.uc new file mode 100644 index 0000000..93fc28a --- /dev/null +++ b/AAL/Classes/_Logger.uc @@ -0,0 +1,20 @@ +class _Logger extends Object + abstract; + +enum E_LogLevel +{ + LL_WrongLevel, + LL_None, + LL_Fatal, + LL_Error, + LL_Warning, + LL_Info, + LL_Debug, + LL_Trace, + LL_All +}; + +defaultproperties +{ + +} diff --git a/AAL/Constants.uci b/AAL/Constants.uci new file mode 100644 index 0000000..1003f19 --- /dev/null +++ b/AAL/Constants.uci @@ -0,0 +1,2 @@ +// Constants +`define NO_CONFIG 0 diff --git a/AAL/Globals.uci b/AAL/Globals.uci new file mode 100644 index 0000000..a48ac52 --- /dev/null +++ b/AAL/Globals.uci @@ -0,0 +1,3 @@ +// Imports +`include(Logger.uci) +`include(Constants.uci) diff --git a/AAL/Logger.uci b/AAL/Logger.uci new file mode 100644 index 0000000..793f846 --- /dev/null +++ b/AAL/Logger.uci @@ -0,0 +1,15 @@ +// Logger +`define Log_Tag 'AAL' + +`define LocationStatic "`{ClassName}::" $ GetFuncName() + +`define Log_Base(msg, cond) `log(`msg `if(`cond), `cond`{endif}, `Log_Tag) + +`define Log_Fatal(msg) `log("FATAL:" @ `msg, (LogLevel >= LL_Fatal), `Log_Tag) +`define Log_Error(msg) `log("ERROR:" @ `msg, (LogLevel >= LL_Error), `Log_Tag) +`define Log_Warn(msg) `log("WARN:" @ `msg, (LogLevel >= LL_Warning), `Log_Tag) +`define Log_Info(msg) `log("INFO:" @ `msg, (LogLevel >= LL_Info), `Log_Tag) +`define Log_Debug(msg) `log("DEBUG:" @ `msg, (LogLevel >= LL_Debug), `Log_Tag) + +`define Log_Trace(msg) `log("TRACE:" @ `Location `if(`msg) @ `msg`{endif}, (LogLevel >= LL_Trace), `Log_Tag) +`define Log_TraceStatic(msg) `log("TRACE:" @ `LocationStatic `if(`msg) @ `msg`{endif}, (LogLevel >= LL_Trace), `Log_Tag) diff --git a/PublicationContent/ID1.png b/PublicationContent/ID1.png new file mode 100644 index 0000000..996c79b Binary files /dev/null and b/PublicationContent/ID1.png differ diff --git a/PublicationContent/ID2.png b/PublicationContent/ID2.png new file mode 100644 index 0000000..2febcce Binary files /dev/null and b/PublicationContent/ID2.png differ diff --git a/PublicationContent/ID3.png b/PublicationContent/ID3.png new file mode 100644 index 0000000..cfc4188 Binary files /dev/null and b/PublicationContent/ID3.png differ diff --git a/PublicationContent/description.txt b/PublicationContent/description.txt new file mode 100644 index 0000000..8821469 --- /dev/null +++ b/PublicationContent/description.txt @@ -0,0 +1,43 @@ +[img]https://img.shields.io/static/v1?logo=GitHub&labelColor=gray&color=blue&logoColor=white&label=&message=Open Source[/img] [img]https://img.shields.io/github/license/GenZmeY/KF2-AdminAutoLogin[/img] [img]https://img.shields.io/steam/favorites/2848836389[/img] [img]https://img.shields.io/steam/update-date/2848836389[/img] [url=https://steamcommunity.com/sharedfiles/filedetails/changelog/2848836389][img]https://img.shields.io/github/v/tag/GenZmeY/KF2-AdminAutoLogin[/img][/url] + +[h1]Description[/h1] +Small server-side mutator that allows specified players to automatically login as an admin. + +[h1]Whitelisted?[/h1] +No. This mod is not whitelisted and will de-rank your server. Any XP gained will not be saved. + +[h1]Usage (server)[/h1] +[b]Note:[/b] [i]If you don't understand what is written here, read the article [url=https://wiki.killingfloor2.com/index.php?title=Dedicated_Server_(Killing_Floor_2)][u]Dedicated Server (KF2 wiki)[/u][/url] before following these instructions.[/i] +[olist] +[*]Open your [b]PCServer-KFEngine.ini[/b] / [b]LinuxServer-KFEngine.ini[/b]; +[*]Find the [b][IpDrv.TcpNetDriver][/b] section and make sure that there is a line (add if not): +[b]DownloadManagers=OnlineSubsystemSteamworks.SteamWorkshopDownload[/b] +❗️ If there are several [b]DownloadManagers=[/b] then the line above should be the first ❗️ +[*]Add the following string to the [b][OnlineSubsystemSteamworks.KFWorkshopSteamworks][/b] section (create one if it doesn't exist): +[b]ServerSubscribedWorkshopItems=2848836389[/b] +[*]Start the server and wait until the mutator is downloading; +[*]Add mutator to server start parameters: [b]?Mutator=AAL.AALMut[/b] and restart the server. +[/olist] + +[h1]Setup (KFAAL.ini)[/h1] +Config will be created at the first start. +[list] +[*]Use [b]AdminId[/b] to set the list of admins. You can use UniqueID or SteamID; +[/list] + +[h1]Getting ID[/h1] +You can view the Steam ID and UniqueID in WebAdmin on the PLAYERS tab: +[img]https://raw.githubusercontent.com/GenZmeY/KF2-AdminAutoLogin/master/PublicationContent/ID1.png[/img] + +But don't try to use the SteamID from here for EGS players - it won't work. SteamID is for Steam players only. +UniqueID is suitable for all platforms. + +SteamID can also be obtained from the player's profile, look at the URL: +[img]https://raw.githubusercontent.com/GenZmeY/KF2-AdminAutoLogin/master/PublicationContent/ID2.png[/img] + +If a player uses a nickname in a link to their profile, then add this to the profile url: [b]?xml=1[/b] +SteamID will be at the beginning: +[img]https://raw.githubusercontent.com/GenZmeY/KF2-AdminAutoLogin/master/PublicationContent/ID3.png[/img] + +[h1]Sources[/h1] +[url=https://github.com/GenZmeY/KF2-AdminAutoLogin]https://github.com/GenZmeY/KF2-AdminAutoLogin[/url] [b](GNU GPLv3)[/b] \ No newline at end of file diff --git a/PublicationContent/preview.png b/PublicationContent/preview.png new file mode 100644 index 0000000..b19560b Binary files /dev/null and b/PublicationContent/preview.png differ diff --git a/PublicationContent/tags.txt b/PublicationContent/tags.txt new file mode 100644 index 0000000..b97e882 --- /dev/null +++ b/PublicationContent/tags.txt @@ -0,0 +1 @@ +Gamemodes,Mutators diff --git a/PublicationContent/title.txt b/PublicationContent/title.txt new file mode 100644 index 0000000..b5ea14b --- /dev/null +++ b/PublicationContent/title.txt @@ -0,0 +1 @@ +Admin Auto Login diff --git a/README.md b/README.md index 37720b6..051b4e8 100644 --- a/README.md +++ b/README.md @@ -1 +1,34 @@ -# KF2-AdminAutoLogin \ No newline at end of file +# Admin Auto Login + +[![Steam Workshop](https://img.shields.io/static/v1?message=workshop&logo=steam&labelColor=gray&color=blue&logoColor=white&label=steam%20)](https://steamcommunity.com/sharedfiles/filedetails/?id=2848836389) +[![Steam Favorites](https://img.shields.io/steam/favorites/2848836389)](https://steamcommunity.com/sharedfiles/filedetails/?id=2848836389) +[![Steam Update Date](https://img.shields.io/steam/update-date/2848836389)](https://steamcommunity.com/sharedfiles/filedetails/?id=2848836389) +[![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/GenZmeY/KF2-AdminAutoLogin)](https://github.com/GenZmeY/KF2-AdminAutoLogin/tags) +[![GitHub](https://img.shields.io/github/license/GenZmeY/KF2-AdminAutoLogin)](LICENSE) + +# Description +Small server-side mutator that allows specified players to automatically login as an admin. + +# Usage & Setup +[See steam workshop page](https://steamcommunity.com/sharedfiles/filedetails/?id=2848836389) + +# Build +**Note:** If you want to build/test/brew/publish a mutator without git-bash and/or scripts, follow [these instructions](https://tripwireinteractive.atlassian.net/wiki/spaces/KF2SW/pages/26247172/KF2+Code+Modding+How-to) instead of what is described here. +1. Install [Killing Floor 2](https://store.steampowered.com/app/232090/Killing_Floor_2/), Killing Floor 2 - SDK and [git for windows](https://git-scm.com/download/win); +2. open git-bash and go to any folder where you want to store sources: +`cd ` +3. Clone this repository and go to the source folder: +`git clone https://github.com/GenZmeY/KF2-AdminAutoLogin && cd KF2-AdminAutoLogin` +4. Download dependencies: +`git submodule init && git submodule update` +5. Compile: +`./tools/builder -c` +5. The compiled files will be here: +`C:\Users\\Documents\My Games\KillingFloor2\KFGame\Unpublished\BrewedPC\Script\` + +# Bug reports +If you find a bug, go to the [issue page](https://github.com/GenZmeY/KF2-AdminAutoLogin/issues) and check if there is a description of your bug. If not, create a new issue. +Describe what the bug looks like and how reproduce it. + +# License +[GNU GPLv3](LICENSE) diff --git a/builder.cfg b/builder.cfg new file mode 100644 index 0000000..ac19eb7 --- /dev/null +++ b/builder.cfg @@ -0,0 +1,52 @@ +### Build parameters ### + +# If True - compresses the mutator when compiling +# Scripts will be stored in binary form +# (reduces the size of the output file) +StripSource="True" + +# Mutators to be compiled +# Specify them with a space as a separator, +# Mutators will be compiled in the specified order +PackageBuildOrder="AAL" + + +### Steam Workshop upload parameters ### + +# Mutators that will be uploaded to the workshop +# Specify them with a space as a separator, +# The order doesn't matter +PackageUpload="AAL" + + +### Test parameters ### + +# Map: +Map="KF-Nuked" + +# Game: +# Survival: KFGameContent.KFGameInfo_Survival +# WeeklyOutbreak: KFGameContent.KFGameInfo_WeeklySurvival +# Endless: KFGameContent.KFGameInfo_Endless +# Objective: KFGameContent.KFGameInfo_Objective +# Versus: KFGameContent.KFGameInfo_VersusSurvival +Game="AAL.restore KFEditor.ini from backup" + +# Difficulty: +# Normal: 0 +# Hard: 1 +# Suicide: 2 +# Hell: 3 +Difficulty="0" + +# GameLength: +# 4 waves: 0 +# 7 waves: 1 +# 10 waves: 2 +GameLength="0" + +# Mutators +Mutators="AAL.AALMut" + +# Additional parameters +Args="" diff --git a/tools b/tools new file mode 160000 index 0000000..2f173aa --- /dev/null +++ b/tools @@ -0,0 +1 @@ +Subproject commit 2f173aad7a6f4578574764801136a0d86e830653