Overview
A modding library for GTA V, for Legacy and Enhanced.
mojito-core injects into GTA V, patches the RAGE engine at runtime through pattern scanning and detours, and exposes what it finds as a stable C++ API. Your mod links one library and includes one header; none of the reverse engineering leaks into your code.
It targets both the Legacy and Enhanced builds from a single binary. Where a feature only works on one build, the API says so and degrades to a safe no-op or an empty result on the other rather than guessing.
| Namespace | What it covers |
|---|---|
| mjgame | Build identification and thread marshaling |
| mjstreaming | Streaming modules, asset slots, load requests |
| mjentity | Reading entities and walking the map entity pool |
| mjarchetypes | Archetype lookup, flags, bounds, model attributes |
| mjextracontent | DLC change sets, RPF mounting, data files, islands |
| mjfiles | The RAGE virtual filesystem |
| mjwater / mjterrain / mjvfx | World systems: water, heightmap, fog volumes |
| mjminimap / mjaudio / mjpathfind | Minimap tiles, audio sectors, path grids |
| mjcamera / mjscripting / mjdiag | Idle cameras, script pausing, diagnostics |
| mojito | Init, game skeleton hooks, boot flow |
Alongside the namespaces there is a small set of wrapper classes -- MjDwbl, MjModel, MjShader, MjTxd and MjTexture -- for the object graphs where a handle plus free functions would be awkward.
Getting started
Link the library, wait for init, respect the threads.
Linking
You need two files from a mojito-core build: the public header and the import library. Add the header directory to your include path and link the .lib. mojito-core.dll must be present alongside the game executable at runtime.
mojito_core_api.h -> add its directory to your include path
mojito-core.lib -> link it
mojito-core.dll -> ships next to GTA5.exeThe header is self-contained. It pulls in only the standard library and needs no RAGE headers, so you do not have to build or reference mojito-rage-five.
Initialisation
mojito-core initialises on its own once the game is far enough along. Nothing in the API is safe before that finishes, so block on WaitForInit before your first call. Doing that on a worker thread, not in DllMain, keeps you out of loader lock.
#include <mojito_core_api.h>
#include <windows.h>
static DWORD WINAPI MainThread(LPVOID)
{
// Blocks until mojito::Init() has finished.
mojito::WaitForInit();
if (mjgame::IsEnhanced())
{
mojito::ShowMsg("running on Enhanced, build " +
std::to_string(mjgame::GetGameBuild()));
}
// Run something every game-skeleton update tick.
mojito::InstallGameSkelHook([]
{
// ... per-tick work, on the update thread ...
});
return 0;
}
BOOL APIENTRY DllMain(HMODULE module, DWORD reason, LPVOID)
{
if (reason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(module);
CloseHandle(CreateThread(nullptr, 0, MainThread, nullptr, 0, nullptr));
}
return TRUE;
}Threads
Getting this wrong crashes the game
The game runs separate script, update and render threads. Touching render resources off the render thread, or entities off the update thread, is not safe. If you are in a Present hook, a UI callback, or your own thread, marshal the work instead of doing it inline.
// Queue work onto the render thread -- anything touching textures,
// shader resource views, or render targets.
mjgame::RunOnRenderThread([]
{
// ... render-thread-only work ...
});
// Queue work onto the update loop, before or after the game's own update.
mjgame::RunBeforeUpdate([] { /* ... */ });
mjgame::RunAfterUpdate([] { /* ... */ });All three return immediately and run the callback once, on the next tick of the target loop. InstallGameSkelHook is different: it registers a callback that fires every update tick until the process exits.
Handles and lifetime
MjEntity, MjArchetype and MjStreamingModule are opaque handles: they are the real engine pointers, and they stay valid exactly as long as the engine object does. A handle to an asset the streamer has since evicted is dangling.
Every accessor validates the pointer before dereferencing it, so a stale handle returns a null, a zero or false rather than faulting. That is a guard against crashing, not a correctness guarantee -- do not cache handles across a level load or a streaming eviction.
Wrapper classes are cached by pointer
MjDwbl, MjTxd and the other wrappers are interned: asking for the same engine pointer twice gives you the same wrapper. The cache is never pruned, so a wrapper whose asset has been evicted will still hand you a stale pointer. Re-Find after anything that could unload the asset.
mjgame
Which build you are on, and how to get onto the right thread.
bool mjgame::IsLegacy()True on the Legacy build of GTA V.
bool mjgame::IsEnhanced()True on the Enhanced build.
int mjgame::GetGameBuild()The game build number, e.g. 3095.
void mjgame::RunOnRenderThread(std::function<void()> fn)Runs fn once on the next render tick.
void mjgame::RunBeforeUpdate(std::function<void()> fn)Runs fn once, before the game's next update.
void mjgame::RunAfterUpdate(std::function<void()> fn)Runs fn once, after the game's next update.
Branch on the build wherever behaviour differs. Several parts of the API are Legacy-only today and say so; checking IsLegacy first is cheaper than handling an empty result.
mjstreaming
Modules, slots, and making assets resident.
Every streamable asset lives in a module, one per extension: "ydr" for drawables, "ytd" for texture dictionaries, "yft" for fragments, "ymap" for map data, and so on. Within a module each asset has a slot. Across the whole streamer each asset also has a global streaming index.
Two index spaces
Slots are local to one module and are what you look up by name. Streaming indices are global and are what Request and Release take. Convert with ToStreamingIndex -- passing a slot straight to Request will act on an unrelated asset.
MjStreamingModule* mjstreaming::GetModule(const char* extension)The module for an asset extension, e.g. "ydr". Null while the streamer is still registering modules.
MjStreamingModule* mjstreaming::GetModuleByIndex(int index)The module that owns a given module index.
const char* mjstreaming::GetModuleName(MjStreamingModule*)The store name, e.g. "DrawableStore". Null if it does not read back as a plausible string.
int mjstreaming::GetModuleSlotCount(MjStreamingModule*)How many slots the module has.
int mjstreaming::GetSlotByName(MjStreamingModule*, const char* name)Slot for an asset name without extension, e.g. "prop_bench_01a".
Note: Returns mjstreaming::kInvalidSlot (-1) when the asset is not registered.
void* mjstreaming::GetSlotPtr(MjStreamingModule*, int slot)The loaded asset, or null when it is not resident. The concrete type depends on the module.
int mjstreaming::GetSlotRefCount(MjStreamingModule*, int slot)How many references the streamer is holding to the slot.
uint32_t mjstreaming::ToStreamingIndex(MjStreamingModule*, int slot)Converts a module-local slot to a global streaming index.
bool mjstreaming::Request(uint32_t streamingIndex, int flags)Asks the streamer to load an asset. Flags are MJ_STRFLAG_*.
bool mjstreaming::Release(uint32_t streamingIndex, int flags)Drops a request, allowing the asset to be evicted.
void mjstreaming::LoadAllRequestedNow()Blocks until every outstanding request is resident.
Note: Update thread only. Calling it elsewhere will stall or deadlock.
int mjstreaming::GetPendingRequestCount()How many requests are still in flight.
const char* mjstreaming::GetIndexName(uint32_t streamingIndex)The registered path for a streaming index, or null.
Note: Filled in by the manifest hook, so it only covers assets registered after init. Always null on FiveM builds.
| Flag | Meaning |
|---|---|
| MJ_STRFLAG_PRIORITY_LOAD | Jump the queue |
| MJ_STRFLAG_DONTDELETE | Keep resident until explicitly released |
| MJ_STRFLAG_FORCE_LOAD | Load even if the streamer would defer it |
MjStreamingModule* ydr = mjstreaming::GetModule("ydr");
if (!ydr) { return; } // streamer not ready yet
const int slot = mjstreaming::GetSlotByName(ydr, "prop_bench_01a");
if (slot == mjstreaming::kInvalidSlot) { return; }
if (!mjstreaming::GetSlotPtr(ydr, slot))
{
const uint32_t index = mjstreaming::ToStreamingIndex(ydr, slot);
mjstreaming::Request(index, mjstreaming::MJ_STRFLAG_FORCE_LOAD);
// Update thread only.
mjstreaming::LoadAllRequestedNow();
}
void* drawable = mjstreaming::GetSlotPtr(ydr, slot);mjentity
Reading entities and walking the map entity pool.
These accessors are read-only views over the engine entity types. They work on any entity pointer, including one you already have from ScriptHookV, so you can mix mojito reads with native calls on the same object.
// getScriptHandleBaseAddress comes from ScriptHookV's nativeCaller.
auto* entity = reinterpret_cast<MjEntity*>(getScriptHandleBaseAddress(handle));
if (mjentity::GetEntityType(entity) == mjentity::MjEntityType::Vehicle)
{
float pos[3];
mjentity::GetPosition(entity, pos);
const uint32_t model = mjentity::GetModelHash(entity);
const uint32_t flags = mjentity::GetEntityFlags(entity);
if (flags & mjentity::MJ_ENTFLAG_IS_ON_FIRE) { /* ... */ }
}Reading an entity
MjEntityType mjentity::GetEntityType(MjEntity*)Which concrete engine class the handle really is: Building, Vehicle, Ped, Object, Mlo, Light and so on.
MjArchetype* mjentity::GetArchetype(MjEntity*)The entity's archetype, or null.
uint32_t mjentity::GetModelHash(MjEntity*)Model name hash, or 0.
bool mjentity::GetMatrix(MjEntity*, float outMatrix[16])World matrix, row-major, translation in elements 12 to 14.
bool mjentity::GetPosition(MjEntity*, float outPos[3])World position only.
uint32_t mjentity::GetEntityFlags(MjEntity*)The CEntity flag word. Test it against the MJ_ENTFLAG_* bits.
uint32_t mjentity::GetBaseFlags(MjEntity*)The lower-level fwEntity flag word.
MjEntityOwnedBy mjentity::GetOwnedBy(MjEntity*)Which game system created and owns the entity.
Note: Deleting something owned by Ipl or StaticBounds out from under the streamer is a reliable way to crash.
uint32_t mjentity::GetIplIndex(MjEntity*)Which IPL the entity was placed by.
uint32_t mjentity::GetTintIndex(MjEntity*)Tint palette index.
void* mjentity::GetDrawHandler(MjEntity*)The fwDrawData pointer, or null.
LOD
Map entities form a LOD hierarchy: a high-detail entity fades into a LOD parent, which fades into progressively coarser SLOD levels. These accessors read that relationship.
MjLodType mjentity::GetLodType(MjEntity*)Where the entity sits in the hierarchy: Hd, Lod, Slod1 to Slod4, or OrphanHd for high detail with no parent.
uint32_t mjentity::GetLodDistance(MjEntity*)Distance at which this entity gives way to its LOD.
uint32_t mjentity::GetChildLodDistance(MjEntity*)Distance at which its children give way to it.
uint32_t mjentity::GetNumChildren(MjEntity*)How many entities fade into this one.
uint8_t mjentity::GetAlpha(MjEntity*)Current fade alpha: 0 invisible, 255 fully faded in.
MjEntity* mjentity::GetLodParent(MjEntity*)The entity this one fades into, or null if it is a LOD root.
The map entity pool
Legacy only for now
The CBuilding pool global has no unique signature on Enhanced yet, so GetBuildingPoolSize returns 0 there and FindInstancesOfModel finds nothing. Guard with mjgame::IsLegacy().
int mjentity::GetBuildingPoolSize()Number of slots in the map entity pool. 0 when the pool could not be resolved.
MjEntity* mjentity::GetBuildingAt(int index)The entity in a slot.
Note: The pool is sparse -- free slots return null, so skip them rather than treating null as the end.
int mjentity::FindInstancesOfModel(uint32_t modelHash, MjEntity** out, int maxOut)Every streamed-in placed instance of a model. Returns the count written.
int trees = 0;
const int poolSize = mjentity::GetBuildingPoolSize();
for (int i = 0; i < poolSize; ++i)
{
MjEntity* entity = mjentity::GetBuildingAt(i);
if (!entity) { continue; } // sparse pool: free slot
MjArchetype* arch = mjentity::GetArchetype(entity);
if (!arch) { continue; }
if (mjarchetypes::GetFlags(arch) & mjarchetypes::MJ_ARCHFLAG_IS_TREE)
{
++trees;
}
}mjarchetypes
Model definitions: lookup, flags, bounds, attributes.
An archetype is the loaded definition behind a model: what asset it draws, how big it is, and how the engine should treat it. Look one up by name or hash, then read from it.
MjArchetype* mjarchetypes::FindByName(const char* modelName)Archetype for a model name, or null when it is not currently loaded.
MjArchetype* mjarchetypes::FindByHash(uint32_t modelHash)Same, by hash.
MjModelInfoType mjarchetypes::GetModelType(MjArchetype*)Which model-info subclass it is: Base, Mlo, Time, Weapon, Vehicle, Ped or Composite.
MjDrawableType mjarchetypes::GetDrawableType(MjArchetype*)What asset it draws: Fragment, Drawable, DrawableDictionary or Assetless.
uint32_t mjarchetypes::GetDrawableIndex(MjArchetype*)Slot of that asset in its store.
uint32_t mjarchetypes::GetFlags(MjArchetype*)The runtime archetype flag word. Test against MJ_ARCHFLAG_*.
void mjarchetypes::SetFlags(MjArchetype*, uint32_t flags)Replaces the whole flag word.
Note: Read, modify, write. Assigning a bare flag clears everything else, including the packed attribute in the top bits.
uint32_t mjarchetypes::GetAttribute(MjArchetype*)The exclusive MJ_MODELATTR_* value packed into flag bits 26 to 31.
bool mjarchetypes::GetBoundingBox(MjArchetype*, float outMin[3], float outMax[3])Model-space bounds.
bool mjarchetypes::GetBoundingSphere(MjArchetype*, float outSphere[4])Model-space sphere: xyz centre, w radius.
int mjarchetypes::GetRefCount(MjArchetype*)How many entities reference the archetype.
bool mjarchetypes::HasPhysics(MjArchetype*)Whether it has a physics archetype attached.
void mjarchetypes::AddNeverDummyModel(uint32_t modelHash)Stops a model from being converted to a dummy object when the player moves away.
These are not the .ytyp flags
MJ_ARCHFLAG_* are the runtime flag bits. The flags attribute you edit in CodeWalker is a different bit assignment that the loader translates into this one, so the numbers do not line up. IS_TREE is bit 16 in a .ytyp and bit 17 here.
Bits 26 to 31 are not flags
The top six bits hold one exclusive value -- ladder, traffic light, garage door, street light and so on -- not a set of independent bits. Read it with GetAttribute, or shift it out yourself with MJ_ARCHFLAG_ATTRIBUTE_SHIFT and MJ_ARCHFLAG_ATTRIBUTE_MASK. Testing them as bits gives nonsense.
MjArchetype* arch = mjarchetypes::FindByName("prop_streetlight_01");
if (!arch) { return; } // not currently loaded
float sphere[4];
mjarchetypes::GetBoundingSphere(arch, sphere);
if (mjarchetypes::GetAttribute(arch) == mjarchetypes::MJ_MODELATTR_IS_STREET_LIGHT)
{
// Read, modify, write -- never assign a bare flag.
const uint32_t flags = mjarchetypes::GetFlags(arch);
mjarchetypes::SetFlags(arch, flags | mjarchetypes::MJ_ARCHFLAG_DONT_CAST_SHADOWS);
}Drawables and textures
The wrapper classes: MjDwbl, MjModel, MjShader, MjTxd, MjTexture.
Asset graphs are exposed as small wrapper classes instead of free functions, because you are usually walking from one object to the next: a drawable to its LOD, to a model, to a geometry, to the shader that draws it.
Wrappers do not own anything
A wrapper is a view onto an engine object. Never delete one. They are interned by pointer and never pruned, so re-Find rather than holding one across a streaming eviction.
MjDwbl
A streamed-in drawable (.ydr). Four LOD slots, numbered 0 high to 3 very low; slots can be empty, so test with HasLod before reading one.
static MjDwbl* MjDwbl::Find(const std::string& name)Resident drawable by name, or null.
const char* MjDwbl::GetDebugName()Resource debug name. Usually null in retail builds.
int MjDwbl::GetShaderCount()Shaders in the drawable shader group.
MjShader* MjDwbl::GetShader(int index)One shader from the group.
MjTxd* MjDwbl::GetTextureDictionary()The embedded texture dictionary, or null.
bool MjDwbl::GetBoundingSphere(float outSphere[4])Model-space sphere: xyz centre, w radius.
bool MjDwbl::GetBoundingBox(float outMin[3], float outMax[3])Model-space bounds.
bool MjDwbl::HasLod(int lod)Whether a LOD slot is populated.
float MjDwbl::GetLodThreshold(int lod)Distance at which that LOD takes over. -1 when the slot is empty.
int MjDwbl::GetModelCount(int lod)Models in a LOD.
MjModel* MjDwbl::GetModel(int lod, int modelIndex)One model from a LOD.
bool MjDwbl::GetLodTotals(int lod, uint32_t* outVerts, uint32_t* outTris)Summed vertex and triangle counts across a whole LOD.
int MjDwbl::GetBoneCount()Bones in the skeleton. 0 for a static prop.
const char* MjDwbl::GetBoneName(int boneIndex)Bone name.
int MjDwbl::GetBoneParentIndex(int boneIndex)Parent bone index, or -1 for a root bone.
bool MjDwbl::GetBoneDefaultTranslation(int boneIndex, float outPos[3])Bone-space default translation.
MjModel
One model inside a LOD. It owns geometries; each geometry is drawn with one shader from the parent drawable, which GetGeometryShaderIndex resolves for you.
int MjModel::GetGeometryCount()Geometries in the model.
bool MjModel::IsSkinned()Whether the model is skinned to the skeleton.
int MjModel::GetGeometryShaderIndex(int geomIndex)Which MjDwbl::GetShader slot draws this geometry, or -1.
bool MjModel::GetGeometryInfo(int geomIndex, MjGeometryInfo* out)Vertex count, index count, triangle count, vertex stride and primitive type.
MjDwbl* dwbl = MjDwbl::Find("prop_bench_01a");
if (!dwbl) { return; }
for (int lod = 0; lod < MjDwbl::kMaxLods; ++lod)
{
if (!dwbl->HasLod(lod)) { continue; }
uint32_t verts = 0, tris = 0;
dwbl->GetLodTotals(lod, &verts, &tris);
printf("lod %d at %.0fm: %u verts, %u tris\n",
lod, dwbl->GetLodThreshold(lod), verts, tris);
for (int m = 0; m < dwbl->GetModelCount(lod); ++m)
{
MjModel* model = dwbl->GetModel(lod, m);
for (int g = 0; g < model->GetGeometryCount(); ++g)
{
MjModel::MjGeometryInfo info{};
if (!model->GetGeometryInfo(g, &info)) { continue; }
MjShader* shader = dwbl->GetShader(model->GetGeometryShaderIndex(g));
printf(" geom %d: %u verts, shader %s\n",
g, info.vertexCount, shader ? shader->GetName() : "?");
}
}
}MjShader
A material. Parameters are addressed by index; the type tells you which value accessor is valid. Reading a float4 from a texture parameter gives you garbage, so switch on the type first.
const char* MjShader::GetName()Shader name, e.g. "default" or "vehicle_paint1".
int MjShader::GetParmCount()Number of parameters.
const char* MjShader::GetParmName(int index)Parameter name.
eMjShaderParamType MjShader::GetParmType(int index)Parameter type: VT_FLOAT, VT_VECTOR4, VT_TEXTURE and so on.
float* MjShader::GetParmValueFloat4(int paramIndex)Pointer to the live value. Writing through it edits the material in memory.
Note: Only valid for the float-shaped types. Check GetParmType first.
void* MjShader::GetParmValueTexture(int paramIndex)The bound texture, for VT_TEXTURE parameters. Wrap it as an MjTexture to read it.
MjTxd
A texture dictionary (.ytd). Entries are keyed by lowercased name hash. A dictionary can chain to a parent it falls back to -- GetTexture only sees its own entries, while FindTexture follows the chain.
static MjTxd* MjTxd::Find(const std::string& name)Resident dictionary by name, or null.
static int MjTxd::GetSlot(const char* name)Streaming slot for a dictionary name, or -1. Feed it to mjstreaming to make one resident.
static MjTxd* MjTxd::FindBySlot(int slot)Dictionary in a known slot.
static int MjTxd::GetParentSlot(int slot)Slot the dictionary falls back to, or -1.
int MjTxd::GetCount()Textures held directly by this dictionary.
MjTexture* MjTxd::GetTexture(int index)One of its own entries.
uint32_t MjTxd::GetTextureHash(int index)Name hash of an entry.
MjTexture* MjTxd::FindTexture(const char* name)Lookup by name, following the parent chain.
MjTexture* MjTxd::FindTextureByHash(uint32_t hash)Same, by hash.
MjTxd* MjTxd::GetParent()The fallback dictionary, or null.
MjTexture
const char* MjTexture::GetName()Texture name.
uint16_t MjTexture::GetWidth() / GetHeight() / GetDepth()Dimensions in pixels.
uint32_t MjTexture::GetFormat()A DXGI_FORMAT value. A .ytd stores a DX9 format; the loader translates it.
uint8_t MjTexture::GetMipCount()Mip levels present.
uint32_t MjTexture::GetLayerCount()Array layers. A cube map reports 6.
MjImageType MjTexture::GetImageType()Standard, Cube, Depth or Volume.
uint32_t MjTexture::GetPhysicalSize()GPU memory in bytes, rounded up to 128.
void* MjTexture::GetShaderResourceView()The ID3D11ShaderResourceView, ready to hand to ImGui::Image.
bool MjTexture::GetInfo(MjTextureInfo* out)Everything above in one read, plus stride, template type and conversion flags.
MjTxd* txd = MjTxd::Find("prop_bench_01a");
if (!txd) { return 0; }
uint32_t bytes = 0;
for (int i = 0; i < txd->GetCount(); ++i)
{
MjTexture::MjTextureInfo info{};
if (txd->GetTexture(i)->GetInfo(&info))
{
bytes += info.physicalSize;
}
}
return bytes;mjextracontent
DLC change sets, RPF mounting, data files, islands.
Change set groups are how the game swaps blocks of content in and out -- the mechanism behind DLC map switches and the Cayo Perico island. Executing one mounts its files and registers its assets; reverting undoes that.
Check IsCCSSafeToExecute first
Executing a change set group while the streamer is mid-flight can deadlock or evict assets that are still in use. Poll IsCCSSafeToExecute and defer until it returns true.
void mjextracontent::ExecuteContentChangeSetGroup(const std::string& contentName, const std::string& changeSetGroupName, bool isMapGroup = false)Applies one change set group from one content package. Hash overloads exist too.
void mjextracontent::RevertContentChangeSetGroup(const std::string& contentName, const std::string& changeSetGroupName, bool isMapGroup = false)Undoes it.
void mjextracontent::ExecuteContentChangeSetGroupForAll(const std::string& changeSetGroupName)Applies a group across every mounted content package.
bool mjextracontent::IsCCSSafeToExecute()False while the streamer is busy.
void mjextracontent::LoadRpfFile(const std::string& rpfPath)Mounts an .rpf archive at runtime.
void mjextracontent::UnloadRpfFile(const std::string& rpfPath)Unmounts it again.
void mjextracontent::SetIslandEnabled(const char* islandName, bool enable)Toggles an island, e.g. "HeistIsland" for Cayo Perico.
int mjextracontent::GetNumRegisteredDataFiles()How many data files the content manager knows about.
bool mjextracontent::GetRegisteredDataFile(int index, MjDataFile* out)Full record for one: name, type, contents, and the locked / disabled / persistent / overlay / patch flags.
mjextracontent::MjDataFile file{};
for (int i = 0; i < mjextracontent::GetNumRegisteredDataFiles(); ++i)
{
if (!mjextracontent::GetRegisteredDataFile(i, &file)) { continue; }
if (file.contents == mjextracontent::MJ_CONTENTS_MAP && !file.disabled)
{
printf("%s\n", file.name);
}
}mjfiles
Reading through the RAGE virtual filesystem.
Reads go through mounted RPFs as well as loose files, so a path resolves the same way the game resolves it. Paths are engine paths, e.g. "common:/data/levels/gta5/water.xml".
Legacy only for now
The device lookup has no unique signature on Enhanced yet. Every mjfiles call degrades to not-found there rather than guessing: Exists returns false, Read returns -1.
bool mjfiles::Exists(const char* path)Whether the path resolves and opens.
uint64_t mjfiles::GetSize(const char* path)File size in bytes, or 0.
int mjfiles::Read(const char* path, void* buffer, int bufferSize)Reads up to bufferSize bytes from the start. Returns bytes read, or -1 on failure.
int mjfiles::List(const char* directory, char* outNames, int maxOut)Directory listing into a char[maxOut][128]. Returns the count written.
World systems
Water, terrain, fog volumes, minimap, audio sectors, path grids.
These namespaces replace or reconfigure world data that the game normally only loads at boot. They exist because a total conversion needs to swap the map underneath a running game.
mjwater and mjterrain
void mjwater::RequestWaterFile(const char* fileName)Resets the loaded water quads and loads a replacement water.xml.
void mjwater::SetWaterClipRect(int xMin, int yMin, int xMax, int yMax)Restricts water rendering and simulation to a tile rect. Applied on the render thread.
void mjwater::LoadWaterHeightMap(const char* path)Swaps the water height map.
bool mjterrain::LoadHeightMap(const std::string& path)Replaces heightmap.dat at runtime.
void mjterrain::SetFarlodsVisible(bool visible)Shows or hides distant terrain LODs.
mjvfx, mjminimap, mjpathfind
void mjvfx::SetCustomFogVolumeInfoPath(const std::string& path)Points the fog volume system at a replacement vfxfogvolumeinfo.ymt.
void mjvfx::ReloadFogVolumeInfo()Reloads it. Call after setting the path.
void mjminimap::SetMinimapVisible(bool toggle)Shows or hides the minimap.
void mjminimap::ResetSuperTiles(bool forceStreamingRemoval)Drops and re-streams minimap super tiles, e.g. after swapping map tiles.
void mjpathfind::SetPathGridIndex(int index)Selects which path node grid the pathfinder streams.
Runtime and diagnostics
Boot flow, cameras, scripts, resource diagnostics.
void mojito::WaitForInit()Blocks until mojito-core has finished initialising. Call before anything else.
void mojito::InstallGameSkelHook(std::function<void()> fn)Registers a callback fired every game-skeleton update tick.
void mojito::SetFastLegalScreen(bool enable)Skips the legal screen wait. No-op on Enhanced.
Note: Defaults to enabled at init, so call it early in startup to take effect for that boot.
void mojito::SetSkipIntroMovie(bool enable)Skips the intro movie. Same timing caveat.
void mojito::SetPrologueBypass(bool isBypassed)Skips the prologue and drops straight into the main map.
void mjcamera::SetIdleCameraDisabled(bool disabled)Disables the on-foot cinematic idle camera.
void mjcamera::SetVehiclePassengerIdleCameraDisabled(bool disabled)Disables the in-vehicle and passenger idle camera.
void mjscripting::PauseAllGameScripts(bool pause, bool killBlipScripts = true)Pauses every running game script. Useful when swapping the map underneath them.
void mjdiag::EnableResourceDiag(bool enable)Turns on resource load diagnostics.