Skip to main content

Amx

Struct Amx 

Source
pub struct Amx { /* private fields */ }
Expand description

Wrapper over the raw *mut AMX and the exported function table.

Implementations§

Source§

impl Amx

Source

pub fn new(ptr: *mut AMX, fn_table: usize) -> Amx

Builds the wrapper.

ptr is the pointer received in callbacks such as AmxLoad; fn_table is the address resolved during plugin initialization (typically stored in a global AtomicUsize read in Load() from crate::consts::ServerData::AmxExports).

Source

pub fn data_only(ptr: *mut AMX) -> Amx

Wraps a VM for data-side access only, with no function table.

The register accessors and read_cell/write_cell/read_cells/ read_bytes/read_code resolve addresses straight from the AMX struct, so they need no exported function table. Anything that calls into the VM (register, exec, get_ref, allot…) does, and will fail on an Amx built here.

Meant for a debug hook or a paused VM, where a plugin holds the pointer but has no native call context — it states that intent instead of passing a bare 0 as the function table.

Source

pub fn register(&self, natives: &[AMX_NATIVE_INFO]) -> Result<(), AmxError>

Registers plugin natives in the VM via amx_Register.

Generally called in AmxLoad — the #[native] macro + initialize_plugin! build the list automatically; only call manually from raw code.

§Errors

Propagates any AmxError returned by amx_Register — typically AmxError::NotFound if a listed native is not declared in the script, or VM state errors if called outside the load cycle.

Source

pub fn exec(&self, index: AmxExecIdx) -> Result<i32, AmxError>

Executes the public function identified by index in the VM.

Returns the Pawn return value (i32). Arguments must have been pushed via push (in reverse order) and Allocator (for strings/arrays) before this call.

§Errors

Propagates any AmxError from script execution — notably Exit/Assert (Pawn aborted), StackError/StackLow/HeapLow (stack or heap overflow), Divide, Native (a called native returned an error) or Index if index does not match a valid function.

Source

