1use crate::block::{BlockRegistry, Block};
2use crate::biome::{BiomeRegistry, Biome};
3use crate::version::Version;
4use crate::rand::jrand;
5use std::collections::hash_map::Entry;
6use std::collections::HashMap;
7use std::rc::Rc;
8
9pub mod chunk;
10pub mod loader;
11pub mod gen;
12
13use loader::{ChunkError, ChunkLoader};
14use chunk::Chunk;
15
16
17#[inline]
19pub fn combine_chunk_coords(cx: i32, cz: i32) -> u64 {
20 cx as u32 as u64 | ((cz as u32 as u64) << 32)
21}
22
23
24pub struct WorldInfo {
26 pub version: Version,
27 pub seed: i64,
28 pub block_registry: BlockRegistry,
29 pub biome_registry: BiomeRegistry
30}
31
32pub struct World {
34 info: Rc<WorldInfo>,
35 loader: Box<dyn ChunkLoader>,
36 chunks: HashMap<u64, Chunk>
37}
38
39impl World {
40
41 pub fn new(seed: i64, version: Version) -> World {
43
44 let block_registry = BlockRegistry::from(version);
45 let biome_registry = BiomeRegistry::from(version);
46
47 let info = Rc::new(WorldInfo {
48 version,
49 seed,
50 block_registry,
51 biome_registry
52 });
53
54 World {
55 loader: gen::for_world(Rc::clone(&info)),
56 chunks: HashMap::new(),
57 info
58 }
59
60 }
61
62 pub fn new_seeded(version: Version) -> World {
65 Self::new(jrand::gen_seed(), version)
66 }
67
68 pub fn get_info(&self) -> &WorldInfo {
69 &self.info
70 }
71
72 pub fn get_chunks(&self) -> &HashMap<u64, Chunk> {
74 &self.chunks
75 }
76
77 pub fn provide_chunk(&mut self, cx: i32, cz: i32) -> Result<&Chunk, ChunkError> {
82 match self.chunks.entry(combine_chunk_coords(cx, cz)) {
83 Entry::Occupied(o) => Ok(o.into_mut()),
84 Entry::Vacant(v) => {
85 Ok(v.insert(self.loader.load_chunk(cx, cz)?))
86 }
87 }
88 }
89
90 pub fn provide_chunk_at(&mut self, x: i32, z: i32) -> Result<&Chunk, ChunkError> {
93 self.provide_chunk(x >> 4, z >> 4)
94 }
95
96 pub fn get_chunk(&self, cx: i32, cz: i32) -> Option<&Chunk> {
100 self.chunks.get(&combine_chunk_coords(cx, cz))
101 }
102
103 pub fn get_chunk_mut(&mut self, cx: i32, cz: i32) -> Option<&mut Chunk> {
105 self.chunks.get_mut(&combine_chunk_coords(cx, cz))
106 }
107
108 pub fn get_chunk_at(&self, x: i32, z: i32) -> Option<&Chunk> {
110 self.get_chunk(x >> 4, z >> 4)
111 }
112
113 pub fn get_chunk_mut_at(&mut self, x: i32, z: i32) -> Option<&mut Chunk> {
115 self.get_chunk_mut(x >> 4, z >> 4)
116 }
117
118 fn with_chunk_at<'a, F, R>(&'a self, x: i32, y: i32, z: i32, func: F) -> Option<R>
121 where F: FnOnce(&'a Chunk, usize, usize, usize) -> Option<R>
122 {
123 if y < 0 {
124 None
125 } else {
126 let chunk = self.get_chunk_at(x, z)?;
127 let y = y as usize;
128 if y >= chunk.get_max_height() {
129 None
130 } else {
131 func(chunk, (x & 15) as usize, y, (z & 15) as usize)
132 }
133 }
134 }
135
136 fn with_chunk_mut_at<'a, F>(&'a mut self, x: i32, y: i32, z: i32, func: F)
137 where F: FnOnce(&'a mut Chunk, usize, usize, usize)
138 {
139 if y >= 0 {
140 if let Some(chunk) = self.get_chunk_mut_at(x, z) {
141 let y = y as usize;
142 if y < chunk.get_max_height() {
143 func(chunk, (x & 15) as usize, y, (z & 15) as usize)
144 }
145 }
146 }
147 }
148
149 pub fn get_block_id(&self, x: i32, y: i32, z: i32) -> Option<u16> {
154 self.with_chunk_at(x, y, z, |c, x, y, z| {
155 Some(c.get_block_id(x, y, z))
156 })
157 }
158
159 pub fn get_block(&self, x: i32, y: i32, z: i32) -> Option<&Block> {
164 self.info.block_registry.0.get_from_id(self.get_block_id(x, y, z)?)
165 }
166
167 pub fn set_block(&mut self, x: i32, y: i32, z: i32, block: Option<&Block>) {
169 self.with_chunk_mut_at(x, y, z, |c, x, y, z| {
170 c.set_block(x, y, z, block);
171 });
172 }
173
174 pub fn get_biome_2d(&self, x: i32, z: i32) -> Option<&Biome> {
177 self.with_chunk_at(x, 0, z, |c, x, _, z| {
178 Some(c.get_biome_2d(x, z))
179 })
180 }
181
182 pub fn get_biome_3d(&self, x: i32, y: i32, z: i32) -> Option<&Biome> {
183 self.with_chunk_at(x, y, z, |c, x, y, z| {
184 Some(c.get_biome_3d(x, y, z))
185 })
186 }
187
188 pub fn set_biome_2d(&mut self, x: i32, z: i32, biome: &Biome) {
189 self.with_chunk_mut_at(x, 0, z, |c, x, _, z| {
190 c.set_biome_2d(x, z, biome);
191 })
192 }
193
194 pub fn set_biome_3d(&mut self, x: i32, y: i32, z: i32, biome: &Biome) {
195 self.with_chunk_mut_at(x, y, z, |c, x, y, z| {
196 c.set_biome_3d(x, y, z, biome);
197 })
198 }
199
200 }