From 211ab0289797a09f8b53654132c6216ef94af716 Mon Sep 17 00:00:00 2001 From: Vincent Foulon Date: Tue, 30 Mar 2021 12:55:50 +0200 Subject: [PATCH] Use Behavior::CanTrade instead of Agent::trade_for_site + addressed comments --- common/src/comp/agent.rs | 11 ++--------- common/src/comp/behavior.rs | 23 ++++++++++++++--------- common/src/states/basic_summon.rs | 6 +++--- server/src/cmd.rs | 4 ++-- server/src/events/invite.rs | 9 +++++---- server/src/events/trade.rs | 12 +++++++++--- server/src/rtsim/tick.rs | 6 +++--- server/src/sys/agent.rs | 6 +++--- server/src/sys/terrain.rs | 14 +++++++++++--- world/src/index.rs | 20 ++++++++++++-------- 10 files changed, 64 insertions(+), 47 deletions(-) diff --git a/common/src/comp/agent.rs b/common/src/comp/agent.rs index 9de3e110f5..c908e02adb 100644 --- a/common/src/comp/agent.rs +++ b/common/src/comp/agent.rs @@ -2,7 +2,7 @@ use crate::{ comp::{humanoid, quadruped_low, quadruped_medium, quadruped_small, Body}, path::Chaser, rtsim::RtSimController, - trade::{PendingTrade, ReducedInventory, SiteId, SitePrices, TradeId, TradeResult}, + trade::{PendingTrade, ReducedInventory, SitePrices, TradeId, TradeResult}, uid::Uid, }; use specs::{Component, Entity as EcsEntity}; @@ -212,7 +212,6 @@ pub struct Agent { pub chaser: Chaser, /// Does the agent talk when e.g. hit by the player // TODO move speech patterns into a Behavior component - pub trade_for_site: Option, pub psyche: Psyche, pub inbox: VecDeque, pub action_timer: f32, @@ -233,15 +232,9 @@ impl Agent { } } - pub fn new( - patrol_origin: Option>, - trade_for_site: Option, - body: &Body, - no_flee: bool, - ) -> Self { + pub fn new(patrol_origin: Option>, body: &Body, no_flee: bool) -> Self { Agent { patrol_origin, - trade_for_site, psyche: if no_flee { Psyche { aggro: 1.0 } } else { diff --git a/common/src/comp/behavior.rs b/common/src/comp/behavior.rs index 524edcfe3f..9773181f2f 100644 --- a/common/src/comp/behavior.rs +++ b/common/src/comp/behavior.rs @@ -2,7 +2,13 @@ use specs::Component; use specs_idvs::IdvStorage; use std::mem; -/// Behavior Component +use crate::trade::SiteId; + +/// # Behavior Component +/// This component allow an Entity to register one or more behavior tags. +/// These tags act as flags of what an Entity can do, or what it is doing. +/// Behaviors Tags can be added and removed as the Entity lives, to update its +/// state when needed #[derive(Default, Clone, Debug)] pub struct Behavior { tags: Vec, @@ -14,7 +20,7 @@ pub enum BehaviorTag { /// The entity is allowed to speak CanSpeak, /// The entity is able to trade - CanTrade, + CanTrade(Option), /// The entity is currently trading IsTrading, @@ -23,13 +29,10 @@ pub enum BehaviorTag { } impl Behavior { - pub fn new(can_speak: bool, can_trade: bool) -> Self { + pub fn new(behavior_tags: &[BehaviorTag]) -> Self { let mut behavior = Self::default(); - if can_speak { - behavior.add_tag(BehaviorTag::CanSpeak); - } - if can_trade { - behavior.add_tag(BehaviorTag::CanTrade); + for tag in behavior_tags.iter() { + behavior.add_tag(tag.clone()) } behavior } @@ -56,7 +59,9 @@ impl Behavior { /// Check if the Behavior possess a specific tag pub fn has_tag(&self, tag: &BehaviorTag) -> bool { - self.tags.iter().any(|behavior_tag| behavior_tag == tag) + self.tags + .iter() + .any(|behavior_tag| mem::discriminant(behavior_tag) == mem::discriminant(tag)) } /// Get a specific tag by variant diff --git a/common/src/states/basic_summon.rs b/common/src/states/basic_summon.rs index 7f2838e229..392b2a2242 100644 --- a/common/src/states/basic_summon.rs +++ b/common/src/states/basic_summon.rs @@ -2,7 +2,7 @@ use crate::{ comp::{ self, inventory::loadout_builder::{LoadoutBuilder, LoadoutConfig}, - Behavior, CharacterState, StateUpdate, + Behavior, BehaviorTag, CharacterState, StateUpdate, }, event::{LocalEvent, ServerEvent}, outcome::Outcome, @@ -104,8 +104,8 @@ impl CharacterBehavior for Data { poise: comp::Poise::new(body), loadout, body, - agent: Some(comp::Agent::new(None, None, &body, true)), - behavior: Some(Behavior::new(true, false)), + agent: Some(comp::Agent::new(None, &body, true)), + behavior: Some(Behavior::new(&[BehaviorTag::CanSpeak])), alignment: comp::Alignment::Owned(*data.uid), scale: self .static_data diff --git a/server/src/cmd.rs b/server/src/cmd.rs index 17119d471b..d0a733525c 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -15,7 +15,7 @@ use common::{ buff::{BuffCategory, BuffData, BuffKind, BuffSource}, inventory::item::MaterialStatManifest, invite::InviteKind, - ChatType, Inventory, Item, LightEmitter, WaypointArea, + BehaviorTag, ChatType, Inventory, Item, LightEmitter, WaypointArea, }, effect::Effect, event::{EventBus, ServerEvent}, @@ -1075,7 +1075,7 @@ fn handle_spawn_airship( }); if let Some(pos) = destination { builder = builder.with(comp::Agent::with_destination(pos)); - builder = builder.with(comp::Behavior::new(true, false)) + builder = builder.with(comp::Behavior::new(&[BehaviorTag::CanSpeak])) } builder.build(); diff --git a/server/src/events/invite.rs b/server/src/events/invite.rs index dd859c910e..caac3d3adc 100644 --- a/server/src/events/invite.rs +++ b/server/src/events/invite.rs @@ -6,7 +6,7 @@ use common::{ agent::{Agent, AgentEvent}, group::GroupManager, invite::{Invite, InviteKind, InviteResponse, PendingInvites}, - ChatType, + Behavior, ChatType, }, trade::Trades, uid::Uid, @@ -167,6 +167,7 @@ pub fn handle_invite_accept(server: &mut Server, entity: specs::Entity) { let clients = state.ecs().read_storage::(); let uids = state.ecs().read_storage::(); let mut agents = state.ecs().write_storage::(); + let behaviors = state.ecs().read_storage::(); let mut invites = state.ecs().write_storage::(); if let Some((inviter, kind)) = invites.remove(entity).and_then(|invite| { let Invite { inviter, kind } = invite; @@ -223,10 +224,10 @@ pub fn handle_invite_accept(server: &mut Server, entity: specs::Entity) { .inbox .push_front(AgentEvent::TradeAccepted(invitee_uid)); } - let pricing = agents + let pricing = behaviors .get(inviter) - .and_then(|a| index.get_site_prices(a)) - .or_else(|| agents.get(entity).and_then(|a| index.get_site_prices(a))); + .and_then(|b| index.get_site_prices(b)) + .or_else(|| behaviors.get(entity).and_then(|b| index.get_site_prices(b))); clients.get(inviter).map(|c| { c.send(ServerGeneral::UpdatePendingTrade( id, diff --git a/server/src/events/trade.rs b/server/src/events/trade.rs index ae39974cc6..ade0e6e3e6 100644 --- a/server/src/events/trade.rs +++ b/server/src/events/trade.rs @@ -3,6 +3,7 @@ use common::{ comp::{ agent::{Agent, AgentEvent}, inventory::{item::MaterialStatManifest, Inventory}, + Behavior, }, trade::{PendingTrade, ReducedInventory, TradeAction, TradeId, TradeResult, Trades}, }; @@ -28,12 +29,13 @@ fn notify_agent_simple( fn notify_agent_prices( mut agents: specs::WriteStorage, + behaviors: specs::ReadStorage, index: &IndexOwned, entity: EcsEntity, event: AgentEvent, ) { - if let Some(agent) = agents.get_mut(entity) { - let prices = index.get_site_prices(agent); + if let (Some(agent), Some(behavior)) = (agents.get_mut(entity), behaviors.get(entity)) { + let prices = index.get_site_prices(behavior); if let AgentEvent::UpdatePendingTrade(boxval) = event { // Box<(tid, pend, _, inventories)>) = event { agent @@ -104,6 +106,7 @@ pub fn handle_process_trade_action( let mut inventories: [Option; 2] = [None, None]; let mut prices = None; let agents = server.state.ecs().read_storage::(); + let behaviors = server.state.ecs().read_storage::(); // sadly there is no map and collect on arrays for i in 0..2 { // parties.len()) { @@ -118,7 +121,9 @@ pub fn handle_process_trade_action( // Get price info from the first Agent in the trade (currently, an // Agent will never initiate a trade with another agent though) prices = prices.or_else(|| { - agents.get(e).and_then(|a| server.index.get_site_prices(a)) + behaviors + .get(e) + .and_then(|b| server.index.get_site_prices(b)) }); } } @@ -135,6 +140,7 @@ pub fn handle_process_trade_action( ); notify_agent_prices( server.state.ecs().write_storage::(), + server.state.ecs().read_storage::(), &server.index, e, AgentEvent::UpdatePendingTrade(Box::new(( diff --git a/server/src/rtsim/tick.rs b/server/src/rtsim/tick.rs index 35bad1bcae..3c8895e2fa 100644 --- a/server/src/rtsim/tick.rs +++ b/server/src/rtsim/tick.rs @@ -2,7 +2,7 @@ use super::*; use common::{ - comp::{self, inventory::loadout_builder::LoadoutBuilder, Behavior}, + comp::{self, inventory::loadout_builder::LoadoutBuilder, Behavior, BehaviorTag}, event::{EventBus, ServerEvent}, resources::{DeltaTime, Time}, terrain::TerrainGrid, @@ -103,9 +103,9 @@ impl<'a> System<'a> for Sys { .map(|e| e as f32) + Vec3::new(0.5, 0.5, body.flying_height()); let pos = comp::Pos(spawn_pos); - let agent = Some(comp::Agent::new(None, None, &body, false)); + let agent = Some(comp::Agent::new(None, &body, false)); let behavior = if matches!(body, comp::Body::Humanoid(_)) { - Some(Behavior::new(true, false)) + Some(Behavior::new(&[BehaviorTag::CanSpeak])) } else { None }; diff --git a/server/src/sys/agent.rs b/server/src/sys/agent.rs index 86554c1997..0aa03c3b87 100644 --- a/server/src/sys/agent.rs +++ b/server/src/sys/agent.rs @@ -935,7 +935,7 @@ impl<'a> AgentData<'a> { event_emitter.emit(ServerEvent::Chat( UnresolvedChatMsg::npc(*self.uid, msg), )); - } else if self.behavior.has_tag(&BehaviorTag::CanTrade) { + } else if self.behavior.has_tag(&BehaviorTag::CanTrade(None)) { let msg = "npc.speech.merchant_advertisement".to_string(); event_emitter.emit(ServerEvent::Chat( UnresolvedChatMsg::npc(*self.uid, msg), @@ -948,7 +948,7 @@ impl<'a> AgentData<'a> { } }, Subject::Trade => { - if self.behavior.has_tag(&BehaviorTag::CanTrade) { + if self.behavior.has_tag(&BehaviorTag::CanTrade(None)) { if !self.behavior.has_tag(&BehaviorTag::IsTrading) { controller.events.push(ControlEvent::InitiateInvite( by, @@ -1097,7 +1097,7 @@ impl<'a> AgentData<'a> { } }, Some(AgentEvent::TradeInvite(with)) => { - if self.behavior.has_tag(&BehaviorTag::CanTrade) { + if self.behavior.has_tag(&BehaviorTag::CanTrade(None)) { if !self.behavior.has_tag(&BehaviorTag::IsTrading) { // stand still and looking towards the trading player controller.actions.push(ControlAction::Stand); diff --git a/server/src/sys/terrain.rs b/server/src/sys/terrain.rs index e060bacd0e..9bee6fd9e8 100644 --- a/server/src/sys/terrain.rs +++ b/server/src/sys/terrain.rs @@ -2,7 +2,9 @@ use crate::{ chunk_generator::ChunkGenerator, client::Client, presence::Presence, rtsim::RtSim, Tick, }; use common::{ - comp::{self, bird_medium, inventory::loadout_builder::LoadoutConfig, Alignment, Pos}, + comp::{ + self, bird_medium, inventory::loadout_builder::LoadoutConfig, Alignment, BehaviorTag, Pos, + }, event::{EventBus, ServerEvent}, generation::get_npc_name, npc::NPC_NAMES, @@ -191,7 +193,6 @@ impl<'a> System<'a> for Sys { agent: if entity.has_agency { Some(comp::Agent::new( Some(entity.pos), - trade_for_site, &body, matches!( loadout_config, @@ -202,7 +203,14 @@ impl<'a> System<'a> for Sys { None }, behavior: if entity.has_agency { - Some(comp::Behavior::new(can_speak, trade_for_site.is_some())) + let mut behavior_tags = vec![]; + if can_speak { + behavior_tags.push(BehaviorTag::CanSpeak); + } + if trade_for_site.is_some() { + behavior_tags.push(BehaviorTag::CanTrade(trade_for_site)); + } + Some(comp::Behavior::new(&behavior_tags)) } else { None }, diff --git a/world/src/index.rs b/world/src/index.rs index feaef98cf0..ec5bc51e9f 100644 --- a/world/src/index.rs +++ b/world/src/index.rs @@ -4,7 +4,7 @@ use crate::{ }; use common::{ assets::{AssetExt, AssetHandle}, - comp::Agent, + comp::{Behavior, BehaviorTag}, store::Store, trade::SitePrices, }; @@ -72,13 +72,17 @@ impl Index { pub fn colors(&self) -> AssetHandle> { self.colors } - pub fn get_site_prices(&self, agent: &Agent) -> Option { - agent - .trade_for_site - .map(|i| self.sites.recreate_id(i)) - .flatten() - .map(|i| self.sites.get(i)) - .map(|s| s.economy.get_site_prices()) + pub fn get_site_prices(&self, behavior: &Behavior) -> Option { + if let Some(BehaviorTag::CanTrade(site_id)) = behavior.get_tag(BehaviorTag::CanTrade(None)) + { + site_id + .map(|i| self.sites.recreate_id(i)) + .flatten() + .map(|i| self.sites.get(i)) + .map(|s| s.economy.get_site_prices()) + } else { + None + } } }