veloren_common_state/plugin/
memory_manager.rs1use atomic_refcell::AtomicRefCell;
2use common::{
3 comp::{Health, Player},
4 uid::{IdMaps, Uid},
5};
6use core::ptr::NonNull;
7use specs::{
8 Component, Entities, Entity, Read, ReadStorage, WriteStorage, storage::GenericReadStorage,
9};
10use tracing::error;
11
12pub struct EcsWorld<'a, 'b> {
13 pub entities: &'b Entities<'a>,
14 pub health: EcsComponentAccess<'a, 'b, Health>,
15 pub uid: EcsComponentAccess<'a, 'b, Uid>,
16 pub player: EcsComponentAccess<'a, 'b, Player>,
17 pub id_maps: &'b Read<'a, IdMaps>,
18}
19
20pub enum EcsComponentAccess<'a, 'b, T: Component> {
21 Read(&'b ReadStorage<'a, T>),
22 ReadOwned(ReadStorage<'a, T>),
23 Write(&'b WriteStorage<'a, T>),
24 WriteOwned(WriteStorage<'a, T>),
25}
26
27impl<T: Component> EcsComponentAccess<'_, '_, T> {
28 pub fn get(&self, entity: Entity) -> Option<&T> {
29 match self {
30 EcsComponentAccess::Read(e) => e.get(entity),
31 EcsComponentAccess::Write(e) => e.get(entity),
32 EcsComponentAccess::ReadOwned(e) => e.get(entity),
33 EcsComponentAccess::WriteOwned(e) => e.get(entity),
34 }
35 }
36}
37
38impl<'a, 'b, T: Component> From<&'b ReadStorage<'a, T>> for EcsComponentAccess<'a, 'b, T> {
39 fn from(a: &'b ReadStorage<'a, T>) -> Self { Self::Read(a) }
40}
41
42impl<'a, T: Component> From<ReadStorage<'a, T>> for EcsComponentAccess<'a, '_, T> {
43 fn from(a: ReadStorage<'a, T>) -> Self { Self::ReadOwned(a) }
44}
45
46impl<'a, 'b, T: Component> From<&'b WriteStorage<'a, T>> for EcsComponentAccess<'a, 'b, T> {
47 fn from(a: &'b WriteStorage<'a, T>) -> Self { Self::Write(a) }
48}
49
50impl<'a, T: Component> From<WriteStorage<'a, T>> for EcsComponentAccess<'a, '_, T> {
51 fn from(a: WriteStorage<'a, T>) -> Self { Self::WriteOwned(a) }
52}
53
54pub struct EcsAccessManager {
56 ecs_pointer: AtomicRefCell<Option<NonNull<EcsWorld<'static, 'static>>>>,
57}
58
59unsafe impl Send for EcsAccessManager where for<'a, 'b, 'c> &'a EcsWorld<'b, 'c>: Send {}
62unsafe impl Sync for EcsAccessManager where for<'a, 'b, 'c> &'a EcsWorld<'b, 'c>: Sync {}
63
64impl Default for EcsAccessManager {
65 fn default() -> Self {
66 Self {
67 ecs_pointer: AtomicRefCell::new(None),
68 }
69 }
70}
71
72impl EcsAccessManager {
73 pub fn execute_with<T>(&self, world: &EcsWorld, func: impl FnOnce() -> T) -> T {
76 let _guard = scopeguard::guard((), |_| {
77 if let Ok(mut ptr) = self.ecs_pointer.try_borrow_mut() {
79 *ptr = None;
80 } else {
81 error!("EcsWorld reference still in use when `func` finished, aborting");
82 std::process::abort();
83 }
84 });
85 *self.ecs_pointer.borrow_mut() =
86 Some(NonNull::from(world).cast::<EcsWorld<'static, 'static>>());
87 func()
88 }
89
90 pub fn with<F, R>(&self, f: F) -> R
98 where
99 F: for<'a, 'b, 'c> FnOnce(Option<&'a EcsWorld<'b, 'c>>) -> R,
100 {
101 let ptr = self.ecs_pointer.borrow();
102 let ecs_world = ptr.map(|ptr| {
103 unsafe { ptr.as_ref() }
114 });
115 f(ecs_world)
116 }
117}