From 8a6a60d5bb9ba25a372ad9968b51e4d1bad733f7 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 9 Mar 2023 20:27:54 -0500 Subject: [PATCH] Buffs from auras no longer need to be mutably accessed every tick in aura system to prevent applying a buff every tick and ensure duration only starts after leaving aura --- common/src/comp/buff.rs | 20 ++++++++--- common/systems/src/aura.rs | 70 +++++++++++--------------------------- common/systems/src/buff.rs | 70 +++++++++++++++++++++++++++++++++++++- 3 files changed, 104 insertions(+), 56 deletions(-) diff --git a/common/src/comp/buff.rs b/common/src/comp/buff.rs index 720a7ad8bf..72024114b5 100644 --- a/common/src/comp/buff.rs +++ b/common/src/comp/buff.rs @@ -1,5 +1,9 @@ #![allow(clippy::nonstandard_macro_braces)] //tmp as of false positive !? -use crate::{comp::Stats, resources::Time, uid::Uid}; +use crate::{ + comp::{aura::AuraKey, Stats}, + resources::Time, + uid::Uid, +}; use core::cmp::Ordering; #[cfg(not(target_arch = "wasm32"))] use hashbrown::HashMap; @@ -168,7 +172,7 @@ pub enum BuffCategory { Magical, Divine, PersistOnDeath, - FromAura(bool), // bool used to check if buff recently set by aura + FromActiveAura(Uid, AuraKey), } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -285,7 +289,7 @@ impl Buff { }, BuffKind::Potion => { vec![BuffEffect::HealthChangeOverTime { - rate: data.strength * dbg!(stats.map_or(1.0, |s| s.heal_multiplier)), + rate: data.strength * stats.map_or(1.0, |s| s.heal_multiplier), kind: ModifierKind::Additive, instance, }] @@ -366,12 +370,20 @@ impl Buff { BuffKind::PotionSickness => vec![BuffEffect::HealReduction(data.strength)], }; let start_time = Time(time.0 + data.delay.unwrap_or(0.0)); + let end_time = if cat_ids + .iter() + .any(|cat_id| matches!(cat_id, BuffCategory::FromActiveAura(..))) + { + None + } else { + data.duration.map(|dur| Time(start_time.0 + dur)) + }; Buff { kind, data, cat_ids, start_time, - end_time: data.duration.map(|dur| Time(start_time.0 + dur)), + end_time, effects, source, } diff --git a/common/systems/src/aura.rs b/common/systems/src/aura.rs index 3e26646822..77f15f903e 100644 --- a/common/systems/src/aura.rs +++ b/common/systems/src/aura.rs @@ -33,45 +33,32 @@ pub struct ReadData<'a> { groups: ReadStorage<'a, Group>, uids: ReadStorage<'a, Uid>, stats: ReadStorage<'a, Stats>, + buffs: ReadStorage<'a, Buffs>, } #[derive(Default)] pub struct Sys; impl<'a> System<'a> for Sys { - type SystemData = ( - ReadData<'a>, - WriteStorage<'a, Auras>, - WriteStorage<'a, Buffs>, - ); + type SystemData = (ReadData<'a>, WriteStorage<'a, Auras>); const NAME: &'static str = "aura"; const ORIGIN: Origin = Origin::Common; const PHASE: Phase = Phase::Create; - fn run(_job: &mut Job, (read_data, mut auras, mut buffs): Self::SystemData) { + fn run(_job: &mut Job, (read_data, mut auras): Self::SystemData) { let mut server_emitter = read_data.server_bus.emitter(); let dt = read_data.dt.0; auras.set_event_emission(false); - buffs.set_event_emission(false); - - // Iterate through all buffs, on any buffs that are from an aura, sets the check - // for whether the buff recently set by aura to false - for (_, mut buffs_comp) in (&read_data.entities, &mut buffs).join() { - for (_, buff) in buffs_comp.buffs.iter_mut() { - if let Some(cat_id) = buff - .cat_ids - .iter_mut() - .find(|cat_id| matches!(cat_id, BuffCategory::FromAura(true))) - { - *cat_id = BuffCategory::FromAura(false); - } - } - } // Iterate through all entities with an aura - for (entity, pos, mut auras_comp) in - (&read_data.entities, &read_data.positions, &mut auras).join() + for (entity, pos, mut auras_comp, uid) in ( + &read_data.entities, + &read_data.positions, + &mut auras, + &read_data.uids, + ) + .join() { let mut expired_auras = Vec::::new(); // Iterate through the auras attached to this entity @@ -108,7 +95,7 @@ impl<'a> System<'a> for Sys { }) }); target_iter.for_each(|(target, target_pos, health, target_uid, stats)| { - let mut target_buffs = match buffs.get_mut(target) { + let target_buffs = match read_data.buffs.get(target) { Some(buff) => buff, None => return, }; @@ -135,10 +122,12 @@ impl<'a> System<'a> for Sys { if is_target { activate_aura( + key, aura, + *uid, target, health, - &mut target_buffs, + target_buffs, stats, &read_data, &mut server_emitter, @@ -155,17 +144,18 @@ impl<'a> System<'a> for Sys { } } auras.set_event_emission(true); - buffs.set_event_emission(true); } } #[warn(clippy::pedantic)] //#[warn(clippy::nursery)] fn activate_aura( + key: AuraKey, aura: &Aura, + applier: Uid, target: EcsEntity, health: &Health, - target_buffs: &mut Buffs, + target_buffs: &Buffs, stats: Option<&Stats>, read_data: &ReadData, server_emitter: &mut Emitter, @@ -247,13 +237,9 @@ fn activate_aura( let emit_buff = !target_buffs.buffs.iter().any(|(_, buff)| { buff.cat_ids .iter() - .any(|cat_id| matches!(cat_id, BuffCategory::FromAura(_))) + .any(|cat_id| matches!(cat_id, BuffCategory::FromActiveAura(uid, aura_key) if *aura_key == key && *uid == applier)) && buff.kind == kind && buff.data.strength >= data.strength - && buff.end_time.map_or(true, |end| { - data.duration - .map_or(false, |dur| end.0 >= read_data.time.0 + dur) - }) }); if emit_buff { server_emitter.emit(ServerEvent::Buff { @@ -261,31 +247,13 @@ fn activate_aura( buff_change: BuffChange::Add(Buff::new( kind, data, - vec![category, BuffCategory::FromAura(true)], + vec![category, BuffCategory::FromActiveAura(applier, key)], source, *read_data.time, stats, )), }); } - // Finds all buffs on target that are from an aura, are of - // the same buff kind, and are of at most the same strength. - // For any such buffs, marks it as recently applied. - for (_, buff) in target_buffs.buffs.iter_mut().filter(|(_, buff)| { - buff.cat_ids - .iter() - .any(|cat_id| matches!(cat_id, BuffCategory::FromAura(_))) - && buff.kind == kind - && buff.data.strength <= data.strength - }) { - if let Some(cat_id) = buff - .cat_ids - .iter_mut() - .find(|cat_id| matches!(cat_id, BuffCategory::FromAura(false))) - { - *cat_id = BuffCategory::FromAura(true); - } - } }, } } diff --git a/common/systems/src/buff.rs b/common/systems/src/buff.rs index aa3b38602f..13899c7f89 100644 --- a/common/systems/src/buff.rs +++ b/common/systems/src/buff.rs @@ -1,6 +1,7 @@ use common::{ combat::DamageContributor, comp::{ + aura::Auras, body::{object, Body}, buff::{ Buff, BuffCategory, BuffChange, BuffData, BuffEffect, BuffId, BuffKind, BuffSource, @@ -9,7 +10,7 @@ use common::{ fluid_dynamics::{Fluid, LiquidKind}, item::MaterialStatManifest, Energy, Group, Health, HealthChange, Inventory, LightEmitter, ModifierKind, PhysicsState, - Stats, + Pos, Stats, }, event::{Emitter, EventBus, ServerEvent}, resources::{DeltaTime, Time}, @@ -39,6 +40,8 @@ pub struct ReadData<'a> { time: Read<'a, Time>, msm: ReadExpect<'a, MaterialStatManifest>, buffs: ReadStorage<'a, Buffs>, + auras: ReadStorage<'a, Auras>, + positions: ReadStorage<'a, Pos>, } #[derive(Default)] @@ -233,6 +236,71 @@ impl<'a> System<'a> for Sys { } let mut expired_buffs = Vec::::new(); + + // Replace buffs from an active aura with a normal buff when out of range of the + // aura + buff_comp + .buffs + .iter() + .filter_map(|(id, buff)| { + if let Some((uid, aura_key)) = buff.cat_ids.iter().find_map(|cat_id| { + if let BuffCategory::FromActiveAura(uid, aura_key) = cat_id { + Some((uid, aura_key)) + } else { + None + } + }) { + Some((id, buff, uid, aura_key)) + } else { + None + } + }) + .for_each(|(buff_id, buff, uid, aura_key)| { + let replace = if let Some(aura_entity) = read_data + .uid_allocator + .retrieve_entity_internal((*uid).into()) + { + if let Some(aura) = read_data + .auras + .get(aura_entity) + .and_then(|auras| auras.auras.get(*aura_key)) + { + if let (Some(pos), Some(aura_pos)) = ( + read_data.positions.get(entity), + read_data.positions.get(aura_entity), + ) { + pos.0.distance_squared(aura_pos.0) > aura.radius.powi(2) + } else { + true + } + } else { + true + } + } else { + true + }; + if replace { + expired_buffs.push(*buff_id); + server_emitter.emit(ServerEvent::Buff { + entity, + buff_change: BuffChange::Add(Buff::new( + buff.kind, + buff.data, + buff.cat_ids + .iter() + .copied() + .filter(|cat_id| { + !matches!(cat_id, BuffCategory::FromActiveAura(..)) + }) + .collect::>(), + buff.source, + *read_data.time, + Some(&stat), + )), + }); + } + }); + buff_comp.buffs.iter().for_each(|(id, buff)| { if buff.end_time.map_or(false, |end| end.0 < read_data.time.0) { expired_buffs.push(*id)