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