Killing Floor Guide

Декомпиляция заскриптованного кода unreal engine 2.5 (Killing floor). for Killing Floor

Декомпиляция заскриптованного кода unreal engine 2.5 (Killing floor).

Overview

Декомпиляция заскриптованного кода unreal engine 2.5 (Killing floor).

1.

Для этой процедуры нам понадобиться две программы: HexEdit для правки шестнадцатеричного кода и UT Package Tool v2.0 beta 5, который собственно и декомпилирует код с удаленным текстом исходного кода. Так же рекомендую программу UnCodeX для удобного просмотра и поиска нужной функции в исходниках Killing Floor (которые загружаются вместе с редактором Killing Floor SDK). Берем зашифрованный файл (обычно это *.u файлы ), который нужно декомпилить, и для начала декомпилируем его обычными средствами Killing Floor (ucc.exe), для того чтоб получить defaultproperties, так как программа UT Package Tool декомпилит эти значения по умолчанию с некоторыми ошибками. Для этого создаем в папке System bat файл, в котором пишем

ucc batchexport Mut.u class uc ..MutClasses
pause

Вместо Mut имя вашего заскриптованного файла. Сохраняем. Запускаем. Сохраняем полученные *.uc файлы к примеру в папке под именем Default.

2.

Далее опять же исходный *.u файл открываем в HexEdit и меняем первый байт значение которого C2 на значение C1, для того чтоб UT Package Tool определил этот файл как файл игры Unreal Tournament 2004, так как программа не знакома с игрой Killing Floor. Сохраняем его в HexEdit. Запускаем UT Package Tool и открываем полученный файл. Во вкладке Export Tree щелкаем на любом классе правой кнопкой и нажимаем Full Collapse. Нажимаем File/Options и убеждаемся, что стоит галочка Add line offsets to decompiled code. Далее по порядку на каждом классе щелкаем правой кнопкой мыши и нажимаем Decompile. В правом окне должен появиться декомпилированный код данного класса. Справа нажимаем Save. Создаем какую-нибудь папку с будущим названием данного мутатора, например Mut, и в этой же папке создаем подпапку Classes, в которой и сохраняем декомпилированный код. Данную процедуру проделываем со всеми классами слева. Далее сохраненные *.uc файлы в папке MutClasses открываем с помощью блокнота и заменяем все defaultproperties на defaultproperties из сохраненной ранее папки Default. Если, например, в описании класса есть

class AntiBlocker extends Mutator
Localized
HideCategories(Movement,Collision,Lighting,LightColor,Karma,Force);

то удаляем Localized и HideCategories(Movement,Collision,Lighting,LightColor,Karma,Force). Знак ; оставляем, получается просто

class AntiBlocker extends Mutator;

3.

Далее рассмотрим некоторые ошибки и недочеты допущенные самим UT Package Tool. Иногда при компилировании данного дешифрованного кода ucc.exe может выдать, к примеру, следующее сообщение

Log: Parsing ClientPerkRepLink
Error: E:GamesGameSteamsteamappscommonkillingfloorKFpubModClassesClientPerkRepLink.uc(46) : Error, Unrecognized type ‘FPerksListType’

Данный класс выглядит следующим образом

class ClientPerkRepLink extends LinkedReplicationInfo;
var array<FPerksListType> CachePerks;
struct FPerksListType
{
var Class<KFpubVet> PerkClass;
var byte CurrentLevel;
};

Тут ошибка в следующем, что UT Package Tool сначала присваивает переменную CachePerks, ссылаясь на переменную FPerksListType, структура которой описывается уже после объявления CachePerks, правильно будет сначала объявить переменную FPerksListType, а затем уже ссылаться на нее, будет так

class ClientPerkRepLink extends LinkedReplicationInfo;
struct FPerksListType
{
var Class<KFpubVet> PerkClass;
var byte CurrentLevel;
};
var array<FPerksListType> CachePerks;

Короче, надо проверить все uc файлы, и перенести все структуры (struct) в начало файла сразу после объявления класса, или на усмотрение самого кодера. Следующая ошибка, которая выпала на одном примере по компиляции взломанного мутатора

