From 98194b3917e24023b6e03711ae2210a19ff16cbd Mon Sep 17 00:00:00 2001 From: GenZmeY Date: Sun, 14 May 2023 04:20:07 +0300 Subject: [PATCH 1/5] update build tools --- tools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools b/tools index 88b35bd..fb458ac 160000 --- a/tools +++ b/tools @@ -1 +1 @@ -Subproject commit 88b35bd7ebb7e30448579f1564220398f990541c +Subproject commit fb458ac61f7e6c6426b8dff366dd5e7499e0d95f From 0a5e62e3e75ed67f3801dc66746289c30161af90 Mon Sep 17 00:00:00 2001 From: GenZmeY Date: Sun, 14 May 2023 04:32:25 +0300 Subject: [PATCH 2/5] add .editorconfig --- .editorconfig | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..b60821d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,32 @@ +root = true + +# Global +[*] +indent_style = unset +indent_size = 4 +tab_width = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = unset + +# Unreal Engine 3 / Source +[*.uc] +indent_style = tab + +[*.{uci,upkg}] + +# Unreal Engine 3 / i18n +[*.{chn,cht,cze,dan,deu,dut,esl,esn,fra,frc,hun,int,ita,jpn,kor,pol,por,ptb,rus,tur,ukr}] +charset = utf-16le + +# Other +[*.md] +trim_trailing_whitespace = false + +[*.yml] +indent_style = space +indent_size = 2 + +[*.{txt,cfg,conf}] +indent_style = tab From 64893b7484a3f59ed14bf2476f4ff1a10b579d11 Mon Sep 17 00:00:00 2001 From: GenZmeY Date: Sun, 14 May 2023 04:32:45 +0300 Subject: [PATCH 3/5] add MegaLinter --- .github/workflows/mega-linter.yml | 72 +++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 .github/workflows/mega-linter.yml diff --git a/.github/workflows/mega-linter.yml b/.github/workflows/mega-linter.yml new file mode 100644 index 0000000..24897f3 --- /dev/null +++ b/.github/workflows/mega-linter.yml @@ -0,0 +1,72 @@ +--- +name: MegaLinter + +permissions: read-all + +on: + push: + pull_request: + branches: [master] + +env: + APPLY_FIXES: none + APPLY_FIXES_EVENT: pull_request + APPLY_FIXES_MODE: commit + DISABLE: SPELL + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +jobs: + build: + name: MegaLinter + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v3 + with: + token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }} + + - name: MegaLinter + id: ml + uses: oxsecurity/megalinter@v6 + env: + VALIDATE_ALL_CODEBASE: true + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Archive production artifacts + if: ${{ success() }} || ${{ failure() }} + uses: actions/upload-artifact@v3 + with: + name: MegaLinter reports + path: | + megalinter-reports + mega-linter.log + + - name: Create Pull Request with applied fixes + id: cpr + if: steps.ml.outputs.has_updated_sources == 1 && (env.APPLY_FIXES_EVENT == 'all' || env.APPLY_FIXES_EVENT == github.event_name) && env.APPLY_FIXES_MODE == 'pull_request' && (github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository) + uses: peter-evans/create-pull-request@v5 + with: + token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }} + commit-message: "[MegaLinter] Apply linters automatic fixes" + title: "[MegaLinter] Apply linters automatic fixes" + labels: bot + - name: Create PR output + if: steps.ml.outputs.has_updated_sources == 1 && (env.APPLY_FIXES_EVENT == 'all' || env.APPLY_FIXES_EVENT == github.event_name) && env.APPLY_FIXES_MODE == 'pull_request' && (github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository) + run: | + echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}" + echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}" + + - name: Prepare commit + if: steps.ml.outputs.has_updated_sources == 1 && (env.APPLY_FIXES_EVENT == 'all' || env.APPLY_FIXES_EVENT == github.event_name) && env.APPLY_FIXES_MODE == 'commit' && github.ref != 'refs/heads/main' && (github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository) + run: sudo chown -Rc $UID .git/ + - name: Commit and push applied linter fixes + if: steps.ml.outputs.has_updated_sources == 1 && (env.APPLY_FIXES_EVENT == 'all' || env.APPLY_FIXES_EVENT == github.event_name) && env.APPLY_FIXES_MODE == 'commit' && github.ref != 'refs/heads/main' && (github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository) + uses: stefanzweifel/git-auto-commit-action@v4 + with: + branch: ${{ github.event.pull_request.head.ref || github.head_ref || github.ref }} + commit_message: "[MegaLinter] Apply linters fixes" + commit_user_name: megalinter-bot + commit_user_email: nicolas.vuillamy@ox.security From 42c844fffda199c5a21b5c89c9939db709d83d84 Mon Sep 17 00:00:00 2001 From: GenZmeY Date: Sun, 14 May 2023 04:41:54 +0300 Subject: [PATCH 4/5] update style --- DEV.md | 112 +++--- README.md | 18 +- SML/Classes/KFGI_Access.uc | 2 +- SML/Classes/Mut.uc | 282 +++++++-------- SML/Classes/SML.upkg | 8 +- SML/Classes/SafeMutLoader.uc | 660 +++++++++++++++++------------------ SML/Classes/_Logger.uc | 40 +-- SML/Constants.uci | 4 +- SML/Globals.uci | 6 +- SML/Logger.uci | 30 +- builder.cfg | 6 +- 11 files changed, 584 insertions(+), 584 deletions(-) diff --git a/DEV.md b/DEV.md index e25afa6..f300868 100644 --- a/DEV.md +++ b/DEV.md @@ -2,7 +2,7 @@ **SML compatible mutator development guide** -# Mutator template +## Mutator template You can use this template to make the mutator compatible with SML. Here I will use `Example` as mutator name. **Replace it with yours.** @@ -10,64 +10,64 @@ Here I will use `Example` as mutator name. **Replace it with yours.** **ExampleMut.uc** ```unrealscript class ExampleMut extends KFMutator; - + var private Example Example; public simulated function bool SafeDestroy() { - return (bPendingDelete || bDeleteMe || Destroy()); + return (bPendingDelete || bDeleteMe || Destroy()); } public event PreBeginPlay() { - Super.PreBeginPlay(); - - if (WorldInfo.NetMode == NM_Client) return; - - foreach WorldInfo.DynamicActors(class'Example', Example) - { - break; - } - - if (Example == None) - { - Example = WorldInfo.Spawn(class'Example'); - } - - if (Example == None) - { - `Log("Example: FATAL: Can't Spawn 'Example'"); - SafeDestroy(); - } + Super.PreBeginPlay(); + + if (WorldInfo.NetMode == NM_Client) return; + + foreach WorldInfo.DynamicActors(class'Example', Example) + { + break; + } + + if (Example == None) + { + Example = WorldInfo.Spawn(class'Example'); + } + + if (Example == None) + { + `Log("Example: FATAL: Can't Spawn 'Example'"); + SafeDestroy(); + } } public function AddMutator(Mutator Mut) { - if (Mut == Self) return; - - if (Mut.Class == Class) - ExampleMut(Mut).SafeDestroy(); - else - Super.AddMutator(Mut); + if (Mut == Self) return; + + if (Mut.Class == Class) + ExampleMut(Mut).SafeDestroy(); + else + Super.AddMutator(Mut); } public function NotifyLogin(Controller C) { - Example.NotifyLogin(C); - - Super.NotifyLogin(C); + Example.NotifyLogin(C); + + Super.NotifyLogin(C); } public function NotifyLogout(Controller C) { - Example.NotifyLogout(C); - - Super.NotifyLogout(C); + Example.NotifyLogout(C); + + Super.NotifyLogout(C); } static function String GetLocalString(optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2) { - return String(class'Example'); + return String(class'Example'); } defaultproperties @@ -82,34 +82,34 @@ class Example extends Info; public event PreBeginPlay() { - Super.PreBeginPlay(); + Super.PreBeginPlay(); - // do some initialization here + // do some initialization here } public event PostBeginPlay() { - Super.PostBeginPlay(); + Super.PostBeginPlay(); - // do some initialization here + // do some initialization here } public function NotifyLogin(Controller C) { - // Do what you need here when the player log in + // Do what you need here when the player log in } public function NotifyLogout(Controller C) { - // Do what you need here when the player log out + // Do what you need here when the player log out } public simulated function vector GetTargetLocation(optional actor RequestedBy, optional bool bRequestAlternateLoc) { - local Controller C; - C = Controller(RequestedBy); - if (C != None) { bRequestAlternateLoc ? NotifyLogout(C) : NotifyLogin(C); } - return Super.GetTargetLocation(RequestedBy, bRequestAlternateLoc); + local Controller C; + C = Controller(RequestedBy); + if (C != None) { bRequestAlternateLoc ? NotifyLogout(C) : NotifyLogin(C); } + return Super.GetTargetLocation(RequestedBy, bRequestAlternateLoc); } defaultproperties @@ -120,21 +120,21 @@ defaultproperties That's all. You can create new classes and add any code to `Example.uc` (yay!), but refrain from implementing anything else in `ExampleMut.uc` because it will not be used. -# Limitations +## Limitations ❌ Can't make ranked game mode this way; ❌ SML can only emulate [`NotifyLogin(...)`](https://github.com/GenZmeY/KF2-Dev-Scripts/blob/23d1ca3a9a2f62692741e77039f03fe0a913be1d/Engine/Classes/Mutator.uc#L147) and [`NotifyLogout(...)`](https://github.com/GenZmeY/KF2-Dev-Scripts/blob/23d1ca3a9a2f62692741e77039f03fe0a913be1d/Engine/Classes/Mutator.uc#L141), other functions of the [`Mutator`](https://github.com/GenZmeY/KF2-Dev-Scripts/blob/master/Engine/Classes/Mutator.uc) and [`KFMutator`](https://github.com/GenZmeY/KF2-Dev-Scripts/blob/master/KFGame/Classes/KFMutator.uc) classes are not supported - look for workarounds in this case. -# Tips +## Tips ## Alternative to the InitMutator(...) function Even though the [`InitMutator(...)`](https://github.com/GenZmeY/KF2-Dev-Scripts/blob/23d1ca3a9a2f62692741e77039f03fe0a913be1d/KFGame/Classes/KFMutator.uc#L22) function is not supported, you can still parse the startup string if you need to: Refer to [`WorldInfo.GetLocalURL()`](https://github.com/GenZmeY/KF2-Dev-Scripts/blob/23d1ca3a9a2f62692741e77039f03fe0a913be1d/Engine/Classes/WorldInfo.uc#L1315) and get the option from there. It's best to do this in `PreBeginPlay()` or `PostBeginPlay()` of your `Example.uc` (as well as other initializations). -## XP for custom Zeds / Weapons +### XP for custom Zeds / Weapons While custom weapons and zeds won't make your server unranked, the [`ValidateForXP(...)`](https://github.com/GenZmeY/KF2-Dev-Scripts/blob/23d1ca3a9a2f62692741e77039f03fe0a913be1d/KFGame/Classes/KFGameInfo.uc#L2564) function will not allow you to gain experience if it detects a custom zed or custom damage type. Therefore, if you want to gain experience - make sure that [`ValidateForXP(...)`](https://github.com/GenZmeY/KF2-Dev-Scripts/blob/23d1ca3a9a2f62692741e77039f03fe0a913be1d/KFGame/Classes/KFGameInfo.uc#L2564) does not receive custom zed classes or custom damage types. For example you can change your custom weapon to use only default damage types or try changing the `DamageHistory` and/or `MonsterClass` before it gets into [`DistributeMoneyAndXP(...)`](https://github.com/GenZmeY/KF2-Dev-Scripts/blob/23d1ca3a9a2f62692741e77039f03fe0a913be1d/KFGame/Classes/KFGameInfo.uc#L2489). -## Replacing base classes to bypass restrictions +### Replacing base classes to bypass restrictions In some cases, changing the base classes of the game can help. For example, we cannot make [TAWOD](https://steamcommunity.com/sharedfiles/filedetails/?id=2379769040) and SML compatible because the [PreventDeath(...)](https://github.com/GenZmeY/KF2-TAWOD/blob/master/TAWOD/Classes/TAWODMut.uc#L19) function is not supported. But this can be bypassed by replacing the player's Pawn base class with custom Pawn class: ```unrealscript WorldInfo.Game.DefaultPawnClass = class'ExamplePawn_Human'; // Put this to `PostBeginPlay()` of your Example.uc @@ -146,13 +146,13 @@ class ExamplePawn_Human extends KFPawn_Human; public function ThrowWeaponOnDeath() { - local KFWeapon KFW; - - if (InvManager == None) return; - - foreach InvManager.InventoryActors(class'KFWeapon', KFW) - if (KFW.bDropOnDeath && KFW.CanThrow()) - KFP.TossInventory(KFW); + local KFWeapon KFW; + + if (InvManager == None) return; + + foreach InvManager.InventoryActors(class'KFWeapon', KFW) + if (KFW.bDropOnDeath && KFW.CanThrow()) + KFP.TossInventory(KFW); } ``` diff --git a/README.md b/README.md index 1dbe8d3..fc1a5dc 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,19 @@ # KF2-SafeMutLoader Use non-whitelisted mutators and stay ranked. -# Disclaimer +## Disclaimer **SML only uses KF2 and UnrealScript features, it doesn't change game executables or RAM or anything like that, so it's not a hack and it doesn't violate [Killing Floor 2 EULA](https://store.steampowered.com/eula/232090_eula_0).** However, [AccessPlus](https://forums.tripwireinteractive.com/index.php?threads/utility-admin-access-plus-manager.118740) is also not a hack for the same reason, but it is constantly banned in the steam workshop. Why? I dont know. **So use this at your own risk!** -# Usage (server only) +## Usage (server only) 1. Add SML to your server. There are two ways: * **without workshop:** download `SML.u` from [releases](https://github.com/GenZmeY/KF2-SafeMutLoader/releases) and put it to `KFGame/BrewedPC` * **with workshop:** Use the [instructions below](https://github.com/GenZmeY/KF2-SafeMutLoader#build--upload) to build the SML and upload it to your workshop, then subscribe your server to SML 2. Add `SML.Mut` **first** to your list of mutators, example: -``` +```text ?Mutator=SML.Mut,UnofficialKFPatch.UKFPMutator,AAL.AALMut,DiscordMessage.DMMutator,YAS.YASMut,CTI.CTIMut,CVC.CVCMut,ZedSpawner.ZedSpawnerMut ``` (add/remove **compatible** mutators you need) @@ -24,7 +24,7 @@ However, [AccessPlus](https://forums.tripwireinteractive.com/index.php?threads/u ⚠️ SML is a server-side mutator, clients never download it. Therefore, no one will know about you using SML if you don’t tell yourself (or if you share with the whole world the `BrewedPC` folder where you put the SML, lol). ⚠️ SML is incompatible with [AccessPlus](https://github.com/th3-z/kf2-acpp) and other mods based on it. If you need something from there, implement it as an SML compatible mutator using [developer guide](https://github.com/GenZmeY/KF2-SafeMutLoader/blob/master/DEV.md). -# Compatible mutators +## Compatible mutators 🟢 Any whitelisted mutators 🟢 [Admin Auto Login](https://steamcommunity.com/sharedfiles/filedetails/?id=2848836389) 🟢 [Controlled Vote Collector](https://steamcommunity.com/sharedfiles/filedetails/?id=2847465899) @@ -38,10 +38,10 @@ Since KF2 [v1133](https://wiki.killingfloor2.com/index.php?title=Update_1133_(Ki 🟡 [Zed Spawner](https://steamcommunity.com/sharedfiles/filedetails/?id=2811290931) Since KF2 [v1133](https://wiki.killingfloor2.com/index.php?title=Update_1133_(Killing_Floor_2)) zed preload causes the server to unrank for some reason. Disable it in ZedSpawner settings (`bPreloadContentServer=False`) to stay ranked. -# Making SML-compatible mutators +## Making SML-compatible mutators See [developer guide](https://github.com/GenZmeY/KF2-SafeMutLoader/blob/master/DEV.md) -# Build & Upload +## Build & Upload **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: @@ -54,9 +54,9 @@ See [developer guide](https://github.com/GenZmeY/KF2-SafeMutLoader/blob/master/D `./tools/builder -cbu` 6. Find `SafeMutLoader` in your workshop and change `Visibility` to `Unlisted` so your server can download it (don't use `Public` visibility) -# Contributing +## Contributing If you make a mod compatible with SML I'll be happy to add it to the list of compatible mutators. Contact me in any convenient way (for example, create an [issue](https://github.com/GenZmeY/KF2-SafeMutLoader/issues)) -# License -[GNU GPLv3](LICENSE) +## License +[![license](https://www.gnu.org/graphics/gplv3-with-text-136x68.png)](LICENSE) diff --git a/SML/Classes/KFGI_Access.uc b/SML/Classes/KFGI_Access.uc index 84c1ab6..89fb482 100644 --- a/SML/Classes/KFGI_Access.uc +++ b/SML/Classes/KFGI_Access.uc @@ -7,5 +7,5 @@ public function bool IsRankedGame() defaultproperties { - + } diff --git a/SML/Classes/Mut.uc b/SML/Classes/Mut.uc index 02a86b8..358c710 100644 --- a/SML/Classes/Mut.uc +++ b/SML/Classes/Mut.uc @@ -1,142 +1,142 @@ -class Mut extends KFMutator; - -const SML = class'SafeMutLoader'; - -const OptAC = "AccessControl"; -const OptMut = "Mutator"; - -var private E_LogLevel LogLevel; - -public function PreBeginPlay() -{ - Super.PreBeginPlay(); - - LogLevel = SML.static.GetLogLevel(); - - `Log_Trace(); - - if (CorrectLoadOrder()) - { - ModifyLoad(); - } - else - { - `Log_Fatal(SML.static.GetName(Self) @ "must be loaded first."); - } -} - -public function AddMutator(Mutator Mut) -{ - `Log_Trace(); - - if (CorrectLoadOrder() || Mut == Self) return; - - if (Mut.Class == Class) - { - Mut.Destroy(); - } - else - { - Super.AddMutator(Mut); - } -} - -private function bool CorrectLoadOrder() -{ - `Log_Trace(); - - return ( - WorldInfo.Game.BaseMutator == None || - WorldInfo.Game.BaseMutator == Self); -} - -private function ModifyLoad() -{ - local String LoadURL; - local String LoadParams; - local String MutatorsRaw; - local String AccessControlRaw; - local Array Mutators; - local int PrevServerActorsCount; - local int Index; - local GameEngine GameEngine; - - `Log_Trace(); - - LoadURL = WorldInfo.GetLocalURL(); - LoadParams = Mid(LoadURL, InStr(LoadURL, "?")); - MutatorsRaw = WorldInfo.Game.ParseOption(LoadParams, OptMut); - AccessControlRaw = WorldInfo.Game.ParseOption(LoadParams, OptAC); - - LoadURL = Repl(LoadURL, Subst(OptMut) $ MutatorsRaw, ""); - LoadURL = Repl(LoadURL, Subst(OptAC) $ AccessControlRaw, ""); - - SML.static.ClearMutators(); - SML.static.ClearServerActors(); - ParseStringIntoArray(MutatorsRaw, Mutators, ",", true); - - Index = 0; - while (Index < Mutators.Length) - { - if (SML.static.AddMutator(Mutators[Index]) || - Mutators[Index] ~= SML.static.GetName(Self)) - { - Mutators.Remove(Index, 1); - } - else - { - ++Index; - } - } - - GameEngine = GameEngine(Class'Engine'.static.GetEngine()); - if (GameEngine == None) - { - `Log_Error("GameEngine is None, skip loading server actors"); - } - else - { - PrevServerActorsCount = GameEngine.ServerActors.Length; - - Index = 0; - while (Index < GameEngine.ServerActors.Length) - { - if (SML.static.AddServerActor(GameEngine.ServerActors[Index])) - { - GameEngine.ServerActors.Remove(Index, 1); - } - else - { - ++Index; - } - } - - if (GameEngine.ServerActors.Length != PrevServerActorsCount) - { - GameEngine.SaveConfig(); - } - } - - SML.static.StaticSaveConfig(); - - JoinArray(Mutators, MutatorsRaw); - LoadURL $= (Subst(OptMut) $ MutatorsRaw); - if (SML.static.WantsToSpawn()) - { - LoadURL $= (Subst(OptAC) $ SML.static.GetName()); - } - - `Log_Info("Loader modified, do server travel..."); - - WorldInfo.ServerTravel(LoadURL, true); -} - -private static function String Subst(String Option) -{ - return ("?" $ Option $ "="); -} - -defaultproperties -{ - +class Mut extends KFMutator; + +const SML = class'SafeMutLoader'; + +const OptAC = "AccessControl"; +const OptMut = "Mutator"; + +var private E_LogLevel LogLevel; + +public function PreBeginPlay() +{ + Super.PreBeginPlay(); + + LogLevel = SML.static.GetLogLevel(); + + `Log_Trace(); + + if (CorrectLoadOrder()) + { + ModifyLoad(); + } + else + { + `Log_Fatal(SML.static.GetName(Self) @ "must be loaded first."); + } +} + +public function AddMutator(Mutator Mut) +{ + `Log_Trace(); + + if (CorrectLoadOrder() || Mut == Self) return; + + if (Mut.Class == Class) + { + Mut.Destroy(); + } + else + { + Super.AddMutator(Mut); + } +} + +private function bool CorrectLoadOrder() +{ + `Log_Trace(); + + return ( + WorldInfo.Game.BaseMutator == None || + WorldInfo.Game.BaseMutator == Self); +} + +private function ModifyLoad() +{ + local String LoadURL; + local String LoadParams; + local String MutatorsRaw; + local String AccessControlRaw; + local Array Mutators; + local int PrevServerActorsCount; + local int Index; + local GameEngine GameEngine; + + `Log_Trace(); + + LoadURL = WorldInfo.GetLocalURL(); + LoadParams = Mid(LoadURL, InStr(LoadURL, "?")); + MutatorsRaw = WorldInfo.Game.ParseOption(LoadParams, OptMut); + AccessControlRaw = WorldInfo.Game.ParseOption(LoadParams, OptAC); + + LoadURL = Repl(LoadURL, Subst(OptMut) $ MutatorsRaw, ""); + LoadURL = Repl(LoadURL, Subst(OptAC) $ AccessControlRaw, ""); + + SML.static.ClearMutators(); + SML.static.ClearServerActors(); + ParseStringIntoArray(MutatorsRaw, Mutators, ",", true); + + Index = 0; + while (Index < Mutators.Length) + { + if (SML.static.AddMutator(Mutators[Index]) || + Mutators[Index] ~= SML.static.GetName(Self)) + { + Mutators.Remove(Index, 1); + } + else + { + ++Index; + } + } + + GameEngine = GameEngine(Class'Engine'.static.GetEngine()); + if (GameEngine == None) + { + `Log_Error("GameEngine is None, skip loading server actors"); + } + else + { + PrevServerActorsCount = GameEngine.ServerActors.Length; + + Index = 0; + while (Index < GameEngine.ServerActors.Length) + { + if (SML.static.AddServerActor(GameEngine.ServerActors[Index])) + { + GameEngine.ServerActors.Remove(Index, 1); + } + else + { + ++Index; + } + } + + if (GameEngine.ServerActors.Length != PrevServerActorsCount) + { + GameEngine.SaveConfig(); + } + } + + SML.static.StaticSaveConfig(); + + JoinArray(Mutators, MutatorsRaw); + LoadURL $= (Subst(OptMut) $ MutatorsRaw); + if (SML.static.WantsToSpawn()) + { + LoadURL $= (Subst(OptAC) $ SML.static.GetName()); + } + + `Log_Info("Loader modified, do server travel..."); + + WorldInfo.ServerTravel(LoadURL, true); +} + +private static function String Subst(String Option) +{ + return ("?" $ Option $ "="); +} + +defaultproperties +{ + } \ No newline at end of file diff --git a/SML/Classes/SML.upkg b/SML/Classes/SML.upkg index 7d148dd..ae6c83c 100644 --- a/SML/Classes/SML.upkg +++ b/SML/Classes/SML.upkg @@ -1,4 +1,4 @@ -[Flags] -AllowDownload=False -ClientOptional=False -ServerSideOnly=True +[Flags] +AllowDownload=False +ClientOptional=False +ServerSideOnly=True diff --git a/SML/Classes/SafeMutLoader.uc b/SML/Classes/SafeMutLoader.uc index 67d368b..cce2819 100644 --- a/SML/Classes/SafeMutLoader.uc +++ b/SML/Classes/SafeMutLoader.uc @@ -1,331 +1,331 @@ -class SafeMutLoader extends KFAccessControl - config(SML); - -struct CMR -{ - var String Mutator; - var String Replacement; -}; - -var private Array ActiveMutators; -var private Array ActiveServerActors; -var private Array CustomMutReplacements; -var private Array SystemServerActors; -var private config E_LogLevel LogLevel; -var private config Array Mutators; -var private config Array ServerActors; - -public function PreBeginPlay() -{ - LogLevel = GetLogLevel(); - - `Log_Trace(); - - Super.PreBeginPlay(); - - LoadMutators(); - LoadServerActors(); -} - -public function PostBeginPlay() -{ - local KFGI_Access KFGIA; - - `Log_Trace(); - - Super.PostBeginPlay(); - - RestoreServerActors(); - - KFGIA = GetKFGIA(); - if (KFGIA == None) - { - `Log_Error("Can't check ranked status"); - } - else if (KFGIA.IsRankedGame()) - { - `Log_Info("Mutators and server actors successfully loaded! Your server is RANKED!"); - } - else - { - `Log_Warn("Your server is UNRANKED! Check the mutators and server actors you are using. Maybe some of them are incompatible with SML"); - } -} - -private function KFGI_Access GetKFGIA() -{ - local KFGameInfo KFGI; - - if (WorldInfo == None || WorldInfo.Game == None) - { - return None; - } - - KFGI = KFGameInfo(WorldInfo.Game); - if (KFGI == None) - { - return None; - } - - return new(KFGI) class'KFGI_Access'; -} - -private function LoadMutators() -{ - local String MutString; - local class MutClass; - local class ActClass; - local Actor ServerActor; - - `Log_Trace(); - - foreach Mutators(MutString) - { - MutClass = class(DynamicLoadObject(MutString, class'Class')); - if (MutClass == None) - { - `Log_Error("Can't load mutator:" @ MutString); - continue; - } - - ActClass = GetMutReplacement(MutClass); - if (ActClass == None) - { - `Log_Warn("Incompatible:" @ MutString @ "(skip)"); - continue; - } - - ServerActor = WorldInfo.Spawn(ActClass); - if (ServerActor == None) - { - `Log_Error("Can't spawn:" @ MutString); - continue; - } - - ActiveMutators.AddItem(ServerActor); - `Log_Info("Loaded:" @ MutString); - } -} - -private function LoadServerActors() -{ - local String ActorString; - local class ActorClass; - local Actor ServerActor; - - foreach ServerActors(ActorString) - { - ActorClass = class(DynamicLoadObject(ActorString, class'Class')); - if (ActorClass == None) - { - `Log_Error("Can't load server actor:" @ ActorString); - continue; - } - - ServerActor = WorldInfo.Spawn(ActorClass); - if (ServerActor == None) - { - `Log_Error("Can't spawn:" @ ActorString); - continue; - } - - ActiveServerActors.AddItem(ServerActor); - `Log_Info("Loaded:" @ ActorString); - } -} - -private function RestoreServerActors() -{ - local GameEngine GameEngine; - local String ActorString; - local int PrevServerActorsCount; - - GameEngine = GameEngine(Class'Engine'.static.GetEngine()); - - if (GameEngine == None) - { - `Log_Error("GameEngine is None! Can't restore ServerActors!"); - return; - } - - PrevServerActorsCount = GameEngine.ServerActors.Length; - foreach ServerActors(ActorString) - { - if (GameEngine.ServerActors.Find(ActorString) != INDEX_NONE) - { - GameEngine.ServerActors.AddItem(ActorString); - } - } - - if (GameEngine.ServerActors.Length != PrevServerActorsCount) - { - GameEngine.SaveConfig(); - } -} - -public static function bool AddServerActor(String ServerActor) -{ - local class ActorClass; - - if (default.SystemServerActors.Find(ServerActor) != INDEX_NONE) - { - return false; - } - - ActorClass = class(DynamicLoadObject(ServerActor, class'Class')); - - if (ActorClass == None) - { - return false; - } - - if (ClassIsChildOf(ActorClass, class'Mutator')) - { - return false; - } - - if (default.ServerActors.Find(ServerActor) == INDEX_NONE) - { - default.ServerActors.AddItem(ServerActor); - } - - return true; -} - -public static function bool AddMutator(String MutString) -{ - if (GetMutStringReplacement(MutString) != None) - { - if (default.Mutators.Find(MutString) == INDEX_NONE) - { - default.Mutators.AddItem(MutString); - } - return true; - } - - return false; -} - -public static function ClearMutators() -{ - default.Mutators.Length = 0; -} - -public static function ClearServerActors() -{ - default.ServerActors.Length = 0; -} - -public static function bool WantsToSpawn() -{ - return (default.Mutators.Length > 0); -} - -public static function String GetName(optional Object O) -{ - if (O == None) - { - return (default.class.GetPackageName() $ "." $ String(default.class)); - } - else - { - return (O.class.GetPackageName() $ "." $ String(O.class)); - } -} - -public static function String GetMutName(class CMut) -{ - if (CMut == None) return ""; - - return CMut.GetPackageName() $ "." $ String(CMut); -} - -public function PostLogin(PlayerController C) -{ - local Actor A; - - `Log_Trace(); - - if (C != None) - { - foreach ActiveMutators(A) - { - A.GetTargetLocation(C, false); - } - } - - Super.PostLogin(C); -} - -public function OnClientConnectionClose(Player ClientConnection) -{ - local Controller C; - local Actor A; - - `Log_Trace(); - - C = ClientConnection.Actor; - if (C != None) - { - foreach ActiveMutators(A) - { - A.GetTargetLocation(C, true); - } - } - - Super.OnClientConnectionClose(ClientConnection); -} - -public static function E_LogLevel GetLogLevel() -{ - if (default.LogLevel == LL_WrongLevel) - { - default.LogLevel = LL_Info; - StaticSaveConfig(); - } - - return default.LogLevel; -} - -private static function class GetMutReplacement(class MutClass) -{ - local int Index; - local String Replacement; - - if (MutClass == None) return None; - - Index = default.CustomMutReplacements.Find('Mutator', GetMutName(MutClass)); - if (Index != INDEX_NONE) - { - Replacement = default.CustomMutReplacements[Index].Replacement; - } - else if (MutClass.static.GetLocalString() == "") - { - return None; - } - else - { - Replacement = MutClass.GetPackageName() $ "." $ MutClass.static.GetLocalString(); - } - - return class(DynamicLoadObject(Replacement, class'Class')); -} - -private static function class GetMutStringReplacement(String MutString) -{ - return GetMutReplacement(class(DynamicLoadObject(MutString, class'Class'))); -} - -defaultproperties -{ - CustomMutReplacements.Add({( - Mutator="UnofficialKFPatch.UKFPMutator", - Replacement="UnofficialKFPatch.UKFPReplicationInfo" - )}) - CustomMutReplacements.Add({( - Mutator="UnofficialKFPatch.UKFPMutatorNW", - Replacement="UnofficialKFPatch.UKFPReplicationInfo" - )}) - - SystemServerActors.Add("IpDrv.WebServer") +class SafeMutLoader extends KFAccessControl + config(SML); + +struct CMR +{ + var String Mutator; + var String Replacement; +}; + +var private Array ActiveMutators; +var private Array ActiveServerActors; +var private Array CustomMutReplacements; +var private Array SystemServerActors; +var private config E_LogLevel LogLevel; +var private config Array Mutators; +var private config Array ServerActors; + +public function PreBeginPlay() +{ + LogLevel = GetLogLevel(); + + `Log_Trace(); + + Super.PreBeginPlay(); + + LoadMutators(); + LoadServerActors(); +} + +public function PostBeginPlay() +{ + local KFGI_Access KFGIA; + + `Log_Trace(); + + Super.PostBeginPlay(); + + RestoreServerActors(); + + KFGIA = GetKFGIA(); + if (KFGIA == None) + { + `Log_Error("Can't check ranked status"); + } + else if (KFGIA.IsRankedGame()) + { + `Log_Info("Mutators and server actors successfully loaded! Your server is RANKED!"); + } + else + { + `Log_Warn("Your server is UNRANKED! Check the mutators and server actors you are using. Maybe some of them are incompatible with SML"); + } +} + +private function KFGI_Access GetKFGIA() +{ + local KFGameInfo KFGI; + + if (WorldInfo == None || WorldInfo.Game == None) + { + return None; + } + + KFGI = KFGameInfo(WorldInfo.Game); + if (KFGI == None) + { + return None; + } + + return new(KFGI) class'KFGI_Access'; +} + +private function LoadMutators() +{ + local String MutString; + local class MutClass; + local class ActClass; + local Actor ServerActor; + + `Log_Trace(); + + foreach Mutators(MutString) + { + MutClass = class(DynamicLoadObject(MutString, class'Class')); + if (MutClass == None) + { + `Log_Error("Can't load mutator:" @ MutString); + continue; + } + + ActClass = GetMutReplacement(MutClass); + if (ActClass == None) + { + `Log_Warn("Incompatible:" @ MutString @ "(skip)"); + continue; + } + + ServerActor = WorldInfo.Spawn(ActClass); + if (ServerActor == None) + { + `Log_Error("Can't spawn:" @ MutString); + continue; + } + + ActiveMutators.AddItem(ServerActor); + `Log_Info("Loaded:" @ MutString); + } +} + +private function LoadServerActors() +{ + local String ActorString; + local class ActorClass; + local Actor ServerActor; + + foreach ServerActors(ActorString) + { + ActorClass = class(DynamicLoadObject(ActorString, class'Class')); + if (ActorClass == None) + { + `Log_Error("Can't load server actor:" @ ActorString); + continue; + } + + ServerActor = WorldInfo.Spawn(ActorClass); + if (ServerActor == None) + { + `Log_Error("Can't spawn:" @ ActorString); + continue; + } + + ActiveServerActors.AddItem(ServerActor); + `Log_Info("Loaded:" @ ActorString); + } +} + +private function RestoreServerActors() +{ + local GameEngine GameEngine; + local String ActorString; + local int PrevServerActorsCount; + + GameEngine = GameEngine(Class'Engine'.static.GetEngine()); + + if (GameEngine == None) + { + `Log_Error("GameEngine is None! Can't restore ServerActors!"); + return; + } + + PrevServerActorsCount = GameEngine.ServerActors.Length; + foreach ServerActors(ActorString) + { + if (GameEngine.ServerActors.Find(ActorString) != INDEX_NONE) + { + GameEngine.ServerActors.AddItem(ActorString); + } + } + + if (GameEngine.ServerActors.Length != PrevServerActorsCount) + { + GameEngine.SaveConfig(); + } +} + +public static function bool AddServerActor(String ServerActor) +{ + local class ActorClass; + + if (default.SystemServerActors.Find(ServerActor) != INDEX_NONE) + { + return false; + } + + ActorClass = class(DynamicLoadObject(ServerActor, class'Class')); + + if (ActorClass == None) + { + return false; + } + + if (ClassIsChildOf(ActorClass, class'Mutator')) + { + return false; + } + + if (default.ServerActors.Find(ServerActor) == INDEX_NONE) + { + default.ServerActors.AddItem(ServerActor); + } + + return true; +} + +public static function bool AddMutator(String MutString) +{ + if (GetMutStringReplacement(MutString) != None) + { + if (default.Mutators.Find(MutString) == INDEX_NONE) + { + default.Mutators.AddItem(MutString); + } + return true; + } + + return false; +} + +public static function ClearMutators() +{ + default.Mutators.Length = 0; +} + +public static function ClearServerActors() +{ + default.ServerActors.Length = 0; +} + +public static function bool WantsToSpawn() +{ + return (default.Mutators.Length > 0); +} + +public static function String GetName(optional Object O) +{ + if (O == None) + { + return (default.class.GetPackageName() $ "." $ String(default.class)); + } + else + { + return (O.class.GetPackageName() $ "." $ String(O.class)); + } +} + +public static function String GetMutName(class CMut) +{ + if (CMut == None) return ""; + + return CMut.GetPackageName() $ "." $ String(CMut); +} + +public function PostLogin(PlayerController C) +{ + local Actor A; + + `Log_Trace(); + + if (C != None) + { + foreach ActiveMutators(A) + { + A.GetTargetLocation(C, false); + } + } + + Super.PostLogin(C); +} + +public function OnClientConnectionClose(Player ClientConnection) +{ + local Controller C; + local Actor A; + + `Log_Trace(); + + C = ClientConnection.Actor; + if (C != None) + { + foreach ActiveMutators(A) + { + A.GetTargetLocation(C, true); + } + } + + Super.OnClientConnectionClose(ClientConnection); +} + +public static function E_LogLevel GetLogLevel() +{ + if (default.LogLevel == LL_WrongLevel) + { + default.LogLevel = LL_Info; + StaticSaveConfig(); + } + + return default.LogLevel; +} + +private static function class GetMutReplacement(class MutClass) +{ + local int Index; + local String Replacement; + + if (MutClass == None) return None; + + Index = default.CustomMutReplacements.Find('Mutator', GetMutName(MutClass)); + if (Index != INDEX_NONE) + { + Replacement = default.CustomMutReplacements[Index].Replacement; + } + else if (MutClass.static.GetLocalString() == "") + { + return None; + } + else + { + Replacement = MutClass.GetPackageName() $ "." $ MutClass.static.GetLocalString(); + } + + return class(DynamicLoadObject(Replacement, class'Class')); +} + +private static function class GetMutStringReplacement(String MutString) +{ + return GetMutReplacement(class(DynamicLoadObject(MutString, class'Class'))); +} + +defaultproperties +{ + CustomMutReplacements.Add({( + Mutator="UnofficialKFPatch.UKFPMutator", + Replacement="UnofficialKFPatch.UKFPReplicationInfo" + )}) + CustomMutReplacements.Add({( + Mutator="UnofficialKFPatch.UKFPMutatorNW", + Replacement="UnofficialKFPatch.UKFPReplicationInfo" + )}) + + SystemServerActors.Add("IpDrv.WebServer") } \ No newline at end of file diff --git a/SML/Classes/_Logger.uc b/SML/Classes/_Logger.uc index 93fc28a..d9cfb52 100644 --- a/SML/Classes/_Logger.uc +++ b/SML/Classes/_Logger.uc @@ -1,20 +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 -{ - -} +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/SML/Constants.uci b/SML/Constants.uci index 1003f19..432fa68 100644 --- a/SML/Constants.uci +++ b/SML/Constants.uci @@ -1,2 +1,2 @@ -// Constants -`define NO_CONFIG 0 +// Constants +`define NO_CONFIG 0 diff --git a/SML/Globals.uci b/SML/Globals.uci index a48ac52..4dcd4fb 100644 --- a/SML/Globals.uci +++ b/SML/Globals.uci @@ -1,3 +1,3 @@ -// Imports -`include(Logger.uci) -`include(Constants.uci) +// Imports +`include(Logger.uci) +`include(Constants.uci) diff --git a/SML/Logger.uci b/SML/Logger.uci index 076215a..ac5c556 100644 --- a/SML/Logger.uci +++ b/SML/Logger.uci @@ -1,15 +1,15 @@ -// Logger -`define Log_Tag 'SML' - -`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) +// Logger +`define Log_Tag 'SML' + +`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/builder.cfg b/builder.cfg index d62af68..b932d3c 100644 --- a/builder.cfg +++ b/builder.cfg @@ -7,7 +7,7 @@ StripSource="True" # Mutators to be compiled # Specify them with a space as a separator, -# Mutators will be compiled in the specified order +# Mutators will be compiled in the specified order PackageBuildOrder="SML" @@ -16,7 +16,7 @@ PackageBuildOrder="SML" # Packages you want to brew using @peelz's patched KFEditor. # Useful for cases where regular brew doesn't put *.upk inside the package. # Specify them with a space as a separator, -# The order doesn't matter +# The order doesn't matter PackagePeelzBrew="" @@ -24,7 +24,7 @@ PackagePeelzBrew="" # Mutators that will be uploaded to the workshop # Specify them with a space as a separator, -# The order doesn't matter +# The order doesn't matter PackageUpload="SML" From cfa8257071816409a1b67d21739a275447f1bddb Mon Sep 17 00:00:00 2001 From: GenZmeY Date: Sun, 14 May 2023 04:46:11 +0300 Subject: [PATCH 5/5] update .editorconfig --- .editorconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/.editorconfig b/.editorconfig index b60821d..a3108ab 100644 --- a/.editorconfig +++ b/.editorconfig @@ -22,6 +22,7 @@ charset = utf-16le # Other [*.md] +indent_style = space trim_trailing_whitespace = false [*.yml]