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) {} /// // 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; } /// # impl G for Player {fn get_entity_health(&self) -> Option {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 { 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 { 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_` /// /// If you return an Error the displayed message will be the error message /// in red You can return a Vec that will be print to player /// chat as info /// /// # Example /// ```ignore /// #[event_handler] /// pub fn on_command_testplugin(command: ChatCommandEvent) -> Result, 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, pub player: Player, } impl Event for ChatCommandEvent { type Response = Result, 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 // } // } }