1use std::collections::{HashMap, HashSet};
7use std::io::{Read, Write};
8use std::path::Path;
9
10use super::game_loop::{FlagValue, GameState, Item, ItemType, SaveData, Scene};
11use super::runtime::{
12 Alter, AlterCategory, AlterPresenceState, AnimaState, FrontingState,
13 MemoryAccess, PluralSystem, RealityLayer, Trigger, TriggerCategory,
14};
15
16pub const SAVE_FORMAT_VERSION: u32 = 1;
22
23pub const SAVE_MAGIC: &[u8; 8] = b"DAEMNGM\0";
25
26#[derive(Debug, Clone)]
32pub struct SaveFile {
33 pub version: u32,
35 pub metadata: SaveMetadata,
37 pub data: SaveData,
39}
40
41#[derive(Debug, Clone)]
43pub struct SaveMetadata {
44 pub name: String,
46 pub timestamp: u64,
48 pub play_time: u64,
50 pub location_name: String,
52 pub fronter_name: String,
54 pub completion: u8,
56}
57
58#[derive(Debug, Clone)]
64pub struct SerializedPluralSystem {
65 pub name: Option<String>,
66 pub alters: Vec<SerializedAlter>,
67 pub fronting: SerializedFrontingState,
68 pub anima: SerializedAnimaState,
69 pub reality_layer: String,
70 pub dissociation: f32,
71 pub stability: f32,
72}
73
74#[derive(Debug, Clone)]
76pub struct SerializedAlter {
77 pub id: String,
78 pub name: String,
79 pub category: String,
80 pub state: String,
81 pub anima: SerializedAnimaState,
82 pub base_arousal: f32,
83 pub base_dominance: f32,
84 pub time_since_front: u64,
85 pub triggers: Vec<String>,
86 pub abilities: Vec<String>,
87 pub preferred_reality: String,
88 pub memory_access: SerializedMemoryAccess,
89}
90
91#[derive(Debug, Clone)]
93pub struct SerializedAnimaState {
94 pub pleasure: f32,
95 pub arousal: f32,
96 pub dominance: f32,
97 pub expressiveness: f32,
98 pub stability: f32,
99}
100
101#[derive(Debug, Clone)]
103pub enum SerializedFrontingState {
104 None,
105 Single(String),
106 Blended(Vec<String>),
107 Rapid(Vec<String>),
108 Unknown,
109}
110
111#[derive(Debug, Clone)]
113pub enum SerializedMemoryAccess {
114 Full,
115 Partial(Vec<String>),
116 Own,
117 None,
118}
119
120pub struct SaveManager {
126 save_dir: String,
128 num_slots: usize,
130 auto_save_enabled: bool,
132 auto_save_interval: u64,
134}
135
136impl SaveManager {
137 pub fn new(save_dir: &str) -> Self {
139 Self {
140 save_dir: save_dir.to_string(),
141 num_slots: 3,
142 auto_save_enabled: true,
143 auto_save_interval: 300, }
145 }
146
147 fn slot_path(&self, slot: usize) -> String {
149 format!("{}/save_{}.daem", self.save_dir, slot)
150 }
151
152 fn auto_save_path(&self) -> String {
154 format!("{}/autosave.daem", self.save_dir)
155 }
156
157 pub fn save_to_slot(&self, slot: usize, state: &GameState) -> Result<(), SaveError> {
159 if slot >= self.num_slots {
160 return Err(SaveError::InvalidSlot(slot));
161 }
162
163 let save_file = self.create_save_file(state, &format!("Save {}", slot + 1))?;
164 let path = self.slot_path(slot);
165 self.write_save_file(&path, &save_file)
166 }
167
168 pub fn load_from_slot(&self, slot: usize) -> Result<GameState, SaveError> {
170 if slot >= self.num_slots {
171 return Err(SaveError::InvalidSlot(slot));
172 }
173
174 let path = self.slot_path(slot);
175 let save_file = self.read_save_file(&path)?;
176 self.create_game_state(save_file)
177 }
178
179 pub fn auto_save(&self, state: &GameState) -> Result<(), SaveError> {
181 if !self.auto_save_enabled {
182 return Ok(());
183 }
184
185 let save_file = self.create_save_file(state, "Auto Save")?;
186 let path = self.auto_save_path();
187 self.write_save_file(&path, &save_file)
188 }
189
190 pub fn load_auto_save(&self) -> Result<GameState, SaveError> {
192 let path = self.auto_save_path();
193 let save_file = self.read_save_file(&path)?;
194 self.create_game_state(save_file)
195 }
196
197 pub fn slot_exists(&self, slot: usize) -> bool {
199 let path = self.slot_path(slot);
200 Path::new(&path).exists()
201 }
202
203 pub fn get_slot_metadata(&self, slot: usize) -> Result<SaveMetadata, SaveError> {
205 if slot >= self.num_slots {
206 return Err(SaveError::InvalidSlot(slot));
207 }
208
209 let path = self.slot_path(slot);
210 let save_file = self.read_save_file(&path)?;
211 Ok(save_file.metadata)
212 }
213
214 pub fn delete_slot(&self, slot: usize) -> Result<(), SaveError> {
216 if slot >= self.num_slots {
217 return Err(SaveError::InvalidSlot(slot));
218 }
219
220 let path = self.slot_path(slot);
221 std::fs::remove_file(&path).map_err(|e| SaveError::IoError(e.to_string()))
222 }
223
224 fn create_save_file(&self, state: &GameState, name: &str) -> Result<SaveFile, SaveError> {
226 let fronter_name = match &state.system.fronting {
227 FrontingState::Single(id) => state.system.alters.get(id)
228 .map(|a| a.name.clone())
229 .unwrap_or_else(|| "Unknown".to_string()),
230 FrontingState::Blended(ids) => {
231 if ids.is_empty() {
232 "None".to_string()
233 } else {
234 format!("{} & others", ids.first().unwrap())
235 }
236 }
237 _ => "Unknown".to_string(),
238 };
239
240 let metadata = SaveMetadata {
241 name: name.to_string(),
242 timestamp: current_timestamp(),
243 play_time: state.game_time,
244 location_name: state.scene.name.clone(),
245 fronter_name,
246 completion: calculate_completion(state),
247 };
248
249 Ok(SaveFile {
250 version: SAVE_FORMAT_VERSION,
251 metadata,
252 data: state.to_save(),
253 })
254 }
255
256 fn create_game_state(&self, save_file: SaveFile) -> Result<GameState, SaveError> {
258 if save_file.version > SAVE_FORMAT_VERSION {
260 return Err(SaveError::VersionMismatch {
261 expected: SAVE_FORMAT_VERSION,
262 found: save_file.version,
263 });
264 }
265
266 Ok(GameState::from_save(save_file.data))
267 }
268
269 fn write_save_file(&self, path: &str, save_file: &SaveFile) -> Result<(), SaveError> {
271 if let Some(parent) = Path::new(path).parent() {
273 std::fs::create_dir_all(parent)
274 .map_err(|e| SaveError::IoError(e.to_string()))?;
275 }
276
277 let data = serialize_save_file(save_file)?;
279
280 let mut file = std::fs::File::create(path)
282 .map_err(|e| SaveError::IoError(e.to_string()))?;
283
284 file.write_all(&data)
285 .map_err(|e| SaveError::IoError(e.to_string()))?;
286
287 Ok(())
288 }
289
290 fn read_save_file(&self, path: &str) -> Result<SaveFile, SaveError> {
292 let mut file = std::fs::File::open(path)
294 .map_err(|e| SaveError::IoError(e.to_string()))?;
295
296 let mut data = Vec::new();
297 file.read_to_end(&mut data)
298 .map_err(|e| SaveError::IoError(e.to_string()))?;
299
300 deserialize_save_file(&data)
302 }
303}
304
305fn serialize_save_file(save_file: &SaveFile) -> Result<Vec<u8>, SaveError> {
311 let mut buffer = Vec::new();
312
313 buffer.extend_from_slice(SAVE_MAGIC);
315
316 buffer.extend_from_slice(&save_file.version.to_le_bytes());
318
319 write_string(&mut buffer, &save_file.metadata.name);
321 buffer.extend_from_slice(&save_file.metadata.timestamp.to_le_bytes());
322 buffer.extend_from_slice(&save_file.metadata.play_time.to_le_bytes());
323 write_string(&mut buffer, &save_file.metadata.location_name);
324 write_string(&mut buffer, &save_file.metadata.fronter_name);
325 buffer.push(save_file.metadata.completion);
326
327 serialize_save_data(&mut buffer, &save_file.data)?;
329
330 Ok(buffer)
331}
332
333fn deserialize_save_file(data: &[u8]) -> Result<SaveFile, SaveError> {
335 let mut cursor = 0;
336
337 if data.len() < 8 || &data[0..8] != SAVE_MAGIC {
339 return Err(SaveError::InvalidFormat("Invalid magic bytes".to_string()));
340 }
341 cursor += 8;
342
343 let version = read_u32(data, &mut cursor)?;
345
346 let name = read_string(data, &mut cursor)?;
348 let timestamp = read_u64(data, &mut cursor)?;
349 let play_time = read_u64(data, &mut cursor)?;
350 let location_name = read_string(data, &mut cursor)?;
351 let fronter_name = read_string(data, &mut cursor)?;
352 let completion = read_u8(data, &mut cursor)?;
353
354 let metadata = SaveMetadata {
355 name,
356 timestamp,
357 play_time,
358 location_name,
359 fronter_name,
360 completion,
361 };
362
363 let save_data = deserialize_save_data(data, &mut cursor)?;
365
366 Ok(SaveFile {
367 version,
368 metadata,
369 data: save_data,
370 })
371}
372
373fn serialize_save_data(buffer: &mut Vec<u8>, data: &SaveData) -> Result<(), SaveError> {
375 serialize_plural_system(buffer, &data.system)?;
377
378 serialize_scene(buffer, &data.scene);
380
381 buffer.extend_from_slice(&data.game_time.to_le_bytes());
383
384 write_u32(buffer, data.flags.len() as u32);
386 for (key, value) in &data.flags {
387 write_string(buffer, key);
388 serialize_flag_value(buffer, value);
389 }
390
391 write_u32(buffer, data.inventory.len() as u32);
393 for item in &data.inventory {
394 serialize_item(buffer, item);
395 }
396
397 write_u32(buffer, data.unlocked_abilities.len() as u32);
399 for ability in &data.unlocked_abilities {
400 write_string(buffer, ability);
401 }
402
403 write_u32(buffer, data.processed_traumas.len() as u32);
405 for trauma in &data.processed_traumas {
406 write_string(buffer, trauma);
407 }
408
409 Ok(())
410}
411
412fn deserialize_save_data(data: &[u8], cursor: &mut usize) -> Result<SaveData, SaveError> {
414 let system = deserialize_plural_system(data, cursor)?;
416
417 let scene = deserialize_scene(data, cursor)?;
419
420 let game_time = read_u64(data, cursor)?;
422
423 let flag_count = read_u32(data, cursor)? as usize;
425 let mut flags = HashMap::new();
426 for _ in 0..flag_count {
427 let key = read_string(data, cursor)?;
428 let value = deserialize_flag_value(data, cursor)?;
429 flags.insert(key, value);
430 }
431
432 let inventory_count = read_u32(data, cursor)? as usize;
434 let mut inventory = Vec::new();
435 for _ in 0..inventory_count {
436 inventory.push(deserialize_item(data, cursor)?);
437 }
438
439 let ability_count = read_u32(data, cursor)? as usize;
441 let mut unlocked_abilities = Vec::new();
442 for _ in 0..ability_count {
443 unlocked_abilities.push(read_string(data, cursor)?);
444 }
445
446 let trauma_count = read_u32(data, cursor)? as usize;
448 let mut processed_traumas = Vec::new();
449 for _ in 0..trauma_count {
450 processed_traumas.push(read_string(data, cursor)?);
451 }
452
453 Ok(SaveData {
454 system,
455 scene,
456 game_time,
457 flags,
458 inventory,
459 unlocked_abilities,
460 processed_traumas,
461 })
462}
463
464fn serialize_plural_system(buffer: &mut Vec<u8>, system: &PluralSystem) -> Result<(), SaveError> {
466 write_option_string(buffer, &system.name);
468
469 write_u32(buffer, system.alters.len() as u32);
471 for alter in system.alters.values() {
472 serialize_alter(buffer, alter)?;
473 }
474
475 serialize_fronting_state(buffer, &system.fronting);
477
478 serialize_anima_state(buffer, &system.anima);
480
481 serialize_reality_layer(buffer, &system.reality_layer);
483
484 buffer.extend_from_slice(&system.dissociation.to_le_bytes());
486 buffer.extend_from_slice(&system.stability.to_le_bytes());
487
488 Ok(())
489}
490
491fn deserialize_plural_system(data: &[u8], cursor: &mut usize) -> Result<PluralSystem, SaveError> {
493 let name = read_option_string(data, cursor)?;
494
495 let alter_count = read_u32(data, cursor)? as usize;
496 let mut alters = HashMap::new();
497 for _ in 0..alter_count {
498 let alter = deserialize_alter(data, cursor)?;
499 alters.insert(alter.id.clone(), alter);
500 }
501
502 let fronting = deserialize_fronting_state(data, cursor)?;
503 let anima = deserialize_anima_state(data, cursor)?;
504 let reality_layer = deserialize_reality_layer(data, cursor)?;
505 let dissociation = read_f32(data, cursor)?;
506 let stability = read_f32(data, cursor)?;
507
508 Ok(PluralSystem {
509 name,
510 alters,
511 fronting,
512 anima,
513 reality_layer,
514 active_triggers: Vec::new(), headspace: super::runtime::HeadspaceState::default(),
516 dissociation,
517 stability,
518 })
519}
520
521fn serialize_alter(buffer: &mut Vec<u8>, alter: &Alter) -> Result<(), SaveError> {
523 write_string(buffer, &alter.id);
524 write_string(buffer, &alter.name);
525 serialize_alter_category(buffer, &alter.category);
526 serialize_alter_state(buffer, &alter.state);
527 serialize_anima_state(buffer, &alter.anima);
528 buffer.extend_from_slice(&alter.base_arousal.to_le_bytes());
529 buffer.extend_from_slice(&alter.base_dominance.to_le_bytes());
530 buffer.extend_from_slice(&alter.time_since_front.to_le_bytes());
531
532 write_u32(buffer, alter.triggers.len() as u32);
534 for trigger in &alter.triggers {
535 write_string(buffer, trigger);
536 }
537
538 write_u32(buffer, alter.abilities.len() as u32);
540 for ability in &alter.abilities {
541 write_string(buffer, ability);
542 }
543
544 serialize_reality_layer(buffer, &alter.preferred_reality);
545 serialize_memory_access(buffer, &alter.memory_access);
546
547 Ok(())
548}
549
550fn deserialize_alter(data: &[u8], cursor: &mut usize) -> Result<Alter, SaveError> {
552 let id = read_string(data, cursor)?;
553 let name = read_string(data, cursor)?;
554 let category = deserialize_alter_category(data, cursor)?;
555 let state = deserialize_alter_state(data, cursor)?;
556 let anima = deserialize_anima_state(data, cursor)?;
557 let base_arousal = read_f32(data, cursor)?;
558 let base_dominance = read_f32(data, cursor)?;
559 let time_since_front = read_u64(data, cursor)?;
560
561 let trigger_count = read_u32(data, cursor)? as usize;
562 let mut triggers = Vec::new();
563 for _ in 0..trigger_count {
564 triggers.push(read_string(data, cursor)?);
565 }
566
567 let ability_count = read_u32(data, cursor)? as usize;
568 let mut abilities = HashSet::new();
569 for _ in 0..ability_count {
570 abilities.insert(read_string(data, cursor)?);
571 }
572
573 let preferred_reality = deserialize_reality_layer(data, cursor)?;
574 let memory_access = deserialize_memory_access(data, cursor)?;
575
576 Ok(Alter {
577 id,
578 name,
579 category,
580 state,
581 anima,
582 base_arousal,
583 base_dominance,
584 time_since_front,
585 triggers,
586 abilities,
587 preferred_reality,
588 memory_access,
589 })
590}
591
592fn serialize_anima_state(buffer: &mut Vec<u8>, anima: &AnimaState) {
597 buffer.extend_from_slice(&anima.pleasure.to_le_bytes());
598 buffer.extend_from_slice(&anima.arousal.to_le_bytes());
599 buffer.extend_from_slice(&anima.dominance.to_le_bytes());
600 buffer.extend_from_slice(&anima.expressiveness.to_le_bytes());
601 buffer.extend_from_slice(&anima.stability.to_le_bytes());
602}
603
604fn deserialize_anima_state(data: &[u8], cursor: &mut usize) -> Result<AnimaState, SaveError> {
605 Ok(AnimaState {
606 pleasure: read_f32(data, cursor)?,
607 arousal: read_f32(data, cursor)?,
608 dominance: read_f32(data, cursor)?,
609 expressiveness: read_f32(data, cursor)?,
610 stability: read_f32(data, cursor)?,
611 })
612}
613
614fn serialize_fronting_state(buffer: &mut Vec<u8>, state: &FrontingState) {
615 match state {
616 FrontingState::None => buffer.push(0),
617 FrontingState::Single(id) => {
618 buffer.push(1);
619 write_string(buffer, id);
620 }
621 FrontingState::Blended(ids) => {
622 buffer.push(2);
623 write_u32(buffer, ids.len() as u32);
624 for id in ids {
625 write_string(buffer, id);
626 }
627 }
628 FrontingState::Rapid(ids) => {
629 buffer.push(3);
630 write_u32(buffer, ids.len() as u32);
631 for id in ids {
632 write_string(buffer, id);
633 }
634 }
635 FrontingState::Unknown => buffer.push(4),
636 }
637}
638
639fn deserialize_fronting_state(data: &[u8], cursor: &mut usize) -> Result<FrontingState, SaveError> {
640 let tag = read_u8(data, cursor)?;
641 match tag {
642 0 => Ok(FrontingState::None),
643 1 => Ok(FrontingState::Single(read_string(data, cursor)?)),
644 2 => {
645 let count = read_u32(data, cursor)? as usize;
646 let mut ids = Vec::new();
647 for _ in 0..count {
648 ids.push(read_string(data, cursor)?);
649 }
650 Ok(FrontingState::Blended(ids))
651 }
652 3 => {
653 let count = read_u32(data, cursor)? as usize;
654 let mut ids = Vec::new();
655 for _ in 0..count {
656 ids.push(read_string(data, cursor)?);
657 }
658 Ok(FrontingState::Rapid(ids))
659 }
660 4 => Ok(FrontingState::Unknown),
661 _ => Err(SaveError::InvalidFormat(format!("Unknown FrontingState tag: {}", tag))),
662 }
663}
664
665fn serialize_reality_layer(buffer: &mut Vec<u8>, layer: &RealityLayer) {
666 match layer {
667 RealityLayer::Grounded => buffer.push(0),
668 RealityLayer::Fractured => buffer.push(1),
669 RealityLayer::Shattered => buffer.push(2),
670 RealityLayer::Custom(name) => {
671 buffer.push(3);
672 write_string(buffer, name);
673 }
674 }
675}
676
677fn deserialize_reality_layer(data: &[u8], cursor: &mut usize) -> Result<RealityLayer, SaveError> {
678 let tag = read_u8(data, cursor)?;
679 match tag {
680 0 => Ok(RealityLayer::Grounded),
681 1 => Ok(RealityLayer::Fractured),
682 2 => Ok(RealityLayer::Shattered),
683 3 => Ok(RealityLayer::Custom(read_string(data, cursor)?)),
684 _ => Err(SaveError::InvalidFormat(format!("Unknown RealityLayer tag: {}", tag))),
685 }
686}
687
688fn serialize_alter_category(buffer: &mut Vec<u8>, category: &AlterCategory) {
689 match category {
690 AlterCategory::Council => buffer.push(0),
691 AlterCategory::Servant => buffer.push(1),
692 AlterCategory::Fragment => buffer.push(2),
693 AlterCategory::Introject => buffer.push(3),
694 AlterCategory::Persecutor => buffer.push(4),
695 AlterCategory::TraumaHolder => buffer.push(5),
696 AlterCategory::Custom(name) => {
697 buffer.push(6);
698 write_string(buffer, name);
699 }
700 };
701}
702
703fn deserialize_alter_category(data: &[u8], cursor: &mut usize) -> Result<AlterCategory, SaveError> {
704 let tag = read_u8(data, cursor)?;
705 match tag {
706 0 => Ok(AlterCategory::Council),
707 1 => Ok(AlterCategory::Servant),
708 2 => Ok(AlterCategory::Fragment),
709 3 => Ok(AlterCategory::Introject),
710 4 => Ok(AlterCategory::Persecutor),
711 5 => Ok(AlterCategory::TraumaHolder),
712 6 => Ok(AlterCategory::Custom(read_string(data, cursor)?)),
713 _ => Err(SaveError::InvalidFormat(format!("Unknown AlterCategory tag: {}", tag))),
714 }
715}
716
717fn serialize_alter_state(buffer: &mut Vec<u8>, state: &AlterPresenceState) {
718 let tag = match state {
719 AlterPresenceState::Dormant => 0,
720 AlterPresenceState::Stirring => 1,
721 AlterPresenceState::CoConscious => 2,
722 AlterPresenceState::Emerging => 3,
723 AlterPresenceState::Fronting => 4,
724 AlterPresenceState::Receding => 5,
725 AlterPresenceState::Triggered => 6,
726 AlterPresenceState::Dissociating => 7,
727 };
728 buffer.push(tag);
729}
730
731fn deserialize_alter_state(data: &[u8], cursor: &mut usize) -> Result<AlterPresenceState, SaveError> {
732 let tag = read_u8(data, cursor)?;
733 match tag {
734 0 => Ok(AlterPresenceState::Dormant),
735 1 => Ok(AlterPresenceState::Stirring),
736 2 => Ok(AlterPresenceState::CoConscious),
737 3 => Ok(AlterPresenceState::Emerging),
738 4 => Ok(AlterPresenceState::Fronting),
739 5 => Ok(AlterPresenceState::Receding),
740 6 => Ok(AlterPresenceState::Triggered),
741 7 => Ok(AlterPresenceState::Dissociating),
742 _ => Err(SaveError::InvalidFormat(format!("Unknown AlterPresenceState tag: {}", tag))),
743 }
744}
745
746fn serialize_memory_access(buffer: &mut Vec<u8>, access: &MemoryAccess) {
747 match access {
748 MemoryAccess::Full => buffer.push(0),
749 MemoryAccess::Partial(ids) => {
750 buffer.push(1);
751 write_u32(buffer, ids.len() as u32);
752 for id in ids {
753 write_string(buffer, id);
754 }
755 }
756 MemoryAccess::Own => buffer.push(2),
757 MemoryAccess::None => buffer.push(3),
758 }
759}
760
761fn deserialize_memory_access(data: &[u8], cursor: &mut usize) -> Result<MemoryAccess, SaveError> {
762 let tag = read_u8(data, cursor)?;
763 match tag {
764 0 => Ok(MemoryAccess::Full),
765 1 => {
766 let count = read_u32(data, cursor)? as usize;
767 let mut ids = Vec::new();
768 for _ in 0..count {
769 ids.push(read_string(data, cursor)?);
770 }
771 Ok(MemoryAccess::Partial(ids))
772 }
773 2 => Ok(MemoryAccess::Own),
774 3 => Ok(MemoryAccess::None),
775 _ => Err(SaveError::InvalidFormat(format!("Unknown MemoryAccess tag: {}", tag))),
776 }
777}
778
779fn serialize_scene(buffer: &mut Vec<u8>, scene: &Scene) {
780 write_string(buffer, &scene.id);
781 write_string(buffer, &scene.name);
782 buffer.extend_from_slice(&scene.safety_level.to_le_bytes());
783 buffer.extend_from_slice(&scene.player_position.0.to_le_bytes());
784 buffer.extend_from_slice(&scene.player_position.1.to_le_bytes());
785 }
787
788fn deserialize_scene(data: &[u8], cursor: &mut usize) -> Result<Scene, SaveError> {
789 let id = read_string(data, cursor)?;
790 let name = read_string(data, cursor)?;
791 let safety_level = read_f32(data, cursor)?;
792 let x = read_f32(data, cursor)?;
793 let y = read_f32(data, cursor)?;
794
795 Ok(Scene {
796 id,
797 name,
798 safety_level,
799 player_position: (x, y),
800 entities: Vec::new(), trigger_zones: Vec::new(),
802 interactables: Vec::new(),
803 active_cutscene: None,
804 })
805}
806
807fn serialize_flag_value(buffer: &mut Vec<u8>, value: &FlagValue) {
808 match value {
809 FlagValue::Bool(b) => {
810 buffer.push(0);
811 buffer.push(if *b { 1 } else { 0 });
812 }
813 FlagValue::Int(i) => {
814 buffer.push(1);
815 buffer.extend_from_slice(&i.to_le_bytes());
816 }
817 FlagValue::String(s) => {
818 buffer.push(2);
819 write_string(buffer, s);
820 }
821 }
822}
823
824fn deserialize_flag_value(data: &[u8], cursor: &mut usize) -> Result<FlagValue, SaveError> {
825 let tag = read_u8(data, cursor)?;
826 match tag {
827 0 => Ok(FlagValue::Bool(read_u8(data, cursor)? != 0)),
828 1 => Ok(FlagValue::Int(read_i32(data, cursor)?)),
829 2 => Ok(FlagValue::String(read_string(data, cursor)?)),
830 _ => Err(SaveError::InvalidFormat(format!("Unknown FlagValue tag: {}", tag))),
831 }
832}
833
834fn serialize_item(buffer: &mut Vec<u8>, item: &Item) {
835 write_string(buffer, &item.id);
836 write_string(buffer, &item.name);
837 write_string(buffer, &item.description);
838 let type_tag = match item.item_type {
839 ItemType::Key => 0,
840 ItemType::Consumable => 1,
841 ItemType::Document => 2,
842 ItemType::Memento => 3,
843 };
844 buffer.push(type_tag);
845}
846
847fn deserialize_item(data: &[u8], cursor: &mut usize) -> Result<Item, SaveError> {
848 let id = read_string(data, cursor)?;
849 let name = read_string(data, cursor)?;
850 let description = read_string(data, cursor)?;
851 let type_tag = read_u8(data, cursor)?;
852 let item_type = match type_tag {
853 0 => ItemType::Key,
854 1 => ItemType::Consumable,
855 2 => ItemType::Document,
856 3 => ItemType::Memento,
857 _ => return Err(SaveError::InvalidFormat(format!("Unknown ItemType tag: {}", type_tag))),
858 };
859
860 Ok(Item {
861 id,
862 name,
863 description,
864 item_type,
865 })
866}
867
868fn write_u32(buffer: &mut Vec<u8>, value: u32) {
873 buffer.extend_from_slice(&value.to_le_bytes());
874}
875
876fn read_u8(data: &[u8], cursor: &mut usize) -> Result<u8, SaveError> {
877 if *cursor >= data.len() {
878 return Err(SaveError::UnexpectedEof);
879 }
880 let value = data[*cursor];
881 *cursor += 1;
882 Ok(value)
883}
884
885fn read_u32(data: &[u8], cursor: &mut usize) -> Result<u32, SaveError> {
886 if *cursor + 4 > data.len() {
887 return Err(SaveError::UnexpectedEof);
888 }
889 let bytes: [u8; 4] = data[*cursor..*cursor + 4].try_into().unwrap();
890 *cursor += 4;
891 Ok(u32::from_le_bytes(bytes))
892}
893
894fn read_i32(data: &[u8], cursor: &mut usize) -> Result<i32, SaveError> {
895 if *cursor + 4 > data.len() {
896 return Err(SaveError::UnexpectedEof);
897 }
898 let bytes: [u8; 4] = data[*cursor..*cursor + 4].try_into().unwrap();
899 *cursor += 4;
900 Ok(i32::from_le_bytes(bytes))
901}
902
903fn read_u64(data: &[u8], cursor: &mut usize) -> Result<u64, SaveError> {
904 if *cursor + 8 > data.len() {
905 return Err(SaveError::UnexpectedEof);
906 }
907 let bytes: [u8; 8] = data[*cursor..*cursor + 8].try_into().unwrap();
908 *cursor += 8;
909 Ok(u64::from_le_bytes(bytes))
910}
911
912fn read_f32(data: &[u8], cursor: &mut usize) -> Result<f32, SaveError> {
913 if *cursor + 4 > data.len() {
914 return Err(SaveError::UnexpectedEof);
915 }
916 let bytes: [u8; 4] = data[*cursor..*cursor + 4].try_into().unwrap();
917 *cursor += 4;
918 Ok(f32::from_le_bytes(bytes))
919}
920
921fn write_string(buffer: &mut Vec<u8>, s: &str) {
922 let bytes = s.as_bytes();
923 write_u32(buffer, bytes.len() as u32);
924 buffer.extend_from_slice(bytes);
925}
926
927fn read_string(data: &[u8], cursor: &mut usize) -> Result<String, SaveError> {
928 let len = read_u32(data, cursor)? as usize;
929 if *cursor + len > data.len() {
930 return Err(SaveError::UnexpectedEof);
931 }
932 let bytes = &data[*cursor..*cursor + len];
933 *cursor += len;
934 String::from_utf8(bytes.to_vec())
935 .map_err(|e| SaveError::InvalidFormat(e.to_string()))
936}
937
938fn write_option_string(buffer: &mut Vec<u8>, opt: &Option<String>) {
939 match opt {
940 Some(s) => {
941 buffer.push(1);
942 write_string(buffer, s);
943 }
944 None => buffer.push(0),
945 }
946}
947
948fn read_option_string(data: &[u8], cursor: &mut usize) -> Result<Option<String>, SaveError> {
949 let has_value = read_u8(data, cursor)?;
950 if has_value != 0 {
951 Ok(Some(read_string(data, cursor)?))
952 } else {
953 Ok(None)
954 }
955}
956
957fn current_timestamp() -> u64 {
962 std::time::SystemTime::now()
963 .duration_since(std::time::UNIX_EPOCH)
964 .map(|d| d.as_secs())
965 .unwrap_or(0)
966}
967
968fn calculate_completion(state: &GameState) -> u8 {
969 let trauma_progress = (state.processed_traumas.len() as f32 / 10.0 * 100.0).min(100.0);
972 trauma_progress as u8
973}
974
975#[derive(Debug)]
981pub enum SaveError {
982 InvalidSlot(usize),
984 IoError(String),
986 InvalidFormat(String),
988 VersionMismatch { expected: u32, found: u32 },
990 UnexpectedEof,
992 Corrupted(String),
994}
995
996impl std::fmt::Display for SaveError {
997 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
998 match self {
999 SaveError::InvalidSlot(slot) => write!(f, "Invalid save slot: {}", slot),
1000 SaveError::IoError(msg) => write!(f, "I/O error: {}", msg),
1001 SaveError::InvalidFormat(msg) => write!(f, "Invalid save format: {}", msg),
1002 SaveError::VersionMismatch { expected, found } => {
1003 write!(f, "Save version mismatch: expected {}, found {}", expected, found)
1004 }
1005 SaveError::UnexpectedEof => write!(f, "Unexpected end of save file"),
1006 SaveError::Corrupted(msg) => write!(f, "Save file corrupted: {}", msg),
1007 }
1008 }
1009}
1010
1011impl std::error::Error for SaveError {}
1012
1013#[cfg(test)]
1018mod tests {
1019 use super::*;
1020
1021 #[test]
1022 fn test_serialize_anima_state() {
1023 let anima = AnimaState::new(0.5, 0.3, 0.7);
1024 let mut buffer = Vec::new();
1025 serialize_anima_state(&mut buffer, &anima);
1026
1027 let mut cursor = 0;
1028 let result = deserialize_anima_state(&buffer, &mut cursor).unwrap();
1029
1030 assert!((result.pleasure - 0.5).abs() < 0.001);
1031 assert!((result.arousal - 0.3).abs() < 0.001);
1032 assert!((result.dominance - 0.7).abs() < 0.001);
1033 }
1034
1035 #[test]
1036 fn test_serialize_fronting_state() {
1037 let states = vec![
1038 FrontingState::None,
1039 FrontingState::Single("host".to_string()),
1040 FrontingState::Blended(vec!["a".to_string(), "b".to_string()]),
1041 FrontingState::Unknown,
1042 ];
1043
1044 for state in states {
1045 let mut buffer = Vec::new();
1046 serialize_fronting_state(&mut buffer, &state);
1047
1048 let mut cursor = 0;
1049 let result = deserialize_fronting_state(&buffer, &mut cursor).unwrap();
1050
1051 match (&state, &result) {
1052 (FrontingState::None, FrontingState::None) => {}
1053 (FrontingState::Single(a), FrontingState::Single(b)) => assert_eq!(a, b),
1054 (FrontingState::Blended(a), FrontingState::Blended(b)) => assert_eq!(a, b),
1055 (FrontingState::Unknown, FrontingState::Unknown) => {}
1056 _ => panic!("Mismatch: {:?} vs {:?}", state, result),
1057 }
1058 }
1059 }
1060
1061 #[test]
1062 fn test_serialize_reality_layer() {
1063 let layers = vec![
1064 RealityLayer::Grounded,
1065 RealityLayer::Fractured,
1066 RealityLayer::Shattered,
1067 RealityLayer::Custom("nightmare".to_string()),
1068 ];
1069
1070 for layer in layers {
1071 let mut buffer = Vec::new();
1072 serialize_reality_layer(&mut buffer, &layer);
1073
1074 let mut cursor = 0;
1075 let result = deserialize_reality_layer(&buffer, &mut cursor).unwrap();
1076
1077 match (&layer, &result) {
1078 (RealityLayer::Grounded, RealityLayer::Grounded) => {}
1079 (RealityLayer::Fractured, RealityLayer::Fractured) => {}
1080 (RealityLayer::Shattered, RealityLayer::Shattered) => {}
1081 (RealityLayer::Custom(a), RealityLayer::Custom(b)) => assert_eq!(a, b),
1082 _ => panic!("Mismatch: {:?} vs {:?}", layer, result),
1083 }
1084 }
1085 }
1086
1087 #[test]
1088 fn test_save_file_roundtrip() {
1089 let state = GameState::new();
1090 let manager = SaveManager::new("/tmp/test_saves");
1091
1092 let save_file = manager.create_save_file(&state, "Test Save").unwrap();
1093 let serialized = serialize_save_file(&save_file).unwrap();
1094 let deserialized = deserialize_save_file(&serialized).unwrap();
1095
1096 assert_eq!(save_file.version, deserialized.version);
1097 assert_eq!(save_file.metadata.name, deserialized.metadata.name);
1098 assert_eq!(save_file.data.game_time, deserialized.data.game_time);
1099 }
1100
1101 #[test]
1102 fn test_save_manager_slot_validation() {
1103 let manager = SaveManager::new("/tmp/test_saves");
1104
1105 let result = manager.save_to_slot(10, &GameState::new());
1107 assert!(matches!(result, Err(SaveError::InvalidSlot(_))));
1108 }
1109}