diff --git a/Cargo.lock b/Cargo.lock index d394200d4c..02ce377567 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5698,6 +5698,7 @@ dependencies = [ name = "veloren-plugin-api" version = "0.1.0" dependencies = [ + "bincode", "serde", "veloren-common", ] diff --git a/assets/plugins/hello.wasm b/assets/plugins/hello.wasm index 71c52f6d82..86ca77d284 100644 Binary files a/assets/plugins/hello.wasm and b/assets/plugins/hello.wasm differ diff --git a/assets/plugins/plugin1.plugin.tar b/assets/plugins/plugin1.plugin.tar index 0e9f0e9b60..51cb41424c 100644 Binary files a/assets/plugins/plugin1.plugin.tar and b/assets/plugins/plugin1.plugin.tar differ diff --git a/common/src/combat.rs b/common/src/combat.rs index 958e3436c3..4bbfc9a546 100644 --- a/common/src/combat.rs +++ b/common/src/combat.rs @@ -1,6 +1,8 @@ +use crate::comp::buff::BuffKind; +#[cfg(not(target_arch = "wasm32"))] use crate::{ comp::{ - buff::{Buff, BuffChange, BuffData, BuffKind, BuffSource}, + buff::{Buff, BuffChange, BuffData, BuffSource}, inventory::{ item::{ armor::Protection, @@ -18,18 +20,26 @@ use crate::{ uid::Uid, util::Dir, }; -use rand::{thread_rng, Rng}; -use serde::{Deserialize, Serialize}; -use specs::Entity as EcsEntity; -use std::time::Duration; -use vek::*; +#[cfg(not(target_arch = "wasm32"))] +use rand::{thread_rng, Rng}; + +use serde::{Deserialize, Serialize}; + +#[cfg(not(target_arch = "wasm32"))] +use specs::Entity as EcsEntity; +#[cfg(not(target_arch = "wasm32"))] +use std::time::Duration; +#[cfg(not(target_arch = "wasm32"))] use vek::*; + +#[cfg(not(target_arch = "wasm32"))] #[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub enum GroupTarget { InGroup, OutOfGroup, } +#[cfg(not(target_arch = "wasm32"))] #[derive(Copy, Clone)] pub struct AttackerInfo<'a> { pub entity: EcsEntity, @@ -37,6 +47,7 @@ pub struct AttackerInfo<'a> { pub energy: Option<&'a Energy>, } +#[cfg(not(target_arch = "wasm32"))] #[derive(Clone, Debug, Serialize, Deserialize)] // TODO: Yeet clone derive pub struct Attack { damages: Vec, @@ -45,6 +56,7 @@ pub struct Attack { crit_multiplier: f32, } +#[cfg(not(target_arch = "wasm32"))] impl Default for Attack { fn default() -> Self { Self { @@ -56,6 +68,7 @@ impl Default for Attack { } } +#[cfg(not(target_arch = "wasm32"))] impl Attack { pub fn with_damage(mut self, damage: AttackDamage) -> Self { self.damages.push(damage); @@ -296,6 +309,7 @@ impl Attack { } } +#[cfg(not(target_arch = "wasm32"))] #[derive(Clone, Debug, Serialize, Deserialize)] pub struct AttackDamage { damage: Damage, @@ -303,6 +317,7 @@ pub struct AttackDamage { effects: Vec, } +#[cfg(not(target_arch = "wasm32"))] impl AttackDamage { pub fn new(damage: Damage, target: Option) -> Self { Self { @@ -318,6 +333,7 @@ impl AttackDamage { } } +#[cfg(not(target_arch = "wasm32"))] #[derive(Clone, Debug, Serialize, Deserialize)] pub struct AttackEffect { target: Option, @@ -325,6 +341,7 @@ pub struct AttackEffect { requirement: Option, } +#[cfg(not(target_arch = "wasm32"))] impl AttackEffect { pub fn new(target: Option, effect: CombatEffect) -> Self { Self { @@ -342,6 +359,7 @@ impl AttackEffect { pub fn effect(&self) -> &CombatEffect { &self.effect } } +#[cfg(not(target_arch = "wasm32"))] #[derive(Clone, Debug, Serialize, Deserialize)] pub enum CombatEffect { Heal(f32), @@ -352,6 +370,7 @@ pub enum CombatEffect { Poise(f32), } +#[cfg(not(target_arch = "wasm32"))] #[derive(Clone, Debug, Serialize, Deserialize)] pub enum CombatRequirement { AnyDamage, @@ -370,12 +389,14 @@ pub enum DamageSource { Other, } +#[cfg(not(target_arch = "wasm32"))] #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Damage { pub source: DamageSource, pub value: f32, } +#[cfg(not(target_arch = "wasm32"))] impl Damage { /// Returns the total damage reduction provided by all equipped items pub fn compute_damage_reduction(inventory: &Inventory) -> f32 { @@ -520,12 +541,14 @@ impl Damage { } } +#[cfg(not(target_arch = "wasm32"))] #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Knockback { pub direction: KnockbackDir, pub strength: f32, } +#[cfg(not(target_arch = "wasm32"))] #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum KnockbackDir { Away, @@ -534,6 +557,7 @@ pub enum KnockbackDir { TowardsUp, } +#[cfg(not(target_arch = "wasm32"))] impl Knockback { pub fn calculate_impulse(self, dir: Dir) -> Vec3 { match self.direction { @@ -554,6 +578,7 @@ impl Knockback { } } +#[cfg(not(target_arch = "wasm32"))] #[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct CombatBuff { pub kind: BuffKind, @@ -562,12 +587,14 @@ pub struct CombatBuff { pub chance: f32, } +#[cfg(not(target_arch = "wasm32"))] #[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub enum CombatBuffStrength { DamageFraction(f32), Value(f32), } +#[cfg(not(target_arch = "wasm32"))] impl CombatBuffStrength { fn to_strength(self, damage: f32) -> f32 { match self { @@ -577,6 +604,7 @@ impl CombatBuffStrength { } } +#[cfg(not(target_arch = "wasm32"))] impl CombatBuff { fn to_buff(self, uid: Option, damage: f32) -> Buff { // TODO: Generate BufCategoryId vec (probably requires damage overhaul?) @@ -606,7 +634,8 @@ impl CombatBuff { } } -fn equipped_item_and_tool(inv: &Inventory, slot: EquipSlot) -> Option<(&Item, &Tool)> { +#[cfg(not(target_arch = "wasm32"))] +fn equipped_item_and_tool(inv: &Inventory, slot: EquipSlot) -> Option<&Tool> { inv.equipped(slot).and_then(|i| { if let ItemKind::Tool(tool) = &i.kind() { Some((i, tool)) @@ -616,6 +645,7 @@ fn equipped_item_and_tool(inv: &Inventory, slot: EquipSlot) -> Option<(&Item, &T }) } +#[cfg(not(target_arch = "wasm32"))] pub fn get_weapons(inv: &Inventory) -> (Option, Option) { ( equipped_item_and_tool(inv, EquipSlot::Mainhand).map(|(_, tool)| tool.kind), @@ -623,6 +653,7 @@ pub fn get_weapons(inv: &Inventory) -> (Option, Option) { ) } +#[cfg(not(target_arch = "wasm32"))] fn offensive_rating(inv: &Inventory, skillset: &SkillSet) -> f32 { let active_damage = equipped_item_and_tool(inv, EquipSlot::Mainhand).map_or(0.0, |(item, tool)| { @@ -639,6 +670,7 @@ fn offensive_rating(inv: &Inventory, skillset: &SkillSet) -> f32 { active_damage.max(second_damage) } +#[cfg(not(target_arch = "wasm32"))] pub fn combat_rating(inventory: &Inventory, health: &Health, stats: &Stats, body: Body) -> f32 { let defensive_weighting = 1.0; let offensive_weighting = 1.0; diff --git a/common/src/comp/buff.rs b/common/src/comp/buff.rs index 8aab7fcd43..144406a398 100644 --- a/common/src/comp/buff.rs +++ b/common/src/comp/buff.rs @@ -1,8 +1,13 @@ +#[cfg(not(target_arch = "wasm32"))] use crate::uid::Uid; +#[cfg(not(target_arch = "wasm32"))] use hashbrown::HashMap; use serde::{Deserialize, Serialize}; +#[cfg(not(target_arch = "wasm32"))] use specs::{Component, DerefFlaggedStorage}; +#[cfg(not(target_arch = "wasm32"))] use specs_idvs::IdvStorage; +#[cfg(not(target_arch = "wasm32"))] use std::{cmp::Ordering, time::Duration}; /// De/buff Kind. @@ -28,6 +33,7 @@ pub enum BuffKind { IncreaseMaxHealth, } +#[cfg(not(target_arch = "wasm32"))] impl BuffKind { /// Checks if buff is buff or debuff pub fn is_buff(self) -> bool { @@ -48,12 +54,14 @@ impl BuffKind { } // Struct used to store data relevant to a buff +#[cfg(not(target_arch = "wasm32"))] #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub struct BuffData { pub strength: f32, pub duration: Option, } +#[cfg(not(target_arch = "wasm32"))] impl BuffData { pub fn new(strength: f32, duration: Option) -> Self { Self { strength, duration } } } @@ -61,6 +69,7 @@ impl BuffData { /// De/buff category ID. /// Similar to `BuffKind`, but to mark a category (for more generic usage, like /// positive/negative buffs). +#[cfg(not(target_arch = "wasm32"))] #[derive(Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize)] pub enum BuffCategory { Natural, @@ -70,6 +79,7 @@ pub enum BuffCategory { PersistOnDeath, } +#[cfg(not(target_arch = "wasm32"))] #[derive(Clone, Debug, Serialize, Deserialize)] pub enum ModifierKind { Additive, @@ -77,6 +87,7 @@ pub enum ModifierKind { } /// Data indicating and configuring behaviour of a de/buff. +#[cfg(not(target_arch = "wasm32"))] #[derive(Clone, Debug, Serialize, Deserialize)] pub enum BuffEffect { /// Periodically damages or heals entity @@ -101,6 +112,7 @@ pub enum BuffEffect { /// /// To provide more classification info when needed, /// buff can be in one or more buff category. +#[cfg(not(target_arch = "wasm32"))] #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Buff { pub kind: BuffKind, @@ -113,6 +125,7 @@ pub struct Buff { /// Information about whether buff addition or removal was requested. /// This to implement "on_add" and "on_remove" hooks for constant buffs. +#[cfg(not(target_arch = "wasm32"))] #[derive(Clone, Debug)] pub enum BuffChange { /// Adds this buff. @@ -134,6 +147,7 @@ pub enum BuffChange { }, } +#[cfg(not(target_arch = "wasm32"))] impl Buff { /// Builder function for buffs pub fn new( @@ -200,6 +214,7 @@ impl Buff { } } +#[cfg(not(target_arch = "wasm32"))] impl PartialOrd for Buff { fn partial_cmp(&self, other: &Self) -> Option { if self == other { @@ -218,10 +233,12 @@ impl PartialOrd for Buff { } } +#[cfg(not(target_arch = "wasm32"))] fn compare_duration(a: Option, b: Option) -> bool { a.map_or(true, |dur_a| b.map_or(false, |dur_b| dur_a > dur_b)) } +#[cfg(not(target_arch = "wasm32"))] impl PartialEq for Buff { fn eq(&self, other: &Self) -> bool { self.data.strength == other.data.strength && self.time == other.time @@ -229,6 +246,7 @@ impl PartialEq for Buff { } /// Source of the de/buff +#[cfg(not(target_arch = "wasm32"))] #[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)] pub enum BuffSource { /// Applied by a character @@ -256,6 +274,7 @@ pub enum BuffSource { /// and undone on removal of the buff (by the specs system). /// Example could be decreasing max health, which, if repeated each tick, /// would be probably an undesired effect). +#[cfg(not(target_arch = "wasm32"))] #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct Buffs { /// Uid used for synchronization @@ -266,6 +285,7 @@ pub struct Buffs { pub buffs: HashMap, } +#[cfg(not(target_arch = "wasm32"))] impl Buffs { fn sort_kind(&mut self, kind: BuffKind) { if let Some(buff_order) = self.kinds.get_mut(&kind) { @@ -339,8 +359,10 @@ impl Buffs { } } +#[cfg(not(target_arch = "wasm32"))] pub type BuffId = u64; +#[cfg(not(target_arch = "wasm32"))] impl Component for Buffs { type Storage = DerefFlaggedStorage>; } diff --git a/common/src/comp/health.rs b/common/src/comp/health.rs index a840ddecd4..d32e9b7228 100644 --- a/common/src/comp/health.rs +++ b/common/src/comp/health.rs @@ -1,6 +1,11 @@ -use crate::{comp::Body, uid::Uid, DamageSource}; +#[cfg(not(target_arch = "wasm32"))] +use crate::comp::Body; +use crate::{uid::Uid, DamageSource}; use serde::{Deserialize, Serialize}; + +#[cfg(not(target_arch = "wasm32"))] use specs::{Component, DerefFlaggedStorage}; +#[cfg(not(target_arch = "wasm32"))] use specs_idvs::IdvStorage; /// Specifies what and how much changed current health @@ -40,6 +45,7 @@ pub struct Health { } impl Health { + #[cfg(not(target_arch = "wasm32"))] pub fn new(body: Body, level: u16) -> Self { let mut health = Health::empty(); @@ -67,6 +73,7 @@ impl Health { pub fn maximum(&self) -> u32 { self.maximum } + #[cfg(not(target_arch = "wasm32"))] pub fn set_to(&mut self, amount: u32, cause: HealthSource) { let amount = amount.min(self.maximum); self.last_change = (0.0, HealthChange { @@ -76,6 +83,7 @@ impl Health { self.current = amount; } + #[cfg(not(target_arch = "wasm32"))] pub fn change_by(&mut self, change: HealthChange) { self.current = ((self.current as i32 + change.amount).max(0) as u32).min(self.maximum); self.last_change = (0.0, change); @@ -90,6 +98,7 @@ impl Health { } // This is private because max hp is based on the level + #[cfg(not(target_arch = "wasm32"))] fn set_base_max(&mut self, amount: u32) { self.base_max = amount; self.current = self.current.min(self.maximum); @@ -97,12 +106,14 @@ impl Health { pub fn should_die(&self) -> bool { self.current == 0 } + #[cfg(not(target_arch = "wasm32"))] pub fn revive(&mut self) { self.set_to(self.maximum(), HealthSource::Revive); self.is_dead = false; } // TODO: Delete this once stat points will be a thing + #[cfg(not(target_arch = "wasm32"))] pub fn update_max_hp(&mut self, body: Option, level: u16) { if let Some(body) = body { self.set_base_max(body.base_health() + body.base_health_increase() * level as u32); @@ -114,14 +125,17 @@ impl Health { } } + #[cfg(not(target_arch = "wasm32"))] pub fn with_max_health(mut self, amount: u32) -> Self { self.maximum = amount; self.current = amount; self } + #[cfg(not(target_arch = "wasm32"))] pub fn last_set(&mut self) { self.last_max = self.maximum } + #[cfg(not(target_arch = "wasm32"))] pub fn reset_max(&mut self) { self.maximum = self.base_max; if self.current > self.last_max { @@ -131,6 +145,8 @@ impl Health { } } } + +#[cfg(not(target_arch = "wasm32"))] impl Component for Health { type Storage = DerefFlaggedStorage>; } @@ -140,6 +156,7 @@ pub struct Dead { pub cause: HealthSource, } +#[cfg(not(target_arch = "wasm32"))] impl Component for Dead { type Storage = IdvStorage; } diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index 734b3f48b7..7347999cf3 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -1,76 +1,89 @@ -mod ability; -mod admin; -pub mod agent; -pub mod aura; -pub mod beam; -pub mod body; +#[cfg(not(target_arch = "wasm32"))] mod ability; +#[cfg(not(target_arch = "wasm32"))] mod admin; +#[cfg(not(target_arch = "wasm32"))] pub mod agent; +#[cfg(not(target_arch = "wasm32"))] pub mod aura; +#[cfg(not(target_arch = "wasm32"))] pub mod beam; +#[cfg(not(target_arch = "wasm32"))] pub mod body; pub mod buff; +#[cfg(not(target_arch = "wasm32"))] mod character_state; -pub mod chat; +#[cfg(not(target_arch = "wasm32"))] pub mod chat; +#[cfg(not(target_arch = "wasm32"))] mod controller; -mod energy; -pub mod group; +#[cfg(not(target_arch = "wasm32"))] mod energy; +#[cfg(not(target_arch = "wasm32"))] pub mod group; mod health; +#[cfg(not(target_arch = "wasm32"))] pub mod home_chunk; -mod inputs; +#[cfg(not(target_arch = "wasm32"))] mod inputs; +#[cfg(not(target_arch = "wasm32"))] pub mod inventory; +#[cfg(not(target_arch = "wasm32"))] pub mod invite; -mod last; -mod location; -mod misc; -pub mod ori; -mod phys; -mod player; -pub mod poise; +#[cfg(not(target_arch = "wasm32"))] mod last; +#[cfg(not(target_arch = "wasm32"))] mod location; +#[cfg(not(target_arch = "wasm32"))] mod misc; +#[cfg(not(target_arch = "wasm32"))] pub mod ori; +#[cfg(not(target_arch = "wasm32"))] mod phys; +#[cfg(not(target_arch = "wasm32"))] mod player; +#[cfg(not(target_arch = "wasm32"))] pub mod poise; +#[cfg(not(target_arch = "wasm32"))] pub mod projectile; +#[cfg(not(target_arch = "wasm32"))] pub mod shockwave; +#[cfg(not(target_arch = "wasm32"))] pub mod skills; -mod stats; +#[cfg(not(target_arch = "wasm32"))] mod stats; +#[cfg(not(target_arch = "wasm32"))] pub mod visual; // Reexports -pub use ability::{CharacterAbility, CharacterAbilityType}; -pub use admin::Admin; -pub use agent::{Agent, Alignment}; -pub use aura::{Aura, AuraChange, AuraKind, Auras}; -pub use beam::{Beam, BeamSegment}; -pub use body::{ - biped_large, bird_medium, bird_small, dragon, fish_medium, fish_small, golem, humanoid, object, - quadruped_low, quadruped_medium, quadruped_small, theropod, AllBodies, Body, BodyData, -}; -pub use buff::{ - Buff, BuffCategory, BuffChange, BuffData, BuffEffect, BuffId, BuffKind, BuffSource, Buffs, - ModifierKind, -}; -pub use character_state::{CharacterState, Melee, StateUpdate}; -pub use chat::{ - ChatMode, ChatMsg, ChatType, Faction, SpeechBubble, SpeechBubbleType, UnresolvedChatMsg, -}; -pub use controller::{ - Climb, ControlAction, ControlEvent, Controller, ControllerInputs, GroupManip, Input, - InventoryManip, LoadoutManip, MountState, Mounting, SlotManip, -}; -pub use energy::{Energy, EnergyChange, EnergySource}; -pub use group::Group; -pub use health::{Health, HealthChange, HealthSource}; -pub use home_chunk::HomeChunk; -pub use inputs::CanBuild; -pub use inventory::{ - item, - item::{Item, ItemConfig, ItemDrop}, - slot, Inventory, InventoryUpdate, InventoryUpdateEvent, -}; -pub use last::Last; -pub use location::{Waypoint, WaypointArea}; -pub use misc::Object; -pub use ori::Ori; -pub use phys::{ - Collider, ForceUpdate, Gravity, Mass, PhysicsState, Pos, PreviousPhysCache, Scale, Sticky, Vel, -}; -pub use player::Player; -pub use poise::{Poise, PoiseChange, PoiseSource, PoiseState}; -pub use projectile::{Projectile, ProjectileConstructor}; -pub use shockwave::{Shockwave, ShockwaveHitEntities}; -pub use skills::{Skill, SkillGroup, SkillGroupKind, SkillSet}; -pub use stats::Stats; -pub use visual::{LightAnimation, LightEmitter}; +#[cfg(not(target_arch = "wasm32"))] +pub use self::{ + ability::{CharacterAbility, CharacterAbilityType}, + admin::Admin, + agent::{Agent, Alignment}, + aura::{Aura, AuraChange, AuraKind, Auras}, + beam::{Beam, BeamSegment}, + body::{ + biped_large, bird_medium, bird_small, dragon, fish_medium, fish_small, golem, humanoid, + object, quadruped_low, quadruped_medium, quadruped_small, theropod, AllBodies, Body, + BodyData, + }, + buff::{ + Buff, BuffCategory, BuffChange, BuffData, BuffEffect, BuffId, BuffKind, BuffSource, Buffs, + ModifierKind, + }, + character_state::{CharacterState, Melee, StateUpdate}, + chat::{ + ChatMode, ChatMsg, ChatType, Faction, SpeechBubble, SpeechBubbleType, UnresolvedChatMsg, + }, + controller::{ + Climb, ControlAction, ControlEvent, Controller, ControllerInputs, GroupManip, Input, + InventoryManip, LoadoutManip, MountState, Mounting, SlotManip, + }, + energy::{Energy, EnergyChange, EnergySource}, + group::Group, + home_chunk::HomeChunk, + inputs::CanBuild, + inventory::{ + item, + item::{Item, ItemConfig, ItemDrop}, + slot, Inventory, InventoryUpdate, InventoryUpdateEvent, + }, + last::Last, + location::{Waypoint, WaypointArea}, + misc::Object, + ori::Ori, + phys::{ + Collider, ForceUpdate, Gravity, Mass, PhysicsState, Pos, PreviousVelDtCache, Scale, + Sticky, Vel, + }, + player::Player, + poise::{Poise, PoiseChange, PoiseSource, PoiseState}, + projectile::{Projectile, ProjectileConstructor}, + shockwave::{Shockwave, ShockwaveHitEntities}, + skills::{Skill, SkillGroup, SkillGroupKind, SkillSet}, + stats::Stats, + visual::{LightAnimation, LightEmitter}, +}; \ No newline at end of file diff --git a/common/src/lib.rs b/common/src/lib.rs index 841fa50135..472cd38b64 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -25,9 +25,8 @@ pub mod assets; pub mod character; #[cfg(not(target_arch = "wasm32"))] pub mod clock; #[cfg(not(target_arch = "wasm32"))] pub mod cmd; -#[cfg(not(target_arch = "wasm32"))] pub mod combat; -#[cfg(not(target_arch = "wasm32"))] pub mod comp; +pub mod comp; #[cfg(not(target_arch = "wasm32"))] pub mod consts; #[cfg(not(target_arch = "wasm32"))] @@ -73,8 +72,9 @@ pub mod uid; #[cfg(not(target_arch = "wasm32"))] pub mod volumes; +pub use combat::DamageSource; #[cfg(not(target_arch = "wasm32"))] -pub use combat::{Damage, DamageSource, GroupTarget, Knockback, KnockbackDir}; +pub use combat::{Damage, GroupTarget, Knockback, KnockbackDir}; #[cfg(not(target_arch = "wasm32"))] pub use comp::inventory::loadout_builder::LoadoutBuilder; #[cfg(not(target_arch = "wasm32"))] diff --git a/common/sys/src/plugin/memory_manager.rs b/common/sys/src/plugin/memory_manager.rs index 353909439b..00ae92dd54 100644 --- a/common/sys/src/plugin/memory_manager.rs +++ b/common/sys/src/plugin/memory_manager.rs @@ -1,4 +1,4 @@ -use std::sync::atomic::{AtomicI32, AtomicPtr, AtomicU32, AtomicU64, Ordering}; +use std::sync::atomic::{AtomicI32, AtomicPtr, AtomicU32, Ordering}; use serde::{de::DeserializeOwned, Serialize}; use specs::World; @@ -12,26 +12,28 @@ pub struct EcsAccessManager { } impl Default for EcsAccessManager { - fn default() -> Self { Self { - ecs_pointer: AtomicPtr::new(std::ptr::null_mut::<_>()) + ecs_pointer: AtomicPtr::new(std::ptr::null_mut::<_>()), } } } impl EcsAccessManager { - + // This function take a World reference and a function to execute ensuring the + // pointer will never be corrupted during the execution of the function! pub fn execute_with(&self, world: &World, func: impl FnOnce() -> T) -> T { - self.ecs_pointer.store(world as *const _ as *mut _, Ordering::SeqCst); + self.ecs_pointer + .store(world as *const _ as *mut _, Ordering::SeqCst); let out = func(); - self.ecs_pointer.store(std::ptr::null_mut::<_>(), Ordering::SeqCst); + self.ecs_pointer + .store(std::ptr::null_mut::<_>(), Ordering::SeqCst); out } pub fn get(&self) -> Option<&World> { // ptr::as_ref will automatically check for null - unsafe {self.ecs_pointer.load(Ordering::SeqCst).as_ref()} + unsafe { self.ecs_pointer.load(Ordering::SeqCst).as_ref() } } } @@ -50,7 +52,6 @@ impl Default for MemoryManager { } impl MemoryManager { - // This function check if the buffer is wide enough if not it realloc the buffer // calling the `wasm_prepare_buffer` function Note: There is probably // optimizations that can be done using less restrictive ordering diff --git a/common/sys/src/plugin/module.rs b/common/sys/src/plugin/module.rs index a150d5af03..faecdb7a69 100644 --- a/common/sys/src/plugin/module.rs +++ b/common/sys/src/plugin/module.rs @@ -1,14 +1,24 @@ +use std::{ + collections::HashSet, + convert::TryInto, + marker::PhantomData, + sync::{Arc, Mutex}, +}; -use std::{collections::HashSet, convert::TryInto, marker::PhantomData, sync::{Arc, Mutex}}; - -use common::{comp::Player, uid::UidAllocator}; -use common_net::sync::WorldSyncExt; -use specs::{World, WorldExt, saveload::MarkerAllocator}; +use common::{ + comp::{Health, Player}, + uid::UidAllocator, +}; +use specs::{saveload::MarkerAllocator, World, WorldExt}; use wasmer::{imports, Cranelift, Function, Instance, Memory, Module, Store, Value, JIT}; -use super::{errors::{PluginError, PluginModuleError}, memory_manager::{self, EcsAccessManager, MemoryManager}, wasm_env::HostFunctionEnvironement}; +use super::{ + errors::{PluginError, PluginModuleError}, + memory_manager::{self, EcsAccessManager, MemoryManager}, + wasm_env::HostFunctionEnvironement, +}; -use plugin_api::{Action, Event, Retreive}; +use plugin_api::{Action, EcsAccessError, Event, Retrieve, RetrieveError, RetrieveResult}; #[derive(Clone)] // This structure represent the WASM State of the plugin. @@ -43,31 +53,17 @@ impl PluginModule { }); } - fn raw_retreive_action(env: &HostFunctionEnvironement, ptr: u32, len: u32) -> i64 { - - println!("HOST DEBUG 1"); + fn raw_retrieve_action(env: &HostFunctionEnvironement, ptr: u32, len: u32) -> i64 { // TODO: Handle correctly the error - let data: Retreive = env.read_data(ptr as _, len).unwrap(); - println!("HOST DEBUG 2"); + let data: Retrieve = env.read_data(ptr as _, len).unwrap(); - let out = match data { - Retreive::GetEntityName(e) => { - println!("HOST DEBUG 3 {:?}",env.ecs.get().is_some()); - let world = env.ecs.get().expect("Can't get entity name because ECS pointer isn't set"); - println!("HOST DEBUG 4 {}",world.has_value::()); - println!("HOST DEBUG 5 {:?}",&*world.read_resource::()); - let player = world.read_resource::().retrieve_entity_internal(e.0).expect("Invalid uid"); - println!("HOST DEBUG 6"); - format!("{:?}",world.read_component::().get(player)) - } - }; - println!("{}",out); - let (ptr,len) = env.write_data(&out).unwrap(); + let out = retrieve_action(&env.ecs, data); + let (ptr, len) = env.write_data(&out).unwrap(); to_i64(ptr, len as _) } fn dbg(a: i32) { - println!("WASM DEBUG: {}",a); + println!("WASM DEBUG: {}", a); } let ecs = Arc::new(EcsAccessManager::default()); @@ -77,7 +73,7 @@ impl PluginModule { let import_object = imports! { "env" => { "raw_emit_actions" => Function::new_native_with_env(&store, HostFunctionEnvironement::new(name.clone(), ecs.clone(),memory_manager.clone()), raw_emit_actions), - "raw_retreive_action" => Function::new_native_with_env(&store, HostFunctionEnvironement::new(name.clone(), ecs.clone(),memory_manager.clone()), raw_retreive_action), + "raw_retrieve_action" => Function::new_native_with_env(&store, HostFunctionEnvironement::new(name.clone(), ecs.clone(),memory_manager.clone()), raw_retrieve_action), "dbg" => Function::new_native(&store, dbg), } }; @@ -217,6 +213,60 @@ fn execute_raw( )) } +fn retrieve_action( + ecs: &EcsAccessManager, + action: Retrieve, +) -> Result { + match action { + Retrieve::GetPlayerName(e) => { + let world = ecs.get().ok_or(RetrieveError::EcsAccessError( + EcsAccessError::EcsPointerNotAvailable, + ))?; + let player = world + .read_resource::() + .retrieve_entity_internal(e.0) + .ok_or(RetrieveError::EcsAccessError( + EcsAccessError::EcsEntityNotFound(e), + ))?; + Ok(RetrieveResult::GetPlayerName( + world + .read_component::() + .get(player) + .ok_or_else(|| { + RetrieveError::EcsAccessError(EcsAccessError::EcsComponentNotFound( + e, + "Player".to_owned(), + )) + })? + .alias + .to_owned(), + )) + }, + Retrieve::GetEntityHealth(e) => { + let world = ecs.get().ok_or(RetrieveError::EcsAccessError( + EcsAccessError::EcsPointerNotAvailable, + ))?; + let player = world + .read_resource::() + .retrieve_entity_internal(e.0) + .ok_or(RetrieveError::EcsAccessError( + EcsAccessError::EcsEntityNotFound(e), + ))?; + Ok(RetrieveResult::GetEntityHealth( + *world + .read_component::() + .get(player) + .ok_or_else(|| { + RetrieveError::EcsAccessError(EcsAccessError::EcsComponentNotFound( + e, + "Health".to_owned(), + )) + })?, + )) + }, + } +} + fn handle_actions(actions: Vec) { for action in actions { match action { diff --git a/common/sys/src/plugin/wasm_env.rs b/common/sys/src/plugin/wasm_env.rs index ddacc968b2..c166019d13 100644 --- a/common/sys/src/plugin/wasm_env.rs +++ b/common/sys/src/plugin/wasm_env.rs @@ -1,23 +1,31 @@ -use std::sync::{atomic::AtomicI32, Arc}; +use std::sync::Arc; use serde::{de::DeserializeOwned, Serialize}; use wasmer::{Function, HostEnvInitError, Instance, LazyInit, Memory, WasmerEnv}; -use super::{errors::PluginModuleError, memory_manager::{self, EcsAccessManager, MemoryManager}}; +use super::{ + errors::PluginModuleError, + memory_manager::{self, EcsAccessManager, MemoryManager}, +}; #[derive(Clone)] pub struct HostFunctionEnvironement { - pub ecs: Arc, /* This represent the pointer to the ECS object (set to i32::MAX if - * to ECS is availible) */ + pub ecs: Arc, /* This represent the pointer to the ECS object (set to + * i32::MAX if to ECS is + * availible) */ pub memory: LazyInit, // This object represent the WASM Memory pub allocator: LazyInit, // Linked to: wasm_prepare_buffer pub memory_manager: Arc, /* This object represent the current buffer size and - * pointer */ + * pointer */ pub name: String, // This represent the plugin name } impl HostFunctionEnvironement { - pub fn new(name: String, ecs: Arc, memory_manager: Arc) -> Self { + pub fn new( + name: String, + ecs: Arc, + memory_manager: Arc, + ) -> Self { Self { memory_manager, ecs, diff --git a/plugin/api/Cargo.toml b/plugin/api/Cargo.toml index 84d8e9b270..7f75aaeef8 100644 --- a/plugin/api/Cargo.toml +++ b/plugin/api/Cargo.toml @@ -7,3 +7,4 @@ edition = "2018" [dependencies] serde = { version = "1.0.118", features = ["derive"] } common = { package = "veloren-common", path = "../../common", features = ["no-assets"] } +bincode = "1.3.1" \ No newline at end of file diff --git a/plugin/api/src/errors.rs b/plugin/api/src/errors.rs new file mode 100644 index 0000000000..7b7715591d --- /dev/null +++ b/plugin/api/src/errors.rs @@ -0,0 +1,71 @@ +use common::uid::Uid; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub enum RetrieveError { + EcsAccessError(EcsAccessError), + OtherError(String), + DataReadError, + BincodeError(String), + InvalidType, +} + +impl core::fmt::Display for RetrieveError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + RetrieveError::EcsAccessError(e) => { + write!(f, "RetrieveError: {}", e) + }, + RetrieveError::OtherError(e) => { + write!(f, "RetrieveError: Unknown error: {}", e) + }, + RetrieveError::DataReadError => { + write!( + f, + "RetrieveError: Can't pass data through WASM FFI: WASM Memory is corrupted" + ) + }, + RetrieveError::BincodeError(e) => { + write!(f, "RetrieveError: Bincode error: {}", e) + }, + RetrieveError::InvalidType => { + write!( + f, + "RetrieveError: This type wasn't expected as the result for this Retrieve" + ) + }, + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum EcsAccessError { + EcsPointerNotAvailable, + EcsComponentNotFound(Uid, String), + EcsResourceNotFound(String), + EcsEntityNotFound(Uid), +} + +impl core::fmt::Display for EcsAccessError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + EcsAccessError::EcsPointerNotAvailable => { + write!(f, "EcsAccessError can't read the ECS pointer") + }, + EcsAccessError::EcsComponentNotFound(a, b) => { + write!( + f, + "EcsAccessError can't find component {} for entity from UID {}", + b, a + ) + }, + EcsAccessError::EcsResourceNotFound(a) => { + write!(f, "EcsAccessError can't find resource {}", a) + }, + EcsAccessError::EcsEntityNotFound(a) => { + write!(f, "EcsAccessError can't find entity from UID {}", a) + }, + } + } +} diff --git a/plugin/api/src/lib.rs b/plugin/api/src/lib.rs index ffaf761e94..043ac0ea0f 100644 --- a/plugin/api/src/lib.rs +++ b/plugin/api/src/lib.rs @@ -1,7 +1,14 @@ +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::*; + #[derive(Deserialize, Serialize, Debug)] pub enum Action { ServerClose, @@ -11,8 +18,15 @@ pub enum Action { } #[derive(Deserialize, Serialize, Debug)] -pub enum Retreive { - GetEntityName(Uid), +pub enum Retrieve { + GetPlayerName(Uid), + GetEntityHealth(Uid), +} + +#[derive(Serialize, Deserialize, Debug)] +pub enum RetrieveResult { + GetPlayerName(String), + GetEntityHealth(Health), } pub trait Event: Serialize + DeserializeOwned + Send + Sync { diff --git a/plugin/rt/examples/hello.rs b/plugin/rt/examples/hello.rs index 6bf7c836a9..f2894b5083 100644 --- a/plugin/rt/examples/hello.rs +++ b/plugin/rt/examples/hello.rs @@ -15,8 +15,17 @@ pub fn on_load(load: PluginLoadEvent) { #[event_handler] pub fn on_command_testplugin(command: ChatCommandEvent) -> Result, String> { Ok(vec![format!( - "Player of id {:?} named {} sended command with args {:?}", - command.player, command.player.get_entity_name(), command.command_args + "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 name"), + command.command_args )]) } diff --git a/plugin/rt/src/lib.rs b/plugin/rt/src/lib.rs index c5872f1d05..954f412e52 100644 --- a/plugin/rt/src/lib.rs +++ b/plugin/rt/src/lib.rs @@ -2,13 +2,14 @@ pub extern crate plugin_derive; -pub mod retreive; +pub mod retrieve; -pub use retreive::*; +use api::RetrieveError; +pub use retrieve::*; use std::convert::TryInto; -pub use retreive::*; +pub use retrieve::*; pub use plugin_api as api; pub use plugin_derive::*; @@ -18,23 +19,19 @@ use serde::{de::DeserializeOwned, Serialize}; #[cfg(target_arch = "wasm32")] extern "C" { fn raw_emit_actions(ptr: *const u8, len: usize); - fn raw_retreive_action(ptr: *const u8, len: usize) -> i64; + fn raw_retrieve_action(ptr: *const u8, len: usize) -> i64; pub fn dbg(i: i32); } -pub fn retreive_action(_actions: &api::Retreive) -> Result { +pub fn retrieve_action(_actions: &api::Retrieve) -> Result { #[cfg(target_arch = "wasm32")] { - unsafe{dbg(0);} - let ret = bincode::serialize(&_actions).expect("Can't serialize action in emit"); - unsafe{dbg(1);} + let ret = bincode::serialize(&_actions).expect("Can't serialize action in emit"); unsafe { - dbg(2); - let (ptr,len) = from_i64(raw_retreive_action(ret.as_ptr(), ret.len())); - dbg(3); + let (ptr, len) = from_i64(raw_retrieve_action(ret.as_ptr(), ret.len())); let a = ::std::slice::from_raw_parts(ptr as _, len as _); - dbg(4); - bincode::deserialize(&a) + bincode::deserialize::>(&a) + .map_err(|x| RetrieveError::BincodeError(x.to_string()))? } } #[cfg(not(target_arch = "wasm32"))] diff --git a/plugin/rt/src/retreive.rs b/plugin/rt/src/retreive.rs deleted file mode 100644 index b214009776..0000000000 --- a/plugin/rt/src/retreive.rs +++ /dev/null @@ -1,15 +0,0 @@ -use crate::api::Retreive; - -pub trait GetEntityName { - fn get_entity_name(&self) -> String; -} - -impl GetEntityName for crate::api::event::Player { - fn get_entity_name(&self) -> String { - #[cfg(target_arch = "wasm32")] - unsafe { - crate::dbg(-1); - } - crate::retreive_action(&Retreive::GetEntityName(self.id)).expect("Can't get entity name") - } -} diff --git a/plugin/rt/src/retrieve.rs b/plugin/rt/src/retrieve.rs new file mode 100644 index 0000000000..823e974f54 --- /dev/null +++ b/plugin/rt/src/retrieve.rs @@ -0,0 +1,35 @@ +use plugin_api::{Health, RetrieveError}; + +use crate::api::{Retrieve, RetrieveResult}; + +pub trait GetPlayerName { + fn get_player_name(&self) -> Result; +} + +pub trait GetEntityHealth { + fn get_entity_health(&self) -> Result; +} + +impl GetEntityHealth for crate::api::event::Player { + fn get_entity_health(&self) -> Result { + if let RetrieveResult::GetEntityHealth(e) = + crate::retrieve_action(&Retrieve::GetEntityHealth(self.id))? + { + Ok(e) + } else { + Err(RetrieveError::InvalidType) + } + } +} + +impl GetPlayerName for crate::api::event::Player { + fn get_player_name(&self) -> Result { + if let RetrieveResult::GetPlayerName(e) = + crate::retrieve_action(&Retrieve::GetPlayerName(self.id))? + { + Ok(e) + } else { + Err(RetrieveError::InvalidType) + } + } +}