Finalized Retrieve API

This commit is contained in:
ccgauche 2021-02-17 14:03:20 +01:00 committed by Marcel Märtens
parent 06aa7ab70c
commit 267e7d8b4c
18 changed files with 405 additions and 149 deletions

1
Cargo.lock generated
View File

@ -5698,6 +5698,7 @@ dependencies = [
name = "veloren-plugin-api"
version = "0.1.0"
dependencies = [
"bincode",
"serde",
"veloren-common",
]

Binary file not shown.

BIN
assets/plugins/plugin1.plugin.tar (Stored with Git LFS)

Binary file not shown.

View File

@ -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<AttackDamage>,
@ -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<CombatEffect>,
}
#[cfg(not(target_arch = "wasm32"))]
impl AttackDamage {
pub fn new(damage: Damage, target: Option<GroupTarget>) -> Self {
Self {
@ -318,6 +333,7 @@ impl AttackDamage {
}
}
#[cfg(not(target_arch = "wasm32"))]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AttackEffect {
target: Option<GroupTarget>,
@ -325,6 +341,7 @@ pub struct AttackEffect {
requirement: Option<CombatRequirement>,
}
#[cfg(not(target_arch = "wasm32"))]
impl AttackEffect {
pub fn new(target: Option<GroupTarget>, 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<f32> {
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<Uid>, 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<ToolKind>, Option<ToolKind>) {
(
equipped_item_and_tool(inv, EquipSlot::Mainhand).map(|(_, tool)| tool.kind),
@ -623,6 +653,7 @@ pub fn get_weapons(inv: &Inventory) -> (Option<ToolKind>, Option<ToolKind>) {
)
}
#[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;

View File

@ -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<Duration>,
}
#[cfg(not(target_arch = "wasm32"))]
impl BuffData {
pub fn new(strength: f32, duration: Option<Duration>) -> 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<Ordering> {
if self == other {
@ -218,10 +233,12 @@ impl PartialOrd for Buff {
}
}
#[cfg(not(target_arch = "wasm32"))]
fn compare_duration(a: Option<Duration>, b: Option<Duration>) -> 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<BuffId, Buff>,
}
#[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<Self, IdvStorage<Self>>;
}

View File

@ -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<Body>, 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<Self, IdvStorage<Self>>;
}
@ -140,6 +156,7 @@ pub struct Dead {
pub cause: HealthSource,
}
#[cfg(not(target_arch = "wasm32"))]
impl Component for Dead {
type Storage = IdvStorage<Self>;
}

View File

@ -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},
};

View File

@ -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"))]

View File

@ -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<T>(&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

View File

@ -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::<UidAllocator>());
println!("HOST DEBUG 5 {:?}",&*world.read_resource::<UidAllocator>());
let player = world.read_resource::<UidAllocator>().retrieve_entity_internal(e.0).expect("Invalid uid");
println!("HOST DEBUG 6");
format!("{:?}",world.read_component::<Player>().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<RetrieveResult, RetrieveError> {
match action {
Retrieve::GetPlayerName(e) => {
let world = ecs.get().ok_or(RetrieveError::EcsAccessError(
EcsAccessError::EcsPointerNotAvailable,
))?;
let player = world
.read_resource::<UidAllocator>()
.retrieve_entity_internal(e.0)
.ok_or(RetrieveError::EcsAccessError(
EcsAccessError::EcsEntityNotFound(e),
))?;
Ok(RetrieveResult::GetPlayerName(
world
.read_component::<Player>()
.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::<UidAllocator>()
.retrieve_entity_internal(e.0)
.ok_or(RetrieveError::EcsAccessError(
EcsAccessError::EcsEntityNotFound(e),
))?;
Ok(RetrieveResult::GetEntityHealth(
*world
.read_component::<Health>()
.get(player)
.ok_or_else(|| {
RetrieveError::EcsAccessError(EcsAccessError::EcsComponentNotFound(
e,
"Health".to_owned(),
))
})?,
))
},
}
}
fn handle_actions(actions: Vec<Action>) {
for action in actions {
match action {

View File

@ -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<EcsAccessManager>, /* This represent the pointer to the ECS object (set to i32::MAX if
* to ECS is availible) */
pub ecs: Arc<EcsAccessManager>, /* This represent the pointer to the ECS object (set to
* i32::MAX if to ECS is
* availible) */
pub memory: LazyInit<Memory>, // This object represent the WASM Memory
pub allocator: LazyInit<Function>, // Linked to: wasm_prepare_buffer
pub memory_manager: Arc<MemoryManager>, /* 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<EcsAccessManager>, memory_manager: Arc<MemoryManager>) -> Self {
pub fn new(
name: String,
ecs: Arc<EcsAccessManager>,
memory_manager: Arc<MemoryManager>,
) -> Self {
Self {
memory_manager,
ecs,

View File

@ -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"

71
plugin/api/src/errors.rs Normal file
View File

@ -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)
},
}
}
}

View File

@ -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 {

View File

@ -15,8 +15,17 @@ pub fn on_load(load: PluginLoadEvent) {
#[event_handler]
pub fn on_command_testplugin(command: ChatCommandEvent) -> Result<Vec<String>, 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
)])
}

View File

@ -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<T: DeserializeOwned>(_actions: &api::Retreive) -> Result<T,bincode::Error> {
pub fn retrieve_action<T: DeserializeOwned>(_actions: &api::Retrieve) -> Result<T, RetrieveError> {
#[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::<Result<T, RetrieveError>>(&a)
.map_err(|x| RetrieveError::BincodeError(x.to_string()))?
}
}
#[cfg(not(target_arch = "wasm32"))]

View File

@ -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")
}
}

35
plugin/rt/src/retrieve.rs Normal file
View File

@ -0,0 +1,35 @@
use plugin_api::{Health, RetrieveError};
use crate::api::{Retrieve, RetrieveResult};
pub trait GetPlayerName {
fn get_player_name(&self) -> Result<String, RetrieveError>;
}
pub trait GetEntityHealth {
fn get_entity_health(&self) -> Result<Health, RetrieveError>;
}
impl GetEntityHealth for crate::api::event::Player {
fn get_entity_health(&self) -> Result<Health, RetrieveError> {
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<String, RetrieveError> {
if let RetrieveResult::GetPlayerName(e) =
crate::retrieve_action(&Retrieve::GetPlayerName(self.id))?
{
Ok(e)
} else {
Err(RetrieveError::InvalidType)
}
}
}