Log: Parsing ClientPerkRepLink
Error: E:GamesGameSteamsteamappscommonkillingfloorKFpubModClassesClientPerkRepLink.uc(290) : Error, Missing ‘>’ in ‘class limitor’

Ошибка в следующем тексте программы

local array<Class<KFpubVet>> ca;

Здесь просто надо после local array<Class<KFpubVet> поставить пробел, получиться

local array<Class<KFpubVet> > ca;

Далее

Log: Parsing KillingFloorPub
Error: E:GamesGameSteamsteamappscommonkillingfloorKFpubModClassesKillingFloorPub.uc(251) : Error, Unrecognized type ‘ServerResponseLine’

Текст с ошибкой

function GetServerDetails (out ServerResponseLine ServerState)

Правильно будет

function GetServerDetails (out GameInfo.ServerResponseLine ServerState)

Если компилятор говорит что переменная не найдена, то можно покопаться в исходных кодах Killing Floor и посмотреть правильное написание данной переменной, в данном случае это ServerResponseLine, копируете название, запускаете UnCodeX и в поиске вбиваете эту переменную, и программа покажет возможно правильное написание этой переменной. Некоторые примеры переменных, когда UT Package Tool не прописывает их полностью: PlayerRecord (правильно xUtil.PlayerRecord ), ServerFavorite (правильно ExtendedConsole.ServerFavorite), AllowWeaponInTrader ( правильно Static.AllowWeaponInTrader, по поводу Static, это слово много где будет приписываться по ходу компиляции кода ) .
Далее

Log: Parsing KFpubGT
Error: E:GamesGameSteamsteamappscommonkillingfloorKFpubModClassesKFpubGT.uc(424) : Error, ‘Extends’ not allowed here: state ‘PendingMatch’ overrides version in parent class

Текст с ошибкой

auto state PendingMatch extends PendingMatch

Продублировался PendingMatch, просто удаляем и получаем

auto state PendingMatch

Далее

Log: Parsing KFpubTabMidGameVC
Error: E:GamesGameSteamsteamappscommonkillingfloorKFpubModClassesKFpubTabMidGameVC.uc(20) : Error, Specified type modifiers not allowed here

Текст с ошибкой

function bool ButtonClicked (export editinlineuse GUIComponent Sender)

Правильно

function bool ButtonClicked ( GUIComponent Sender)

Просто удаляем export editinlineuse. Это также касается объявления переменных, например

local export editinlineuse GUIList List;

Правильно

local GUIList List;

Далее

Log: Compiling KFpubLC
Error: E:GamesGameSteamsteamappscommonkillingfloorKFpubModClassesKFpubLC.uc(41) : Error, Type mismatch in ‘new’ name

Текс с ошибкой

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

Правильно

C = new (None) Class’KFpubLC’;

Далее

Log: Compiling KFpubLC
Error: E:GamesGameSteamsteamappscommonkillingfloorKFpubModClassesKFpubLC.uc(48) : Error, Label ‘JL0021’ not found in this block of code

Текст с ошибкой

static final function AddSafeCleanup (PlayerController PC)
{
local int i;
local KFpubLC C;

i = PC.Player.LocalInteractions.Length – 1; // 0x00000019 : 0x0000
if ( i >= 0 ) // 0x00000032 : 0x0021
{
if ( PC.Player.LocalInteractions[i ].Class == Default.Class ) // 0x0000003B : 0x002C
{
return; // 0x0000005F : 0x005C
}
–i; // 0x00000061 : 0x005E
goto JL0021; // 0x00000066 : 0x0065
}
C = new (None) Class’KFpubLC’; // 0x00000069 : 0x0068
C.ViewportOwner = PC.Player; // 0x00000074 : 0x0077
C.Master = PC.Player.InteractionMaster; // 0x00000089 : 0x0094
i = PC.Player.LocalInteractions.Length; // 0x000000A5 : 0x00BA
PC.Player.LocalInteractions.Length = i + 1; // 0x000000BB : 0x00D8
PC.Player.LocalInteractions[i ] = C; // 0x000000D4 : 0x00F9
C.Initialize(); // 0x000000ED : 0x011C
}

