MW Tools, Most Wanted SDK

MWSDK

A C++ modding SDK where every address traces back to verified data.

MWSDK gives you two things: a library for reading and writing Most Wanted's files, and a header-only runtime layer for mods and trainers that run inside the game. Every game address in it is generated from MWEncyclopedia's data, so none of them is a guess.

#include <mwsdk/mod.hpp>
using namespace mwsdk;

void my_mod() {
    auto& game = mw05::process();                // rebased for ASLR
    void*  rn  = mw05::road_network();          // a confirmed singleton
    auto*  cls = mw05::identify(game, rn);      // what class is this?

    // the engine's own string hash, checked at compile time
    static_assert(hash::attrib("default") == 0xEEC2271A);
}
MWSDK_MOD(my_mod)

The data library

Plain C++20 with no dependencies: JDLZ compression, the EAGL chunk container, texture packs, geometry, the attribute vaults, and the world itself. Each world parser was checked byte for byte against the retail track files L2RA.BUN and STREAML2RA.BUN:

ModuleReadsChecked against retail
sceneryPlaced props, model info, the cull tree947 sections, 28,525 model infos, 6,833 LOD models
triggersTrigger volumes and position markers705 regions, 328 markers
pathsTraffic paths and the CARP road graph443 paths, 4,385 nodes, 6,538 segments
collisionTerrain collision and breakable props51,504 triangles, 13,484 props
#include <mwsdk/jdlz.hpp>
#include <mwsdk/eagl.hpp>
using namespace mwsdk;

Result<std::vector<std::uint8_t>> raw = jdlz::decompress(file_bytes);
if (raw)
    eagl::walk(*raw, [](const eagl::Chunk& c, int) { return true; });

The runtime layer

The address database is generated by a script from the encyclopedia's verified tables. It holds 1,778 recovered symbols, 296 of them hand-verified functions, plus 124 reflected classes with their vtables and sizes, 126 typed script natives, and confirmed singletons such as WRoadNetwork, CameraAI and GManager. A research import from a third-party toolkit is kept in its own namespace, mw05::research, so weaker evidence is visible at the call site.

There are three levels, and you only go deeper when you need to:

// Level 1: one-liners against the live process
mw05::vehicle(car).top_speed() *= 1.10f;
mw05::attrib(coll).set<float>(
    vault::schema::aivehicle::TopSpeedMultiplier, 1.25f);
auto guard = mw05::nop(mw05::fn::SomeCheck, 6);     // reverts at scope exit

// Level 2: explicit, with verified offsets
float& top = mw05::field<float>(v, mw05::layout::AIVehicle::mTopSpeed);   // +0x84

// Level 3: raw calls, the symbol database, batches of patches
auto trainer = mw05::group("Trainer");

Live attributes go through the game's own AttribCollection::GetField (0x00454810), keyed by 780 verified field hashes. A missing field is a typed error, never a crash. Members whose names were stripped from the game are exposed as slot_0xNN rather than being given invented names.

Hooking

MWSDK has its own reversible byte patcher and never requires a hooking library. When you do want to hook a game function, the optional VanHooks adapter gives you RAII hooks against verified addresses:

#include <mwsdk/adapters/vanhooks.hpp>

using SetWorldHeatFn = void(MWSDK_CDECL*)(float heat);
static SetWorldHeatFn orig = nullptr;
void MWSDK_CDECL detour(float heat) { orig(heat); }

auto h = mw05::hook::at(mw05::lua::Game::SetWorldHeat, &detour, &orig);
// the hook lifts when `h` is destroyed

Adding it to a project

The runtime layer is header-only: add include/ to your include path and build a 32-bit DLL, since the retail game is x86. For the file formats, link the small data library too.

target_include_directories(my_mod PRIVATE ${MWSDK_DIR}/include)

add_subdirectory(${MWSDK_DIR} mwsdk)
target_link_libraries(my_mod PRIVATE MWSDK::game)   # or MWSDK::data for files

NFSPluginSDK covers Most Wanted, Carbon and ProStreet with hand-written structures and is the long-standing choice for Black Box-era plugins. MWSDK goes deep on one game instead, with every address generated from verified data, and adds an offline file layer.