Minimal Rust component example for the official open.mp C API.
This project is a proof of concept for running open.mp server logic from Rust without writing a Pawn gamemode. It builds a native 32-bit Linux component, loads the open.mp C API at runtime, registers a player event callback, and uses the component lifecycle hook exposed by the C API.
Experimental. The component loads in open.mp v1.5.8.3079, but the Rust API is
still raw FFI plus a small C shim. Treat it as a starting point for a safer
wrapper, not as a finished framework.
- Exports
ComponentEntryPoint, so open.mp loads it as a native component. - Initializes the official C API through
components/$CAPI.so. - Creates an
OpenMPRustCapicomponent. - Uses the C API
onReadycomponent lifecycle hook as the startup hook. - Sets the gamemode text to
open.mp Rust C API. - Adds one spawn class.
- Registers
onPlayerConnect. - Sends a client message from Rust when a player connects.
- Rust with the
i686-unknown-linux-gnutarget. - Zig, when cross-compiling from macOS or another non-32-bit-Linux host.
- open.mp
v1.5.8.3079or newer. - Docker, only for the included smoke test.
Install the Rust target:
rustup target add i686-unknown-linux-gnuFrom macOS with Zig installed:
cargo build --release --target i686-unknown-linux-gnuThe repo-local Cargo config routes the C shim and final link through:
zig cc -target x86-linux-gnu
The deployable component artifact is:
target/i686-unknown-linux-gnu/release/libopenmp_rust_capi.so
On a Debian or Ubuntu x86_64 build host, a native multilib toolchain also works:
sudo apt-get update
sudo apt-get install -y clang libclang-dev gcc-multilib libc6-dev-i386
cargo build --release --target i686-unknown-linux-gnuBuild the release artifact, then copy it into the server components/
directory:
cp target/i686-unknown-linux-gnu/release/libopenmp_rust_capi.so \
/path/to/omp-server/components/OpenMPRustCapi.soOr use the helper:
./scripts/install-to-server.sh /path/to/omp-serverStart the server from its root directory. The C API initializer loads
./components/$CAPI.so, so the working directory matters.
Expected startup log lines:
[openmp-rust-capi] component ready
[openmp-rust-capi] onReady startup hook fired
[openmp-rust-capi] registered onPlayerConnect handler
When a player connects, they should receive:
Hello <name>, this message came from Rust.
With Docker and Zig installed, this downloads the pinned open.mp Linux x86
server, copies the component into components/, starts the server under
linux/386, and checks the startup log:
./scripts/smoke-test-openmp.shThe test is considered passing when open.mp logs:
Successfully loaded component OpenMPRustCapi
[openmp-rust-capi] component ready
[openmp-rust-capi] onReady startup hook fired
[openmp-rust-capi] registered onPlayerConnect handler
On Apple Silicon, Docker runs this through qemu. A qemu segfault can appear
when timeout tears down the server; the same shutdown issue occurs without
this Rust component.
The C API Component.Create path exposes onReady, onReset, and onFree
callbacks. It does not directly expose Pawn's OnGameModeInit callback.
For this component path, onReady is the closest native startup hook: it fires
after components are initialized and before normal server runtime.
src/lib.rs- Rust component entrypoint, lifecycle hooks, and event callback.c/omp_capi_shim.c- narrow C wrapper around the generated open.mp C API.c/omp_capi_shim.h- C shim declarations consumed by bindgen.vendor/openmp-capi/- vendored open.mp C API header and license.build.rs- compiles the C shim and generates Rust FFI bindings.scripts/install-to-server.sh- builds and installs the component into a server.scripts/smoke-test-openmp.sh- end-to-end open.mp server smoke test.
cargo fmt --check
cargo check
cargo check --target i686-unknown-linux-gnu
./scripts/smoke-test-openmp.shThis project is licensed under the MIT License. See LICENSE.
The vendored open.mp C API header is licensed under the Mozilla Public License
2.0. See vendor/openmp-capi/LICENSE.md and THIRD_PARTY_NOTICES.md.