2023-04-25 02:30:12 +00:00
|
|
|
// TODO: rename this module or create new one for ID maps
|
2020-07-06 14:23:08 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
2020-12-12 01:45:46 +00:00
|
|
|
use std::{fmt, u64};
|
2019-11-24 20:12:03 +00:00
|
|
|
|
2023-04-25 02:30:12 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
|
|
use {
|
|
|
|
crate::character::CharacterId,
|
|
|
|
crate::rtsim::RtSimEntity,
|
2023-04-26 04:31:14 +00:00
|
|
|
core::hash::Hash,
|
2023-04-25 02:30:12 +00:00
|
|
|
hashbrown::HashMap,
|
|
|
|
specs::{Component, Entity, FlaggedStorage, VecStorage},
|
2023-04-26 04:31:14 +00:00
|
|
|
tracing::error,
|
2023-04-25 02:30:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// TODO: could we switch this to `NonZeroU64`?
|
2019-11-24 20:12:03 +00:00
|
|
|
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
|
|
|
pub struct Uid(pub u64);
|
|
|
|
|
2021-03-12 11:10:42 +00:00
|
|
|
impl From<Uid> for u64 {
|
|
|
|
fn from(uid: Uid) -> u64 { uid.0 }
|
2019-11-24 20:12:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl From<u64> for Uid {
|
2020-02-01 20:39:39 +00:00
|
|
|
fn from(uid: u64) -> Self { Self(uid) }
|
2019-11-24 20:12:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for Uid {
|
2020-02-01 20:39:39 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.0) }
|
2019-11-24 20:12:03 +00:00
|
|
|
}
|
|
|
|
|
2023-04-25 02:30:12 +00:00
|
|
|
pub use not_wasm::*;
|
2021-02-16 23:11:05 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2023-04-25 02:30:12 +00:00
|
|
|
mod not_wasm {
|
|
|
|
use super::*;
|
2019-11-24 20:12:03 +00:00
|
|
|
|
2023-04-25 02:30:12 +00:00
|
|
|
impl Component for Uid {
|
|
|
|
type Storage = FlaggedStorage<Self, VecStorage<Self>>;
|
|
|
|
}
|
2019-11-24 20:12:03 +00:00
|
|
|
|
2023-04-25 02:30:12 +00:00
|
|
|
#[derive(Debug)]
|
2023-04-26 04:31:14 +00:00
|
|
|
struct UidAllocator {
|
2023-04-25 02:30:12 +00:00
|
|
|
/// Next Uid.
|
|
|
|
next_uid: u64,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl UidAllocator {
|
2023-04-26 04:31:14 +00:00
|
|
|
fn new() -> Self { Self { next_uid: 0 } }
|
|
|
|
|
|
|
|
fn allocate(&mut self) -> Uid {
|
|
|
|
let id = self.next_uid;
|
|
|
|
self.next_uid += 1;
|
|
|
|
Uid(id)
|
2019-11-24 20:12:03 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-01 20:39:39 +00:00
|
|
|
|
2023-04-25 02:30:12 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct IdMaps {
|
|
|
|
/// "Universal" IDs (used to communicate entity identity over the
|
|
|
|
/// network).
|
|
|
|
uid_mapping: HashMap<Uid, Entity>,
|
|
|
|
|
2023-04-26 04:31:14 +00:00
|
|
|
// -- Fields below only used on the server --
|
|
|
|
uid_allocator: UidAllocator,
|
|
|
|
|
2023-04-25 02:30:12 +00:00
|
|
|
/// Character IDs.
|
|
|
|
cid_mapping: HashMap<CharacterId, Entity>,
|
|
|
|
/// Rtsim Entities.
|
2023-04-26 20:50:06 +00:00
|
|
|
rid_mapping: HashMap<RtSimEntity, Entity>,
|
2019-11-24 20:12:03 +00:00
|
|
|
}
|
|
|
|
|
2023-04-26 04:31:14 +00:00
|
|
|
impl IdMaps {
|
2023-04-25 02:30:12 +00:00
|
|
|
pub fn new() -> Self {
|
|
|
|
Self {
|
|
|
|
uid_mapping: HashMap::new(),
|
2023-04-26 04:31:14 +00:00
|
|
|
uid_allocator: UidAllocator::new(),
|
2023-04-25 02:30:12 +00:00
|
|
|
cid_mapping: HashMap::new(),
|
|
|
|
rid_mapping: HashMap::new(),
|
|
|
|
}
|
|
|
|
}
|
2023-04-23 05:58:29 +00:00
|
|
|
|
2023-04-26 04:31:14 +00:00
|
|
|
/// Given a `Uid` retrieve the corresponding `Entity`.
|
2023-04-25 02:30:12 +00:00
|
|
|
pub fn uid_entity(&self, id: Uid) -> Option<Entity> { self.uid_mapping.get(&id).copied() }
|
|
|
|
|
2023-04-26 04:31:14 +00:00
|
|
|
/// Given a `CharacterId` retrieve the corresponding `Entity`.
|
2023-04-25 02:30:12 +00:00
|
|
|
pub fn cid_entity(&self, id: CharacterId) -> Option<Entity> {
|
2023-04-26 20:50:06 +00:00
|
|
|
self.cid_mapping.get(&id).copied()
|
2023-04-25 02:30:12 +00:00
|
|
|
}
|
|
|
|
|
2023-04-26 04:31:14 +00:00
|
|
|
/// Given a `RtSimEntity` retrieve the corresponding `Entity`.
|
2023-04-25 02:30:12 +00:00
|
|
|
pub fn rid_entity(&self, id: RtSimEntity) -> Option<Entity> {
|
2023-04-26 20:50:06 +00:00
|
|
|
self.rid_mapping.get(&id).copied()
|
2023-04-25 02:30:12 +00:00
|
|
|
}
|
|
|
|
|
2023-04-26 04:31:14 +00:00
|
|
|
// TODO: I think this is suitable to use on both the client and the server.
|
2023-04-25 02:30:12 +00:00
|
|
|
// NOTE: This is only used on the client? Do we not remove on the server?
|
|
|
|
// NOTE: We need UID mapping also on the client but we don't need the other
|
|
|
|
// mappings on the client!
|
|
|
|
//
|
|
|
|
// Useful for when a single entity is deleted because it doesn't reconstruct the
|
|
|
|
// entire hashmap
|
2023-04-26 04:31:14 +00:00
|
|
|
/// Returns the `Entity` that the provided `Uid` was mapped to.
|
2023-04-25 02:30:12 +00:00
|
|
|
pub fn remove_entity(
|
|
|
|
&mut self,
|
|
|
|
expected_entity: Option<Entity>,
|
|
|
|
uid: Uid,
|
|
|
|
cid: Option<CharacterId>,
|
2023-04-26 20:50:06 +00:00
|
|
|
rid: Option<RtSimEntity>,
|
2023-04-25 02:30:12 +00:00
|
|
|
) -> Option<Entity> {
|
|
|
|
#[cold]
|
|
|
|
#[inline(never)]
|
|
|
|
fn unexpected_entity<ID>() {
|
2023-04-26 20:50:06 +00:00
|
|
|
let kind = core::any::type_name::<ID>();
|
|
|
|
error!("Provided {kind} was mapped to an unexpected entity!");
|
2023-04-25 02:30:12 +00:00
|
|
|
}
|
|
|
|
#[cold]
|
|
|
|
#[inline(never)]
|
|
|
|
fn not_present<ID>() {
|
2023-04-26 20:50:06 +00:00
|
|
|
let kind = core::any::type_name::<ID>();
|
|
|
|
error!("Provided {kind} was not mapped to any entity!");
|
2023-04-25 02:30:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn remove<ID: Hash + Eq>(
|
|
|
|
mapping: &mut HashMap<ID, Entity>,
|
|
|
|
id: Option<ID>,
|
|
|
|
expected: Option<Entity>,
|
|
|
|
) -> Option<Entity> {
|
|
|
|
if let Some(id) = id {
|
2023-04-26 20:50:06 +00:00
|
|
|
if let Some(e) = mapping.remove(&id) {
|
|
|
|
if expected.map_or(true, |expected| e != expected) {
|
2023-04-25 02:30:12 +00:00
|
|
|
unexpected_entity::<ID>();
|
|
|
|
}
|
|
|
|
Some(e)
|
|
|
|
} else {
|
|
|
|
not_present::<ID>();
|
|
|
|
None
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let maybe_entity = remove(&mut self.uid_mapping, Some(uid), expected_entity);
|
|
|
|
let expected_entity = expected_entity.or(maybe_entity);
|
|
|
|
remove(&mut self.cid_mapping, cid, expected_entity);
|
|
|
|
remove(&mut self.rid_mapping, rid, expected_entity);
|
|
|
|
maybe_entity
|
|
|
|
}
|
|
|
|
|
2023-04-26 04:31:14 +00:00
|
|
|
/// Only used on the client (server solely uses `Self::allocate` to
|
|
|
|
/// allocate and add Uid mappings).
|
|
|
|
pub fn add_entity(&mut self, uid: Uid, entity: Entity) {
|
|
|
|
Self::insert(&mut self.uid_mapping, uid, entity);
|
|
|
|
}
|
2023-04-25 02:30:12 +00:00
|
|
|
|
2023-04-26 04:31:14 +00:00
|
|
|
/// Only used on the server.
|
|
|
|
pub fn add_character(&mut self, cid: CharacterId, entity: Entity) {
|
|
|
|
Self::insert(&mut self.cid_mapping, cid, entity);
|
|
|
|
}
|
2023-04-25 02:30:12 +00:00
|
|
|
|
2023-04-26 04:31:14 +00:00
|
|
|
/// Only used on the server.
|
|
|
|
pub fn add_rtsim(&mut self, rid: RtSimEntity, entity: Entity) {
|
|
|
|
Self::insert(&mut self.rid_mapping, rid, entity);
|
2023-04-25 02:30:12 +00:00
|
|
|
}
|
|
|
|
|
2023-04-26 04:31:14 +00:00
|
|
|
/// Allocates a new `Uid` and links it to the provided entity.
|
|
|
|
///
|
|
|
|
/// Only used on the server.
|
2023-04-25 02:30:12 +00:00
|
|
|
pub fn allocate(&mut self, entity: Entity) -> Uid {
|
2023-04-26 04:31:14 +00:00
|
|
|
let uid = self.uid_allocator.allocate();
|
|
|
|
self.uid_mapping.insert(uid, entity);
|
|
|
|
uid
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cold]
|
|
|
|
#[inline(never)]
|
|
|
|
fn already_present<ID>() {
|
|
|
|
let kind = core::any::type_name::<ID>();
|
|
|
|
error!("Provided {kind} was already mapped to an entity!!!");
|
|
|
|
}
|
|
|
|
|
|
|
|
fn insert<ID: Hash + Eq>(mapping: &mut HashMap<ID, Entity>, new_id: ID, entity: Entity) {
|
|
|
|
if let Some(_previous_entity) = mapping.insert(new_id, entity) {
|
|
|
|
Self::already_present::<ID>();
|
|
|
|
}
|
2023-04-25 02:30:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for UidAllocator {
|
|
|
|
fn default() -> Self { Self::new() }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for IdMaps {
|
|
|
|
fn default() -> Self { Self::new() }
|
|
|
|
}
|
2023-04-23 05:58:29 +00:00
|
|
|
}
|