pub fn exec_public_scope<F, R>( &self, name: &str, body: F, ) -> Result<R, AmxError>
where F: FnOnce(&Allocator<'_>, AmxExecIdx) -> Result<R, AmxError>,

Calls a public inside a managed Allocator scope — the escape hatch for callbacks with output arrays, which the input-only exec_public! macro cannot express.

Resolves name to its public index and opens an Allocator, then hands both to body. Inside, allocate input/output buffers, push the arguments (in reverse order), call exec, and read any output buffers back — all before the scope closes and frees the heap. The scope also rewinds the VM stack, so a mid-sequence push failure cannot unbalance it.

§Errors

AmxError::NotFound if the public does not exist; otherwise whatever body returns (typically propagated from push/exec).

§Example
// Pawn: forward FillSquares(out[], size);
let squares = amx.exec_public_scope("FillSquares", |alloc, idx| {
    let buf = alloc.allot_buffer(8)?; // output array
    amx.push(8)?;                      // size   (pushed first = last arg)
    amx.push(&buf)?;                   // out[]  (pushed last  = first arg)
    amx.exec(idx)?;
    Ok(buf.as_slice().to_vec())        // read the array back before it frees
})?;
Source

pub fn find_native(&self, name: &str) -> Result<i32, AmxError>

Index of a native by name (resolved via amx_FindNative).

§Errors

AmxError::NotFound if name contains an interior NUL byte or if the native is not registered in the VM.

Source

pub fn call_native(&self, name: &str, params: &[i32]) -> Result<i32, AmxError>

Calls a native registered by another plugin in the same AMX.

SA-MP plugins inject their natives into every loaded AMX via amx_Register, which writes a host function pointer into the native’s entry inside the AMX_HEADER natives table. This helper resolves the name through amx_FindNative, reads that function pointer back, builds the params block in the AMX convention (first cell = argc * sizeof(cell), then the arguments), and invokes the native.

Integer arguments are passed as their i32 value. Floats are passed bit-cast to i32 (use f32::to_bits then i32::from_ne_bytes on to_ne_bytes, or f32::to_bits() as i32). String and array arguments are AMX cell addresses returned by Allocator::allot_string/Allocator::allot_buffer — same marshalling as for exec_public.

§Example
// Calling Streamer_CreateDynamicObject from a Rust plugin
fn on_amx_load(&mut self, amx: &Amx) -> AmxResult<()> {
    let model_id: i32 = 1337;
    #[allow(clippy::cast_possible_wrap)]
    let x = 100.0_f32.to_bits() as i32;
    let y = 200.0_f32.to_bits() as i32;
    let z =  10.0_f32.to_bits() as i32;
    let object_id = amx.call_native(
        "Streamer_CreateDynamicObject",
        &[model_id, x, y, z, 0, 0, 0],
    )?;
    log::info!("created dynamic object id={object_id}");
    Ok(())
}
§Errors
  • AmxError::NotFound if name contains an interior NUL byte, the native is not registered, or its address is still zero (registered name but no host pointer attached).
  • AmxError::MemoryAccess if the AMX header cannot be read.
  • AmxError::Index if the resolved index is out of range for the natives table reported by the AMX header.
  • Any AmxError propagated from the called native via amx.error (re-raised by the caller through amx_try!).
Source

pub fn find_public(&self, name: &str) -> Result<AmxExecIdx, AmxError>

Index of a public function by name — pass the result to exec.

use samp_sdk::amx::Amx;
use samp_sdk::error::AmxResult;
fn has_on_player_connect(amx: &Amx) -> AmxResult<bool> {
    let idx = amx.find_public("OnPlayerConnect")?;
    Ok(i32::from(idx) >= 0)
}
§Errors

AmxError::NotFound if name contains an interior NUL byte or if the public function is not declared in the Pawn script.

Source

pub fn find_pubvar<T>(&self, name: &str) -> Result<Ref<'_, T>, AmxError>
where T: AmxPrimitive,

Ref<T> pointing to a public variable declared in the Pawn script.

let version = amx.find_pubvar::<f32>("my_plugin_version")?;
// outdated
if *version < 1.0 { }
§Errors

AmxError::NotFound if name contains an interior NUL byte or if the pubvar is not declared. AmxError::MemoryAccess if the address returned by the VM is invalid.

Source

pub fn flags(&self) -> Result<AmxFlags, AmxError>

Flags of the loaded .amx.

§Errors

Propagates any AmxError returned by amx_Flags — in practice, it only fails if the internal AMX* is corrupted or null.

Source

pub fn opcode_table(&self, count: usize) -> Option<Vec<usize>>

Returns the VM’s opcode dispatch table (amx_opcodelist): count raw label addresses, one per opcode, in opcode order.

On a server built with computed-goto threading (GCC/Clang, the SA-MP and open.mp builds), the loader rewrites each opcode in the code segment to the address of its handler label, so a byte read with read_code yields a pointer, not the opcode number. Inverting this table (address → opcode) lets a debugger recover the real opcode at cip. The table is fetched the way the loader itself does it — set the BROWSE flag and call amx_Exec with index 0, which returns &amx_opcodelist instead of running code.

count is the number of opcodes the caller expects (OP_NUM_OPCODES); the SDK does not hardcode the VM’s opcode count. Returns None only when the table cannot be obtained (null VM/table).

The AMX_FLAG_RELOC header bit is intentionally not consulted: it is set by the loader in the file header and may not yet be visible at AmxLoad time, even though the dispatch table is already available. A non-computed-goto VM would return a table whose addresses simply never match a real opcode, so inverting it is harmless (the consumer finds no match and treats the code value as a raw opcode).

Source

pub fn get_ref<T>(&self, address: i32) -> Result<Ref<'_, T>, AmxError>
where T: AmxPrimitive,

Resolves an AMX cell (relative address) to a typed Ref<T>.

§Errors

AmxError::MemoryAccess if address does not correspond to a valid cell in the Pawn script address space.

Source

pub fn push<'a, T>(&'a self, value: T) -> Result<(), AmxError>
where T: AmxCell<'a>,

Pushes an AmxCell value onto the VM stack. Use in reverse order of the public function’s arguments before calling exec.

§Errors

Propagates any AmxError from amx_Push — typically AmxError::StackError/StackLow if the stack is full.

Source

pub fn strlen(&self, value: *const i32) -> Result<usize, AmxError>

Length in characters of an AMX string at address value.

§Errors

AmxError::MemoryAccess if value does not point to valid memory in the script space. Other AmxError are propagated from amx_StrLen.

Source

pub fn allocator(&self) -> Allocator<'_>

Creates an Allocator bound to this Amx.

All memory allocated via Allocator::allot/Allocator::allot_buffer/ Allocator::allot_string is released automatically when the Allocator goes out of scope (Drop). Keep it alive while using the returned references.

Source

pub fn amx(&self) -> Option<NonNull<AMX>>

Raw pointer to the AMX (non-null) or None if constructed with null.