Справа типа надписи как // 0x000000A5 : 0x00BA это адреса, которые прописались при декомпиляции при помощи UT Package Tool ( для этого мы выставили галочку Add line offsets to decompiled code в опциях программы). Сделано это для того, чтоб мы могли видеть куда прописать Label, который нужен для оператора goto. Дело в том, что UT Package Tool все операции с циклами типа как for, while и т.д. декомпилирует в оператор goto, при этом программа всячески отказывается самостоятельно расставлять необходимые Label, а если и расставляет (что очень редко), то всегда не правильно, и их надо удалять, после этого расставлять вручную. На данном примере здесь только один оператор goto который хочет перейти на label JL0021. Правильно будет так

static final function AddSafeCleanup (PlayerController PC)
{
local int i;
local KFpubLC C;

i = PC.Player.LocalInteractions.Length – 1; // 0x00000019 : 0x0000
JL0021: if ( i >= 0 ) // 0x00000032 : 0x0021
{
if ( PC.Player.LocalInteractions[i ].Class == Default.Class ) // 0x0000003B : 0x002C
{
return; // 0x0000005F : 0x005C
}
–i; // 0x00000061 : 0x005E
goto JL0021; // 0x00000066 : 0x0065
}
C = new (None) Class’KFpubLC’; // 0x00000069 : 0x0068
C.ViewportOwner = PC.Player; // 0x00000074 : 0x0077
C.Master = PC.Player.InteractionMaster; // 0x00000089 : 0x0094
i = PC.Player.LocalInteractions.Length; // 0x000000A5 : 0x00BA
PC.Player.LocalInteractions.Length = i + 1; // 0x000000BB : 0x00D8
PC.Player.LocalInteractions[i ] = C; // 0x000000D4 : 0x00F9
C.Initialize(); // 0x000000ED : 0x011C
}

Но label нужно прописывать именно в той функции, где используется оператор goto.
Далее

Log: Compiling ClientPerkRepLink
Error: E:GamesGameSteamsteamappscommonkillingfloorKFpubModClassesClientPerkRepLink.uc(78) : Error, Missing ‘Reliable’ or ‘Unreliable’

Текст с ошибкой

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

Правильно

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

Так как UT Package Tool не знал, что применить, Reliable или Unreliable. Насколько я понял в этих понятиях о репликации, то Reliable пересылает обязательно переменную или функцию от сервера к клиенту и наоборот, а при случае с Unreliable, допускается утрата переменной или функции при плохом интернет соединении. Так что в большинстве случаев используется именно Reliable.

4.

Далее

Log: Compiling ClientPerkRepLink
Error: E:GamesGameSteamsteamappscommonkillingfloorKFpubModClassesClientPerkRepLink.uc(496) : Error, ‘If’ is not allowed here

Текст с ошибкой

if ( Level.NetMode == 3 )

Правильно

if ( Level.NetMode == NM_Client )

Дело в том, что UT Package Tool некоторые символьные значения заменяет цифрами, эти цифры соответствуют некоторым значениям переменных, которые состоят из структур. Это касается таких выражениях как ClientState, ClientGrenadeState, NetMode, Role, Physics, PlayOwnedSound, SetDrawType и многих других, все их можно найти в исходникак Killing Floor, например большинство их описано в классе Actor. Вот таблица некоторых из них

ClientState
———–
0- WS_None
1- WS_Hidden
2- WS_BringUp
3- WS_PutDown
4- WS_ReadyToFire

ClientGrenadeState
——————
0- GN_None
1- GN_TempDown
2- GN_BringUp

NetMode
——-
0- NM_Standalone
1- NM_DedicatedServer
2- NM_ListenServer
3- NM_Client

Role
—-
0- ROLE_None
1- ROLE_DumbProxy
2- ROLE_SimulatedProxy
3- ROLE_AutonomousProxy
4- ROLE_Authority

Physics
——-
0- PHYS_None
1- PHYS_Walking
2- PHYS_Falling
3- PHYS_Swimming
4- PHYS_Flying
5- PHYS_Rotating
6- PHYS_Projectile
7- PHYS_Interpolating
8- PHYS_MovingBrush
9- PHYS_Spider
10- PHYS_Trailer
11- PHYS_Ladder
12- PHYS_RootMotion
13- PHYS_Karma
14- PHYS_KarmaRagDoll
15- PHYS_Hovering
16- PHYS_CinMotion

