Mutators & UnrealScript

Decompiling Killing Floor Packages with UT Package Tool: Errors and Fixes

Decompile to learn, to fix abandoned mods, or with the author's permission. Credit the original author in anything you publish.

This is an adaptation of kazachidla's Steam guide on decompiling scripted Unreal Engine 2.5 code for Killing Floor. It uses UT Package Tool 2.0 beta 5 (UTPT), which recovers code from packages whose source text was stripped. UTPT needs much more manual work than UE Explorer, but the author found it more reliable with braces and block boundaries. The second half of the page is the list of compile errors UTPT leaves behind and how to fix each one.

Tools

  • UT Package Tool 2.0 beta 5: the decompiler.
  • A hex editor (the guide uses HexEdit): to make UTPT accept a KF package.
  • UnCodeX (optional): browses and searches the KF script source, which comes with the Killing Floor SDK. You will need it to look up correct type names.

Step 1. Export defaultproperties with ucc

UTPT decompiles default values with errors, so take them from the game's own exporter first. Create a .bat in System:

ucc batchexport Mut.u class uc ..\Mut\Classes
pause

Replace Mut with the package name. Run it and copy the resulting .uc files to a separate folder, for example Default. You only need their defaultproperties blocks.

Step 2. Decompile in UTPT

  1. Open the original .u in a hex editor and change the first byte from C2 to C1. UTPT does not know Killing Floor; after this it treats the file as an Unreal Tournament 2004 package. Save.
  2. Open the patched file in UTPT. In Export Tree, right-click any class and choose Full Collapse.
  3. In File → Options, enable Add line offsets to decompiled code. You will need the offsets to place labels.
  4. For every class: right-click → Decompile, then Save in the right pane. Save into <Package>\Classes in the game root, e.g. Mut\Classes.
  5. Open each saved .uc and replace its defaultproperties with the block from the Default folder.
  6. Clean up the class declaration. UTPT adds specifiers the compiler rejects:
class AntiBlocker extends Mutator
    Localized
    HideCategories(Movement,Collision,Lighting,LightColor,Karma,Force);

becomes

class AntiBlocker extends Mutator;

Then compile with ucc make and work through the errors below.

Compile errors UTPT leaves behind

Unrecognized type 'FPerksListType'

UTPT declares a variable before the struct it uses:

var array<FPerksListType> CachePerks;
struct FPerksListType
{
    var Class<KFpubVet> PerkClass;
    var byte CurrentLevel;
};

Move every struct to the top of the file, right after the class declaration, before any variable that uses it.

Missing '>' in 'class limitor'

local array<Class<KFpubVet>> ca;

The UE2 parser reads >> as the shift operator. Add a space:

local array<Class<KFpubVet> > ca;

Unrecognized type 'ServerResponseLine'

UTPT drops the outer class from types declared in other classes:

function GetServerDetails (out ServerResponseLine ServerState)

Qualify it:

function GetServerDetails (out GameInfo.ServerResponseLine ServerState)

Search the type in UnCodeX to find where it is declared. Common cases: PlayerRecord → xUtil.PlayerRecord, ServerFavorite → ExtendedConsole.ServerFavorite, AllowWeaponInTrader → Static.AllowWeaponInTrader. Missing Static. on static calls is something you will fix often.

'Extends' not allowed here: state overrides version in parent class

auto state PendingMatch extends PendingMatch

The state name got duplicated. Drop the extends part:

auto state PendingMatch

Specified type modifiers not allowed here

function bool ButtonClicked (export editinlineuse GUIComponent Sender)
local export editinlineuse GUIList List;

Remove export editinlineuse from parameters and local variables:

function bool ButtonClicked (GUIComponent Sender)
local GUIList List;

Type mismatch in 'new'

C = new (None,Class'KFpubLC');

Correct syntax:

C = new (None) Class'KFpubLC';

Label 'JL0021' not found in this block of code

UTPT turns every loop into goto but almost never places the labels, and when it does they are usually wrong. Use the line offsets you enabled in step 2: the label name is the target offset, so goto JL0021 jumps to the line whose offset ends in 0x0021.

i = PC.Player.LocalInteractions.Length - 1;   // 0x00000019 : 0x0000
JL0021: if ( i >= 0 )                          // 0x00000032 : 0x0021
{
    if ( PC.Player.LocalInteractions[i].Class == Default.Class )
        return;
    --i;
    goto JL0021;                               // 0x00000066 : 0x0065
}

