Plugin Development ru - Pa-dej/Vex GitHub Wiki
Этот туториал показывает полный путь создания плагина на vex-proxy-sdk.
cargo new whitelist_plugin --lib
cd whitelist_plugin[package]
name = "whitelist_plugin"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
vex-proxy-sdk = "3.0"
serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.9"cargo build --releaseБиблиотека появится в target/release/:
- Windows:
whitelist_plugin.dll - Linux:
libwhitelist_plugin.so - macOS:
libwhitelist_plugin.dylib
Скопируйте библиотеку в plugins/ рядом с vex.toml и перезагрузите:
curl -X POST http://127.0.0.1:8080/reload -H "x-admin-token: change-me"Плагин делает следующее:
- Загружает
config.ymlсо списком разрешённых игроков - Отменяет
OnPreLoginдля не‑whitelist игроков - Отправляет приветствие при логине
- Шлёт broadcast каждые 60 секунд
- Регистрирует команду
/whitelist - Регистрирует Prometheus‑счётчик
allowed:
- Alice
- Bob
welcome: "Welcome to the server!"
broadcast: "Remember to be kind to each other!"use std::error::Error;
use std::sync::Arc;
use serde::Deserialize;
use vex_proxy_sdk::VexPlugin;
use vex_proxy_sdk::api::{PluginApi, CommandContext};
use vex_proxy_sdk::event::{OnPreLogin, OnLoginSuccess};
use vex_proxy_sdk::metrics::Counter;
#[derive(Clone, Debug, Deserialize)]
struct WhitelistConfig {
allowed: Vec<String>,
welcome: String,
broadcast: String,
}
const DEFAULT_CONFIG: &str = r#"
allowed:
- Alice
- Bob
welcome: "Welcome to the server!"
broadcast: "Remember to be kind to each other!"
"#;
struct WhitelistPlugin;
impl VexPlugin for WhitelistPlugin {
fn name(&self) -> &'static str { "whitelist_plugin" }
fn version(&self) -> &'static str { "0.1.0" }
fn on_load(&self, api: Arc<PluginApi>) -> Result<(), Box<dyn Error + Send + Sync>> {
api.config.save_default("config.yml", DEFAULT_CONFIG)?;
let cfg: WhitelistConfig = api.config.load_yaml("config.yml")?;
let cfg = Arc::new(cfg);
let denied: Counter = api.metrics.counter(
"whitelist_denied_total",
"Denied connections by whitelist plugin"
)?;
// Pre-login whitelist check
let cfg_pre = cfg.clone();
let denied_pre = denied.clone();
api.events.on::<OnPreLogin, _, _>(move |event| {
let cfg_pre = cfg_pre.clone();
let denied_pre = denied_pre.clone();
async move {
if !cfg_pre.allowed.iter().any(|name| name.eq_ignore_ascii_case(&event.username)) {
denied_pre.inc();
event.deny("You are not whitelisted.");
}
}
});
// Welcome message after successful login
let cfg_login = cfg.clone();
api.events.on::<OnLoginSuccess, _, _>(move |event| {
let cfg_login = cfg_login.clone();
async move {
event.player.send_message(&cfg_login.welcome);
}
});
// Scheduled broadcast every 60s
let proxy = api.proxy.clone();
let cfg_broadcast = cfg.clone();
api.scheduler.run_timer(60_000, move || {
let proxy = proxy.clone();
let msg = cfg_broadcast.broadcast.clone();
async move {
proxy.broadcast(&msg);
}
});
// /whitelist command
let cfg_cmd = cfg.clone();
api.commands.register(
"whitelist",
"vex.whitelist",
move |ctx: CommandContext| {
let cfg_cmd = cfg_cmd.clone();
async move {
let list = cfg_cmd.allowed.join(\", \");
ctx.reply(&format!(\"Whitelisted: {}\", list));
}
}
);
api.logger.info(\"whitelist_plugin loaded\");
Ok(())
}
fn on_unload(&self) {}
}
#[no_mangle]
pub extern \"C\" fn vex_plugin_create() -> Box<dyn VexPlugin> {
Box::new(WhitelistPlugin)
}