FCSE (Far Cry Script Extender)
Some engine behavior can't be reached through game assets at all. The Dunia engine is versatile,
but Ubisoft had to force some kind of abstract domain on top of it so that it doesn't become "the
next Unity or Unreal" — and that domain logic stayed compiled directly into Dunia.dll. Until now,
the only way to change it was to ship your own patched copy of that file, which works for exactly
one mod at a time: two differently-patched copies of Dunia.dll can't coexist, so the moment two
mods both want to touch engine internals, one of them loses.
FCSE fixes that the way SKSE fixed the
equivalent problem for Skyrim: a separate launcher, FCSE.exe, that loads any number of
third-party plugin DLLs from bin\plugins\ before the game engine spins up, giving each one a safe,
shared way to change engine behavior — without needing a shared pre-patched binary, and without one
mod's changes silently clobbering another's.
Source: tools/FCSE — see its
README for the full technical design
(exactly how it reimplements FarCry2.exe's own WinMain, resolves Dunia.dll's exports by name,
and orders plugin registration around a confirmed engine quirk) and
fcse_api.h for
the full plugin ABI, documented inline. For the underlying reverse-engineering this is built on,
see Engine Internals — particularly the launcher
exe and function registry
notes.
What it can do
A plugin is a plain DLL, dropped into bin\plugins\, exporting one required function
(FCSE_Load) and one optional one (FCSE_OnRegisterFunctions). FCSE gives it three escalating
tools to change engine behavior with:
- Claim a named engine callback (
AddFunctionCB) — zero reverse-engineering required, and version-independent (it's a string key, resolved the same way on every build). Dunia's own code already calls out by name to a fixed set of hooks for real gameplay events — diamond pickups, malaria-curve progression, main-menu construction, loading-screen text, and more (see the function-registry notes for the full surveyed list). A plugin can claim one of these names outright, or override one of FCSE's own 12 stock handlers — plugin registrations run before FCSE's own, specifically so this works. - Detour a function (
Hook) — for engine internals with no existing named hook, backed by MinHook. Needs the plugin author to have found the target address themselves (e.g. via Ghidra against a specific confirmedDunia.dllbuild) — FCSE hands back a working trampoline to call the original. - Patch bytes directly (
Patch) — for small constant/branch-flip edits, applied live and in-process instead of to a shared file on disk. This is the direct successor to whatreverse/patch_toRed.py/patch_incHB.py/patch_carJoke.pyalready do statically againstDunia.dllbefore launch — same idea, but any number of plugins can now each apply their own edit without agreeing on one shared pre-patched binary.
Conflicts are loud, not silent. If two plugins target the same name/address, FCSE doesn't try
to chain their effects together — the second claimant is rejected, and both plugins' identities are
logged, so a real conflict is always visible and debuggable instead of turning into a
hard-to-diagnose behavior change. Every run also writes a single bin\fcse.log, tagged by source
and timestamped to 100ns resolution, so tracing exactly what happened (which plugins loaded, what
each one claimed, what got rejected) never needs a debugger.
See
example_plugin.cpp
for a small, complete plugin exercising all three tiers.
Installing
- Copy
FCSE.exeinto the game'sbin\folder, next to the existingFarCry2.exe— that file is left completely untouched;FCSE.exeis an additional way to launch the game, not a replacement. - Drop plugin
.dllfiles intobin\plugins\(created automatically on first run if it doesn't exist yet). - Launch
FCSE.exeinstead ofFarCry2.exe.