KF2-SafeMutLoader/PublicationContent/dev_guide.txt
2022-09-15 16:12:47 +03:00

177 lines
5.9 KiB
Plaintext

[SML] Developer Guide
[b]SML compatible mutator development guide[/b]
Mutator template
You can use this template to make the mutator compatible with [url=https://steamcommunity.com/sharedfiles/filedetails/?id=2863226847]SML[/url].
Here I will use "[b]Example[/b]" as mutator name. Replace it with yours.
[b]ExampleMut.uc[/b]
[code]
class ExampleMut extends KFMutator;
var private Example Example;
public simulated function bool SafeDestroy()
{
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();
}
}
public function AddMutator(Mutator Mut)
{
if (Mut == Self) return;
if (Mut.Class == Class)
Mut.Destroy();
else
Super.AddMutator(Mut);
}
public function NotifyLogin(Controller C)
{
Example.NotifyLogin(C);
Super.NotifyLogin(C);
}
public function NotifyLogout(Controller 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');
}
defaultproperties
{
}
[/code]
[b]Example.uc[/b]
[code]
class Example extends Info;
public event PreBeginPlay()
{
Super.PreBeginPlay();
// do some initialization here
}
public event PostBeginPlay()
{
Super.PostBeginPlay();
// do some initialization here
}
public function NotifyLogin(Controller C)
{
// 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
}
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);
}
defaultproperties
{
}
[/code]
That's all. You can create new classes and add any code to [b]Example.uc[/b], but refrain from implementing anything else in [b]ExampleMut.uc[/b]
Limitations
❌ Can't make ranked game mode this way;
❌ [url=https://steamcommunity.com/sharedfiles/filedetails/?id=2863226847]SML[/url] can only emulate [url=https://github.com/GenZmeY/KF2-Dev-Scripts/blob/9553ac0b31c729c27e9cd0a460ab5a7bae2fd799/Engine/Classes/Mutator.uc#L147]NotifyLogin(...)[/url] and [url=https://github.com/GenZmeY/KF2-Dev-Scripts/blob/9553ac0b31c729c27e9cd0a460ab5a7bae2fd799/Engine/Classes/Mutator.uc#L141]NotifyLogout(...)[/url], other functions of the [url=https://github.com/GenZmeY/KF2-Dev-Scripts/blob/9553ac0b31c729c27e9cd0a460ab5a7bae2fd799/Engine/Classes/Mutator.uc]Mutator[/url] and [url=https://github.com/GenZmeY/KF2-Dev-Scripts/blob/9553ac0b31c729c27e9cd0a460ab5a7bae2fd799/Engine/Classes/KFMutator.uc]KFMutator[/url] classes are not supported - look for workarounds in this case.
[Tips] Alternative to the InitMutator(...) function
Even though the [url=https://github.com/GenZmeY/KF2-Dev-Scripts/blob/9553ac0b31c729c27e9cd0a460ab5a7bae2fd799/KFGame/Classes/KFMutator.uc#L22]InitMutator(...)[/url] function is not supported, you can still parse the startup string if you need to:
Refer to [url=https://github.com/GenZmeY/KF2-Dev-Scripts/blob/9553ac0b31c729c27e9cd0a460ab5a7bae2fd799/Engine/Classes/GameInfo.uc#L209]WorldInfo.Game.ServerOptions[/url] or [url=https://github.com/GenZmeY/KF2-Dev-Scripts/blob/9553ac0b31c729c27e9cd0a460ab5a7bae2fd799/Engine/Classes/WorldInfo.uc#L1315]WorldInfo.GetLocalURL()[/url] and get the option from there. It's best to do this in [b]PreBeginPlay()[/b] or [b]PostBeginPlay()[/b] of your [b]Example.uc[/b] (as well as other initializations).
[Tips] XP for custom Zeds / Weapons
While custom weapons and zeds won't make your server unranked, the [url=https://github.com/GenZmeY/KF2-Dev-Scripts/blob/513c60070e2b700b5c311843754ed0e39b55a14e/KFGame/Classes/KFGameInfo.uc#L2594]ValidateForXP(...)[/url] function will not allow you to gain experience if it detects a custom zed or custom damage type.
To work around this, don't use custom damage types on custom weapons, or replace information in [url=https://github.com/GenZmeY/KF2-Dev-Scripts/blob/513c60070e2b700b5c311843754ed0e39b55a14e/KFGame/Classes/KFPawn.uc#L182]DamageHistory[/url] before it gets into the [url=https://github.com/GenZmeY/KF2-Dev-Scripts/blob/513c60070e2b700b5c311843754ed0e39b55a14e/KFGame/Classes/KFGameInfo.uc#L2489]DistributeMoneyAndXP(...)[/url] function.
[Tips] Replacing base classes to bypass restrictions
In some cases, changing the base classes of the game can help. For example, we cannot make [b][url=https://steamcommunity.com/sharedfiles/filedetails/?id=2379769040]TAWOD[/url][/b] and [url=https://steamcommunity.com/sharedfiles/filedetails/?id=2863226847]SML[/url] compatible because the [url=https://github.com/GenZmeY/KF2-TAWOD/blob/master/TAWOD/Classes/TAWODMut.uc#L19]PreventDeath(...)[/url] function is not supported. But this can be bypassed by replacing the player's Pawn base class with custom Pawn class:
[code]
WorldInfo.Game.DefaultPawnClass = class'ExamplePawn_Human';
[/code]
(This can be done in [b]PostBeginPlay()[/b])
And now we can implement all weapons drop in [b]ExamplePawn_Human.uc[/b]:
[code]
class TAWODPawn_Human extends KFPawn_Human;
public function ThrowActiveWeapon(optional bool bDestroyWeap)
{
local KFWeapon KFW;
if (Role < ROLE_Authority)
{
return;
}
if (Health <= 0)
{
if (InvManager != None)
foreach KFP.InvManager.InventoryActors(class'KFWeapon', KFW)
if (KFW != None && KFW.bDropOnDeath && KFW.CanThrow())
KFP.TossInventory(KFW);
}
else
{
super.ThrowActiveWeapon(bDestroyWeap);
}
}
[/code]
[Tips] Cloning DLC weapons
🛠[b] <UNDER_CONSTRUCTION> [/b]🛠