use crate::{LifecycleState, Tick};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct EntityId(pub u32);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct NameId(pub u32);
pub trait EntityState: Clone + Default {}
#[derive(Debug, Clone)]
pub struct Event<S: EntityState> {
pub timestamp: Tick,
pub lifecycle: LifecycleState,
pub state: S,
}
impl<S: EntityState> Event<S> {
pub fn new(timestamp: Tick, lifecycle: LifecycleState, state: S) -> Self {
Self {
timestamp,
lifecycle,
state,
}
}
pub fn born(timestamp: Tick, state: S) -> Self {
Self::new(timestamp, LifecycleState::Born, state)
}
pub fn prebirth(timestamp: Tick, state: S) -> Self {
Self::new(timestamp, LifecycleState::Prebirth, state)
}
pub fn dead(timestamp: Tick, state: S) -> Self {
Self::new(timestamp, LifecycleState::Dead, state)
}
pub fn chronoporting(timestamp: Tick, state: S) -> Self {
Self::new(timestamp, LifecycleState::Chronoporting, state)
}
pub fn is_active(&self) -> bool {
matches!(
self.lifecycle,
LifecycleState::Born | LifecycleState::Prebirth
)
}
}
#[derive(Debug)]
pub struct Entity<S: EntityState> {
pub id: EntityId,
pub name_id: NameId,
pub created_at: Tick,
events: Vec<Event<S>>,
}
impl<S: EntityState> Entity<S> {
pub fn new(id: EntityId, name_id: NameId, created_at: Tick, initial_state: S) -> Self {
let initial_event = Event::born(created_at, initial_state);
Self {
id,
name_id,
created_at,
events: vec![initial_event],
}
}
pub fn prebirth(id: EntityId, name_id: NameId, appear_at: Tick, state: S) -> Self {
let event = Event::prebirth(appear_at, state);
Self {
id,
name_id,
created_at: appear_at,
events: vec![event],
}
}
pub fn get_event_at(&self, tick: Tick) -> Option<&Event<S>> {
let idx = self
.events
.partition_point(|e| e.timestamp <= tick)
.saturating_sub(1);
self.events.get(idx).filter(|e| e.timestamp <= tick)
}
pub fn latest_event(&self) -> Option<&Event<S>> {
self.events.last()
}
pub fn add_event(&mut self, event: Event<S>) {
let pos = self.events.partition_point(|e| e.timestamp < event.timestamp);
self.events.insert(pos, event);
}
pub fn set_state(&mut self, tick: Tick, state: S) {
self.add_event(Event::born(tick, state));
}
pub fn destroy(&mut self, tick: Tick) {
if let Some(last) = self.events.last() {
self.add_event(Event::dead(tick, last.state.clone()));
}
}
pub fn mark_chronoporting(&mut self, tick: Tick) {
if let Some(last) = self.events.last() {
self.add_event(Event::chronoporting(tick, last.state.clone()));
}
}
pub fn needs_activation_at(&self, tick: Tick) -> bool {
if let Some(event) = self.get_event_at(tick) {
if event.lifecycle == LifecycleState::Prebirth {
let has_born_after = self.events.iter().any(|e| {
e.timestamp > event.timestamp && e.lifecycle == LifecycleState::Born
});
return !has_born_after;
}
}
false
}
pub fn activate_at(&mut self, tick: Tick) {
if let Some(event) = self.get_event_at(tick) {
if event.lifecycle == LifecycleState::Prebirth {
self.add_event(Event::born(tick, event.state.clone()));
}
}
}
pub fn event_count(&self) -> usize {
self.events.len()
}
pub fn events(&self) -> impl Iterator<Item = &Event<S>> {
self.events.iter()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Clone, Default, Debug, PartialEq)]
struct TestState {
value: i32,
}
impl EntityState for TestState {}
#[test]
fn test_event_at_time() {
let mut entity = Entity::new(
EntityId(0),
NameId(0),
0,
TestState { value: 0 },
);
entity.set_state(5, TestState { value: 50 });
entity.set_state(10, TestState { value: 100 });
assert_eq!(entity.get_event_at(0).unwrap().state.value, 0);
assert_eq!(entity.get_event_at(3).unwrap().state.value, 0);
assert_eq!(entity.get_event_at(7).unwrap().state.value, 50);
assert_eq!(entity.get_event_at(15).unwrap().state.value, 100);
}
}