Перейти до вмісту

The game's own types

Цей контент ще не доступний вашою мовою.

For a struct the API does not wrap, such as a component a hooked system hands you, cargo enshwick types writes the game’s own types as Rust or Luau from the game’s reflection data. The names are the game’s: keen::ecs::Health becomes game::keen::ecs::Health, a field dataStorage becomes data_storage, and an enum constant MagicalFog becomes MAGICAL_FOG.

Name the types you need, or a namespace ending in ::. The types they use come with them:

Terminal window
cargo enshwick types --from "$ENSHROUDED_DIR" keen::ecs::Health \
--rust src/game.rs --luau game.d.luau

--from takes the game folder or one of its executables. Without names, every runtime type comes out, over six thousand of them; the editor’s keen::ds:: copies come only when named. Add pub mod game; to src/lib.rs.

Luau has no namespaces, and luau-lsp makes every exported type global, so a game type whose name the API’s definitions already take keeps its namespace: the game’s keen::ecs::HitEvent is Ecs_HitEvent beside the API’s HitEvent. A Luau mod loads both files at once.

Every struct is repr(C) with each field at the offset the game reflects, and reads through enshwick::raw. A bool is its byte and an enum is a newtype over its integer, so any bytes the game holds read as a value. Check at init that the running build still has the size the module expects:

use game::keen::ecs::Health;
fn init(load: &mut enshwick::Load<'_>) -> Result<(), enshwick::Off> {
if load.type_size("keen::ecs::Health")? as usize != size_of::<Health>() {
return Err(enshwick::Off::new("keen::ecs::Health changed size"));
}
Ok(())
}
/// Reads the health component at `component`.
///
/// # Safety
///
/// - `component` points at a live `keen::ecs::Health` no thread writes now.
unsafe fn health(component: *const u8) -> Health {
// SAFETY: the caller guarantees a whole `Health` at `component`.
unsafe { enshwick::raw::read_at(component, 0) }
}

A field Rust cannot place where the game has it, such as an eight-byte integer at an offset of four, comes out as bytes; one the game does not describe stays in padding, and the struct’s documentation names it.

game.d.luau declares each struct as an exported record type, each enum as a union of its constants’ names, and keeps the game’s field names. Point luau-lsp at it beside enshwick.d.luau. It holds types only, and no Luau call returns game structs.

Offsets and sizes change between game builds, and the file names the build it came from. Run the command again on the new build and rebuild the mod. Until then, the size check at init turns the mod off on a build where the type grew or shrank; for a field that matters, compare load.field_offset(type, field) with its offset too.