The label must be in the same function as the goto. Better still, rewrite it as the loop it was (while (i >= 0)).

Missing 'Reliable' or 'Unreliable'

un?reliable if ( (Role == 4) && bNetOwner )

UTPT could not tell which one it was. reliable guarantees delivery; unreliable may be dropped on a bad connection. Most replication conditions in mods are reliable. If the stock parent class has the same block, copy its keyword.

'If' is not allowed here (numbers instead of enum names)

if ( Level.NetMode == 3 )

UTPT replaces enum names with their numbers. The compiler sometimes accepts them, but not everywhere. Put the names back: Level.NetMode == NM_Client. Tables for the most common enums:

ValueNetModeRoleClientState (weapon)ClientGrenadeState
0NM_StandaloneROLE_NoneWS_NoneGN_None
1NM_DedicatedServerROLE_DumbProxyWS_HiddenGN_TempDown
2NM_ListenServerROLE_SimulatedProxyWS_BringUpGN_BringUp
3NM_ClientROLE_AutonomousProxyWS_PutDown
4ROLE_AuthorityWS_ReadyToFire
ValuePhysicsValuePhysics
0PHYS_None9PHYS_Spider
1PHYS_Walking10PHYS_Trailer
2PHYS_Falling11PHYS_Ladder
3PHYS_Swimming12PHYS_RootMotion
4PHYS_Flying13PHYS_Karma
5PHYS_Rotating14PHYS_KarmaRagDoll
6PHYS_Projectile15PHYS_Hovering
7PHYS_Interpolating16PHYS_CinMotion
8PHYS_MovingBrush
ValueSound slot (PlayOwnedSound)DrawType
0SLOT_NoneDT_None
1SLOT_MiscDT_Sprite
2SLOT_PainDT_Mesh
3SLOT_InteractDT_Brush
4SLOT_AmbientDT_RopeSprite
5SLOT_TalkDT_VerticalSprite
6SLOT_InterfaceDT_Terraform
7DT_SpriteAnimOnce
8DT_StaticMesh
9DT_DrawType
10DT_Particle
11DT_AntiPortal
12DT_FluidSurface

Most of these are declared in Actor.uc; check the source when in doubt.

'If' is not allowed here (missing state label)

The same error has a second cause. UTPT does not place labels in state code:

auto state RepSetup
{
    if ( Level.NetMode == NM_Client )
    {
        stop
    }

State code needs a Begin: label, and stop needs a semicolon:

auto state RepSetup
{
Begin:
    if ( Level.NetMode == NM_Client )
        stop;

Check every state for missing labels. If you skip this, the package may even compile without warnings, but the state code will not run as intended. The guide notes zeds that "act dumb" for this reason, because zed AI relies heavily on state code. Most mod states are rewrites of stock ones, so compare with the stock class.

goto inside state code

goto to a numeric label does not work inside state code, even with labels added. Rewrite the jumps as while and for. Decompiled (does not compile):

SendIndex = 0;
if ( SendIndex < ShopInventory.Length )
{
    ClientReceiveWeapon(SendIndex, ShopInventory[SendIndex].PC, ShopInventory[SendIndex].CatNum);
    Sleep(0.1);
    ++SendIndex;
    goto JL007C;
}

Rewritten:

for( SendIndex=0; SendIndex<ShopInventory.Length; ++SendIndex )
{
    ClientReceiveWeapon(SendIndex, ShopInventory[SendIndex].PC, ShopInventory[SendIndex].CatNum);
    Sleep(0.1f);
}

The guide's full example rebuilds ServerPerks' ClientPerkRepLink.RepSetup this way. Whenever the decompiled code resembles a stock or well-known class, use the original as the reference.

How long it takes

A single weapon, zed or skin can be done quickly. A whole server package can take several days to a week of careful work. The stock source covers nearly every variable and function you will need to look up.

Animations are a separate problem. If an author packed meshes into a large .ukx with the mesh data stripped, it cannot be unpacked, and the guide's author knew no fix. You can still ship the whole package, or try to delete unused content in the KF SDK, but the SDK refuses to delete a mesh that a class in the same package references.