Skip to main content

samp/
lib.rs

1//! Rust toolkit for developing SA-MP plugins and native Open Multiplayer components.
2//!
3//! # Workspace structure
4//!
5//! - `samp` — main crate; re-exports SDK + codegen and exposes the API the plugin uses.
6//! - `samp-codegen` — proc macros (`#[native]`, `initialize_plugin!`,
7//!   `#[derive(SampPlugin)]`) that generate FFI entry points and argument parsing.
8//! - `samp-sdk` — low-level bindings for the AMX VM (SA-MP) and for the component
9//!   ABI (Open Multiplayer).
10//!
11//! # Minimal `Cargo.toml` setup
12//!
13//! ```toml
14//! [lib]
15//! crate-type = ["cdylib"]
16//!
17//! [dependencies]
18//! samp = { git = "https://github.com/NullSablex/rust-samp" }
19//! ```
20//!
21//! # Plugin example
22//!
23//! ```rust,ignore
24//! use samp::prelude::*;
25//! use samp::{native, initialize_plugin, SampPlugin};
26//!
27//! #[derive(SampPlugin, Default)]
28//! struct MyPlugin;
29//!
30//! impl MyPlugin {
31//!     #[native(name = "Greet")]
32//!     fn greet(&mut self, _amx: &Amx, name: &AmxString) -> AmxResult<bool> {
33//!         if name.starts_with("Admin") {
34//!             println!("[VIP] Welcome, {}!", &**name);
35//!         } else {
36//!             println!("Hello, {}!", &**name);
37//!         }
38//!         Ok(true)
39//!     }
40//! }
41//!
42//! // Short form — default constructor via Default::default().
43//! initialize_plugin!(
44//!     type: MyPlugin,
45//!     natives: [MyPlugin::greet],
46//! );
47//!
48//! // Full form when there is setup in the constructor (logger, tick, etc):
49//! // initialize_plugin!(
50//! //     natives: [MyPlugin::greet],
51//! //     {
52//! //         samp::plugin::enable_tick();
53//! //         return MyPlugin;
54//! //     }
55//! // );
56//! ```
57
58pub mod amx;
59#[doc(hidden)]
60pub mod interlayer;
61pub mod logger;
62#[cfg(not(feature = "samp-only"))]
63pub(crate) mod macros;
64pub mod plugin;
65pub(crate) mod runtime;
66
67pub use samp_codegen::{initialize_plugin, native};
68
69/// Version of the `rust-samp` (`samp`) crate the plugin was compiled
70/// against. Useful for diagnostic natives that report the SDK build
71/// back to the gamemode (e.g. `MyPlugin_GetSdkVersion()`), bug reports
72/// and runtime dashboards.
73#[must_use]
74pub fn version() -> &'static str {
75    env!("CARGO_PKG_VERSION")
76}
77
78// Re-export so the generated macro does not leak the `log` dep into the user's Cargo.toml.
79#[doc(hidden)]
80pub use log;
81
82/// Derive macro that generates an empty `impl SampPlugin for T {}` for structs
83/// that do not need to customize any trait method. For structs with logic in
84/// `on_load`/`on_tick`/etc, declare `impl SampPlugin for T { ... }`
85/// manually instead of using the derive.
86pub use samp_codegen::SampPlugin;
87pub use samp_sdk::exec_public;
88pub use samp_sdk::{args, cell, consts, error, exports, raw};
89
90#[cfg(feature = "debug")]
91pub use samp_sdk::debug;
92
93#[cfg(feature = "encoding")]
94pub use samp_sdk::encoding;
95
96#[cfg(not(feature = "samp-only"))]
97pub use samp_sdk::omp;
98
99pub mod prelude {
100    //! Most commonly used imports in plugins.
101    pub use crate::amx::{Amx, AmxExt};
102    pub use crate::cell::{AmxCell, AmxString, Buffer, CellConvert, Ref, UnsizedBuffer};
103    pub use crate::error::AmxResult;
104    pub use crate::plugin::SampPlugin;
105}
106
107/// Installs the SDK logger with defaults derived from the caller's
108/// `Cargo.toml`. Writes to `logs/{CARGO_PKG_NAME}.log` with size-based
109/// rotation (50 MB × 5 archives) and forwards every line to the server's
110/// own log prefixed with `[CARGO_PKG_NAME]`.
111///
112/// Returns `Result<(), samp::logger::InstallError>` — the most common
113/// failures are "already installed" (a second call in the same process)
114/// and "I/O" (the log directory could not be created).
115///
116/// # Example
117/// ```rust,ignore
118/// fn on_load(&mut self) {
119///     let _ = samp::enable_logger!();
120///     log::info!("ready");
121/// }
122/// ```
123#[macro_export]
124macro_rules! enable_logger {
125    () => {
126        $crate::enable_logger_with!($crate::logger::LoggerConfig::new(env!("CARGO_PKG_NAME")))
127    };
128}
129
130/// Installs the SDK logger with an explicit [`LoggerConfig`].
131///
132/// The macro still seeds the banner metadata from the caller's
133/// `CARGO_PKG_*` values before delegating to [`logger::install`], so the
134/// startup banner reports the user's plugin even when every other field
135/// is overridden.
136///
137/// [`LoggerConfig`]: crate::logger::LoggerConfig
138/// [`logger::install`]: crate::logger::install
139#[macro_export]
140macro_rules! enable_logger_with {
141    ($cfg:expr) => {{
142        $crate::logger::__set_banner_metadata($crate::logger::BannerMetadata::new(
143            env!("CARGO_PKG_NAME"),
144            env!("CARGO_PKG_VERSION"),
145            env!("CARGO_PKG_AUTHORS"),
146            env!("CARGO_PKG_REPOSITORY"),
147        ));
148        $crate::logger::install($cfg)
149    }};
150}
151
152#[cfg(test)]
153mod tests {
154    #[test]
155    fn version_matches_cargo_pkg_version() {
156        assert_eq!(super::version(), env!("CARGO_PKG_VERSION"));
157        assert!(!super::version().is_empty());
158    }
159}