mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Initial WIP implementation of the Buff system
This commit is contained in:
parent
32d707e57f
commit
7ab99a3bbf
155
common/src/comp/buff.rs
Normal file
155
common/src/comp/buff.rs
Normal file
@ -0,0 +1,155 @@
|
||||
use crate::sync::Uid;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::{Component, FlaggedStorage};
|
||||
use specs_idvs::IdvStorage;
|
||||
use std::time::Duration;
|
||||
|
||||
/// De/buff ID.
|
||||
/// ID can be independant of an actual type/config of a `BuffData`.
|
||||
/// Therefore, information provided by `BuffId` can be incomplete/incorrect.
|
||||
///
|
||||
/// For example, there could be two regeneration buffs, each with
|
||||
/// different strength, but they could use the same `BuffId`,
|
||||
/// making it harder to recognize which is which.
|
||||
///
|
||||
/// Also, this should be dehardcoded eventually.
|
||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||
pub enum BuffId {
|
||||
/// Restores health/time for some period
|
||||
Regeneration,
|
||||
/// Lowers health/time for some period, but faster
|
||||
Poison,
|
||||
/// Changes entity name as to "Cursed {}"
|
||||
Cursed,
|
||||
}
|
||||
|
||||
/// De/buff category ID.
|
||||
/// Similar to `BuffId`, but to mark a category (for more generic usage, like
|
||||
/// positive/negative buffs).
|
||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||
pub enum BuffCategoryId {
|
||||
Natural,
|
||||
Magical,
|
||||
Divine,
|
||||
Negative,
|
||||
Positive,
|
||||
}
|
||||
|
||||
/// Data indicating and configuring behaviour of a de/buff.
|
||||
///
|
||||
/// NOTE: Contents of this enum are WIP/Placeholder
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum BuffData {
|
||||
/// Periodically damages health
|
||||
RepeatedHealthChange { speed: f32, accumulated: f32 },
|
||||
/// Changes name on_add/on_remove
|
||||
NameChange { prefix: String },
|
||||
}
|
||||
|
||||
/// Actual de/buff.
|
||||
/// Buff can timeout after some time if `time` is Some. If `time` is None,
|
||||
/// Buff will last indefinitely, until removed manually (by some action, like
|
||||
/// uncursing). The `time` field might be moved into the `Buffs` component
|
||||
/// (so that `Buff` does not own this information).
|
||||
///
|
||||
/// Buff has an id and data, which can be independent on each other.
|
||||
/// This makes it hard to create buff stacking "helpers", as the system
|
||||
/// does not assume that the same id is always the same behaviour (data).
|
||||
/// Therefore id=behaviour relationship has to be enforced elsewhere (if
|
||||
/// desired).
|
||||
///
|
||||
/// To provide more classification info when needed,
|
||||
/// buff can be in one or more buff category.
|
||||
///
|
||||
/// `data` is separate, to make this system more flexible
|
||||
/// (at the cost of the fact that id=behaviour relationship might not apply).
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Buff {
|
||||
pub id: BuffId,
|
||||
pub cat_ids: Vec<BuffCategoryId>,
|
||||
pub time: Option<Duration>,
|
||||
pub data: BuffData,
|
||||
}
|
||||
|
||||
/// Information about whether buff addition or removal was requested.
|
||||
/// This to implement "on_add" and "on_remove" hooks for constant buffs.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum BuffChange {
|
||||
/// Adds this buff.
|
||||
Add(Buff),
|
||||
/// Removes all buffs with this ID.
|
||||
/// TODO: Better removal, allowing to specify which ability to remove
|
||||
/// directly.
|
||||
Remove(BuffId),
|
||||
}
|
||||
|
||||
/// Source of the de/buff
|
||||
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
|
||||
pub enum BuffSource {
|
||||
/// Applied by a character
|
||||
Character { by: Uid },
|
||||
/// Applied by world, like a poisonous fumes from a swamp
|
||||
World,
|
||||
/// Applied by command
|
||||
Command,
|
||||
/// Applied by an item
|
||||
Item,
|
||||
/// Applied by another buff (like an after-effect)
|
||||
Buff,
|
||||
/// Some other source
|
||||
Unknown,
|
||||
}
|
||||
|
||||
/// Component holding all de/buffs that gets resolved each tick.
|
||||
/// On each tick, remaining time of buffs get lowered and
|
||||
/// buff effect of each buff is applied or not, depending on the `BuffData`
|
||||
/// (specs system will decide based on `BuffData`, to simplify implementation).
|
||||
/// TODO: Something like `once` flag for `Buff` to remove the dependence on
|
||||
/// `BuffData` enum?
|
||||
///
|
||||
/// In case of one-time buffs, buff effects will be applied on addition
|
||||
/// 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).
|
||||
///
|
||||
/// TODO: Make this net/sync-friendly. Events could help there
|
||||
/// (probably replacing `changes`). Also, the "buff ticking" is really
|
||||
/// not needed to be synced often, only in case that a buff begins/ends
|
||||
/// (as the buff ECS system will probably run on a client too).
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
|
||||
pub struct Buffs {
|
||||
/// Active de/buffs.
|
||||
pub buffs: Vec<Buff>,
|
||||
/// Request to add/remove a buff.
|
||||
/// Used for reacting on buff changes by the ECS system.
|
||||
/// TODO: Can be `EventBus<T>` used instead of this?
|
||||
pub changes: Vec<BuffChange>,
|
||||
/// Last time since any buff change to limit syncing.
|
||||
pub last_change: f64,
|
||||
}
|
||||
|
||||
impl Buffs {
|
||||
/// Adds a request for adding given `buff`.
|
||||
pub fn add_buff(&mut self, buff: Buff) {
|
||||
let change = BuffChange::Add(buff);
|
||||
self.changes.push(change);
|
||||
self.last_change = 0.0;
|
||||
}
|
||||
|
||||
/// Adds a request for removal of all buffs with given Id.
|
||||
/// TODO: Better removal, allowing to specify which ability to remove
|
||||
/// directly.
|
||||
pub fn remove_buff_by_id(&mut self, id: BuffId) {
|
||||
let change = BuffChange::Remove(id);
|
||||
self.changes.push(change);
|
||||
self.last_change = 0.0;
|
||||
}
|
||||
|
||||
/// This is a primitive check if a specific buff is present.
|
||||
/// (for purposes like blocking usage of abilities or something like this).
|
||||
pub fn has_buff_id(&self, id: &BuffId) -> bool { self.buffs.iter().any(|buff| buff.id == *id) }
|
||||
}
|
||||
|
||||
impl Component for Buffs {
|
||||
type Storage = FlaggedStorage<Self, IdvStorage<Self>>;
|
||||
}
|
@ -3,6 +3,7 @@ mod admin;
|
||||
pub mod agent;
|
||||
pub mod beam;
|
||||
pub mod body;
|
||||
mod buff;
|
||||
mod character_state;
|
||||
pub mod chat;
|
||||
mod controller;
|
||||
@ -31,6 +32,7 @@ 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, BuffCategoryId, BuffChange, BuffData, BuffId, Buffs};
|
||||
pub use character_state::{Attacking, CharacterState, StateUpdate};
|
||||
pub use chat::{
|
||||
ChatMode, ChatMsg, ChatType, Faction, SpeechBubble, SpeechBubbleType, UnresolvedChatMsg,
|
||||
|
@ -13,6 +13,7 @@ sum_type! {
|
||||
Player(comp::Player),
|
||||
CanBuild(comp::CanBuild),
|
||||
Stats(comp::Stats),
|
||||
Buffs(comp::Buffs),
|
||||
Energy(comp::Energy),
|
||||
LightEmitter(comp::LightEmitter),
|
||||
Item(comp::Item),
|
||||
@ -42,6 +43,7 @@ sum_type! {
|
||||
Player(PhantomData<comp::Player>),
|
||||
CanBuild(PhantomData<comp::CanBuild>),
|
||||
Stats(PhantomData<comp::Stats>),
|
||||
Buffs(PhantomData<comp::Buffs>),
|
||||
Energy(PhantomData<comp::Energy>),
|
||||
LightEmitter(PhantomData<comp::LightEmitter>),
|
||||
Item(PhantomData<comp::Item>),
|
||||
@ -71,6 +73,7 @@ impl sync::CompPacket for EcsCompPacket {
|
||||
EcsCompPacket::Player(comp) => sync::handle_insert(comp, entity, world),
|
||||
EcsCompPacket::CanBuild(comp) => sync::handle_insert(comp, entity, world),
|
||||
EcsCompPacket::Stats(comp) => sync::handle_insert(comp, entity, world),
|
||||
EcsCompPacket::Buffs(comp) => sync::handle_insert(comp, entity, world),
|
||||
EcsCompPacket::Energy(comp) => sync::handle_insert(comp, entity, world),
|
||||
EcsCompPacket::LightEmitter(comp) => sync::handle_insert(comp, entity, world),
|
||||
EcsCompPacket::Item(comp) => sync::handle_insert(comp, entity, world),
|
||||
@ -98,6 +101,7 @@ impl sync::CompPacket for EcsCompPacket {
|
||||
EcsCompPacket::Player(comp) => sync::handle_modify(comp, entity, world),
|
||||
EcsCompPacket::CanBuild(comp) => sync::handle_modify(comp, entity, world),
|
||||
EcsCompPacket::Stats(comp) => sync::handle_modify(comp, entity, world),
|
||||
EcsCompPacket::Buffs(comp) => sync::handle_modify(comp, entity, world),
|
||||
EcsCompPacket::Energy(comp) => sync::handle_modify(comp, entity, world),
|
||||
EcsCompPacket::LightEmitter(comp) => sync::handle_modify(comp, entity, world),
|
||||
EcsCompPacket::Item(comp) => sync::handle_modify(comp, entity, world),
|
||||
@ -125,6 +129,7 @@ impl sync::CompPacket for EcsCompPacket {
|
||||
EcsCompPhantom::Player(_) => sync::handle_remove::<comp::Player>(entity, world),
|
||||
EcsCompPhantom::CanBuild(_) => sync::handle_remove::<comp::CanBuild>(entity, world),
|
||||
EcsCompPhantom::Stats(_) => sync::handle_remove::<comp::Stats>(entity, world),
|
||||
EcsCompPhantom::Buffs(_) => sync::handle_remove::<comp::Buffs>(entity, world),
|
||||
EcsCompPhantom::Energy(_) => sync::handle_remove::<comp::Energy>(entity, world),
|
||||
EcsCompPhantom::LightEmitter(_) => {
|
||||
sync::handle_remove::<comp::LightEmitter>(entity, world)
|
||||
|
@ -112,6 +112,7 @@ impl State {
|
||||
ecs.register::<comp::Body>();
|
||||
ecs.register::<comp::Player>();
|
||||
ecs.register::<comp::Stats>();
|
||||
ecs.register::<comp::Buffs>();
|
||||
ecs.register::<comp::Energy>();
|
||||
ecs.register::<comp::CanBuild>();
|
||||
ecs.register::<comp::LightEmitter>();
|
||||
|
130
common/src/sys/buff.rs
Normal file
130
common/src/sys/buff.rs
Normal file
@ -0,0 +1,130 @@
|
||||
use crate::{
|
||||
comp::{BuffChange, BuffData, BuffId, Buffs, HealthChange, HealthSource, Stats},
|
||||
state::DeltaTime,
|
||||
};
|
||||
use specs::{Entities, Join, Read, System, WriteStorage};
|
||||
use std::time::Duration;
|
||||
|
||||
/// This system modifies entity stats, changing them using buffs
|
||||
/// Currently, the system is VERY, VERY CRUDE and SYNC UN-FRIENDLY.
|
||||
/// It does not use events and uses `Vec`s stored in component.
|
||||
///
|
||||
/// TODO: Make this production-quality system/design
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)]
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
Read<'a, DeltaTime>,
|
||||
WriteStorage<'a, Stats>,
|
||||
WriteStorage<'a, Buffs>,
|
||||
);
|
||||
|
||||
fn run(&mut self, (entities, dt, mut stats, mut buffs): Self::SystemData) {
|
||||
// Increment last change timer
|
||||
buffs.set_event_emission(false);
|
||||
for buff in (&mut buffs).join() {
|
||||
buff.last_change += f64::from(dt.0);
|
||||
}
|
||||
buffs.set_event_emission(true);
|
||||
|
||||
for (entity, mut buffs) in (&entities, &mut buffs.restrict_mut()).join() {
|
||||
let buff_comp = buffs.get_mut_unchecked();
|
||||
// Add/Remove de/buffs
|
||||
// While adding/removing buffs, it could call respective hooks
|
||||
// Currently, it is done based on enum variant
|
||||
let changes = buff_comp.changes.drain(0..buff_comp.changes.len());
|
||||
for change in changes {
|
||||
match change {
|
||||
// Hooks for on_add could be here
|
||||
BuffChange::Add(new_buff) => {
|
||||
match &new_buff.data {
|
||||
BuffData::NameChange { prefix } => {
|
||||
if let Some(stats) = stats.get_mut(entity) {
|
||||
let mut pref = String::from(prefix);
|
||||
pref.push_str(&stats.name);
|
||||
stats.name = pref;
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
buff_comp.buffs.push(new_buff.clone());
|
||||
},
|
||||
// Hooks for on_remove could be here
|
||||
BuffChange::Remove(id) => {
|
||||
let some_predicate = |current_id: &BuffId| *current_id == id;
|
||||
let mut i = 0;
|
||||
while i != buff_comp.buffs.len() {
|
||||
if some_predicate(&mut buff_comp.buffs[i].id) {
|
||||
let buff = buff_comp.buffs.remove(i);
|
||||
match &buff.data {
|
||||
BuffData::NameChange { prefix } => {
|
||||
if let Some(stats) = stats.get_mut(entity) {
|
||||
stats.name = stats.name.replace(prefix, "");
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
let mut buffs_for_removal = Vec::new();
|
||||
// Tick all de/buffs on a Buffs component.
|
||||
for active_buff in &mut buff_comp.buffs {
|
||||
// First, tick the buff and subtract delta from it
|
||||
// and return how much "real" time the buff took (for tick independence).
|
||||
// TODO: handle delta for "indefinite" buffs, i.e. time since they got removed.
|
||||
let buff_delta = if let Some(remaining_time) = &mut active_buff.time {
|
||||
let pre_tick = remaining_time.as_secs_f32();
|
||||
let new_duration = remaining_time.checked_sub(Duration::from_secs_f32(dt.0));
|
||||
let post_tick = if let Some(dur) = new_duration {
|
||||
// The buff still continues.
|
||||
*remaining_time -= Duration::from_secs_f32(dt.0);
|
||||
dur.as_secs_f32()
|
||||
} else {
|
||||
// The buff has expired.
|
||||
// Mark it for removal.
|
||||
// TODO: This removes by ID! better method required
|
||||
buffs_for_removal.push(active_buff.id.clone());
|
||||
0.0
|
||||
};
|
||||
pre_tick - post_tick
|
||||
} else {
|
||||
// The buff is indefinite, and it takes full tick (delta).
|
||||
// TODO: Delta for indefinite buffs might be shorter since they can get removed
|
||||
// *during a tick* and this treats it as it always happens on a *tick end*.
|
||||
dt.0
|
||||
};
|
||||
|
||||
// Now, execute the buff, based on it's delta
|
||||
match &mut active_buff.data {
|
||||
BuffData::RepeatedHealthChange { speed, accumulated } => {
|
||||
*accumulated += *speed * buff_delta;
|
||||
// Apply only 0.5 or higher damage
|
||||
if accumulated.abs() > 5.0 {
|
||||
if let Some(stats) = stats.get_mut(entity) {
|
||||
let change = HealthChange {
|
||||
amount: *accumulated as i32,
|
||||
cause: HealthSource::Unknown,
|
||||
};
|
||||
stats.health.change_by(change);
|
||||
}
|
||||
*accumulated = 0.0;
|
||||
};
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
}
|
||||
// Truly mark expired buffs for removal.
|
||||
// TODO: Review this, as it is ugly.
|
||||
for to_remove in buffs_for_removal {
|
||||
buff_comp.remove_buff_by_id(to_remove);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
pub mod agent;
|
||||
mod beam;
|
||||
mod buff;
|
||||
pub mod character_behavior;
|
||||
pub mod combat;
|
||||
pub mod controller;
|
||||
@ -23,6 +24,7 @@ pub const PHYS_SYS: &str = "phys_sys";
|
||||
pub const PROJECTILE_SYS: &str = "projectile_sys";
|
||||
pub const SHOCKWAVE_SYS: &str = "shockwave_sys";
|
||||
pub const STATS_SYS: &str = "stats_sys";
|
||||
pub const BUFFS_SYS: &str = "buffs_sys";
|
||||
|
||||
pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) {
|
||||
dispatch_builder.add(agent::Sys, AGENT_SYS, &[]);
|
||||
@ -32,6 +34,7 @@ pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) {
|
||||
CONTROLLER_SYS,
|
||||
]);
|
||||
dispatch_builder.add(stats::Sys, STATS_SYS, &[]);
|
||||
dispatch_builder.add(buff::Sys, BUFFS_SYS, &[]);
|
||||
dispatch_builder.add(phys::Sys, PHYS_SYS, &[CONTROLLER_SYS, MOUNT_SYS, STATS_SYS]);
|
||||
dispatch_builder.add(projectile::Sys, PROJECTILE_SYS, &[PHYS_SYS]);
|
||||
dispatch_builder.add(shockwave::Sys, SHOCKWAVE_SYS, &[PHYS_SYS]);
|
||||
|
@ -93,6 +93,39 @@ impl StateExt for State {
|
||||
loadout: comp::Loadout,
|
||||
body: comp::Body,
|
||||
) -> EcsEntityBuilder {
|
||||
// NOTE: This is placeholder code for testing and does not
|
||||
// belongs here really
|
||||
let mut buffs = comp::Buffs::default();
|
||||
// Damages slightly each NPC spawned for 20 seconds
|
||||
buffs.add_buff(comp::Buff {
|
||||
id: comp::BuffId::Poison,
|
||||
cat_ids: vec![],
|
||||
time: Some(std::time::Duration::from_secs(20)),
|
||||
data: comp::BuffData::RepeatedHealthChange {
|
||||
speed: -10.0,
|
||||
accumulated: 0.0,
|
||||
},
|
||||
});
|
||||
// Prepends "Cursed " to each NPC's name for 35 secs
|
||||
buffs.add_buff(comp::Buff {
|
||||
id: comp::BuffId::Cursed,
|
||||
cat_ids: vec![],
|
||||
time: Some(std::time::Duration::from_secs(35)),
|
||||
data: comp::BuffData::NameChange {
|
||||
prefix: String::from("Cursed "),
|
||||
},
|
||||
});
|
||||
// Adds super-slow regen to each NPC spawned, indefinitely
|
||||
buffs.add_buff(comp::Buff {
|
||||
id: comp::BuffId::Regeneration,
|
||||
cat_ids: vec![],
|
||||
time: None,
|
||||
data: comp::BuffData::RepeatedHealthChange {
|
||||
speed: 1.0,
|
||||
accumulated: 0.0,
|
||||
},
|
||||
});
|
||||
|
||||
self.ecs_mut()
|
||||
.create_entity_synced()
|
||||
.with(pos)
|
||||
@ -111,6 +144,7 @@ impl StateExt for State {
|
||||
.with(comp::Gravity(1.0))
|
||||
.with(comp::CharacterState::default())
|
||||
.with(loadout)
|
||||
.with(buffs)
|
||||
}
|
||||
|
||||
fn create_object(&mut self, pos: comp::Pos, object: comp::object::Body) -> EcsEntityBuilder {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::SysTimer;
|
||||
use common::{
|
||||
comp::{
|
||||
BeamSegment, Body, CanBuild, CharacterState, Collider, Energy, Gravity, Group, Item,
|
||||
BeamSegment, Body, Buffs, CanBuild, CharacterState, Collider, Energy, Gravity, Group, Item,
|
||||
LightEmitter, Loadout, Mass, MountState, Mounting, Ori, Player, Pos, Scale, Shockwave,
|
||||
Stats, Sticky, Vel,
|
||||
},
|
||||
@ -44,6 +44,7 @@ pub struct TrackedComps<'a> {
|
||||
pub body: ReadStorage<'a, Body>,
|
||||
pub player: ReadStorage<'a, Player>,
|
||||
pub stats: ReadStorage<'a, Stats>,
|
||||
pub buffs: ReadStorage<'a, Buffs>,
|
||||
pub energy: ReadStorage<'a, Energy>,
|
||||
pub can_build: ReadStorage<'a, CanBuild>,
|
||||
pub light_emitter: ReadStorage<'a, LightEmitter>,
|
||||
@ -85,6 +86,10 @@ impl<'a> TrackedComps<'a> {
|
||||
.get(entity)
|
||||
.cloned()
|
||||
.map(|c| comps.push(c.into()));
|
||||
self.buffs
|
||||
.get(entity)
|
||||
.cloned()
|
||||
.map(|c| comps.push(c.into()));
|
||||
self.energy
|
||||
.get(entity)
|
||||
.cloned()
|
||||
@ -157,6 +162,7 @@ pub struct ReadTrackers<'a> {
|
||||
pub body: ReadExpect<'a, UpdateTracker<Body>>,
|
||||
pub player: ReadExpect<'a, UpdateTracker<Player>>,
|
||||
pub stats: ReadExpect<'a, UpdateTracker<Stats>>,
|
||||
pub buffs: ReadExpect<'a, UpdateTracker<Buffs>>,
|
||||
pub energy: ReadExpect<'a, UpdateTracker<Energy>>,
|
||||
pub can_build: ReadExpect<'a, UpdateTracker<CanBuild>>,
|
||||
pub light_emitter: ReadExpect<'a, UpdateTracker<LightEmitter>>,
|
||||
@ -187,6 +193,7 @@ impl<'a> ReadTrackers<'a> {
|
||||
.with_component(&comps.uid, &*self.body, &comps.body, filter)
|
||||
.with_component(&comps.uid, &*self.player, &comps.player, filter)
|
||||
.with_component(&comps.uid, &*self.stats, &comps.stats, filter)
|
||||
.with_component(&comps.uid, &*self.buffs, &comps.buffs, filter)
|
||||
.with_component(&comps.uid, &*self.energy, &comps.energy, filter)
|
||||
.with_component(&comps.uid, &*self.can_build, &comps.can_build, filter)
|
||||
.with_component(
|
||||
@ -224,6 +231,7 @@ pub struct WriteTrackers<'a> {
|
||||
body: WriteExpect<'a, UpdateTracker<Body>>,
|
||||
player: WriteExpect<'a, UpdateTracker<Player>>,
|
||||
stats: WriteExpect<'a, UpdateTracker<Stats>>,
|
||||
buffs: WriteExpect<'a, UpdateTracker<Buffs>>,
|
||||
energy: WriteExpect<'a, UpdateTracker<Energy>>,
|
||||
can_build: WriteExpect<'a, UpdateTracker<CanBuild>>,
|
||||
light_emitter: WriteExpect<'a, UpdateTracker<LightEmitter>>,
|
||||
@ -248,6 +256,7 @@ fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) {
|
||||
trackers.body.record_changes(&comps.body);
|
||||
trackers.player.record_changes(&comps.player);
|
||||
trackers.stats.record_changes(&comps.stats);
|
||||
trackers.buffs.record_changes(&comps.buffs);
|
||||
trackers.energy.record_changes(&comps.energy);
|
||||
trackers.can_build.record_changes(&comps.can_build);
|
||||
trackers.light_emitter.record_changes(&comps.light_emitter);
|
||||
@ -283,6 +292,7 @@ fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) {
|
||||
};
|
||||
log_counts!(uid, "Uids");
|
||||
log_counts!(body, "Bodies");
|
||||
log_counts!(buffs, "Buffs");
|
||||
log_counts!(player, "Players");
|
||||
log_counts!(stats, "Stats");
|
||||
log_counts!(energy, "Energies");
|
||||
@ -307,6 +317,7 @@ pub fn register_trackers(world: &mut World) {
|
||||
world.register_tracker::<Body>();
|
||||
world.register_tracker::<Player>();
|
||||
world.register_tracker::<Stats>();
|
||||
world.register_tracker::<Buffs>();
|
||||
world.register_tracker::<Energy>();
|
||||
world.register_tracker::<CanBuild>();
|
||||
world.register_tracker::<LightEmitter>();
|
||||
|
Loading…
Reference in New Issue
Block a user