1use crate::{character::CharacterId, rtsim};
2use core::hash::Hash;
3use hashbrown::HashMap;
4use serde::{Deserialize, Serialize};
5use specs::{Component, Entity, FlaggedStorage, VecStorage};
6use std::{fmt, num::NonZeroU64};
7use tracing::error;
8
9#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
10pub struct Uid(pub NonZeroU64);
11
12impl From<Uid> for NonZeroU64 {
13 fn from(uid: Uid) -> NonZeroU64 { uid.0 }
14}
15
16impl From<NonZeroU64> for Uid {
17 fn from(uid: NonZeroU64) -> Self { Self(uid) }
18}
19
20impl fmt::Display for Uid {
21 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.0) }
22}
23
24impl Component for Uid {
25 type Storage = FlaggedStorage<Self, VecStorage<Self>>;
26}
27
28#[derive(Debug)]
29struct UidAllocator {
30 next_uid: u64,
32}
33
34impl UidAllocator {
35 fn new() -> Self { Self { next_uid: 1 } }
36
37 fn allocate(&mut self) -> Uid {
38 let id = self.next_uid;
39 self.next_uid += 1;
40 Uid(NonZeroU64::new(id).expect("Uid cannot be zero"))
41 }
42}
43
44#[derive(Default, Debug)]
46pub struct IdMaps {
47 uid_mapping: HashMap<Uid, Entity>,
50
51 uid_allocator: UidAllocator,
53
54 character_to_ecs: HashMap<CharacterId, Entity>,
56 rtsim_to_ecs: HashMap<rtsim::ActorId, Entity>,
58}
59
60impl IdMaps {
61 pub fn new() -> Self { Default::default() }
62
63 pub fn uid_entity(&self, id: Uid) -> Option<Entity> { self.uid_mapping.get(&id).copied() }
65
66 pub fn character_entity(&self, id: CharacterId) -> Option<Entity> {
68 self.character_to_ecs.get(&id).copied()
69 }
70
71 pub fn rtsim_entity(&self, id: rtsim::ActorId) -> Option<Entity> {
73 self.rtsim_to_ecs.get(&id).copied()
74 }
75
76 #[track_caller]
85 pub fn remove_entity(
86 &mut self,
87 expected_entity: Option<Entity>,
88 uid: Option<Uid>,
89 cid: Option<CharacterId>,
90 rid: Option<rtsim::ActorId>,
91 ) -> Option<Entity> {
92 use std::fmt::Debug;
93 #[cold]
94 #[inline(never)]
95 fn unexpected_entity<ID>() {
96 let kind = core::any::type_name::<ID>();
97 error!("Provided {kind} was mapped to an unexpected entity!");
98 }
99 #[cold]
100 #[inline(never)]
101 #[track_caller]
102 fn not_present<ID: Debug>(id: ID) {
103 let kind = core::any::type_name::<ID>();
104 error!(
105 "Provided {kind} {id:?} was not mapped to any entity! Caller: {}",
106 std::panic::Location::caller()
107 );
108 }
109
110 #[track_caller]
111 fn remove<ID: Hash + Eq + Debug>(
112 mapping: &mut HashMap<ID, Entity>,
113 id: Option<ID>,
114 expected: Option<Entity>,
115 ) -> Option<Entity> {
116 if let Some(id) = id {
117 if let Some(e) = mapping.remove(&id) {
118 if expected.is_some_and(|expected| e != expected) {
119 unexpected_entity::<ID>();
120 }
121 Some(e)
122 } else {
123 not_present::<ID>(id);
124 None
125 }
126 } else {
127 None
128 }
129 }
130
131 let maybe_entity = remove(&mut self.uid_mapping, uid, expected_entity);
132 let expected_entity = expected_entity.or(maybe_entity);
133 remove(&mut self.character_to_ecs, cid, expected_entity);
134 remove(&mut self.rtsim_to_ecs, rid, expected_entity);
135 maybe_entity
136 }
137
138 pub fn add_entity(&mut self, uid: Uid, entity: Entity) {
142 Self::insert(&mut self.uid_mapping, uid, entity);
143 }
144
145 pub fn add_character(&mut self, cid: CharacterId, entity: Entity) {
147 Self::insert(&mut self.character_to_ecs, cid, entity);
148 }
149
150 pub fn add_rtsim(&mut self, rid: rtsim::ActorId, entity: Entity) {
152 Self::insert(&mut self.rtsim_to_ecs, rid, entity);
153 }
154
155 pub fn allocate(&mut self, entity: Entity) -> Uid {
159 let uid = self.uid_allocator.allocate();
160 self.uid_mapping.insert(uid, entity);
161 uid
162 }
163
164 pub fn remap_entity(&mut self, uid: Uid, new_entity: Entity) {
171 if self.uid_mapping.insert(uid, new_entity).is_none() {
172 error!("Uid {uid:?} remaped but there was no existing entry for it!");
173 }
174 }
175
176 #[cold]
177 #[inline(never)]
178 fn already_present<ID>() {
179 let kind = core::any::type_name::<ID>();
180 error!("Provided {kind} was already mapped to an entity!!!");
181 }
182
183 fn insert<ID: Hash + Eq>(mapping: &mut HashMap<ID, Entity>, new_id: ID, entity: Entity) {
184 if let Some(_previous_entity) = mapping.insert(new_id, entity) {
185 Self::already_present::<ID>();
186 }
187 }
188}
189
190impl Default for UidAllocator {
191 fn default() -> Self { Self::new() }
192}