steel_core/world/player_index/
map.rs1use std::sync::Arc;
4
5use scc::HashMap;
6use steel_utils::locks::SyncMutex;
7use uuid::Uuid;
8
9use crate::{entity::Entity, player::Player};
10
11pub struct PlayerMap {
16 by_uuid: HashMap<Uuid, Arc<Player>>,
18 by_entity_id: HashMap<i32, Arc<Player>>,
20 order: SyncMutex<Vec<Uuid>>,
22}
23
24impl Default for PlayerMap {
25 fn default() -> Self {
26 Self::new()
27 }
28}
29
30impl PlayerMap {
31 #[must_use]
33 pub fn new() -> Self {
34 Self {
35 by_uuid: HashMap::new(),
36 by_entity_id: HashMap::new(),
37 order: SyncMutex::new(Vec::new()),
38 }
39 }
40
41 pub fn insert(&self, player: Arc<Player>) -> bool {
51 let uuid = player.gameprofile.id;
52 let entity_id = player.id();
53
54 if self.by_uuid.insert_sync(uuid, player.clone()).is_err() {
55 return false;
56 }
57
58 if self.by_entity_id.insert_sync(entity_id, player).is_err() {
59 let _ = self.by_uuid.remove_sync(&uuid);
60 panic!("player entity id {entity_id} is already registered");
61 }
62 self.order.lock().push(uuid);
63 true
64 }
65
66 pub async fn remove(&self, uuid: &Uuid) -> Option<Arc<Player>> {
70 if let Some((_, player)) = self.by_uuid.remove_async(uuid).await {
71 let _ = self.by_entity_id.remove_async(&player.id()).await;
72 self.order.lock().retain(|player_uuid| player_uuid != uuid);
73 Some(player)
74 } else {
75 None
76 }
77 }
78
79 pub async fn remove_player(&self, player: &Arc<Player>) -> Option<Arc<Player>> {
85 let uuid = player.gameprofile.id;
86 let (_, removed) = self
87 .by_uuid
88 .remove_if_async(&uuid, |current| Arc::ptr_eq(current, player))
89 .await?;
90 let _ = self
91 .by_entity_id
92 .remove_if_async(&removed.id(), |current| Arc::ptr_eq(current, &removed))
93 .await;
94 self.order
95 .lock()
96 .retain(|uuid| *uuid != removed.gameprofile.id);
97 Some(removed)
98 }
99
100 pub fn remove_sync(&self, uuid: &Uuid) -> Option<Arc<Player>> {
105 if let Some((_, player)) = self.by_uuid.remove_sync(uuid) {
106 let _ = self.by_entity_id.remove_sync(&player.id());
107 self.order.lock().retain(|player_uuid| player_uuid != uuid);
108 Some(player)
109 } else {
110 None
111 }
112 }
113
114 pub fn remove_player_sync(&self, player: &Arc<Player>) -> Option<Arc<Player>> {
116 let uuid = player.gameprofile.id;
117 let (_, removed) = self
118 .by_uuid
119 .remove_if_sync(&uuid, |current| Arc::ptr_eq(current, player))?;
120 let _ = self
121 .by_entity_id
122 .remove_if_sync(&removed.id(), |current| Arc::ptr_eq(current, &removed));
123 self.order
124 .lock()
125 .retain(|uuid| *uuid != removed.gameprofile.id);
126 Some(removed)
127 }
128
129 #[must_use]
131 pub fn get_by_uuid(&self, uuid: &Uuid) -> Option<Arc<Player>> {
132 self.by_uuid.read_sync(uuid, |_, p| p.clone())
133 }
134
135 #[must_use]
137 pub fn get_by_entity_id(&self, entity_id: i32) -> Option<Arc<Player>> {
138 self.by_entity_id.read_sync(&entity_id, |_, p| p.clone())
139 }
140
141 pub fn iter_players<F>(&self, mut f: F)
145 where
146 F: FnMut(&Uuid, &Arc<Player>) -> bool,
147 {
148 let order = self.order.lock().iter().copied().collect::<Vec<_>>();
149 for uuid in order {
150 let Some(player) = self.get_by_uuid(&uuid) else {
151 continue;
152 };
153 if !f(&uuid, &player) {
154 return;
155 }
156 }
157 }
158
159 #[must_use]
161 pub fn len(&self) -> usize {
162 self.by_uuid.len()
163 }
164
165 #[must_use]
167 pub fn is_empty(&self) -> bool {
168 self.by_uuid.is_empty()
169 }
170}