steel_core/chunk_saver/ram_only.rs
1use std::{io, sync::Weak};
2
3use rustc_hash::FxHashMap;
4use steel_utils::{ChunkPos, locks::AsyncRwLock};
5
6use crate::world::World;
7
8use super::{ChunkStorage, LoadedChunk, PreparedChunkSave};
9
10/// In-memory chunk storage.
11///
12/// This storage implementation doesn't
13/// persist any data to disk. It's designed for test worlds and minigame worlds:
14/// - It has chunk generation which can be disabled with `EmptyChunkGen`
15/// - It will save all the data so perfectly for minigames
16///
17/// TODO:
18/// Will later have the option to load a world from storage and clone it for easy world handling
19pub struct RamOnlyStorage {
20 /// This saves every chunk, and it saves the changes in the world to make it possible to run the server fully in memory
21 saved_chunks: AsyncRwLock<FxHashMap<ChunkPos, SimpleRAMChunk>>,
22}
23
24/// Represents a simple in-memory prepared chunk save.
25///
26/// This structure is used to manage the in-memory representation of a chunk in a system,
27/// including its saved data and current processing or usage status.
28pub struct SimpleRAMChunk {
29 /// A `PreparedChunkSave` instance that holds the saved state of the chunk.
30 pub prepared: PreparedChunkSave,
31}
32
33impl RamOnlyStorage {
34 /// Creates a new RAM-only storage which can be used for minigames, etc.
35 ///
36 /// This should be used for a RAM storage solution of a map and every world generation should be supported
37 #[must_use]
38 pub fn empty_world() -> Self {
39 Self {
40 saved_chunks: AsyncRwLock::new(FxHashMap::default()),
41 }
42 }
43
44 /// Loads a chunk from storage.
45 pub async fn load_chunk(
46 &self,
47 pos: ChunkPos,
48 min_y: i32,
49 height: i32,
50 level: Weak<World>,
51 ) -> io::Result<Option<LoadedChunk>> {
52 if let Ok(true) = self.chunk_exists(pos).await {
53 if let Some(storage) = self.saved_chunks.read().await.get(&pos) {
54 Ok(Some(ChunkStorage::try_persistent_to_chunk(
55 &storage.prepared.persistent,
56 pos,
57 storage.prepared.status,
58 min_y,
59 height,
60 level,
61 )?))
62 } else {
63 Ok(None)
64 }
65 } else {
66 Ok(None)
67 }
68 }
69
70 /// Saves prepared chunk data to storage.
71 pub async fn save_chunk_data(&self, prepared: PreparedChunkSave) -> io::Result<bool> {
72 // Just track that this chunk has been saved
73 // The actual data is in the live World/Chunk, not persisted
74 self.saved_chunks
75 .write()
76 .await
77 .insert(prepared.pos, SimpleRAMChunk { prepared });
78 Ok(true)
79 }
80
81 /// Checks if a chunk exists in storage.
82 pub async fn chunk_exists(&self, pos: ChunkPos) -> io::Result<bool> {
83 Ok(self.saved_chunks.read().await.contains_key(&pos))
84 }
85}