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