PlayOwnedSound
————–
0- SLOT_None
1- SLOT_Misc
2- SLOT_Pain
3- SLOT_Interact
4- SLOT_Ambient
5- SLOT_Talk
6- SLOT_Interface

SetDrawType
———–
0- DT_None,
1- DT_Sprite,
2- DT_Mesh,
3- DT_Brush,
4- DT_RopeSprite,
5- DT_VerticalSprite,
6- DT_Terraform,
7- DT_SpriteAnimOnce,
8- DT_StaticMesh,
9- DT_DrawType,
10-DT_Particle,
11-DT_AntiPortal,
12-DT_FluidSurface

Слева цифра, а справа чему эта цифра будет соответствовать, в нашем примере Level.NetMode == 3 равна три, что соответствует значению NM_Client, поэтому нужно поменять на Level.NetMode == NM_Client, повторяю, все эти значения можно найти в исходниках. Иногда компилятор допускает использование цифр вместо буквенного значения, но все равно, лучше этого не допускать.
Далее опять та же ошибка в том же месте, но по другому поводу

Log: Compiling ClientPerkRepLink
Error: E:GamesGameSteamsteamappscommonkillingfloorKFpubModClassesClientPerkRepLink.uc(496) : Error, ‘If’ is not allowed here

Текст с ошибкой

