steel_core/entity/
reference.rs1use std::sync::{Arc, Weak};
2
3use simdnbt::borrow::NbtCompound as BorrowedNbtCompoundView;
4use simdnbt::owned::{NbtCompound, NbtTag};
5use steel_utils::{UuidExt as _, locks::SyncMutex};
6use uuid::Uuid;
7
8use crate::world::World;
9
10use super::{SharedEntity, WeakEntity};
11
12#[derive(Clone)]
16pub struct EntityReference {
17 uuid: Uuid,
18 cached: Arc<SyncMutex<Option<WeakEntity>>>,
20}
21
22impl EntityReference {
23 #[must_use]
25 pub fn from_uuid(uuid: Uuid) -> Self {
26 Self {
27 uuid,
28 cached: Arc::new(SyncMutex::new(None)),
29 }
30 }
31
32 #[must_use]
34 pub fn from_entity(entity: &SharedEntity) -> Self {
35 Self {
36 uuid: entity.uuid(),
37 cached: Arc::new(SyncMutex::new(Some(Arc::downgrade(entity)))),
38 }
39 }
40
41 #[must_use]
43 pub fn read(nbt: &BorrowedNbtCompoundView<'_, '_>, key: &str) -> Option<Self> {
44 Uuid::from_int_array(&nbt.int_array(key)?).map(Self::from_uuid)
45 }
46
47 pub fn store(&self, nbt: &mut NbtCompound, key: &str) {
49 nbt.insert(key, NbtTag::IntArray(self.uuid.to_int_array().to_vec()));
50 }
51
52 #[must_use]
54 pub const fn uuid(&self) -> Uuid {
55 self.uuid
56 }
57
58 pub fn cache_entity(&self, entity: &SharedEntity) {
60 if entity.uuid() == self.uuid {
61 *self.cached.lock() = Some(Arc::downgrade(entity));
62 }
63 }
64
65 #[must_use]
67 pub fn get_entity(&self, world: &World) -> Option<SharedEntity> {
68 {
69 let mut cached = self.cached.lock();
70 if let Some(entity) = cached.as_ref().and_then(Weak::upgrade)
71 && !entity.is_removed()
72 && entity.uuid() == self.uuid
73 && entity
74 .level()
75 .is_some_and(|level| level.domain() == world.domain())
76 {
77 return Some(entity);
78 }
79 *cached = None;
80 }
81
82 let entity = world.get_entity_in_domain_by_uuid(&self.uuid)?;
83 if entity.is_removed() || entity.uuid() != self.uuid {
84 return None;
85 }
86 self.cache_entity(&entity);
87 Some(entity)
88 }
89}