Source

pub fn header(&self) -> Option<NonNull<AMX_HEADER>>

Raw pointer to the AMX_HEADER of the loaded .amx.

Source

pub fn cip(&self) -> Option<u32>

Current instruction pointer (cip) — a code-segment offset in a debug hook. Read as u32.

Source

pub fn frame(&self) -> Option<i32>

Current frame pointer (frm); local/argument symbols are addressed relative to it.

Source

pub fn stack(&self) -> Option<i32>

Current stack pointer (stk).

Source

pub fn heap(&self) -> Option<i32>

Current heap pointer (hea).

Source

pub fn stp(&self) -> Option<i32>

Top of the stack (stp) — the upper bound of the data address space.

Source

pub fn hlw(&self) -> Option<i32>

Heap low-water mark (hlw) — the bottom of the heap segment. The heap grows upward from here; releasing it below hlw is what the VM reports as AMX_ERR_HEAPLOW. A debugger reads it in a debug hook to detect a heap underflow before the VM aborts.

Source

pub fn pri(&self) -> Option<i32>

Primary register (pri) — the VM’s main accumulator. In a debug hook it holds the operand the next instruction will act on; e.g. for OP_BOUNDS it is the index being range-checked.

Source

pub fn alt(&self) -> Option<i32>

Alternate register (alt) — the VM’s secondary accumulator. For the division opcodes (OP_DIV/OP_SDIV) it holds the divisor, so reading it in a debug hook lets a debugger detect a divide-by-zero before it aborts.

Source

pub fn read_code(&self, offset: u32) -> Option<i32>

Reads a 32-bit cell from the code segment at offset (a code-segment offset, like cip). Returns None when the VM pointer is null or the offset is outside the code segment [0, header.dat - header.cod).

The code segment is read-only and laid out as base + header.cod; this is the counterpart of read_cell for instructions. A debugger uses it to decode the opcode at cip inside a debug hook (e.g. to catch a runtime error before the VM aborts). Reads byte-wise (no alignment assumption), since the AMX_HEADER is packed.

Source

pub fn read_cell(&self, addr: i32) -> Option<i32>

Reads a 32-bit cell from the data segment at addr, validating bounds like amx_GetAddr. Returns None if the address is inaccessible.

Reads byte-wise (no alignment assumption). Usable from a debug hook.

Source

pub fn read_cells(&self, addr: i32, count: usize) -> Option<Vec<i32>>

Reads up to count consecutive cells starting at addr, validating each one like read_cell.

Stops early and returns what it read when an address becomes inaccessible — the natural case at the end of the data segment. None only when addr itself is inaccessible.

Unlike get_ref-based access (Buffer, AmxString), this needs no function table, so it works inside a debug hook.

Source

pub fn read_bytes(&self, addr: i32, len: usize) -> Option<Vec<u8>>

Reads up to len raw bytes of the data segment starting at addr, in the VM’s native byte order — the backing read for a hex view.

addr needs no alignment: the read starts at the enclosing cell and the leading bytes are trimmed. Like read_cells, it stops early at the first inaccessible address, so the result may be shorter than len; None only when addr itself is inaccessible.

Source

pub fn write_cell(&self, addr: i32, value: i32) -> bool

Writes a 32-bit cell to the data segment at addr, validating bounds like amx_GetAddr. Returns false if the address is inaccessible.

Writes byte-wise (no alignment assumption). Usable from a debug hook to edit a variable while the VM is paused.

Source

pub fn install_debug_hook(&self, cb: extern "C" fn(*mut AMX) -> i32)

Installs a debug hook callback into this VM (amx->debug = cb), the equivalent of amx_SetDebugHook. The VM then calls cb on every line, provided the .amx was compiled with -d2/-d3.

The callback runs on the VM thread and crosses the FFI boundary, so it must never unwind (no panics).

Source

pub fn remove_debug_hook(&self)

Removes a previously installed debug hook, restoring amx->debug to a no-op callback that returns AMX_ERR_NONE.

Trait Implementations§

Source§

impl AmxExt for Amx

Source§

fn ident(&self) -> AmxIdent

Opaque identity of the Amx — useful for maps and cross references.
Source§

impl Debug for Amx

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl !Send for Amx

§

impl !Sync for Amx

§

impl Freeze for Amx

§

impl RefUnwindSafe for Amx

§

impl Unpin for Amx

§

impl UnsafeUnpin for Amx

§

impl UnwindSafe for Amx

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.