Releases: NullSablex/rust-samp
Release list
v3.3.1
Bug-fix release: the v3.3.0 changes did not build for 64-bit targets. Both fixes
matter to any consumer building the SDK for a 64-bit host (e.g. a DAP adapter
that only needs samp::debug).
Fixed
ompmodule failed to compile on 64-bit MSVC (E0570) — the open.mp
component ABI usesextern "thiscall", which only exists on 32-bit x86 (the
arch SA-MP/open.mp servers run on). The module is now skipped on
windows + msvc + 64-bit, where that ABI is invalid anyway; 32-bit and
non-MSVC targets are unchanged.- FFI signatures used
i8instead ofc_char(E0308 on aarch64) — the
amx_Exportsfunction-pointer types hardcodedi8for C-string/char
arguments.c_charisi8on x86 butu8on aarch64, soCString::as_ptr()
mismatched the signatures when building for a 64-bit target. The C-string/char
pointers inraw::functionsnow usec_char.
Changed
- CI: added an
aarch64-unknown-linux-gnucheck job (a 64-bit target where
c_char == u8) so this class of ABI/type mismatch is caught going forward —
the previous 32-bit-only matrix never exercised it.
Crate versions
rust-samp-sdk(libsamp_sdk): 3.2.0 → 3.2.1 (bug fixes only)rust-samp(libsamp): 3.2.0 — unchangedrust-samp-codegen(libsamp_codegen): 1.3.0 — unchanged
Full Changelog: v3.3.0...v3.3.1
v3.3.0
Added
Amx::pri()/Amx::alt()— safe reads of the VM's primary and
alternate accumulator registers, completing the register set alongside the
existingcip/frame/stack/heap/stp. Read directly from the
#[repr(C, packed)]AMXstruct withread_unaligned(taking a reference
to a packed field is UB), returningNonewhen the VM pointer is null.Amx::read_code(offset)— bounds-checked read of a 32-bit cell from the
code segment, the instruction-side counterpart ofread_cell. Resolves
base + header.cod + offsetand validatesoffsetagainst the code segment
[0, header.dat - header.cod), reading byte-wise (the header is packed). The
SDK exposes the raw bytes only; decoding the instruction is up to the consumer.Amx::opcode_table(count)— returns the VM'samx_opcodelist(the opcode
→ handler-address dispatch table) ascountraw addresses, fetched the way the
loader does it (set theBROWSEflag, callamx_Execwith index 0, restore the
flags). On computed-goto builds (GCC/Clang — SA-MP and open.mp) the loader
rewrites code-segment opcodes to these addresses, so a consumer can invert the
table to recover the real opcode behind aread_codevalue. ReturnsNonefor
a non-relocated image (AMX_FLAG_RELOCunset), where opcodes are stored raw.
Crate versions
rust-samp-sdk(libsamp_sdk): 3.1.0 → 3.2.0 (additive public API)rust-samp(libsamp): 3.2.0 — unchangedrust-samp-codegen(libsamp_codegen): 1.3.0 — unchanged
Full Changelog: v3.2.0...v3.3.0
v3.2.0
New features
-
VM debugging primitives on
Amx— safe accessors that previously had to
be hand-written by tooling poking the#[repr(C, packed)]AMXstruct:
register reads (cip,frame,stack,heap,stp), bounds-checked
data-segment cell access (read_cell/write_cell, mirroringamx_GetAddr
and usable inside a debug hook where no native context exists), and debug
hook management (install_debug_hook/remove_debug_hook, the equivalent of
amx_SetDebugHook). Always available, no feature gate. -
samp::debug— AMX_DBG debug-info parser (featuredebug) — pure-logic
decoder for the debug blockpawncc -d2/-d3appends to the.amx. Maps a
code address ↔ source line ↔ symbol ↔ function (AmxDbg::from_amx/parse,
lookup_line,lookup_file,lookup_function,line_to_address,
symbols_in_scope,tag_name), handling the 16-bit line-count overflow of
large gamemodes and corrupted-count sanity ceilings. No extra dependencies;
opt-in via thedebugfeature.DbgSymbol::effective_address(frm)and
DbgSymbol::is_array()remove the global-vs-frame address boilerplate when
pairing the parser withAmx::read_cell/write_cell. -
External sinks (
samp::logger::Sinktrait +LoggerConfig::add_sink) —
extension point for forwarding accepted log records to a destination
chosen by the plugin author (Sentry, an OTLP collector, an in-house
HTTP endpoint, anything). No telemetry is built into the SDK. No
dependency onsentry/opentelemetryis added;rust-samp
ships exactly the same dependency graph as before. The trait is an
opt-in surface only — implementing it is the plugin author's call,
and instances become active only through an explicit
LoggerConfig::add_sink(Box::new(...))in the plugin's own source.
The SDK contains zeroadd_sinkinvocations of its own; server
operators auditing what arust-sampplugin can export only need
to grep its source foradd_sink(. Zero hits means zero external
traffic from the logger. There is no hidden flag, no environment
override, and no default destination — this is not Microsoft-style
always-on telemetry, it is a hook for plugin authors who already
run their own observability stack to integrate with it on their own
terms. -
samp::version()— free function returning theCARGO_PKG_VERSION
of therust-samp(samp) crate. Pair it with a Pawn-side native
(e.g.MyPlugin_GetSdkVersion()) to surface the active SDK build in
bug reports and diagnostic dashboards. -
samp::logger::flush()— public free function that flushes the
active log file directly through the liveLoggerImpl. Going through
log::logger().flush()did not guarantee a sync of the SDK's own
file handle; callingsamp::logger::flush()does. Safe no-op when
the logger has not been installed — meant for panic hooks and
custom shutdown paths. -
LoggerConfig::from_env()— applies runtime overrides from
environment variables, so server operators can flip the log level,
redirect the directory, change the rotation threshold etc. without
recompiling the plugin. The prefix is derived from the plugin's
crate name uppercased with non-alphanumeric characters replaced by
_(streamer-rs→STREAMER_RS_LOG_*). Recognised keys:
LEVEL,DIR,FILE,ROTATION_MB,ROTATION_KEEP,
NO_ROTATION,NO_BANNER,SERVER, andCOMPRESS(the last only
effective when thecompressionfeature is enabled). Missing vars
leave the existing value untouched; invalid values are reported to
the server console and the previous value is kept. Pairs with
Runtime::try_get()(also new) so the parser can warn gracefully
even when called before the runtime is initialised (e.g. from a
unit test). -
LoggerConfig::compress_archives(bool)— opt-in gzip of rotated
archives. When enabled, every rotation produces
{filename}.{N}.gzinstead of{filename}.{N}and removes the
uncompressed file. Works with both rotation strategies (append-style
androtation_keep(N)shift-style). Gated by the newcompression
Cargo feature, which pulls inflate2with the pure-Rust backend —
not enabled by default, so plugins that do not need it pay no extra
dependency cost. The next-archive scan also recognizes.gz
variants so an index is never reused across restarts. -
Amx::call_native()— invoke a native registered by another
plugin in the same AMX, straight from Rust. Resolves the host
function pointer throughamx_FindNative+ the natives table in the
AMX_HEADER, builds theparamsblock in the AMX convention
([argc * sizeof(cell), arg0, ...]) and surfaces VM-side errors back
viaamx.error. Unblocks integration with the entire existing C++
plugin ecosystem (Streamer, MySQL, sscanf, …) without dropping down
tosamp_sdk::raw. Originally surfaced by
@Day-OS (Discord@daytheipc), who
foundrust-sampon crates.io while trying to drive the Streamer
plugin from Rust for an in-game PNG / video / YouTube-live 3D panel
and hit the gap that this API closes. May or may not have been
exactly what she needed — but it should help.
Examples
- New
examples/sink-demo/— complete, working Sentry
integration for the newSinktrait. Uses the realsentry
crate (sentry = "0.43"withreqwest+rustls+contexts,
default-features = false), withsentry::initand
sentry::capture_eventwired up end-to-end — everylog!call
becomes a real Sentry event. DSN is read from the env var
SINK_DEMO_SENTRY_DSNat plugin load — never hardcoded. Source
code stays clean, the DSN stays in the operator's environment
(systemdEnvironment=, Docker secret, vault sidecar,.env
outside the repo, …). Implements the full backpressure pattern
(mpsc::sync_channelbetween the logger lock and Sentry +
dedicated background drainer thread that owns the
ClientInitGuard, so itsDropflushes pending events at plugin
unload). When the env var is missing the example falls back to a
fake local DSN (http://fake@127.0.0.1:9999/1) — the Sentry
client still initializes but its HTTP transport refuses fast, so
no event ever reaches a real Sentry server. Going to production
is oneexportstatement. When a real DSN is configured, the
plugin also emits a startup smoke test (oneinfo+ one
warning+ oneerror) onon_loadso the operator immediately
sees the wiring working on the Sentry dashboard. The heavy
sentrydep (pinned to 0.48.3) is paid by this example crate,
not by the SDK. Pawn natives:SinkDemo_GetExportedCount,
SinkDemo_GetDroppedCountfor pipeline observability;
SinkDemo_EmitInfo,SinkDemo_EmitWarn,SinkDemo_EmitError
for firing test events at each severity from the gamemode.
Build
- New Cargo feature
compressionon therust-sampcrate. Opt-in;
pulls inflate2 = "1"with the pure-Rust backend
(default-features = false,features = ["rust_backend"]) so plugins
that do not enable it remain dependency-free on this axis. timebumped to>= 0.3.47(also pulls intime-core 0.1.8
andtime-macros 0.2.27) — this is the floor that drove the MSRV bump;
later refreshed to 0.3.51 by Dependabot (see Dependencies, #16).- MSRV bumped to Rust 1.88 (was 1.87) to satisfy those versions.
Declared via[workspace.package].rust-version = "1.88".
Security & governance
- OpenSSF Scorecard — new
.github/workflows/scorecard.ymlthat runs
the OpenSSF Scorecard analysis, uploads the SARIF to code-scanning and
publishes the result. Scorecard badge added to the README. - All GitHub Actions pinned by commit SHA — every
uses:across all
seven workflows is pinned to a full commit SHA (with a# vXcomment),
satisfying the Scorecard Pinned-Dependencies check. - Least-privilege token permissions — every workflow declares a
top-level minimalpermissions: contents: read, with jobs escalating
explicitly only where needed (Scorecard Token-Permissions). - No script injection from untrusted PR fields —
rust.ymlnow passes
github.event.pull_request.*values (e.g.head.ref) throughenv
instead of interpolating them intorun:scripts (Scorecard
Dangerous-Workflow). docs/requirements.txtpinned by hash — the MkDocs Material build
dependencies are now a fully hashed lockfile (pip-compile --generate-hashesfrom the newdocs/requirements.in), installed with
pip install --require-hashesin the docs workflow..github/dependabot.yml— weekly version updates for the
github-actionsandcargoecosystems, keeping the pinned SHAs and
crate dependencies fresh (Scorecard Dependency-Update-Tool).- CI tweaks — the Scorecard workflow gained
workflow_dispatchfor
on-demand re-scans; the Rust workflow ignores docs-only changes via
paths-ignore(**.md,docs/**,mkdocs.yml,LICENSE); and the
benchmark job now runs only when benchmark-relevant code actually changed
(achangespath-filter job gates it), never fordependabot[bot]
(dependency bumps don't need a bench run, and Dependabot's read-only
token cannot post the PR comment). - Release Drafter removed —
.github/release-drafter.ymland
.github/workflows/release-drafter.ymldropped. Releases are cut
directly rather than drafted, so the workflow was dead weight. SECURITY.md— security policy and private vulnerability reporting
via GitHub Security Advisory.CODE_OF_CONDUCT.md— Contributor Covenant 2.1.CONTRIBUTING.md— build/test/lint workflow for the i686 targets,
project structure and code rules.
Documentation
- Single source of truth for crate versions — the per-crate version
columns were removed from theREADME.mdanddocs/index.mdworkspace
tables (they duplicatedCargo.toml...
v3.1.0
Headline: turnkey logger — samp::enable_logger!() installs a complete
per-plugin logging pipeline (file under logs/, size-based rotation
into logs/archive/, prefix derived from CARGO_PKG_NAME, startup
banner, runtime-adjustable level) in a single call. The previous
samp::plugin::logger() DIY path stays unchanged for advanced cases.
v3.1.0 is also the first version available on crates.io —
rust-samp,
rust-samp-sdk and
rust-samp-codegen.
Earlier releases (v3.0.0 and the entire v2.x line) are not published to
the registry; plugins targeting those versions must keep using a git
dependency. The library names (samp, samp_sdk, samp_codegen)
are unchanged; only the package names differ on the registry to
avoid colliding with the upstream samp-rs fork.
Crate versions
rust-samp(libsamp): 3.0.0 → 3.1.0rust-samp-sdk(libsamp_sdk): 3.0.0 — unchanged (metadata only)rust-samp-codegen(libsamp_codegen): 1.3.0 — unchanged (metadata only)
Installation
[lib]
crate-type = ["cdylib"]
[dependencies]
samp = { package = "rust-samp", version = "3" }
log = "0.4"The package is published as rust-samp; the alias keeps the
source-level use samp::prelude::*; imports unchanged. Git consumers
do not need to update anything — both names continue to resolve to the
same library.
New features
- Turnkey logger — new module
samp::loggerplus the
samp::enable_logger!()andsamp::enable_logger_with!(cfg)macros.
The macros capture the caller'sCARGO_PKG_*at compile time and
install alog::Logimplementation that routes through both the
server's log sink and a per-plugin file. LoggerConfigbuilder — every aspect of the pipeline is
configurable through fluent setters:directory,filename,
prefix,level,also_to_server,banner,file_format,
server_format,rotation_size_mb,rotation_keep,
rotation_no_cleanup,no_rotation,no_banner,banner_with.- Format templates —
file_formatandserver_formataccept
{timestamp},{level},{message}and (server-only){prefix}
placeholders with optional alignment specifiers ({level:>5},
{level:<5},{level:^5}). Unknown placeholders pass through
verbatim so typos are visible. - Banner modes —
BannerMode::Default(5-line banner from
CARGO_PKG_*),BannerMode::Off, andBannerMode::Custom(closure
receivingBannerMetadataand returning the lines to render). - Size-based rotation — when the active file passes
rotation_size_mb(default 50 MB), it is renamed into
{directory}/archive/{filename}.{N}and a fresh active file is
opened. Two strategies are available:- Append-style (default): every rotation uses the next free
index, archives are never deleted by the SDK, the dev keeps
full control over cleanup. The archive folder is created lazily on
the first rotation; the next index survives restarts (rescanned at
install time). - Shift-style — opt-in via
rotation_keep(N):.log.Nis
deleted, every other archive shifts down, active becomes.log.1.
Disk footprint becomes(keep + 1) * rotation_size_mb.
- Append-style (default): every rotation uses the next free
- Runtime level adjustment —
samp::logger::set_level(...)and
samp::logger::level()let plugins expose a Pawn-side knob for log
verbosity (e.g. aMyPlugin_SetLogLevel(level)native). InstallError—Display+Errorwithsource()exposing
the innerstd::io::Errorfor theIovariant.
Migrating to the turnkey logger
The previous handcrafted fern::Dispatch pattern keeps working —
adoption is optional.
| Before (v3.0.0) | After (v3.1.0) |
|---|---|
fern::Dispatch::new().level(...).chain(samp::plugin::logger()).chain(fern::log_file(...)?).format(...).apply()?; |
samp::enable_logger!() inside on_load |
Hand-built prefix string format_args!("[my-plugin][{}]: {}", record.level(), message) |
Automatic [CARGO_PKG_NAME] prefix |
| Manually managing the log filename | Default logs/{CARGO_PKG_NAME}.log |
External logrotate setup for file growth |
Built-in 50 MB rotation into logs/archive/ |
Pawn-side SetLogLevel(level) native backed by a static AtomicI32 |
samp::logger::set_level(LevelFilter) direct |
See docs/logging.md for the full reference,
including the three layers (turnkey / LoggerConfig / DIY with fern),
format placeholders, rotation modes, and runtime tuning.
Packaging (crates.io)
The three workspace crates now have crates.io-ready metadata
(description, keywords, categories, rust-version, per-crate
README.md) and centralized shared fields in [workspace.package].
-
Package names:
rust-samp,rust-samp-sdk,rust-samp-codegen.
The upstreamsamp/samp-sdk/samp-codegennames on crates.io
belong to the originalsamp-rsauthor and are not the publication
target of this fork. -
Library names: unchanged —
samp,samp_sdk,samp_codegen.
Existinguse samp::prelude::*;keeps compiling. -
Crates.io consumers add the package alias to their
Cargo.toml:[dependencies] samp = { package = "rust-samp", version = "3" }
-
Git consumers (
samp = { git = "..." }) need no change — the
workspace exposes both names.
Build
- MSRV bumped to Rust 1.88 (was 1.85). Required by stable
i32::cast_unsigned/u32::cast_signed(used internally for AMX
cell bit conversions) and by the patchedtime 0.3.47/time-core 0.1.8/time-macros 0.2.27. Declared via
[workspace.package].rust-version = "1.88". - New transitive dependency —
time = "0.3.47"(features
local-offset,formatting,macros) is pulled in by the turnkey
logger for timestamp formatting. Thechronocrate is not added.
The minimum is pinned to0.3.47to pick up the fix for
RUSTSEC-2026-0009
(DoS via stack exhaustion, medium severity).
CI / release infrastructure
- Release notes are now auto-assembled — workflow
.github/workflows/release.yml
combines the curated CHANGELOG section with the GitHub-native
releases/generate-notesAPI output, keeping the "New Contributors"
block and the "Full Changelog" comparison link while dropping the
redundant## What's Changedheader. - Crates.io publication is wired into the release workflow — on
v*tag push (and manualworkflow_dispatchwith adry_run
input), the workflow validates the workspace, then publishes
rust-samp-sdk→rust-samp-codegen→rust-sampin dependency
order with a 30 s sleep between steps. Eachcargo publishstep
gracefully skips when the version is already on crates.io, so a
patch release that bumps only one crate goes through unattended. - Bench jobs were updated to reference
rust-samp-sdkinstead of
the pre-renamesamp-sdkpackage id. - Release-drafter template no longer emits the duplicated
## What's Changedheading at the top of release notes.
Documentation
docs/logging.md— rewritten end-to-end (139 → 413 lines).
Covers the three layers, format placeholders and alignment specs,
banner modes, rotation strategies, runtime level adjustment, and a
pitfalls section.docs/api-reference.md— newsamp::loggersection with the
full builder signature, error type, and placeholder reference.docs/migration.md— new v3.0.0 → v3.1.0 section with the
before/after migration table and crates.io adoption notes.docs/first-plugin.md— new "Enabling logging" section showing
the one-liner insideon_load.docs/plugin-anatomy.md— explicit note thatenable_logger!
belongs inon_load, not the constructor block (server's log sink
is not connected yet during construction).docs/index.md— the integrated-logging bullet now describes
the turnkey path; workspace table reflects the newsampversion.docs/advanced-examples.md— theexamples/countersnippet
matches the source change (usessamp::enable_logger!()instead of
the handcraftedfern::Dispatch).- Dual-availability sweep —
README.md,migration.md,
docs/setup.md,docs/encoding.mdanddocs/migration.mdnow show
both installation paths side-by-side (crates.io for v3.1.0+, git for
any version including v3.0.0 and earlier) with a consistent
package = "rust-samp"snippet. The workspace version table in
README.mdwas bumped to reflect the newsamp3.1.0.
Examples
examples/counter(1.0.0 → 1.1.0) —on_loadnow calls
samp::enable_logger!(); theferndependency was dropped.examples/hello(1.0.0 → 1.0.1),examples/advanced(1.1.0 →
1.1.1) — switched to thepackage = "rust-samp"alias so the path
dependency matches the published name. No source changes.
Repository housekeeping
ROADMAP.mdmoved out of version control (now under.gitignore)
— it stays as a local working document for the maintainer and is no
longer shipped to crates.io tarballs or GitHub..github/CODEOWNERSadded.CNAMEremoved (project pages are served from the default
nullsablex.github.io/rust-samp/URL).
Code quality
- Clippy
-D warningsand `-W clippy::pedanti...
v3.0.0
Compared to v2.2.0 (2026/03/15).
Headline: native Open Multiplayer component ABI implemented in pure
Rust (Itanium and MSVC); a single binary now works as a SA-MP
plugin and as a first-class Open Multiplayer component, with no extra
configuration.
Migrating from v2.x (or from the upstream samp-rs fork)
This release contains breaking changes. A plugin written against
v2.x will not compile against v3.0.0 without edits. Minimum diff:
| Before (v2.x / upstream) | After (v3.0.0) |
|---|---|
fn process_tick(&mut self) { … } |
fn on_tick(&mut self, _ctx: TickContext) { … } |
samp::plugin::enable_process_tick() |
samp::plugin::enable_tick() (or enable_tick_with(TickConfig)) |
samp::cell::string::put_in_buffer(buf, s)? |
buf.write_str(s)? / unsized.write_str(size, s)? (put_in_buffer is pub(crate) now) |
samp::raw::functions::Logprintf (variadic) |
Same path, now extern "C" fn(*const i8) — the SDK formats in Rust and passes a single C string |
example-hello/ / example-counter/ / plugin-example/ |
examples/hello/ / examples/counter/ / examples/advanced/ |
Open Multiplayer support comes turned on by default — the build
produces both the SA-MP exports and the ComponentEntryPoint. To
keep the v2.x behavior unchanged, enable the new samp-only feature:
samp = { git = "...", tag = "v3.0.0", features = ["samp-only"] }Two new requirements that affect builds:
- The workspace's
[profile.release]addslto = "thin",
codegen-units = 1,strip = true. Override in your own
Cargo.tomlif you need otherwise. - The i686 target is now strictly required at compile time
(OmpComponenthasconst _layout asserts). Set
target = "i686-unknown-linux-gnu"in.cargo/config.tomlif you
were relying on the host target picking up automatically.
The full step-by-step walkthrough lives in
docs/migration.md — including the new
TickConfig knobs (sa_mp_only(), omp_only(Duration), custom
omp_interval) and how to choose between them.
Crate versions
samp: 2.2.0 → 3.0.0samp-sdk: 2.2.0 → 3.0.0samp-codegen: 1.2.0 → 1.3.0
Breaking changes
SampPlugin::process_tickreplaced by
SampPlugin::on_tick(&mut self, ctx: TickContext)— unified
callback that fires on both servers. Cadence is the server's main
loop on SA-MP and the SDK-ownedITimersComponenttimer on native
Open Multiplayer (interval configurable).TickContext::source
reports the origin (TickSource::SaMp/
TickSource::OmpTimer);TickContext::elapsedis the
wall-clock interval since the previous dispatch.samp::plugin::enable_process_tickreplaced by
samp::plugin::enable_tick()(default config) and
samp::plugin::enable_tick_with(config: TickConfig)(explicit
per-server toggle + Open Multiplayer interval).samp::cell::string::put_in_bufferis nowpub(crate)(was
pub). The public API for writing strings isBuffer::write_str
andUnsizedBuffer::write_str.samp_sdk::raw::functions::Logprintfsignature changed from
variadicextern "C" fn(*const i8, ...)to fixed-arity
extern "C" fn(*const i8)— the SDK formats the message in Rust
and passes a single C string, matching whatlogprintf("%s", msg)
does at the ABI level.- Example crates renamed:
example-hello/→examples/hello/,
example-counter/→examples/counter/,
plugin-example/→examples/advanced/. Workspace members
updated accordingly.
Added — native Open Multiplayer support
samp_sdk::omp— new top-level module with eight submodules:component—OmpComponent,IComponentVTable,
IUIDProviderVTable, opaque types (ICore,IComponentList,
ILogger,IEarlyConfig), default vtable implementations for
both ABIs.component_api—OmpComponentHandletrait, generic
component_name<T>()/component_version<T>()helpers.core—LogLevel,core_print_ln,core_log_ln,
core_print_ln_u8,core_log_ln_u8.events—PawnEventHandler,PawnEventHandlerVTable.server—PAWN_COMPONENT_UID,NUM_AMX_FUNCS,
PawnComponent,ServerComponentList,ServerComponent,
ServerPawnComponent,IEventDispatcherPawn,IPawnScript,
AmxFunctionTable, plus the free functions
query_component,add_pawn_event_handler,
remove_pawn_event_handler,get_pawn_event_dispatcher,
get_amx_from_script,get_amx_functions.timers—TIMERS_COMPONENT_UID,TimersComponent,
ITimersComponent,ITimer,TimerHandlerVTable,
TimerTimeOutHandler,create_repeating_timer,kill_timer,
query_timers_component.types—UID,SemanticVersion(withnewand
with_prerel),StringView(withas_str,try_as_str,
from_static),Colour(withrgb,rgba,from_rgba_u32,
to_rgba_u32and theWHITE,BLACK,NONEconstants),
Vector2,Vector3,Vector4,ComponentType.vtable—subobject_ptr,vtable_slot,
secondary_call_targethelpers for safe access to secondary
vtables.
samp::ompre-exports the module above.samp::pluginnew functions:enable_tick,
enable_tick_with,omp_core,omp_query_component,
omp_query::<T>(typed wrapper forOmpComponentHandle
implementors).samp::pluginnew types:TickConfig,TickContext,
TickSource.SampPluginnew hooks:on_tick(ctx),
on_omp_ready(gated bynot(feature = "samp-only")),
on_component_free(same gating).samp::logre-export —#[native]-expanded code now uses
samp::log::error!, so user crates no longer need to declare
logas a direct dependency just to satisfy the macro.
Added — initialize_plugin! extensions
- Optional metadata fields:
uid: <u64 expression>,
component_name: "...",component_version: (x, y, z). samp-codegenreads[package.metadata.samp]from the project's
Cargo.toml. Resolution order per field:
macro argument >[package.metadata.samp]> derived value
(CARGO_PKG_NAME, parsedCARGO_PKG_VERSION, FNV-1a 64 of
CARGO_PKG_NAME@CARGO_PKG_VERSIONfor the UID).- When the UID is missing from both sources, the generated value is
persisted back intoCargo.tomlunder[package.metadata.samp]
so subsequent builds reuse the same identifier. - Generates the SA-MP exports (
Load,Unload,Supports,
AmxLoad,AmxUnload,ProcessTick) and the Open Multiplayer
ComponentEntryPointby default. Opt out with thesamp-only
feature.
Added — #[native] extensions
- Accepts associated functions (no
self), in addition to
methods. - Return type detection:
Result/AmxResultis matched against
Ok/Err; any other type implementingAmxCellis used as the
return cell directly (no spuriousOk(...)wrapping). - Accepts
&AmxString(and any other&T) parameters — the macro
materializes the owned value fromargs.next_arg()and injects
&localat the call site. - Validates the
name = "..."literal at proc-macro time:
interior\0bytes now produce a compile error instead of
panicking atCString::newduring server load. - Wraps every invocation in
std::panic::catch_unwind. Panics that
would otherwise cross theextern "C"boundary (process abort on
Rust 1.71+) are caught, logged as
[<NativeName>] panic in native: <payload>, and converted to a
0return. - Argument parsing failures now log
[<NativeName>] failed to parse argument #<i> '<name>' (expected type: <Type>)
— both the positional index and the expected type are included.
Added — features and build infrastructure
- New
samp-onlyfeature on bothsampandsamp-sdk: removes
every Open Multiplayer code path. The plugin still loads on Open
Multiplayer, but in legacy mode (no component API). - New workspace
[profile.release]:lto = "thin",
codegen-units = 1,strip = true. Cargo.lockis now committed (removed from.gitignore).Cargo.tomlper crate exposes
package.metadata.docs.rs.default-target = "i686-pc-windows-msvc"features = ["encoding"]so docs.rs builds with the right
target.
- New build scripts:
scripts/build-linux.sh— produces.so
(i686-unknown-linux-gnu) and.dll
(i686-pc-windows-msvcviacargo-xwin --xwin-arch x86, or
i686-pc-windows-gnuwith--samp-only).scripts/build-windows.sh— produces.dllnatively and.so
through WSL or Docker/cross (autodetected; forceable with
--wsl/--docker).
- New helper scripts used by the benchmark workflow:
scripts/append-bench-history.py,scripts/extract-bench.py,
scripts/render-bench-entry.py. - New GitHub workflows:
docs.yml(publishes the MkDocs site),
release.yml(creates releases onv*tags, attaches a source
tarball with only the essential crates),release-drafter.yml,
labels.yml,bench-release.yml(per-release benchmark history
on thebench-databranch). .github/labels.ymland.github/release-drafter.ymlfor the
workflows above.rust.ymlworkflow: action versions bumped to
actions/checkout@v6,actions/upload-artifact@v7,
actions/cache/restore@v5,actions/cache/save@v5(Node 24
baseline); benchmark job restricted to-p samp-sdkto avoid
Unrecognized option: 'save-baseline'; artefact retention now
capped at 14 days.
Added — tests and benchmarks
- Unit tests grew from 80 (v2.2.0) to 207 (this r...
v2.2.0
Aviso:
A versão 2.1.0 não havia sido declarada anteriormente, então como uma compensação e correção estou trazendo a v2.2.0 com novas adições e melhorias de código. Desde já peço desculpas.
What's Changed
- Update by @NullSablex in #4
Full Changelog: v2.1.0...v2.2.0
v2.1.0
What's Changed
- Fix files optmize by @NullSablex in #1
- Update-cargo by @NullSablex in #2
- Release v2.1.0: segurança, testes, CI e documentação by @NullSablex in #3
New Contributors
- @NullSablex made their first contribution in #1
Full Changelog: https://github.com/NullSablex/rust-samp/commits/v2.1.0
v1.0.1
What's Changed
- Fix files optmize by @NullSablex in #1
Full Changelog: https://github.com/NullSablex/rust-samp/commits/v1.0.1
v1.0.0
Full Changelog: https://github.com/NullSablex/rust-samp/commits/v1.0.0