steel_core/entity/damage/history/
binding.rs1use std::{
2 ptr,
3 sync::{Arc, Weak},
4};
5
6use steel_utils::locks::SyncMutex;
7
8use super::{DamageHistory, DamageRecord, DamageSource, RecentDamageSource, WeakDamageSource};
9use crate::entity::EntityGeneration;
10use crate::level_data::GameTime;
11
12#[derive(Default)]
14pub(crate) struct DamageHistoryBinding {
15 state: SyncMutex<BindingState>,
16}
17
18#[derive(Default)]
19struct BindingState {
20 victim: Option<Arc<DamageHistoryVictim>>,
21 owner: Weak<()>,
22 removed: bool,
23}
24
25pub(super) struct DamageHistoryVictim {
27 generation: EntityGeneration,
28 history: Weak<DamageHistory>,
29}
30
31impl DamageHistoryBinding {
32 pub(crate) fn retain_owner(&self) -> Arc<()> {
34 let mut state = self.state.lock();
35 if let Some(owner) = state.owner.upgrade() {
36 return owner;
37 }
38 let owner = Arc::new(());
39 state.owner = Arc::downgrade(&owner);
40 owner
41 }
42
43 pub(super) fn record(
44 &self,
45 history: &Arc<DamageHistory>,
46 generation: EntityGeneration,
47 source: &DamageSource,
48 clock: &Arc<GameTime>,
49 ) {
50 let descriptor = WeakDamageSource::new(source);
51 let replaced = {
52 let mut state = self.state.lock();
53 let victim_lifetime = match &state.victim {
54 Some(bound) if ptr::eq(bound.history.as_ptr(), Arc::as_ptr(history)) => {
55 Arc::downgrade(bound)
56 }
57 _ => {
58 let bound = Arc::new(DamageHistoryVictim {
59 generation,
60 history: Arc::downgrade(history),
61 });
62 let lifetime = Arc::downgrade(&bound);
63 state.victim = Some(bound);
64 lifetime
65 }
66 };
67 let record = DamageRecord {
68 victim_lifetime,
69 owner: Weak::clone(&state.owner),
70 retained: (!state.removed && state.owner.strong_count() > 0)
71 .then(|| source.clone()),
72 source: descriptor,
73 timestamp: clock.ticks(),
74 clock: Arc::clone(clock),
75 };
76 history.records.lock().insert(generation, record)
77 };
78 drop(replaced);
80 }
81
82 pub(crate) fn release_on_removal(&self) -> Option<(Arc<DamageHistory>, Option<DamageSource>)> {
85 let mut state = self.state.lock();
86 state.removed = true;
87 let victim = state.victim.as_ref()?;
88 let history = victim.history.upgrade()?;
89 let released = history
90 .records
91 .lock()
92 .get_mut(&victim.generation)
93 .and_then(|record| record.retained.take());
94 Some((history, released))
95 }
96
97 pub(crate) fn clear_removed(&self) {
98 self.state.lock().removed = false;
99 }
100
101 pub(crate) fn last_damage_source(&self) -> Option<RecentDamageSource> {
102 let (history, victim) = self.bound_history()?;
103 history.last_damage_source(victim)
104 }
105
106 pub(crate) fn clear(&self) {
108 if let Some((history, victim)) = self.bound_history() {
109 history.clear_victim(victim);
110 }
111 }
112
113 fn bound_history(&self) -> Option<(Arc<DamageHistory>, EntityGeneration)> {
114 let state = self.state.lock();
115 let bound = state.victim.as_ref()?;
116 Some((bound.history.upgrade()?, bound.generation))
117 }
118}