ddcore_rs/models/
spawnset.rs

1//
2// spawnsets
3//
4
5use std::{io::{Read, Write}, mem::size_of};
6use anyhow::Result;
7use crate::utils::{align_bytes, as_bytes, writer_buf};
8
9#[derive(Debug, Clone)]
10pub struct Spawnset<SpawnType> {
11    pub header: Header,
12    pub arena: Arena,
13    pub spawns_header: SpawnsHeader,
14    pub spawns: Vec<Spawn<SpawnType>>,
15    pub settings: Option<Settings>
16}
17
18#[repr(i32)]
19#[derive(Debug, Clone, Copy, PartialEq)]
20pub enum V3Enemies {
21    Squid1 = 0,
22    Squid2 = 1,
23    Centipede = 2,
24    Spider1 = 3,
25    Leviathan = 4,
26    Gigapede = 5,
27    Squid3 = 6,
28    Thorn = 7,
29    Spider2 = 8,
30    Ghostpede = 9,
31    Empty = -1,
32}
33
34#[repr(i32)]
35#[derive(Debug, Clone, Copy, PartialEq)]
36pub enum V2Enemies {
37    Squid1 = 0,
38    Squid2 = 1,
39    Centipede = 2,
40    Spider1 = 3,
41    Leviathan = 4,
42    Gigapede = 5,
43    Squid3 = 6,
44    Andras = 7,
45    Spider2 = 8,
46    Empty = -1,
47}
48
49#[repr(i32)]
50#[derive(Debug, Clone, Copy, PartialEq)]
51pub enum V1Enemies {
52    Squid1 = 0,
53    Squid2 = 1,
54    Centipede = 2,
55    Spider1 = 3,
56    Leviathan = 4,
57    Gigapede = 5,
58    Empty = -1,
59}
60
61#[repr(C)]
62#[derive(Debug, Copy, Clone)]
63pub struct Spawn<SpawnType> {
64    pub enemy_type: SpawnType,
65    pub delay: f32,
66    pub _u1: u32,
67    pub _u2: u32,
68    pub _u3: u32,
69    pub _u4: u32,
70    pub _u5: u32
71}
72
73#[repr(C)]
74#[derive(Debug, Clone)]
75pub struct Header {
76    pub spawn_version: i32,
77    pub world_version: i32,
78    pub shrink_end_radius: f32,
79    pub shrink_start_radius: f32,
80    pub shrink_rate: f32,
81    pub brightness: f32,
82    pub game_mode: i32,
83    pub _u1: u32,
84    pub _u2: u32,
85}
86
87#[repr(C)]
88#[derive(Debug, Clone)]
89pub struct Arena {
90    pub data: [f32; 51*51],
91}
92
93#[repr(C)]
94#[derive(Debug, Clone)]
95pub struct SpawnsHeader {
96    pub _u1: u32,
97    pub _u2: u32,
98    pub _u3: u32,
99    pub _u4: u32,
100    pub devil_dagger_time: i32,
101    pub gold_dagger_time: i32,
102    pub silver_dagger_time: i32,
103    pub bronze_dagger_time: i32,
104    pub _u5: u32,
105    pub spawn_count: i32,
106}
107
108#[derive(Debug, Clone)]
109pub struct Settings {
110    pub initial_hand: u8,
111    pub additional_gems: i32,
112    pub timer_start: Option<f32>,
113}
114
115///////////////
116/*** IMPLS ***/
117///////////////
118
119impl std::default::Default for V3Enemies {
120    fn default() -> Self {
121        V3Enemies::Empty
122    }
123}
124
125impl std::default::Default for V2Enemies {
126    fn default() -> Self {
127        V2Enemies::Empty
128    }
129}
130
131impl std::default::Default for V1Enemies {
132    fn default() -> Self {
133        V1Enemies::Empty
134    }
135}
136
137impl<T: Default> std::default::Default for Spawn<T> {
138    fn default() -> Self {
139        Spawn {
140            enemy_type: T::default(),
141            delay: 0.0,
142            _u1: 0,
143            _u2: 3,
144            _u3: 0,
145            _u4: 1106247680,
146            _u5: 10,
147        }
148    }
149}
150
151impl std::default::Default for Header {
152    fn default() -> Self {
153        Header {
154            spawn_version: 6,
155            world_version: 9,
156            shrink_end_radius: 20.,
157            shrink_start_radius: 50.,
158            shrink_rate: 0.025,
159            brightness: 60.,
160            game_mode: 0,
161            _u1: 51,
162            _u2: 1,
163        }
164    }
165}
166
167impl std::default::Default for Arena {
168    fn default() -> Self {
169        Arena {
170            data: [-1000.; 51*51],
171        }
172    }
173}
174
175// Accessors 2D -> 1D
176impl Arena {
177    pub fn get_tile(&self, x: u16, y: u16) -> &f32 {
178        &self.data[y as usize * 51 + x as usize]
179    }
180
181    pub fn get_tile_mut(&mut self, x: u16, y: u16) -> &mut f32 {
182        &mut self.data[y as usize * 51 + x as usize]
183    }
184}
185
186impl std::default::Default for SpawnsHeader {
187    fn default() -> Self {
188        SpawnsHeader {
189            devil_dagger_time: 500,
190            gold_dagger_time: 250,
191            silver_dagger_time: 120,
192            bronze_dagger_time: 60,
193            spawn_count: 0,
194            _u1: 0,
195            _u2: 0,
196            _u3: 0,
197            _u4: 1,
198            _u5: 0,
199        }
200    }
201}
202
203impl std::default::Default for Settings {
204    fn default() -> Self {
205        Settings {
206            additional_gems: 0,
207            initial_hand: 0,
208            timer_start: Some(0.0),
209        }
210    }
211}
212
213impl<SpawnType: Clone> Spawnset<SpawnType> {
214    pub fn deserialize<R: Read>(source: &mut R) -> Result<Self> {
215        unsafe {
216            let mut header: Header = std::mem::zeroed();
217            let mut arena: Arena = std::mem::zeroed();
218            let mut spawns_header: SpawnsHeader = std::mem::zeroed();
219            let header_buf = writer_buf::<Header>(&mut header);
220            let arena_buf = writer_buf::<Arena>(&mut arena);
221            let spawns_header_buf = writer_buf::<SpawnsHeader>(&mut spawns_header);
222            source.read_exact(header_buf)?;
223            source.read_exact(arena_buf)?;
224            source.read_exact(spawns_header_buf)?;
225            let spawns_len = size_of::<Spawn<SpawnType>>() * spawns_header.spawn_count as usize;
226            let mut spawns_buf = vec![0u8; spawns_len];
227            source.read_exact(&mut spawns_buf)?;
228            let spawns: &[Spawn<SpawnType>] = align_bytes(&spawns_buf);
229            let mut settings = None;
230            if header.spawn_version >= 5 {
231                let mut b1 = [0u8; 1];
232                let mut b2 = [0u8; 4];
233                source.read_exact(&mut b1)?;
234                source.read_exact(&mut b2)?;
235                settings = Some(Settings {
236                    initial_hand: u8::from_le_bytes(b1),
237                    additional_gems: i32::from_le_bytes(b2),
238                    timer_start: None,
239                });
240            }
241            if header.spawn_version >= 6 {
242                if let Some(sett) = &mut settings {
243                    let mut b2 = [0u8; 4];
244                    source.read_exact(&mut b2)?;
245                    sett.timer_start = Some(f32::from_le_bytes(b2));
246                }
247            }
248
249            Ok(Spawnset {
250                header,
251                arena,
252                spawns_header,
253                spawns: spawns.to_vec(),
254                settings,
255            })
256        }
257    }
258
259    pub fn serialize<W: Write>(&self, sink: &mut W) -> Result<()> {
260        // Safe unconditionally as it's only translating the structs to bytes
261        unsafe {
262            sink.write_all(as_bytes(&self.header))?;
263            sink.write_all(as_bytes(&self.arena))?;
264            sink.write_all(as_bytes(&self.spawns_header))?;
265            for spawn in &self.spawns {
266                sink.write_all(as_bytes(spawn))?;
267            }
268        }
269        if let Some(settings) = &self.settings {
270            if self.header.spawn_version >= 5 {
271                sink.write_all(&settings.initial_hand.to_le_bytes())?;
272                sink.write_all(&settings.additional_gems.to_le_bytes())?;
273            }
274            if let Some(timer_start) = settings.timer_start {
275                if self.header.spawn_version >= 6 {
276                    sink.write_all(&timer_start.to_le_bytes())?;
277                }
278            }
279        }
280        sink.flush()?;
281        Ok(())
282    }
283
284    pub fn recalculate_spawn_count(&mut self) {
285        self.spawns_header.spawn_count = self.spawns.len() as i32;
286    }
287}
288