Skip to main content

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}