Dnes se mrkneme na nejznámější dekompilátory map. Povíme si také něco o tom, jak fungují a jak se dá dekompilaci bránit.
Dekompilátory
Na internetu se můžeme najít docela dost programů na dekompilaci bsp do map souboru. Zatím jsem ale narazil jen na dva druhy způsobu dekompilace.
BSP2MAP
Na tento způsob dekompilace narazíte většinou. Najdete ho v programech BSPTwoMAP, BSPViewer, BSP_MAP nebo bsp2rmf.
Poznáte ho tak, že pro každou stěnu se vytvoří brush tenký 1hu. Ve výsledném map souboru je pak mapa dutá. Takto dekompilované mapy jsou nevhodné pro znovuzkompilování - hodně dlouho vám poběží CSG a BSP, protože dekompilovaná mapa obsahuje mnohem více brushů než původní. Pokud používáte ZHLT, dutiny se nezahodí, ale normálně zkompilují, takže znovuzkompilovaná mapa bude obsahovat zbytečné obslasti. To neplatí pro VHLT, kde už se dutiny zahazují. Pokud někde v mapě stěny svírají ostrý úhel, vznikne nepěkný roh.
Program BSPTwoMAP se používá jako každá jiná konzolová aplikace. Pokud nevíte, jak se používá konzolová aplikace, prostě přetáhněte bsp soubor na aplikaci bsptwomap.exe.
Pomocí parametrů je možné zakázat exportování textur, velikost ORIGIN brushe, nebo předejít bugům v případě, že je mapa kompilovaná v té době převratnými ZHLT 1.7p. :)
WinBSPC
Tento způsob dekompilace jsem nalezl jen u tohoto programu.
Narozdíl od BSP2MAP vytváří větší brushe, takže dekompilovaný map soubor opravdu připomíná mapu a různé brushe občas i odpovídají originálnímu zdrojovému rmf. Takovéhle dekompiláty se dají po opravení všech chyb znovu zkompilovat. Opravit je potřeba posunutí textur, přidat chybějící brushe a CLIPy.
WinBSPC se ovládá jednoduše - ve File -> Convert vyberete kýžené bsp, zaškrtnete možnost MAP a odklepnete. Dá se také nastavit jiná výstupní složka, nebo parametry dekompilace:
best match texturing - dekompilátor se bude snažit o co nejméně brushů nezávisle na tom, jak moc rozhází textury
no brush merging - brushe se nebudou slučovat, ale zůstanou rozděleny stejně jako v bsp
no liquids - voda se zahodí
Pokud po otevření dekompilátu ve VHE jsou stěny pouze barevné, je potřeba všechny brushe označit, otevřít Texture application tool a zaškrtnout World.
Program WinBSPC je ke stažení zde.
Dekompilace
Začneme kompilací (CSG a BSP) - z naší formy (zdrojového rmf) odlijeme odlitek (bsp). Z tohoto odlitku se samozřejmě dá vyrobit forma, ale nikdy ne stejná jako originál. Kompilací se zahodily informace o tloušťce zdí, zůstaly nám jen okraje. Stěny jsou navíc rozřezány jak pravidelně (subdivide - 240), tak nepravidelně. Ztratili jsme také CLIP, ORIGIN a HINT/SKIP brushe. Ty se ale dají vytvořit z informací ve které se přeměňují - CLIP z hullů 1 a 3, ORIGIN z originů entit a HINT/SKIP z portálů.
Při převodu stěn na brushe se většinou používá jednoduchý bsp2map princip - všechny stěny se uloží jako 1hu brushe. Složitější algoritmy naleznou rozřezané stěny a spojí je zpět v jeden celek - ten se samozřejmě může lišit od originálu. Nejsložitější je pak winbspc algoritmus, kdy je potřeba obalit konkávní oblast co nejméně konvexními brushi.
Hodně chybných brushů vznikne kvůli ukládání do formátu map. Při ukládání do rmf je v podstatě možné překopírovat vrcholy přímo z bsp.
Obrana
BSP se nedá zaheslovat, takže je potřeba ochránit jiným způsobem. Dovolím si říci, že dokud se mapa dá otevřít v CSku, dá se i dekompilovat. Tudíž jediný způsob, jak mapu ochránit, je pokusit se vyvolat chybu v dekompilátorech. Našel jsem zatím dva způsoby jak vyvolat chybu.
1, Rozbití parseru entit.
Entity jsou v bsp uloženy v následujícím formátu:
{
"origin" "0 -128 448"
"angles" "-90 270 0"
"_light" "255 255 255 200"
"classname" "light_environment"
}
{
"origin" "-64 -704 64"
"angles" "0 90 0"
"classname" "info_player_start"
}
Parser je program/algoritmus, který tento zápis zpracuje, který se dále použije např. pro vykreslení těchto entit. Každý program, který chce pracovat s jednotlivými entitami v BSP musí mít vlastní parser. Bohudík CSko má mnohem lepší parser než všechny dekompilátory, takže ho nic nerozhodí. Dekompilátory rozhodí ale všechno možné.
> když je v názvu hodnoty nový řádek
> když je mezi uvozovkami nějaký text ("classname"text"light")
> když za ukončenou složenou závorkou nepřijde nový řádek (}{)
Nějaký ten čas zpátky jsem napsal program, který ochrání mapu právě tímto způsobem. Zápis entit v mapě protažené títmo programem by pak vypadal např. takto:
{
"origin" "0 -128 448"
"angles" "-90 270 0"
"_light" "255 255 255 200"
"classname" "light_environment"
"
JaeK
"c0b"iAVp"
}{
"origin" "-64 -704 64"
"angles" "0 90 0"
"classname" "info_player_start"
"QnS
"ism"elEn"
}
Jako protiútok ze strany dekompilátoru by samozřejmě stačlio napsat lepší parser, nebo program, který by toto svinstvo odstranil.
Na tento způsob ochrany jsem přišel, když jsem zjistil, že mapa z korejského CSO nejde dekompilovat a že nedělají nový řádek mezi složenými závorkami. O korejském CSO určitě také něco napíšu.
2, Překročení limitů.
Zdrojové kódy dekompilátorů k sehnání samozřejmě nejsou, ale protože dekompilátory používají zdrojové kódy kompilátorů, není složité zjistit, jaké jsou požadavky na mapu. Mohli bychom si zjistit podle data vydání, jakou verzi zhlt zdrojáků asi používají, ale nám bude stačit poslední verze.
#define MAX_MAP_ENTSTRING (512*1024)
#define MAX_KEY 32
#define ZHLT3_MAX_VALUE 4096
#define DEFAULT_MAX_MAP_MIPTEX 0x400000
Vybral jsem ty limity, které jdou nejlehčeji překročit. První tři se opět vážou k entitám - maximální délka zápisu entit, maximální délka názvu hodnoty a maximální délka hodnoty. Kdybychom tedy přidali na konec zápisu entit tolik mezer abychom překročili limit (524288 znaků), nejspíše bychom opět zamezili dekompilaci.
Poslední limit se váže k includnutým texturám. Pokud k mapě přiložíme více jak 4MB textur, mapa nepůjde dekompilovat.
Možná si říkáte, jestli má cenu zbytečně mapu zvětšovat o 0,5MB entit, nebo 4MB textur. V případě, že tato přidaná velikost bude složena z těch stejných znaků (mezery, černé pixely nebo nulové bajty), tak ji při stahování mapy nepocítíme, protože se jednoduše zkomprimuje na pár bajtů.
Na tento způsob ochrany jsem přišel, když jsem zjistil, že nejde dekompilovat de_varant.
|
A nebo to udělat takhle