mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
7f4411ba1f
# Conflicts: # CHANGELOG.md
225 lines
7.0 KiB
Rust
225 lines
7.0 KiB
Rust
pub extern crate common;
|
|
|
|
pub use common::comp::Health;
|
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
|
|
|
pub use common::{resources::GameMode, uid::Uid};
|
|
|
|
mod errors;
|
|
|
|
pub use errors::*;
|
|
pub use event::*;
|
|
|
|
/// The [`Action`] enum represents a push modification that will be made in the
|
|
/// ECS in the next tick Note that all actions when sent are async and will not
|
|
/// be executed in order like [`Retrieve`] that are sync. All actions sent will
|
|
/// be executed in the send order in the ticking before the rest of the logic
|
|
/// applies.
|
|
///
|
|
/// # Usage:
|
|
/// ```rust
|
|
/// # use veloren_plugin_api::*;
|
|
/// # pub fn emit_action(action: Action) { emit_actions(vec![action]) }
|
|
/// # pub fn emit_actions(_actions: Vec<Action>) {}
|
|
/// // Packing actions is better than sending multiple ones at the same time!
|
|
/// emit_actions(vec![
|
|
/// Action::KillEntity(Uid(1)),
|
|
/// Action::PlayerSendMessage(Uid(0), "This is a test message".to_owned()),
|
|
/// ]);
|
|
/// // You can also use this to only send one action
|
|
/// emit_action(Action::KillEntity(Uid(1)));
|
|
/// ```
|
|
#[derive(Deserialize, Serialize, Debug)]
|
|
pub enum Action {
|
|
ServerClose,
|
|
Print(String),
|
|
PlayerSendMessage(Uid, String),
|
|
KillEntity(Uid),
|
|
}
|
|
|
|
/// The [`Retrieve`] enum represents read of the ECS is sync and blocking.
|
|
/// This enum shouldn't be used by itself. You should always prefer `get`
|
|
/// methods on Plugin API Types For instance, prefer this method:
|
|
/// ```rust
|
|
/// # use veloren_plugin_api::*;
|
|
/// # let entityid = Player {id: Uid(0)};
|
|
/// # trait G { fn get_entity_health(&self) -> Option<i64>; }
|
|
/// # impl G for Player {fn get_entity_health(&self) -> Option<i64> {Some(1)}}
|
|
/// let life = entityid.get_entity_health().unwrap();
|
|
/// // Do something with life
|
|
/// ```
|
|
/// Over this one:
|
|
/// ```rust
|
|
/// # use veloren_plugin_api::*;
|
|
/// # let entityid = Uid(0);
|
|
/// # fn retrieve_action(r: &Retrieve) -> Result<RetrieveResult, RetrieveError> { Ok(RetrieveResult::GetEntityHealth(Health::empty()))}
|
|
/// let life = if let RetrieveResult::GetEntityHealth(e) =
|
|
/// retrieve_action(&Retrieve::GetEntityHealth(entityid)).unwrap()
|
|
/// {
|
|
/// e
|
|
/// } else {
|
|
/// unreachable!()
|
|
/// };
|
|
/// // Do something with life
|
|
/// ```
|
|
#[derive(Deserialize, Serialize, Debug)]
|
|
pub enum Retrieve {
|
|
GetPlayerName(Uid),
|
|
GetEntityHealth(Uid),
|
|
}
|
|
|
|
/// The [`RetrieveResult`] struct is generated while using the `retrieve_action`
|
|
/// function
|
|
///
|
|
/// You should always prefer using `get` methods available in Plugin API types.
|
|
///
|
|
/// Example:
|
|
/// ```rust
|
|
/// # use veloren_plugin_api::*;
|
|
/// # let entityid = Uid(0);
|
|
/// # fn retrieve_action(r: &Retrieve) -> Result<RetrieveResult, RetrieveError> { Ok(RetrieveResult::GetEntityHealth(Health::empty()))}
|
|
/// let life = if let RetrieveResult::GetEntityHealth(e) =
|
|
/// retrieve_action(&Retrieve::GetEntityHealth(entityid)).unwrap()
|
|
/// {
|
|
/// e
|
|
/// } else {
|
|
/// unreachable!()
|
|
/// };
|
|
/// // Do something with life
|
|
/// ```
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
pub enum RetrieveResult {
|
|
GetPlayerName(String),
|
|
GetEntityHealth(Health),
|
|
}
|
|
|
|
/// This trait is implement by all events and ensure type safety of FFI.
|
|
pub trait Event: Serialize + DeserializeOwned + Send + Sync {
|
|
type Response: Serialize + DeserializeOwned + Send + Sync;
|
|
|
|
fn get_event_name(&self) -> String;
|
|
}
|
|
|
|
/// This module contains all events from the api
|
|
pub mod event {
|
|
use super::*;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
/// This event is called when a chat command is run.
|
|
/// Your event should be named `on_command_<Your command>`
|
|
///
|
|
/// If you return an Error the displayed message will be the error message
|
|
/// in red You can return a Vec<String> that will be print to player
|
|
/// chat as info
|
|
///
|
|
/// # Example
|
|
/// ```ignore
|
|
/// #[event_handler]
|
|
/// pub fn on_command_testplugin(command: ChatCommandEvent) -> Result<Vec<String>, String> {
|
|
/// Ok(vec![format!(
|
|
/// "Player of id {:?} named {} with {:?} sended command with args {:?}",
|
|
/// command.player.id,
|
|
/// command
|
|
/// .player
|
|
/// .get_player_name()
|
|
/// .expect("Can't get player name"),
|
|
/// command
|
|
/// .player
|
|
/// .get_entity_health()
|
|
/// .expect("Can't get player health"),
|
|
/// command.command_args
|
|
/// )])
|
|
/// }
|
|
/// ```
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
|
|
pub struct ChatCommandEvent {
|
|
pub command: String,
|
|
pub command_args: Vec<String>,
|
|
pub player: Player,
|
|
}
|
|
|
|
impl Event for ChatCommandEvent {
|
|
type Response = Result<Vec<String>, String>;
|
|
|
|
fn get_event_name(&self) -> String { format!("on_command_{}", self.command) }
|
|
}
|
|
|
|
/// This struct represent a player
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
|
|
pub struct Player {
|
|
pub id: Uid,
|
|
}
|
|
|
|
/// This event is called when a player connects.
|
|
/// Your event should be named `on_join`
|
|
///
|
|
/// You can either return `CloseConnection` or `None`
|
|
/// If `CloseConnection` is returned the player will be kicked
|
|
///
|
|
/// # Example
|
|
/// ```ignore
|
|
/// #[event_handler]
|
|
/// pub fn on_join(command: PlayerJoinEvent) -> PlayerJoinResult {
|
|
/// PlayerJoinResult::CloseConnection
|
|
/// }
|
|
/// ```
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
|
|
pub struct PlayerJoinEvent {
|
|
pub player_name: String,
|
|
pub player_id: [u8; 16],
|
|
}
|
|
|
|
impl Event for PlayerJoinEvent {
|
|
type Response = PlayerJoinResult;
|
|
|
|
fn get_event_name(&self) -> String { "on_join".to_owned() }
|
|
}
|
|
|
|
/// This is the return type of an `on_join` event. See [`PlayerJoinEvent`]
|
|
///
|
|
/// Variants:
|
|
/// - `CloseConnection` will kick the player.
|
|
/// - `None` will let the player join the server.
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
|
|
#[repr(u8)]
|
|
pub enum PlayerJoinResult {
|
|
Kick(String),
|
|
None,
|
|
}
|
|
|
|
impl Default for PlayerJoinResult {
|
|
fn default() -> Self { Self::None }
|
|
}
|
|
|
|
/// This event is called when the plugin is loaded
|
|
/// Your event should be named `on_load`
|
|
///
|
|
/// # Example
|
|
/// ```ignore
|
|
/// #[event_handler]
|
|
/// pub fn on_load(load: PluginLoadEvent) {
|
|
/// match load.game_mode {
|
|
/// GameMode::Server => emit_action(Action::Print("Hello, server!".to_owned())),
|
|
/// GameMode::Client => emit_action(Action::Print("Hello, client!".to_owned())),
|
|
/// GameMode::Singleplayer => emit_action(Action::Print("Hello, singleplayer!".to_owned())),
|
|
/// }
|
|
/// }
|
|
/// ```
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
|
|
pub struct PluginLoadEvent {
|
|
pub game_mode: GameMode,
|
|
}
|
|
|
|
impl Event for PluginLoadEvent {
|
|
type Response = ();
|
|
|
|
fn get_event_name(&self) -> String { "on_load".to_owned() }
|
|
}
|
|
|
|
// impl Default for PlayerJoinResult {
|
|
// fn default() -> Self {
|
|
// Self::None
|
|
// }
|
|
// }
|
|
}
|