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 extra: HashMap<String, String>,
221}
222
223impl Default for YogDimensionDef {
224 fn default() -> Self {
225 Self {
226 id: String::new(),
227 dimension_type: YogDimensionTypeDef::default(),
228 generator_type: None,
229 extra: HashMap::new(),
230 }
231 }
232}
233
234impl YogDimensionDef {
235 pub fn new(id: impl Into<String>) -> Self {
237 Self {
238 id: id.into(),
239 ..Self::default()
240 }
241 }
242
243 pub fn dimension_type(mut self, dimension_type: YogDimensionTypeDef) -> Self {
245 self.dimension_type = dimension_type;
246 self
247 }
248
249 pub fn generator_type(mut self, generator_type_id: impl Into<String>) -> Self {
252 self.generator_type = Some(generator_type_id.into());
253 self
254 }
255
256 pub fn with_extra(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
258 self.extra.insert(key.into(), value.into());
259 self
260 }
261
262 pub fn to_json(&self) -> String {
264 serde_json::to_string(self).expect("YogDimensionDef serializes infallibly")
265 }
266}
267
268pub struct ChunkWriter(*const yog_abi::YogChunkWriterApi);
274
275impl ChunkWriter {
276 #[doc(hidden)]
277 pub unsafe fn from_raw(raw: *const yog_abi::YogChunkWriterApi) -> Self {
278 Self(raw)
279 }
280
281 #[inline]
282 fn api(&self) -> &yog_abi::YogChunkWriterApi {
283 unsafe { &*self.0 }
284 }
285
286 pub fn chunk_x(&self) -> i32 {
288 self.api().chunk_x
289 }
290
291 pub fn chunk_z(&self) -> i32 {
293 self.api().chunk_z
294 }
295
296 pub fn min_y(&self) -> i32 {
298 self.api().min_y
299 }
300
301 pub fn height(&self) -> i32 {
303 self.api().height
304 }
305
306 pub fn set_block(&self, x: i32, y: i32, z: i32, block_id: &str) -> bool {
310 let api = self.api();
311 unsafe { (api.set_block)(api.ctx, x, y, z, yog_abi::YogStr::from_str(block_id)) }
312 }
313}
314
315#[cfg(test)]
316mod tests {
317 use super::*;
318
319 #[test]
320 fn dimension_def_to_json_roundtrips_through_serde() {
321 let def = YogDimensionDef::new("mymod:my_dim")
322 .dimension_type(
323 YogDimensionTypeDef::default()
324 .ultrawarm(true)
325 .effects("nether"),
326 )
327 .generator_type("mymod:custom_terrain")
328 .with_extra("note", "test");
329
330 let json = def.to_json();
331 let back: YogDimensionDef = serde_json::from_str(&json).expect("valid json");
332 assert_eq!(back.id, "mymod:my_dim");
333 assert!(back.dimension_type.ultrawarm);
334 assert_eq!(back.dimension_type.effects, "nether");
335 assert_eq!(back.generator_type.as_deref(), Some("mymod:custom_terrain"));
336 assert_eq!(back.extra.get("note").map(String::as_str), Some("test"));
337 }
338
339 #[test]
340 fn dimension_def_can_target_a_vanilla_id_to_patch_it() {
341 let def =
342 YogDimensionDef::new("minecraft:overworld").generator_type("mymod:custom_terrain");
343 assert_eq!(def.id, "minecraft:overworld");
344 assert_eq!(def.generator_type.as_deref(), Some("mymod:custom_terrain"));
345 }
346}