mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Resolved plugin dependency cycle, allowing more interesting plugin API
This commit is contained in:
parent
8e937a50ca
commit
027842f832
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -5541,7 +5541,6 @@ version = "0.8.0"
|
||||
dependencies = [
|
||||
"arraygen",
|
||||
"authc",
|
||||
"bincode",
|
||||
"criterion",
|
||||
"crossbeam",
|
||||
"csv",
|
||||
@ -5556,7 +5555,6 @@ dependencies = [
|
||||
"num-derive",
|
||||
"num-traits 0.2.12",
|
||||
"ordered-float 2.0.0",
|
||||
"parking_lot 0.11.0",
|
||||
"rand 0.7.3",
|
||||
"rayon",
|
||||
"ron",
|
||||
@ -5571,13 +5569,9 @@ dependencies = [
|
||||
"spin_sleep",
|
||||
"structopt",
|
||||
"sum_type",
|
||||
"tar",
|
||||
"toml",
|
||||
"tracing",
|
||||
"tracy-client",
|
||||
"vek 0.12.0",
|
||||
"veloren-plugin-api",
|
||||
"wasmer-runtime",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5585,6 +5579,7 @@ name = "veloren-plugin-api"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"veloren-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5639,6 +5634,7 @@ dependencies = [
|
||||
"uvth 3.1.1",
|
||||
"vek 0.12.0",
|
||||
"veloren-common",
|
||||
"veloren-plugin-api",
|
||||
"veloren-world",
|
||||
"veloren_common_sys",
|
||||
"veloren_network",
|
||||
@ -5776,6 +5772,7 @@ dependencies = [
|
||||
name = "veloren_common_sys"
|
||||
version = "0.8.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"hashbrown 0.7.2",
|
||||
"indexmap",
|
||||
"rand 0.7.3",
|
||||
@ -5783,11 +5780,14 @@ dependencies = [
|
||||
"serde",
|
||||
"slab",
|
||||
"specs",
|
||||
"tar",
|
||||
"toml",
|
||||
"tracing",
|
||||
"tracy-client",
|
||||
"vek 0.12.0",
|
||||
"veloren-common",
|
||||
"veloren-plugin-api",
|
||||
"wasmer-runtime",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
Binary file not shown.
@ -222,7 +222,7 @@ impl Client {
|
||||
ability_map,
|
||||
} => {
|
||||
// Initialize `State`
|
||||
let mut state = State::default();
|
||||
let mut state = State::client();
|
||||
// Client-only components
|
||||
state
|
||||
.ecs_mut()
|
||||
|
@ -20,7 +20,6 @@ lazy_static = "1.4.0"
|
||||
num-derive = "0.3"
|
||||
num-traits = "0.2"
|
||||
ordered-float = { version = "2.0.0", default-features = false }
|
||||
parking_lot = "0.11.0"
|
||||
rand = "0.7"
|
||||
rayon = "1.3.0"
|
||||
roots = "0.0.6"
|
||||
@ -34,7 +33,6 @@ directories-next = "2.0"
|
||||
dot_vox = "4.0"
|
||||
image = { version = "0.23.8", default-features = false, features = ["png"] }
|
||||
notify = "5.0.0-pre.3"
|
||||
tar = "0.4.30"
|
||||
|
||||
# Auth
|
||||
authc = { git = "https://gitlab.com/veloren/auth.git", rev = "b943c85e4a38f5ec60cd18c34c73097640162bfe" }
|
||||
@ -54,7 +52,6 @@ ron = { version = "0.6", default-features = false }
|
||||
serde = { version = "1.0.110", features = ["derive", "rc"] }
|
||||
serde_json = "1.0.50"
|
||||
serde_repr = "0.1.6"
|
||||
toml = "0.5.7"
|
||||
|
||||
#esv export
|
||||
csv = { version = "1.1.3", optional = true }
|
||||
@ -63,11 +60,6 @@ structopt = { version = "0.3.13", optional = true }
|
||||
# Tracy
|
||||
tracy-client = { version = "0.9.0", optional = true }
|
||||
|
||||
# Plugins
|
||||
wasmer-runtime = "0.17.1"
|
||||
bincode = "1.3.1"
|
||||
plugin-api = { package = "veloren-plugin-api", path = "../plugin/api"}
|
||||
|
||||
[dev-dependencies]
|
||||
#bench
|
||||
criterion = "0.3"
|
||||
|
@ -3,9 +3,12 @@ use comp::{
|
||||
item::{Item, Reagent},
|
||||
Ori, Pos,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use specs::Entity as EcsEntity;
|
||||
use std::{collections::VecDeque, ops::DerefMut};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
sync::Mutex,
|
||||
ops::DerefMut,
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
pub enum LocalEvent {
|
||||
@ -150,10 +153,10 @@ impl<E> EventBus<E> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn emit_now(&self, event: E) { self.queue.lock().push_back(event); }
|
||||
pub fn emit_now(&self, event: E) { self.queue.lock().unwrap().push_back(event); }
|
||||
|
||||
pub fn recv_all(&self) -> impl ExactSizeIterator<Item = E> {
|
||||
std::mem::replace(self.queue.lock().deref_mut(), VecDeque::new()).into_iter()
|
||||
std::mem::replace(self.queue.lock().unwrap().deref_mut(), VecDeque::new()).into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,5 +172,5 @@ impl<'a, E> Emitter<'a, E> {
|
||||
}
|
||||
|
||||
impl<'a, E> Drop for Emitter<'a, E> {
|
||||
fn drop(&mut self) { self.bus.queue.lock().append(&mut self.events); }
|
||||
fn drop(&mut self) { self.bus.queue.lock().unwrap().append(&mut self.events); }
|
||||
}
|
||||
|
@ -38,7 +38,6 @@ pub mod msg;
|
||||
pub mod npc;
|
||||
pub mod outcome;
|
||||
pub mod path;
|
||||
pub mod plugin;
|
||||
pub mod ray;
|
||||
pub mod recipe;
|
||||
pub mod region;
|
||||
@ -59,4 +58,3 @@ pub mod volumes;
|
||||
pub use combat::{Damage, DamageSource, GroupTarget, Knockback};
|
||||
pub use explosion::{Explosion, RadiusEffect};
|
||||
pub use loadout_builder::LoadoutBuilder;
|
||||
pub use plugin_api;
|
||||
|
@ -11,3 +11,15 @@ pub struct Time(pub f64);
|
||||
/// A resource that stores the time since the previous tick.
|
||||
#[derive(Default)]
|
||||
pub struct DeltaTime(pub f32);
|
||||
|
||||
/// A resource that indicates what mode the local game is being played in.
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub enum GameMode {
|
||||
/// The game is being played in server mode (i.e: the code is running server-side)
|
||||
Server,
|
||||
/// The game is being played in client mode (i.e: the code is running client-side)
|
||||
Client,
|
||||
/// The game is being played in singleplayer mode (i.e: both client and server at once)
|
||||
// To be used later when we no longer start up an entirely new server for singleplayer
|
||||
Singleplayer,
|
||||
}
|
||||
|
@ -13,13 +13,6 @@ impl Into<u64> for Uid {
|
||||
fn into(self) -> u64 { self.0 }
|
||||
}
|
||||
|
||||
|
||||
impl Into<plugin_api::Uid> for Uid {
|
||||
fn into(self) -> plugin_api::Uid {
|
||||
plugin_api::Uid(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Uid {
|
||||
fn from(uid: u64) -> Self { Self(uid) }
|
||||
}
|
||||
|
@ -36,4 +36,8 @@ serde = { version = "1.0.110", features = ["derive"] }
|
||||
tracy-client = { version = "0.9.0", optional = true }
|
||||
|
||||
# Plugins
|
||||
toml = "0.5.7"
|
||||
tar = "0.4.30"
|
||||
wasmer-runtime = "0.17.1"
|
||||
bincode = "1.3.1"
|
||||
plugin-api = { package = "veloren-plugin-api", path = "../../plugin/api"}
|
||||
|
@ -9,6 +9,7 @@ pub mod controller;
|
||||
pub mod melee;
|
||||
mod mount;
|
||||
pub mod phys;
|
||||
pub mod plugin;
|
||||
mod projectile;
|
||||
mod shockwave;
|
||||
pub mod state;
|
||||
|
@ -2,7 +2,7 @@
|
||||
pub mod errors;
|
||||
pub mod module;
|
||||
|
||||
use crate::assets::ASSETS_PATH;
|
||||
use common::assets::ASSETS_PATH;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::{HashMap, HashSet}, fs, io::Read, path::{Path, PathBuf}};
|
||||
use tracing::{error, info};
|
@ -1,7 +1,11 @@
|
||||
use std::{cell::Cell, collections::HashSet, marker::PhantomData, sync::Arc};
|
||||
use std::{
|
||||
cell::Cell,
|
||||
collections::HashSet,
|
||||
marker::PhantomData,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use error::RuntimeError;
|
||||
use parking_lot::Mutex;
|
||||
use wasmer_runtime::*;
|
||||
|
||||
use super::errors::{PluginError, PluginModuleError};
|
||||
@ -46,7 +50,7 @@ impl PluginModule {
|
||||
return None;
|
||||
}
|
||||
let bytes = {
|
||||
let instance = self.wasm_instance.lock();
|
||||
let instance = self.wasm_instance.lock().unwrap();
|
||||
let func = match instance.exports.get(event_name).map_err(|e| PluginModuleError::FunctionGet(e)) {
|
||||
Ok(e) => e,
|
||||
Err(e) => return Some(Err(e))
|
@ -2,7 +2,6 @@ use common::{
|
||||
comp,
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
metrics::{PhysicsMetrics, SysMetrics},
|
||||
plugin::PluginMgr,
|
||||
region::RegionMap,
|
||||
resources::{DeltaTime, Time, TimeOfDay},
|
||||
span,
|
||||
@ -10,6 +9,7 @@ use common::{
|
||||
terrain::{Block, TerrainChunk, TerrainGrid},
|
||||
time::DayPeriod,
|
||||
vol::{ReadVol, WriteVol},
|
||||
resources,
|
||||
};
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use rayon::{ThreadPool, ThreadPoolBuilder};
|
||||
@ -21,6 +21,7 @@ use specs::{
|
||||
use std::{sync::Arc, time::Duration};
|
||||
use tracing::info;
|
||||
use vek::*;
|
||||
use crate::plugin::PluginMgr;
|
||||
|
||||
/// How much faster should an in-game day be compared to a real day?
|
||||
// TODO: Don't hard-code this.
|
||||
@ -70,6 +71,13 @@ impl TerrainChanges {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum ExecMode {
|
||||
Server,
|
||||
Client,
|
||||
Singleplayer,
|
||||
}
|
||||
|
||||
/// A type used to represent game state stored on both the client and the
|
||||
/// server. This includes things like entity components, terrain data, and
|
||||
/// global states like weather, time of day, etc.
|
||||
@ -79,21 +87,23 @@ pub struct State {
|
||||
thread_pool: Arc<ThreadPool>,
|
||||
}
|
||||
|
||||
impl Default for State {
|
||||
/// Create a new `State`.
|
||||
fn default() -> Self {
|
||||
impl State {
|
||||
/// Create a new `State` in client mode.
|
||||
pub fn client() -> Self { Self::new(resources::GameMode::Client) }
|
||||
/// Create a new `State` in server mode.
|
||||
pub fn server() -> Self { Self::new(resources::GameMode::Server) }
|
||||
|
||||
pub fn new(game_mode: resources::GameMode) -> Self {
|
||||
Self {
|
||||
ecs: Self::setup_ecs_world(),
|
||||
ecs: Self::setup_ecs_world(game_mode),
|
||||
thread_pool: Arc::new(ThreadPoolBuilder::new().build().unwrap()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl State {
|
||||
/// Creates ecs world and registers all the common components and resources
|
||||
// TODO: Split up registering into server and client (e.g. move
|
||||
// EventBus<ServerEvent> to the server)
|
||||
fn setup_ecs_world() -> specs::World {
|
||||
fn setup_ecs_world(game_mode: resources::GameMode) -> specs::World {
|
||||
let mut ecs = specs::World::new();
|
||||
// Uids for sync
|
||||
ecs.register_sync_marker();
|
||||
@ -171,6 +181,7 @@ impl State {
|
||||
ecs.insert(BlockChange::default());
|
||||
ecs.insert(TerrainChanges::default());
|
||||
ecs.insert(EventBus::<LocalEvent>::default());
|
||||
ecs.insert(game_mode);
|
||||
// TODO: only register on the server
|
||||
ecs.insert(EventBus::<ServerEvent>::default());
|
||||
ecs.insert(comp::group::GroupManager::default());
|
||||
@ -181,7 +192,9 @@ impl State {
|
||||
// Load plugins from asset directory
|
||||
ecs.insert(match PluginMgr::from_assets() {
|
||||
Ok(plugin_mgr) => {
|
||||
if let Err(e) = plugin_mgr.execute_event("on_load", &plugin_api::event::PluginLoadEvent {}) {
|
||||
if let Err(e) = plugin_mgr.execute_event("on_load", &plugin_api::event::PluginLoadEvent {
|
||||
game_mode,
|
||||
}) {
|
||||
tracing::error!(?e, "Failed to run plugin init");
|
||||
info!("Error occurred when loading plugins. Running without plugins instead.");
|
||||
PluginMgr::default()
|
||||
|
@ -4,7 +4,6 @@ version = "0.1.0"
|
||||
authors = ["ccgauche <gaucheron.laurent@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
common = { package = "veloren-common", path = "../../common", features = ["no-assets"] }
|
||||
serde = { version = "1.0.118", features = ["derive"] }
|
||||
|
@ -1,4 +1,5 @@
|
||||
use serde::{Serialize, de::DeserializeOwned, Deserialize};
|
||||
use common::{sync, resources};
|
||||
|
||||
#[derive(Deserialize,Serialize,Debug)]
|
||||
pub enum Action {
|
||||
@ -12,16 +13,7 @@ pub trait Event: Serialize + DeserializeOwned + Send + Sync{
|
||||
type Response: Serialize + DeserializeOwned + Send + Sync;
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
|
||||
pub enum PluginMode {
|
||||
Server,
|
||||
Client,
|
||||
Singleplayer, // To be used later when we no longer start up an entirely new server for singleplayer
|
||||
}
|
||||
|
||||
// TODO: Unify this with common/src/comp/uid.rs:Uid
|
||||
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Uid(pub u64);
|
||||
pub use resources::GameMode;
|
||||
|
||||
pub mod event {
|
||||
use super::*;
|
||||
@ -40,7 +32,7 @@ pub mod event {
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Player {
|
||||
pub id: Uid,
|
||||
pub id: sync::Uid,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
|
||||
@ -67,7 +59,7 @@ pub mod event {
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
|
||||
pub struct PluginLoadEvent {
|
||||
pub mode: PluginMode,
|
||||
pub game_mode: GameMode,
|
||||
}
|
||||
|
||||
impl Event for PluginLoadEvent {
|
||||
|
1521
plugin/hello/Cargo.lock
generated
1521
plugin/hello/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,12 +1,15 @@
|
||||
extern crate plugin_rt;
|
||||
|
||||
use plugin_rt::*;
|
||||
use plugin_rt::api::{Action, event::*};
|
||||
use plugin_rt::api::{Action, GameMode, event::*};
|
||||
|
||||
#[event_handler]
|
||||
pub fn on_load(load: PluginLoadEvent) -> () {
|
||||
emit_action(Action::Print("This is a test".to_owned()));
|
||||
println!("Hello world");
|
||||
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())),
|
||||
}
|
||||
}
|
||||
|
||||
#[event_handler]
|
||||
|
@ -45,3 +45,6 @@ diesel = { version = "1.4.3", features = ["sqlite"] }
|
||||
diesel_migrations = "1.4.0"
|
||||
dotenv = "0.15.0"
|
||||
slab = "0.4"
|
||||
|
||||
# Plugins
|
||||
plugin-api = { package = "veloren-plugin-api", path = "../plugin/api"}
|
||||
|
@ -46,10 +46,24 @@ use crate::{
|
||||
state_ext::StateExt,
|
||||
sys::sentinel::{DeletedEntities, TrackedComps},
|
||||
};
|
||||
use common::{assets::Asset, cmd::ChatCommand, comp::{self, ChatType}, event::{EventBus, ServerEvent}, msg::{
|
||||
ClientType, DisconnectReason, ServerGeneral, ServerInfo, ServerInit, ServerMsg, WorldMapMsg,
|
||||
}, outcome::Outcome, plugin::PluginMgr, recipe::default_recipe_book, resources::TimeOfDay, rtsim::RtSimEntity, sync::{Uid, WorldSyncExt}, terrain::TerrainChunkSize, vol::{ReadVol, RectVolSize}};
|
||||
use common_sys::state::State;
|
||||
use common::{
|
||||
assets::Asset,
|
||||
cmd::ChatCommand,
|
||||
comp::{self, ChatType},
|
||||
event::{EventBus, ServerEvent},
|
||||
msg::{ClientType, DisconnectReason, ServerGeneral, ServerInfo, ServerInit, ServerMsg, WorldMapMsg},
|
||||
outcome::Outcome,
|
||||
recipe::default_recipe_book,
|
||||
resources::TimeOfDay,
|
||||
rtsim::RtSimEntity,
|
||||
sync::{Uid, WorldSyncExt},
|
||||
terrain::TerrainChunkSize,
|
||||
vol::{ReadVol, RectVolSize},
|
||||
};
|
||||
use common_sys::{
|
||||
state::State,
|
||||
plugin::PluginMgr,
|
||||
};
|
||||
use futures_executor::block_on;
|
||||
use metrics::{PhysicsMetrics, ServerMetrics, StateTickMetrics, TickMetrics};
|
||||
use network::{Network, Pid, ProtocolAddr};
|
||||
@ -131,7 +145,7 @@ impl Server {
|
||||
metrics::NetworkRequestMetrics::new().unwrap();
|
||||
let (player_metrics, registry_player) = metrics::PlayerMetrics::new().unwrap();
|
||||
|
||||
let mut state = State::default();
|
||||
let mut state = State::server();
|
||||
state.ecs_mut().insert(settings.clone());
|
||||
state.ecs_mut().insert(editable_settings);
|
||||
state.ecs_mut().insert(DataDir {
|
||||
@ -996,10 +1010,10 @@ impl Server {
|
||||
command.execute(self, entity, args);
|
||||
} else {
|
||||
let plugin_manager = self.state.ecs().read_resource::<PluginMgr>();
|
||||
let rs = plugin_manager.execute_event(&format!("on_command_{}",&kwd), &common::plugin_api::event::ChatCommandEvent {
|
||||
let rs = plugin_manager.execute_event(&format!("on_command_{}",&kwd), &plugin_api::event::ChatCommandEvent {
|
||||
command: kwd.clone(),
|
||||
command_args: args.split(" ").map(|x| x.to_owned()).collect(),
|
||||
player: common::plugin_api::event::Player {
|
||||
player: plugin_api::event::Player {
|
||||
id: (*(self.state.ecs().read_storage::<Uid>().get(entity).expect("Can't get player UUID [This should never appen]"))).into()
|
||||
},
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user