use std::{collections::HashMap, hash::Hash};
use crate::connection::entity_priority::{EntityPriorityData, EntityPriorityMut, EntityPriorityRef};
use crate::world::entity::global_entity::GlobalEntity;
pub trait OutgoingPriorityHook {
fn advance(&mut self, entity: &GlobalEntity) -> f32;
fn reset_after_send(&mut self, entity: &GlobalEntity, current_tick: u32);
}
pub struct GlobalPriorityState<E: Copy + Eq + Hash> {
entries: HashMap<E, EntityPriorityData>,
}
impl<E: Copy + Eq + Hash> GlobalPriorityState<E> {
pub fn new() -> Self {
Self {
entries: HashMap::new(),
}
}
pub fn get_ref(&self, entity: E) -> EntityPriorityRef<'_, E> {
EntityPriorityRef {
state: self.entries.get(&entity),
entity,
}
}
pub fn get_mut(&mut self, entity: E) -> EntityPriorityMut<'_, E> {
EntityPriorityMut {
entries: &mut self.entries,
entity,
}
}
pub fn on_despawn(&mut self, entity: &E) {
self.entries.remove(entity);
}
pub fn gain_override(&self, entity: &E) -> Option<f32> {
self.entries.get(entity).and_then(|d| d.gain_override)
}
}
impl<E: Copy + Eq + Hash> Default for GlobalPriorityState<E> {
fn default() -> Self {
Self::new()
}
}
pub struct UserPriorityState<E: Copy + Eq + Hash> {
entries: HashMap<E, EntityPriorityData>,
}
impl<E: Copy + Eq + Hash> UserPriorityState<E> {
pub fn new() -> Self {
Self {
entries: HashMap::new(),
}
}
pub fn get_ref(&self, entity: E) -> EntityPriorityRef<'_, E> {
EntityPriorityRef {
state: self.entries.get(&entity),
entity,
}
}
pub fn get_mut(&mut self, entity: E) -> EntityPriorityMut<'_, E> {
EntityPriorityMut {
entries: &mut self.entries,
entity,
}
}
pub fn on_scope_exit(&mut self, entity: &E) {
self.entries.remove(entity);
}
pub fn gain_override(&self, entity: &E) -> Option<f32> {
self.entries.get(entity).and_then(|d| d.gain_override)
}
pub fn advance(&mut self, entity: E, gain: f32) -> f32 {
let entry = self.entries.entry(entity).or_default();
entry.accumulated += gain;
entry.accumulated
}
pub fn accumulated(&self, entity: &E) -> f32 {
self.entries.get(entity).map(|d| d.accumulated).unwrap_or(0.0)
}
pub fn reset_after_send(&mut self, entity: &E, current_tick: u32) {
if let Some(data) = self.entries.get_mut(entity) {
data.accumulated = 0.0;
data.last_sent_tick = Some(current_tick);
}
}
}
impl<E: Copy + Eq + Hash> Default for UserPriorityState<E> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn global_on_despawn_evicts_entry() {
let mut s = GlobalPriorityState::<u32>::new();
s.get_mut(7).set_gain(5.0);
assert_eq!(s.get_ref(7).gain(), Some(5.0));
s.on_despawn(&7);
assert_eq!(s.get_ref(7).gain(), None);
}
#[test]
fn user_on_scope_exit_evicts_entry() {
let mut s = UserPriorityState::<u32>::new();
s.get_mut(7).boost_once(3.0);
assert_eq!(s.get_ref(7).accumulated(), 3.0);
s.on_scope_exit(&7);
assert_eq!(s.get_ref(7).accumulated(), 0.0);
}
#[test]
fn global_eviction_preserves_other_entries() {
let mut s = GlobalPriorityState::<u32>::new();
s.get_mut(7).set_gain(5.0);
s.get_mut(9).set_gain(2.0);
s.on_despawn(&7);
assert_eq!(s.get_ref(7).gain(), None);
assert_eq!(s.get_ref(9).gain(), Some(2.0));
}
}