Comparison with Shadow of Mordor
How Shadow of Mordor (2014) differs from Shadow of War at the file and engine level: the executable, the archive format and its compression, container and asset format versions, the GameDB, the orc skeletons, materials and textures, the Army screen's arena, and the Mordor-to-War nemesis importer that ships inside Shadow of War.
Shadow of Mordor (2014) is the predecessor engine generation. Its internal project name is Firebird; Shadow of War's is Kraken. The two games share their archive family, container idea, GameDB format and much of their orc rig, but nearly every asset format moved on by several versions, so no Mordor asset loads in War unchanged.
The executables
| Shadow of Mordor | Shadow of War | |
|---|---|---|
x64 executable |
ShadowOfMordor.exe, 27,930,624 bytes |
ShadowOfWar.exe, 117,732,784 bytes |
| Load address | 0x140000000 preferred, relocatable (DYNAMIC_BASE, relocation table present) |
always 0x140000000 (relocations stripped) |
| Code | a conventional .text section of about 20.6 MB |
.arch (about 30 MB) plus 70 MB of code in .bss a (see The executable) |
Because Mordor's executable is relocatable, its addresses move with ASLR every run; War's static addresses never move.
Archives
Both games use LTAR archives. Mordor's are version 3 (.arch05), War's version 4 (.arch06, see
Archives and file formats). The Mordor install has 66 archives, 45.4 GB.
header (0x18 bytes) "LTAR" | u32 version (3) | u32 names size | u32 folder count | u32 file count | u32 1
names null-separated strings from 0x18; the last string may run past the declared size,
and a small block precedes the entry table
entry (0x20 bytes) u64 data offset | u64 compressed size | u64 uncompressed size | u32 flag (9) | u32 name offset
The entry table is found by its signature (the flag 9 at +0x18 of consecutive entries). Parsing
all 66 archives gives 28,884 entries, equal to the 28,884 declared in the headers; every
entry's data lies inside its file and the data offsets ascend in all 28,828 consecutive pairs. A
name offset may point into the middle of a string, and an entry's name does not reliably describe
its payload, so asset paths are taken from the containers' own path tables, as in War.
Compression. Mordor stores each entry as a stream of chunks {u32 compressed length, u32
uncompressed length (at most 65,536), data} compressed with zlib; chunks whose two lengths are
equal are stored uncompressed (of 192 sampled chunk headers, 166 began with the zlib marker and 26
were stored). Chunks are padded, so the next chunk header can sit a few bytes after the previous
chunk's data. War compresses with Oodle.
Containers and asset formats
Mordor's containers are BNDL version 4 (War: version 6); 8,034 of them hold 67,982 asset paths
(66,731 distinct). Mordor's world prefabs are PRFB version 5 and its Scaleform movies GFX version 8
(ActionScript 2).
Asset formats are older versions that War's loaders reject:
| Format | Shadow of Mordor | Shadow of War |
|---|---|---|
mesh (MMSH) |
9 | 16-17 |
skeleton (SKEL) |
8 (War's loader rejects it) | |
texture (TEXR) |
3 | 8 |
material instance (LTMI) |
4 | 7-8 |
Mordor's version-9 mesh vertex is 60 bytes: half-precision position (4 halves), 16-bit texture coordinates, 32-bit normal, tangent and bitangent, a colour, blend weights in BGRA order and bone indices; strides can differ between a mesh's elements. Every Mordor mesh has one UV set, while War's orc gear shaders read a second one. Mordor's texture coordinates can run to 2.0. Textures use the same DDS-based payload, and War's texture header adds a 23-byte block.
Materials are authored differently: Mordor's orcs use about 21 generic shaders, War's use the dedicated nemesis gear, head and body shader trees (see Rendering). For the one weapon compared directly (the Master Pike), Mordor's albedo was about half as bright as War's equivalent (mean 56 / 45 / 39 against 108 / 93 / 82).
The GameDB
Mordor's GameDB is a GADB version 17 file (the same container version as War's; see GameDB) of
23,264,671 bytes inside hotchunk.arch05's
globaldatabase bundle: the entry after the named manifest entry, a BNDL v4 wrapping the
database. It holds 115 character models named Cha_*. The Black Númenórean characters are
three unique models: Cha_Belroth (the Hammer), Cha_Imrakhad (the Tower) and Cha_Zainzadan
(the Black Hand, whose mesh one of Talion's alternative skins in Mordor is built from). Mordor ships no
generic Black Númenórean soldier armour: a census of every container path (66,731 distinct), every
self-named texture (12,714, none unreferenced) and every XML manifest (8,071) finds none.
The warband downloads (layer52 to layer56 archives) are 216-byte unlock stubs: the Guardian,
Blood Hunter, Crusher and Flesh Burner orcs are GameDB presets assembling base-game pieces with
paint, not new assets.
Orc skeletons
| Shadow of Mordor | Shadow of War | |
|---|---|---|
| orc body rig | 112 bones (the berserker 116) | orc_base, 100 bones |
| shared bone names | 72 | 72 |
| face rig | 33 joints | 124 joints |
The 72 shared bones sit at the same bind positions (median difference 0.07 cm, at most 0.94 cm for
the core bones), but 36 of them differ in bind rotation (the forearm twist by 81 degrees). The face
rigs share no joint names. Of Mordor's orc pieces, those that use only bones orc_base also has:
armour 35 of 40, flair 116 of 131, bodies 15 of 15, heads 44 of 111.
The Army screen
Mordor's hierarchy screen is a world of its own,
worlds\cinematics\wraith_visions\hierarchymenu_son.bndl (son.arch05 entry 15, 232,667,989 bytes,
446 assets; near-identical copies in intro.arch05 and outro.arch05): a scene, an object database,
a world mesh and 10 prefabs (the hierarchy art, the Warchief pedestals, glyphs, orc light posts, a
ruin wall, backdrop rocks), with the crowd drawn as card meshes
(fx\ui\hierarchy\models\orcarmy_outlinecards.mesh). The seats are logical rows and columns in
_StructuresFaction.HierarchyFactionPos (5 Warchiefs and captain rows of 8, 7 and 5: 25 seats),
placed in the world as objects Hier.Faction_<row>_<column> with a character spot .Chr, a camera
.Cam and about 20 points of interest each. The screen's movie is
interface\flash\widgets\hierarchy.gfx, which holds no logic.
The Mordor importer in Shadow of War
Shadow of War ships an importer that rebuilds a player's Shadow of Mordor nemesis as a War captain or
follower, compiled from ...\KRAKEN_CODE_STREAM\source\Game\Shared\NemesisForgeUtils.cpp (log tag
[NEMESISFORGE]:; the logger is compiled out of the shipping build).
The check. The loading-progress tick 0x1E3E78 ([GM+0x6D30]) calls 0x1B3ABFC. It returns without
checking when either of two state bytes of its object (+0x38, +0x80) is set, or when the predicate
Invasion/Settings.HaltNemesisForgeCheckPredicate (the settings record at +0x468) evaluates true.
Otherwise it tail-jumps to 0x1B3AA94, which builds an online request carrying the player's
FirebirdProfileID and platform and registers 0x1B32CD0 as its completion handler. The data therefore
comes from the publisher's online service, not from Mordor's local save.
The conversion. When an army's pool is filled (0xFD51A0, the Faction/Definition.Pool consumer)
an imported nemesis goes through 0x1BC05D0, which logs its name and faction and calls 0x1C6369C. That
maps each Mordor value to a War record through the conversion tables: combat tree, personality, role,
the minimum level (MinXPLevel), whether it becomes the player's follower, its scar type, its traits
and its trait markers. 0x1BC05D0 then builds the captain with the ordinary FactionMember builder
0x1BBF928 (see The Nemesis system). The builder's model step 0x1C04F20 converts the look: the base
model (NemesisForge/FirebirdSimpleModel.Base), body and body type, armour, head
(FirebirdSimpleModelHead.KrakenHead), helmet, hair (CanApplyHair), legs and accessories, then nine
colour channels (skin, eyes, clothing, tattoo, paint, hair, two armour colours and leg leather). Each
colour goes through 0x1C7664C: the Mordor colour id is looked up in a War colour setup's entries by
their FirebirdColorId, with the entry's HueDeltaRange and NumRandomCalls applied. The record's
CreationSimEventPicker chooses the sim event that introduces the captain, and quest jobs can ask for
the imported captain through Quest/Jobs/Definition.UseNemesisForgeNemesis and UseNemesisForgeAlly.
The tables in the shipped GameDB:
| Category | Records | Examples |
|---|---|---|
NemesisForge/FirebirdSimpleModel |
5 | the Mordor orc classes AI_Spearman, AI_Infantry, AI_Berserker, AI_Defender, AI_Archer |
NemesisForge/FirebirdFactionRole |
131 | Role_LimpLeg, Role_GrogBurner, Role_NeckSnapper, Role_Massive_DLC2 |
NemesisForge/FirebirdFactionTrait |
83 | Ground_Pound, Flaming_Weapon_Spearman, Monster_Slayer, Quirk_Aggressive |
NemesisForge/FirebirdFactionPersonality |
12 | Clever_Sniveling, Psychotic, Commanding_1 |
NemesisForge/FirebirdModelScarType |
6 | Wraith, Burn, Pin_Cusion, Sack_Head, Eyepatch, Melee |
NemesisForge/FirebirdSimpleModelHead |
30 | OrcStk03 ... |
NemesisForge/FirebirdSimpleModelPiece |
76 | Smp_Orc_Buff_Hair01_Head03_01 ... |
NemesisForge/FirebirdSimpleModelColorId |
15 | Red, White, Fleshtone, Grey, Black, Blue |
NemesisForge/FirebirdSimpleModelColorSetup |
11 | Orc_Infantry_Skin_Color, Orc_Hair_Color, Armor_Color_01_Grey |
The executable also names the console commands NemesisForge.CreateNemesis,
NemesisForge.CreateFollower and NemesisForge.Override.ClearAll, the events
Events_NemesisForgeImportEnabled and Events_NemesisForgeImportSampled, and a user property
User.OwnsShadowOfMordor.
Open questions
- What the online request's completion handler 0x1B32CD0 stores, and where the imported nemesis waits until a pool fill picks it up.
- Whether some of War's orc geometry is Mordor geometry carried over (the broom and the Beheader helmet have identical level-of-detail counts in both games).
Shadow of War (Steam), game version 1.21. An unofficial fan research project, not affiliated with or endorsed by Warner Bros. Games, Monolith Productions or Middle-earth Enterprises. Middle-earth: Shadow of War belongs to its owners.