1
1
use std:: { collections:: HashMap , path:: PathBuf , sync:: Arc } ;
2
2
3
- use parking_lot:: { Mutex , RwLock } ;
4
- use pumpkin_core:: math:: vector2:: Vector2 ;
5
- use rayon:: prelude:: * ;
6
- use tokio:: sync:: mpsc;
7
-
8
3
use crate :: {
9
4
chunk:: {
10
5
anvil:: AnvilChunkReader , ChunkData , ChunkParsingError , ChunkReader , ChunkReadingError ,
11
6
} ,
12
7
world_gen:: { get_world_gen, Seed , WorldGenerator } ,
13
8
} ;
9
+ use pumpkin_core:: math:: vector2:: Vector2 ;
10
+ use tokio:: sync:: mpsc;
11
+ use tokio:: sync:: { Mutex , RwLock } ;
12
+
13
+ type RAMChunkStorage = Arc < RwLock < HashMap < Vector2 < i32 > , Arc < RwLock < ChunkData > > > > > ;
14
14
15
15
/// The `Level` module provides functionality for working with chunks within or outside a Minecraft world.
16
16
///
@@ -23,12 +23,12 @@ use crate::{
23
23
/// For more details on world generation, refer to the `WorldGenerator` module.
24
24
pub struct Level {
25
25
save_file : Option < SaveFile > ,
26
- loaded_chunks : Arc < RwLock < HashMap < Vector2 < i32 > , Arc < ChunkData > > > > ,
26
+ loaded_chunks : RAMChunkStorage ,
27
27
chunk_watchers : Arc < Mutex < HashMap < Vector2 < i32 > , usize > > > ,
28
- chunk_reader : Box < dyn ChunkReader > ,
29
- world_gen : Box < dyn WorldGenerator > ,
28
+ chunk_reader : Arc < Box < dyn ChunkReader > > ,
29
+ world_gen : Arc < Box < dyn WorldGenerator > > ,
30
30
}
31
-
31
+ # [ derive ( Clone ) ]
32
32
pub struct SaveFile {
33
33
#[ expect( dead_code) ]
34
34
root_folder : PathBuf ,
@@ -37,7 +37,7 @@ pub struct SaveFile {
37
37
38
38
impl Level {
39
39
pub fn from_root_folder ( root_folder : PathBuf ) -> Self {
40
- let world_gen = get_world_gen ( Seed ( 0 ) ) ; // TODO Read Seed from config.
40
+ let world_gen = get_world_gen ( Seed ( 0 ) ) . into ( ) ; // TODO Read Seed from config.
41
41
42
42
if root_folder. exists ( ) {
43
43
let region_folder = root_folder. join ( "region" ) ;
@@ -52,7 +52,7 @@ impl Level {
52
52
root_folder,
53
53
region_folder,
54
54
} ) ,
55
- chunk_reader : Box :: new ( AnvilChunkReader :: new ( ) ) ,
55
+ chunk_reader : Arc :: new ( Box :: new ( AnvilChunkReader :: new ( ) ) ) ,
56
56
loaded_chunks : Arc :: new ( RwLock :: new ( HashMap :: new ( ) ) ) ,
57
57
chunk_watchers : Arc :: new ( Mutex :: new ( HashMap :: new ( ) ) ) ,
58
58
}
@@ -64,7 +64,7 @@ impl Level {
64
64
Self {
65
65
world_gen,
66
66
save_file : None ,
67
- chunk_reader : Box :: new ( AnvilChunkReader :: new ( ) ) ,
67
+ chunk_reader : Arc :: new ( Box :: new ( AnvilChunkReader :: new ( ) ) ) ,
68
68
loaded_chunks : Arc :: new ( RwLock :: new ( HashMap :: new ( ) ) ) ,
69
69
chunk_watchers : Arc :: new ( Mutex :: new ( HashMap :: new ( ) ) ) ,
70
70
}
@@ -76,8 +76,8 @@ impl Level {
76
76
/// Marks chunks as "watched" by a unique player. When no players are watching a chunk,
77
77
/// it is removed from memory. Should only be called on chunks the player was not watching
78
78
/// before
79
- pub fn mark_chunk_as_newly_watched ( & self , chunks : & [ Vector2 < i32 > ] ) {
80
- let mut watchers = self . chunk_watchers . lock ( ) ;
79
+ pub async fn mark_chunk_as_newly_watched ( & self , chunks : & [ Vector2 < i32 > ] ) {
80
+ let mut watchers = self . chunk_watchers . lock ( ) . await ;
81
81
for chunk in chunks {
82
82
match watchers. entry ( * chunk) {
83
83
std:: collections:: hash_map:: Entry :: Occupied ( mut occupied) => {
@@ -93,9 +93,9 @@ impl Level {
93
93
94
94
/// Marks chunks no longer "watched" by a unique player. When no players are watching a chunk,
95
95
/// it is removed from memory. Should only be called on chunks the player was watching before
96
- pub fn mark_chunk_as_not_watched_and_clean ( & self , chunks : & [ Vector2 < i32 > ] ) {
96
+ pub async fn mark_chunk_as_not_watched_and_clean ( & self , chunks : & [ Vector2 < i32 > ] ) {
97
97
let dropped_chunks = {
98
- let mut watchers = self . chunk_watchers . lock ( ) ;
98
+ let mut watchers = self . chunk_watchers . lock ( ) . await ;
99
99
chunks
100
100
. iter ( )
101
101
. filter ( |chunk| match watchers. entry ( * * chunk) {
@@ -119,77 +119,95 @@ impl Level {
119
119
} )
120
120
. collect :: < Vec < _ > > ( )
121
121
} ;
122
- let mut loaded_chunks = self . loaded_chunks . write ( ) ;
122
+ let mut loaded_chunks = self . loaded_chunks . write ( ) . await ;
123
123
let dropped_chunk_data = dropped_chunks
124
124
. iter ( )
125
125
. filter_map ( |chunk| {
126
- log:: debug!( "Unloading chunk {:?}" , chunk) ;
126
+ // log::debug!("Unloading chunk {:?}", chunk);
127
127
loaded_chunks. remove_entry ( * chunk)
128
128
} )
129
129
. collect ( ) ;
130
130
self . write_chunks ( dropped_chunk_data) ;
131
131
}
132
132
133
- pub fn write_chunks ( & self , _chunks_to_write : Vec < ( Vector2 < i32 > , Arc < ChunkData > ) > ) {
133
+ pub fn write_chunks ( & self , _chunks_to_write : Vec < ( Vector2 < i32 > , Arc < RwLock < ChunkData > > ) > ) {
134
134
//TODO
135
135
}
136
136
137
137
/// Reads/Generates many chunks in a world
138
138
/// MUST be called from a tokio runtime thread
139
139
///
140
140
/// Note: The order of the output chunks will almost never be in the same order as the order of input chunks
141
+ pub fn fetch_chunks (
142
+ & self ,
143
+ chunks : & [ Vector2 < i32 > ] ,
144
+ channel : mpsc:: Sender < Arc < RwLock < ChunkData > > > ,
145
+ ) {
146
+ for chunk in chunks {
147
+ {
148
+ let chunk_location = * chunk;
149
+ let channel = channel. clone ( ) ;
150
+ let loaded_chunks = self . loaded_chunks . clone ( ) ;
151
+ let chunk_reader = self . chunk_reader . clone ( ) ;
152
+ let save_file = self . save_file . clone ( ) ;
153
+ let world_gen = self . world_gen . clone ( ) ;
154
+ tokio:: spawn ( async move {
155
+ let loaded_chunks_read = loaded_chunks. read ( ) . await ;
156
+ let possibly_loaded_chunk = loaded_chunks_read. get ( & chunk_location) . cloned ( ) ;
157
+ drop ( loaded_chunks_read) ;
158
+ match possibly_loaded_chunk {
159
+ Some ( chunk) => {
160
+ let chunk = chunk. clone ( ) ;
161
+ channel. send ( chunk) . await . unwrap ( ) ;
162
+ }
163
+ None => {
164
+ let chunk_data = match save_file {
165
+ Some ( save_file) => {
166
+ match chunk_reader. read_chunk ( & save_file, & chunk_location) {
167
+ Ok ( data) => Ok ( Arc :: new ( RwLock :: new ( data) ) ) ,
168
+ Err (
169
+ ChunkReadingError :: ChunkNotExist
170
+ | ChunkReadingError :: ParsingError (
171
+ ChunkParsingError :: ChunkNotGenerated ,
172
+ ) ,
173
+ ) => {
174
+ // This chunk was not generated yet.
175
+ let chunk = Arc :: new ( RwLock :: new (
176
+ world_gen. generate_chunk ( chunk_location) ,
177
+ ) ) ;
178
+ let mut loaded_chunks = loaded_chunks. write ( ) . await ;
179
+ loaded_chunks. insert ( chunk_location, chunk. clone ( ) ) ;
180
+ drop ( loaded_chunks) ;
181
+ Ok ( chunk)
182
+ }
183
+ Err ( err) => Err ( err) ,
184
+ }
185
+ }
186
+ None => {
187
+ // There is no savefile yet -> generate the chunks
188
+ let chunk = Arc :: new ( RwLock :: new (
189
+ world_gen. generate_chunk ( chunk_location) ,
190
+ ) ) ;
141
191
142
- pub fn fetch_chunks ( & self , chunks : & [ Vector2 < i32 > ] , channel : mpsc:: Sender < Arc < ChunkData > > ) {
143
- chunks. into_par_iter ( ) . for_each ( |at| {
144
- let channel = channel. clone ( ) ;
145
-
146
- let maybe_chunk = {
147
- let loaded_chunks = self . loaded_chunks . read ( ) ;
148
- loaded_chunks. get ( at) . cloned ( )
149
- }
150
- . or_else ( || {
151
- let chunk_data = match & self . save_file {
152
- Some ( save_file) => {
153
- match self . chunk_reader . read_chunk ( save_file, at) {
154
- Ok ( data) => Ok ( Arc :: new ( data) ) ,
155
- Err (
156
- ChunkReadingError :: ChunkNotExist
157
- | ChunkReadingError :: ParsingError (
158
- ChunkParsingError :: ChunkNotGenerated ,
159
- ) ,
160
- ) => {
161
- // This chunk was not generated yet.
162
- let chunk = Arc :: new ( self . world_gen . generate_chunk ( * at) ) ;
163
- Ok ( chunk)
192
+ let mut loaded_chunks = loaded_chunks. write ( ) . await ;
193
+ loaded_chunks. insert ( chunk_location, chunk. clone ( ) ) ;
194
+ Ok ( chunk)
195
+ }
196
+ } ;
197
+ match chunk_data {
198
+ Ok ( data) => channel. send ( data) . await . unwrap ( ) ,
199
+ Err ( err) => {
200
+ log:: warn!(
201
+ "Failed to read chunk {:?}: {:?}" ,
202
+ chunk_location,
203
+ err
204
+ ) ;
205
+ }
164
206
}
165
- Err ( err) => Err ( err) ,
166
207
}
167
208
}
168
- None => {
169
- // There is no savefile yet -> generate the chunks
170
- let chunk = Arc :: new ( self . world_gen . generate_chunk ( * at) ) ;
171
- Ok ( chunk)
172
- }
173
- } ;
174
- match chunk_data {
175
- Ok ( data) => Some ( data) ,
176
- Err ( err) => {
177
- // TODO: Panic here?
178
- log:: warn!( "Failed to read chunk {:?}: {:?}" , at, err) ;
179
- None
180
- }
181
- }
182
- } ) ;
183
- match maybe_chunk {
184
- Some ( chunk) => {
185
- channel
186
- . blocking_send ( chunk. clone ( ) )
187
- . expect ( "Failed sending ChunkData." ) ;
188
- }
189
- None => {
190
- log:: error!( "Unable to send chunk {:?}!" , at) ;
191
- }
192
- } ;
193
- } )
209
+ } ) ;
210
+ }
211
+ }
194
212
}
195
213
}
0 commit comments