Contract J.A.C.K. (Monolith, 2003), built from source.
Monolith never released Contract J.A.C.K.'s source, as it did for No One
Lives Forever 2. This project reconstructs it: the game code from NOLF2's
source release (Contract J.A.C.K. was built from the same tree,
C:\proj\to2\source\Game\, as its binaries' strings show), and the
engine from the LithTech Jupiter engine source (the 2006 distribution of
the same engine line, built with the same compiler), each brought to what
the retail binaries are, function by function. As for
nolfsrc and
nolf2src, the aim is two builds:
- legacy: Contract J.A.C.K. (Europe) at its last update, 1.1, rebuilt so that it compiles back to the retail binaries byte for byte, as far as that can be done -- with the compiler Monolith used, Visual C++ .NET 2003 (13.10.3077), under Wine;
- modern: the same source with fixes and new features (
CJACK_MODERN).
Compiling back to the retail bytes means compiling the retail game's bugs as
well; their fixes go behind CJACK_MODERN, into the modern build only, so
the legacy build keeps matching the retail one.
Started. The retail game is installed from its discs and update (ext/rez/),
the compiler is in ext/toolchains/ (msvc-7.10-3077), and the scoreboard
scores every retail binary against our build. ltmsg.dll is built (the
retail file but for its link time stamp) and SndDrv.dll builds; the rest
is to come. docs/PLAN.md is the plan, package by package.
How much of each binary compiles to exactly the bytes of the retail game (version 1.1). A function counts when our compiled code is identical to the retail function, with only the addresses the linker fills in left out of the comparison; the bars measure the share of each binary's code, by size, those functions make up.
| Binary | Byte-identical functions | Byte-identical code | Unwritten | Unplaced | ||
|---|---|---|---|---|---|---|
Lithtech.exe |
the engine | 7,297 / 7,972 | 1,126,387 / 1,163,487 bytes | ███████████████████░ 96.8% |
0 | 38 |
server.dll |
the engine's server | 2,902 / 3,136 | 392,698 / 403,695 bytes | ███████████████████░ 97.2% |
0 | 10 |
SndDrv.dll |
the sound driver | 251 / 264 | 28,521 / 28,605 bytes | ███████████████████░ 99.7% |
0 | 0 |
GameSpy.dll |
the GameSpy services | 176 / 191 | 19,322 / 20,268 bytes | ███████████████████░ 95.3% |
0 | 0 |
ContractJack.exe |
the launcher | 328 / 344 | 40,582 / 40,763 bytes | ███████████████████░ 99.5% |
0 | 0 |
ContractJackServer.exe |
the dedicated server | 627 / 669 | 75,174 / 75,852 bytes | ███████████████████░ 99.1% |
0 | 0 |
CShell.dll |
the game: client | 6,329 / 6,658 | 1,092,275 / 1,155,989 bytes | ██████████████████░░ 94.4% |
0 | 0 |
Object.lto |
the game: server objects | 9,507 / 9,876 | 1,590,396 / 1,638,452 bytes | ███████████████████░ 97.0% |
0 | 0 |
ClientFx.fxd |
the game: client effects | 443 / 455 | 104,672 / 104,763 bytes | ███████████████████░ 99.9% |
0 | 0 |
ltmsg.dll |
the engine's messages, not in the total | 5 / 5 resources | 2,054 / 2,054 bytes | ████████████████████ 100.0% |
0 | -- |
CRes.dll |
the game's client resources, not in the total | 457 / 457 resources | 330,555 / 330,555 bytes | ████████████████████ 100.0% |
0 | -- |
SRes.dll |
the game's server resources, not in the total | no resources | -- | -- | -- | -- |
Lithtech.exe:rsrc |
the engine's resources, not in the total | 18 / 53 resources | 8,296 / 20,810 bytes | ███████░░░░░░░░░░░░░ 39.8% |
1 | -- |
server.dll:rsrc |
the engine's server's resources, not in the total | 2 / 2 resources | 760 / 760 bytes | ████████████████████ 100.0% |
0 | -- |
ContractJack.exe:rsrc |
the launcher's resources, not in the total | 101 / 101 resources | 4,917,154 / 4,917,154 bytes | ████████████████████ 100.0% |
0 | -- |
ContractJackServer.exe:rsrc |
the dedicated server's resources, not in the total | 18 / 18 resources | 937,508 / 937,508 bytes | ████████████████████ 100.0% |
0 | -- |
| All | 27,860 / 29,565 | 4,470,027 / 4,631,874 bytes | ███████████████████░ 96.5% |
0 | 48 |
Every function in that table is recorded in progress/identical.txt, and
make progress re-scores the current build against the retail binaries and
fails if any of them stops matching. See progress/README.md for how the
scoring works and what it leaves out. Which compiler built each binary, and
the evidence, is progress/COMPILERS.md.
Needs docker and the submodules (git submodule update --init):
ext/toolchains/ (the compilers), ext/rez/ (which fetches the European discs from
archive.org and installs the game with its 1.1 update), ext/tools/ (the
reconstruction tools) and ext/lithtools/ (whose lithrez packs the 1.1
update's data, assets/, into cjacksrc.rez); and, for make modern, ext/ffmpeg (FFmpeg n8.1.3,
which the modern build's Bink player is built on, by build/ext.sh).
make # out/cjack-legacy-release/: what is built so far, with the retail data
make progress # score the build against the retail binaries
make help # everything elseEach build also makes two archives of its game directory
(build/package.sh): out/<name>-private.tar.gz, with the retail game's
data, for your own machines, and out/<name>-public.tar.gz, without
the discs' data, to give to other people (it carries only the free 1.1
update's, as cjacksrc.rez: assets/README.md). The public one
carries scripts that copy the rest out of the player's own images of both
discs (European or USA; a plain .iso, redump's .bin/.cue or its
.zip), checking every file they write (ext/tools/mkinstall.py):
cjack-modern-release/linux-install.sh disc1.zip disc2.zip # Linux
cjack-modern-release/mac-install.command disc1.zip disc2.zip # a Mac, for CrossOverOn Windows, drop the two images onto windows-install.bat. Each script
also finds them in the game directory or the one above it by itself
(double-click mac-install.command in Finder), and can be run again.
Both archives also carry the scripts that start the game
(build/game-scripts/): linux-run.sh (starts the game under Wine, in a
prefix of its own; the legacy build's launcher gets the registry values
the retail installer wrote) and linux-server.sh (a dedicated server,
headless under xvfb-run without a display); each prints its usage with
--help. On Windows, start ContractJack.exe.
In modern builds, ContractJack.exe (and linux-run.sh) starts the game
immediately using the launcher's saved settings and arguments, skips the
first-run detail prompt, and waits until Lithtech.exe exits. Open
ContractJackLauncher.exe for the interactive launcher. Under Wine, use
the same prefix as linux-run.sh (~/.wine-cjack by default). Legacy
builds keep their original launcher behavior.
The modern build plays the intro movies with its own binkw32.dll, built
on FFmpeg, and decodes the characters' speech (MP3) in its own
SndDrv.dll, so it needs no codec (MODERN.md X-1, EN-50). The legacy
build is the retail game's: it plays the movies with RAD's Bink, which
stalls under some Wine setups, so linux-run.sh turns them off
(+DisableMovies 1); and under Wine its speech needs Fraunhofer's MP3
codec, since Wine's own (winemp3.acm) plays the streamed lines as a drone
of their first samples. linux-run.sh installs it into the legacy build's
prefix the first time (winetricks l3codecx); with another Wine prefix or
a CrossOver bottle, run WINEPREFIX=<its folder> winetricks l3codecx once.
Windows has it already.
GitHub Actions (.github/workflows/public-archives.yml) builds the four
public archives on every push and pull request. Pushing a tag v* makes a
GitHub release of it with the modern build's two public archives
(cjacksrc-<tag>.tar.gz and cjacksrc-debug-<tag>.tar.gz; a tag with a
hyphen is a pre-release), and every push to master whose builds pass
replaces the pre-release nightly with that commit's
(cjacksrc-nightly-<commit>.tar.gz). The release text is
.github/release_notes.md.