1use std::collections::HashMap;
34
35use serde::{Deserialize, Serialize};
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
46#[serde(default)]
47pub struct YogDimensionTypeDef {
48 pub min_y: i32,
49 pub height: i32,
50 pub logical_height: i32,
51 pub has_sky_light: bool,
52 pub sky_light_updates: bool,
53 pub ambient_light: f32,
54 pub coordinate_scale: f32,
55 pub ultrawarm: bool,
56 pub beds_explode: bool,
57 pub respawn_anchors_explode: bool,
58 pub piglin_safe: bool,
59 pub natural: bool,
60 pub has_ceiling: bool,
61 pub effects: String,
62 pub has_sky: bool,
63 pub has_clouds: bool,
64 pub cloud_height: f64,
65 pub has_fog: bool,
66 pub fog_color: Option<i32>,
67 pub sky_color: Option<i32>,
68 pub water_color: Option<i32>,
69 pub water_fog_color: Option<i32>,
70}
71
72impl Default for YogDimensionTypeDef {
73 fn default() -> Self {
74 Self {
75 min_y: -64,
76 height: 384,
77 logical_height: 384,
78 has_sky_light: true,
79 sky_light_updates: true,
80 ambient_light: 0.0,
81 coordinate_scale: 1.0,
82 ultrawarm: false,
83 beds_explode: false,
84 respawn_anchors_explode: false,
85 piglin_safe: false,
86 natural: true,
87 has_ceiling: false,
88 effects: "overworld".to_owned(),
89 has_sky: true,
90 has_clouds: true,
91 cloud_height: 192.0,
92 has_fog: false,
93 fog_color: None,
94 sky_color: None,
95 water_color: None,
96 water_fog_color: None,
97 }
98 }
99}
100
101impl YogDimensionTypeDef {
102 pub fn min_y(mut self, v: i32) -> Self {
106 self.min_y = v;
107 self
108 }
109 pub fn height(mut self, v: i32) -> Self {
110 self.height = v;
111 self.logical_height = v;
112 self
113 }
114 pub fn logical_height(mut self, v: i32) -> Self {
115 self.logical_height = v;
116 self
117 }
118 pub fn has_sky_light(mut self, v: bool) -> Self {
119 self.has_sky_light = v;
120 self
121 }
122 pub fn sky_light_updates(mut self, v: bool) -> Self {
123 self.sky_light_updates = v;
124 self
125 }
126 pub fn ambient_light(mut self, v: f32) -> Self {
127 self.ambient_light = v;
128 self
129 }
130 pub fn coordinate_scale(mut self, v: f32) -> Self {
131 self.coordinate_scale = v;
132 self
133 }
134 pub fn ultrawarm(mut self, v: bool) -> Self {
135 self.ultrawarm = v;
136 self
137 }
138 pub fn beds_explode(mut self, v: bool) -> Self {
139 self.beds_explode = v;
140 self
141 }
142 pub fn respawn_anchors_explode(mut self, v: bool) -> Self {
143 self.respawn_anchors_explode = v;
144 self
145 }
146 pub fn piglin_safe(mut self, v: bool) -> Self {
147 self.piglin_safe = v;
148 self
149 }
150 pub fn natural(mut self, v: bool) -> Self {
151 self.natural = v;
152 self
153 }
154 pub fn has_ceiling(mut self, v: bool) -> Self {
155 self.has_ceiling = v;
156 self
157 }
158 pub fn effects(mut self, v: impl Into<String>) -> Self {
159 self.effects = v.into();
160 self
161 }
162 pub fn has_sky(mut self, v: bool) -> Self {
163 self.has_sky = v;
164 self
165 }
166 pub fn has_clouds(mut self, v: bool) -> Self {
167 self.has_clouds = v;
168 self
169 }
170 pub fn cloud_height(mut self, v: f64) -> Self {
171 self.cloud_height = v;
172 self
173 }
174 pub fn has_fog(mut self, v: bool) -> Self {
175 self.has_fog = v;
176 self
177 }
178 pub fn fog_color(mut self, v: i32) -> Self {
179 self.fog_color = Some(v);
180 self
181 }
182 pub fn sky_color(mut self, v: i32) -> Self {
183 self.sky_color = Some(v);
184 self
185 }
186 pub fn water_color(mut self, v: i32) -> Self {
187 self.water_color = Some(v);
188 self
189 }
190 pub fn water_fog_color(mut self, v: i32) -> Self {
191 self.water_fog_color = Some(v);
192 self
193 }
194}
195
196#[derive(Debug, Clone, Serialize, Deserialize)]
207#[serde(default)]
208pub struct YogDimensionDef {
209 pub id: String,
213 pub dimension_type: YogDimensionTypeDef,
214 pub generator_type: Option<String>,
218 pub biome: String,
221 pub structures: bool,
224 pub features: bool,
227 pub mob_spawning: bool,
230 pub extra: HashMap<String, String>,
233}
234
235impl Default for YogDimensionDef {
236 fn default() -> Self {
237 Self {
238 id: String::new(),
239 dimension_type: YogDimensionTypeDef::default(),
240 generator_type: None,
241 biome: "minecraft:plains".into(),
242 structures: true,
243 features: true,
244 mob_spawning: true,
245 extra: HashMap::new(),
246 }
247 }
248}
249
250impl YogDimensionDef {
251 pub fn new(id: impl Into<String>) -> Self {
253 Self {
254 id: id.into(),
255 ..Self::default()
256 }
257 }
258
259 pub fn dimension_type(mut self, dimension_type: YogDimensionTypeDef) -> Self {
261 self.dimension_type = dimension_type;
262 self
263 }
264
265 pub fn generator_type(mut self, generator_type_id: impl Into<String>) -> Self {
268 self.generator_type = Some(generator_type_id.into());
269 self
270 }
271
272 pub fn biome(mut self, biome: impl Into<String>) -> Self {
274 self.biome = biome.into();
275 self
276 }
277
278 pub fn structures(mut self, on: bool) -> Self {
280 self.structures = on;
281 self
282 }
283
284 pub fn features(mut self, on: bool) -> Self {
286 self.features = on;
287 self
288 }
289
290 pub fn mob_spawning(mut self, on: bool) -> Self {
292 self.mob_spawning = on;
293 self
294 }
295
296 pub fn with_extra(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
298 self.extra.insert(key.into(), value.into());
299 self
300 }
301
302 pub fn to_json(&self) -> String {
304 serde_json::to_string(self).expect("YogDimensionDef serializes infallibly")
305 }
306}
307
308pub struct ChunkWriter(*const yog_abi::YogChunkWriterApi);
314
315impl ChunkWriter {
316 #[doc(hidden)]
317 pub unsafe fn from_raw(raw: *const yog_abi::YogChunkWriterApi) -> Self {
318 Self(raw)
319 }
320
321 #[inline]
322 fn api(&self) -> &yog_abi::YogChunkWriterApi {
323 unsafe { &*self.0 }
324 }
325
326 pub fn chunk_x(&self) -> i32 {
328 self.api().chunk_x
329 }
330
331 pub fn chunk_z(&self) -> i32 {
333 self.api().chunk_z
334 }
335
336 pub fn min_y(&self) -> i32 {
338 self.api().min_y
339 }
340
341 pub fn height(&self) -> i32 {
343 self.api().height
344 }
345
346 pub fn set_block(&self, x: i32, y: i32, z: i32, block_id: &str) -> bool {
350 let api = self.api();
351 unsafe { (api.set_block)(api.ctx, x, y, z, yog_abi::YogStr::from_str(block_id)) }
352 }
353}
354
355#[cfg(test)]
356mod tests {
357 use super::*;
358
359 #[test]
360 fn dimension_def_to_json_roundtrips_through_serde() {
361 let def = YogDimensionDef::new("mymod:my_dim")
362 .dimension_type(
363 YogDimensionTypeDef::default()
364 .ultrawarm(true)
365 .effects("nether"),
366 )
367 .generator_type("mymod:custom_terrain")
368 .with_extra("note", "test");
369
370 let json = def.to_json();
371 let back: YogDimensionDef = serde_json::from_str(&json).expect("valid json");
372 assert_eq!(back.id, "mymod:my_dim");
373 assert!(back.dimension_type.ultrawarm);
374 assert_eq!(back.dimension_type.effects, "nether");
375 assert_eq!(back.generator_type.as_deref(), Some("mymod:custom_terrain"));
376 assert_eq!(back.extra.get("note").map(String::as_str), Some("test"));
377 }
378
379 #[test]
380 fn dimension_def_can_target_a_vanilla_id_to_patch_it() {
381 let def =
382 YogDimensionDef::new("minecraft:overworld").generator_type("mymod:custom_terrain");
383 assert_eq!(def.id, "minecraft:overworld");
384 assert_eq!(def.generator_type.as_deref(), Some("mymod:custom_terrain"));
385 }
386}