1use 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
115impl 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
175impl 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 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