auto state RepSetup
{
if ( Level.NetMode == NM_Client ) // 0x00000018 : 0x0000
{
stop // 0x0000002C : 0x0019
}

Это не весь код, а только кусочек, где произошла ошибка, ошибка заключается в следующем, программа UT Package Tool в функциях State не хочет расставлять Label, здесь должна быть метка begin, будет правильно выглядеть так

auto state RepSetup
{
Begin:
if ( Level.NetMode == NM_Client ) // 0x00000018 : 0x0000
{
stop; // 0x0000002C : 0x0019
}

Так что в каждом state нужно визуально просмотреть на необходимость нужных меток, а если есть сомнения лучше подглядеть в исходниках, в основном все статы переписываются из уже имеющихся в самой игре. Если этого не сделать, то компилятор может и закончить компиляцию мода без ошибок и предупреждений, но в этом случае возможно наблюдать, что, к примеру, какой-нибудь зомби будет себя вести не адекватно, тупить и так далее, именно из-за того, что мы в стате не прописали нужную метку, почему зомби? Потому что в основном они и используют такие функции как state, но не только они конечно. Если кто-то заметил, то после оператора stop я поставил знак ; это тоже была ошибка допущенная UT Package Tool. Оператор goto нельзя использовать в state, заменяйте выражения на команду while в основном, в этом вам помогут исходники. Например текст с кодом как делать нельзя

auto state RepSetup
{
begin:
if ( Level.NetMode == NM_Client ) // 0x00000018 : 0x0000
{
stop; // 0x0000002C : 0x0019
}
Sleep(1.0); // 0x0000002D : 0x001A
NetUpdateFrequency = 0.5; // 0x00000035 : 0x0022
if ( NetConnection(StatObject.PlayerOwner.Player) != None ) // 0x0000003E : 0x002D
{
if ( (ClientAccknowledged[0] < ShopInventory.Length) || (ClientAccknowledged[1] < ShopCategories.Length) ) // 0x00000057 : 0x004F
{
SendIndex = 0; // 0x00000075 : 0x0075
if ( SendIndex < ShopInventory.Length ) // 0x0000007A : 0x007C
{
ClientReceiveWeapon(SendIndex,ShopInventory[SendIndex].PC,ShopInventory[SendIndex].CatNum); // 0x00000086 : 0x008C
Sleep(0.1); // 0x000000A1 : 0x00B7
++SendIndex; // 0x000000A9 : 0x00BF
goto JL007C; // 0x000000AE : 0x00C6
}
SendIndex = 0; // 0x000000B1 : 0x00C9
if ( SendIndex < ShopCategories.Length ) // 0x000000B6 : 0x00D0
{
ClientReceiveCategory(SendIndex,ShopCategories[SendIndex]); // 0x000000C2 : 0x00E0
Sleep(0.1); // 0x000000D2 : 0x00F8
++SendIndex; // 0x000000DA : 0x0100
goto JL00D0; // 0x000000DF : 0x0107
}
ClientSendAcknowledge(); // 0x000000E2 : 0x010A
Sleep(1.0); // 0x000000E6 : 0x0110
goto JL004F; // 0x000000EE : 0x0118
}
if ( ClientAckSkinNum < CustomChars.Length ) // 0x000000F1 : 0x011B
{
ClientReceiveChar(CustomChars[ClientAckSkinNum],ClientAckSkinNum); // 0x000000FD : 0x012B
Sleep(0.151); // 0x0000010B : 0x0141
goto JL011B; // 0x00000113 : 0x0149
}
}
GotoState(‘None’); // 0x00000116 : 0x014C
}

И даже если вы тут расставите label, то код не откомпилится. Будет правильно так

Auto state RepSetup
{
Begin:
if( Level.NetMode==NM_Client )
Stop;
Sleep(1.f);
NetUpdateFrequency = 0.5f;

if( NetConnection(StatObject.PlayerOwner.Player)!=None ) // Network client.
{
// Now MAKE SURE client receives the full inventory list.
while( ClientAccknowledged[0]<ShopInventory.Length || ClientAccknowledged[1]<ShopCategories.Length )
{
for( SendIndex=0; SendIndex<ShopInventory.Length; ++SendIndex )
{
ClientReceiveWeapon(SendIndex,ShopInventory[SendIndex].PC,ShopInventory[SendIndex].CatNum);
Sleep(0.1f);
}
for( SendIndex=0; SendIndex<ShopCategories.Length; ++SendIndex )
{
ClientReceiveCategory(SendIndex,ShopCategories[SendIndex]);
Sleep(0.1f);
}
ClientSendAcknowledge();
Sleep(1.f);
}

// Send client all the custom characters.
while( ClientAckSkinNum<CustomChars.Length )
{
ClientReceiveChar(CustomChars[ClientAckSkinNum],ClientAckSkinNum);
Sleep(0.15f);
}

}

GoToState(”);
}

Здесь все goto заменены на while и for.

5.

Здесь не все ошибки, которые допускает программа при декомпиляции, требуется много времени, терпения и внимания, чтоб все их исправить вручную. В основном помогают исходники самой игры, там можно найти почти все переменные, функции и так далее и проследить, где была допущена ошибка. Есть более лучшие программы, чем UT Package Tool, тем более они бесплатны, как со своими плюсами, так и минусы тоже имеются, в другой программе не надо проделывать столько много ручной работы, не надо самому уже прописывать label, копировать defaultproperties и так далее, но жутко смущает один факт, что опять же не правильно расставляет окончания каких-нибудь циклов, условий, это знаки {}, из-за чего код может оказаться далеко не тем, что желали, хотя и меньше работы, а с другой стороны в UT Package Tool намного больше ручной работы, но в то время еще не разу не подводил. Если пытаться декомпилить полностью весь сервер, то это может занять несколько дней, может и неделю таким способом, зависит от сложности самого сервера, но а если говорить о каком-нибудь оружии, зомби, скина, то можно управиться очень даже быстро, при условии, если анимация нужной информации не упакована в большой пак, где удалена информация о мешах, что приводит к невозможности распаковать пак и вытянуть от туда нужную информацию с последующей упаковкой в собственный пак, но это только относиться к анимации, если и существует лекарство, то мне оно не известно. Так или иначе, можно в крайнем случае использовать весь пак, который нельзя распаковать, просто не многие пойдут на то, чтоб использовать один скин из , к примеру, десяти, которые находятся в этом паке. Конечно, можно попытаться удалить всю ненужную информацию с пака средствами Killing Floor SDK, и сохранить только нужную, но опять же, если в этом паке вшит класс, который ссылается на данную анимацию, то SDK скажет, что не может удалить меш, так как она используется.

SteamSolo.com