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, MemoryAccess,
13 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
228 .system
229 .alters
230 .get(id)
231 .map(|a| a.name.clone())
232 .unwrap_or_else(|| "Unknown".to_string()),
233 FrontingState::Blended(ids) => {
234 if ids.is_empty() {
235 "None".to_string()
236 } else {
237 format!("{} & others", ids.first().unwrap())
238 }
239 }
240 _ => "Unknown".to_string(),
241 };
242
243 let metadata = SaveMetadata {
244 name: name.to_string(),
245 timestamp: current_timestamp(),
246 play_time: state.game_time,
247 location_name: state.scene.name.clone(),
248 fronter_name,
249 completion: calculate_completion(state),
250 };
251
252 Ok(SaveFile {
253 version: SAVE_FORMAT_VERSION,
254 metadata,
255 data: state.to_save(),
256 })
257 }
258
259 fn create_game_state(&self, save_file: SaveFile) -> Result<GameState, SaveError> {
261 if save_file.version > SAVE_FORMAT_VERSION {
263 return Err(SaveError::VersionMismatch {
264 expected: SAVE_FORMAT_VERSION,
265 found: save_file.version,
266 });
267 }
268
269 Ok(GameState::from_save(save_file.data))
270 }
271
272 fn write_save_file(&self, path: &str, save_file: &SaveFile) -> Result<(), SaveError> {
274 if let Some(parent) = Path::new(path).parent() {
276 std::fs::create_dir_all(parent).map_err(|e| SaveError::IoError(e.to_string()))?;
277 }
278
279 let data = serialize_save_file(save_file)?;
281
282 let mut file =
284 std::fs::File::create(path).map_err(|e| SaveError::IoError(e.to_string()))?;
285
286 file.write_all(&data)
287 .map_err(|e| SaveError::IoError(e.to_string()))?;
288
289 Ok(())
290 }
291
292 fn read_save_file(&self, path: &str) -> Result<SaveFile, SaveError> {
294 let mut file = std::fs::File::open(path).map_err(|e| SaveError::IoError(e.to_string()))?;
296
297 let mut data = Vec::new();
298 file.read_to_end(&mut data)
299 .map_err(|e| SaveError::IoError(e.to_string()))?;
300
301 deserialize_save_file(&data)
303 }
304}
305
306fn serialize_save_file(save_file: &SaveFile) -> Result<Vec<u8>, SaveError> {
312 let mut buffer = Vec::new();
313
314 buffer.extend_from_slice(SAVE_MAGIC);
316
317 buffer.extend_from_slice(&save_file.version.to_le_bytes());
319
320 write_string(&mut buffer, &save_file.metadata.name);
322 buffer.extend_from_slice(&save_file.metadata.timestamp.to_le_bytes());
323 buffer.extend_from_slice(&save_file.metadata.play_time.to_le_bytes());
324 write_string(&mut buffer, &save_file.metadata.location_name);
325 write_string(&mut buffer, &save_file.metadata.fronter_name);
326 buffer.push(save_file.metadata.completion);
327
328 serialize_save_data(&mut buffer, &save_file.data)?;
330
331 Ok(buffer)
332}
333
334fn deserialize_save_file(data: &[u8]) -> Result<SaveFile, SaveError> {
336 let mut cursor = 0;
337
338 if data.len() < 8 || &data[0..8] != SAVE_MAGIC {
340 return Err(SaveError::InvalidFormat("Invalid magic bytes".to_string()));
341 }
342 cursor += 8;
343
344 let version = read_u32(data, &mut cursor)?;
346
347 let name = read_string(data, &mut cursor)?;
349 let timestamp = read_u64(data, &mut cursor)?;
350 let play_time = read_u64(data, &mut cursor)?;
351 let location_name = read_string(data, &mut cursor)?;
352 let fronter_name = read_string(data, &mut cursor)?;
353 let completion = read_u8(data, &mut cursor)?;
354
355 let metadata = SaveMetadata {
356 name,
357 timestamp,
358 play_time,
359 location_name,
360 fronter_name,
361 completion,
362 };
363
364 let save_data = deserialize_save_data(data, &mut cursor)?;
366
367 Ok(SaveFile {
368 version,
369 metadata,
370 data: save_data,
371 })
372}
373
374fn serialize_save_data(buffer: &mut Vec<u8>, data: &SaveData) -> Result<(), SaveError> {
376 serialize_plural_system(buffer, &data.system)?;
378
379 serialize_scene(buffer, &data.scene);
381
382 buffer.extend_from_slice(&data.game_time.to_le_bytes());
384
385 write_u32(buffer, data.flags.len() as u32);
387 for (key, value) in &data.flags {
388 write_string(buffer, key);
389 serialize_flag_value(buffer, value);
390 }
391
392 write_u32(buffer, data.inventory.len() as u32);
394 for item in &data.inventory {
395 serialize_item(buffer, item);
396 }
397
398 write_u32(buffer, data.unlocked_abilities.len() as u32);
400 for ability in &data.unlocked_abilities {
401 write_string(buffer, ability);
402 }
403
404 write_u32(buffer, data.processed_traumas.len() as u32);
406 for trauma in &data.processed_traumas {
407 write_string(buffer, trauma);
408 }
409
410 Ok(())
411}
412
413fn deserialize_save_data(data: &[u8], cursor: &mut usize) -> Result<SaveData, SaveError> {
415 let system = deserialize_plural_system(data, cursor)?;
417
418 let scene = deserialize_scene(data, cursor)?;
420
421 let game_time = read_u64(data, cursor)?;
423
424 let flag_count = read_u32(data, cursor)? as usize;
426 let mut flags = HashMap::new();
427 for _ in 0..flag_count {
428 let key = read_string(data, cursor)?;
429 let value = deserialize_flag_value(data, cursor)?;
430 flags.insert(key, value);
431 }
432
433 let inventory_count = read_u32(data, cursor)? as usize;
435 let mut inventory = Vec::new();
436 for _ in 0..inventory_count {
437 inventory.push(deserialize_item(data, cursor)?);
438 }
439
440 let ability_count = read_u32(data, cursor)? as usize;
442 let mut unlocked_abilities = Vec::new();
443 for _ in 0..ability_count {
444 unlocked_abilities.push(read_string(data, cursor)?);
445 }
446
447 let trauma_count = read_u32(data, cursor)? as usize;
449 let mut processed_traumas = Vec::new();
450 for _ in 0..trauma_count {
451 processed_traumas.push(read_string(data, cursor)?);
452 }
453
454 Ok(SaveData {
455 system,
456 scene,
457 game_time,
458 flags,
459 inventory,
460 unlocked_abilities,
461 processed_traumas,
462 })
463}
464
465fn serialize_plural_system(buffer: &mut Vec<u8>, system: &PluralSystem) -> Result<(), SaveError> {
467 write_option_string(buffer, &system.name);
469
470 write_u32(buffer, system.alters.len() as u32);
472 for alter in system.alters.values() {
473 serialize_alter(buffer, alter)?;
474 }
475
476 serialize_fronting_state(buffer, &system.fronting);
478
479 serialize_anima_state(buffer, &system.anima);
481
482 serialize_reality_layer(buffer, &system.reality_layer);
484
485 buffer.extend_from_slice(&system.dissociation.to_le_bytes());
487 buffer.extend_from_slice(&system.stability.to_le_bytes());
488
489 Ok(())
490}
491
492fn deserialize_plural_system(data: &[u8], cursor: &mut usize) -> Result<PluralSystem, SaveError> {
494 let name = read_option_string(data, cursor)?;
495
496 let alter_count = read_u32(data, cursor)? as usize;
497 let mut alters = HashMap::new();
498 for _ in 0..alter_count {
499 let alter = deserialize_alter(data, cursor)?;
500 alters.insert(alter.id.clone(), alter);
501 }
502
503 let fronting = deserialize_fronting_state(data, cursor)?;
504 let anima = deserialize_anima_state(data, cursor)?;
505 let reality_layer = deserialize_reality_layer(data, cursor)?;
506 let dissociation = read_f32(data, cursor)?;
507 let stability = read_f32(data, cursor)?;
508
509 Ok(PluralSystem {
510 name,
511 alters,
512 fronting,
513 anima,
514 reality_layer,
515 active_triggers: Vec::new(), headspace: super::runtime::HeadspaceState::default(),
517 dissociation,
518 stability,
519 })
520}
521
522fn serialize_alter(buffer: &mut Vec<u8>, alter: &Alter) -> Result<(), SaveError> {
524 write_string(buffer, &alter.id);
525 write_string(buffer, &alter.name);
526 serialize_alter_category(buffer, &alter.category);
527 serialize_alter_state(buffer, &alter.state);
528 serialize_anima_state(buffer, &alter.anima);
529 buffer.extend_from_slice(&alter.base_arousal.to_le_bytes());
530 buffer.extend_from_slice(&alter.base_dominance.to_le_bytes());
531 buffer.extend_from_slice(&alter.time_since_front.to_le_bytes());
532
533 write_u32(buffer, alter.triggers.len() as u32);
535 for trigger in &alter.triggers {
536 write_string(buffer, trigger);
537 }
538
539 write_u32(buffer, alter.abilities.len() as u32);
541 for ability in &alter.abilities {
542 write_string(buffer, ability);
543 }
544
545 serialize_reality_layer(buffer, &alter.preferred_reality);
546 serialize_memory_access(buffer, &alter.memory_access);
547
548 Ok(())
549}
550
551fn deserialize_alter(data: &[u8], cursor: &mut usize) -> Result<Alter, SaveError> {
553 let id = read_string(data, cursor)?;
554 let name = read_string(data, cursor)?;
555 let category = deserialize_alter_category(data, cursor)?;
556 let state = deserialize_alter_state(data, cursor)?;
557 let anima = deserialize_anima_state(data, cursor)?;
558 let base_arousal = read_f32(data, cursor)?;
559 let base_dominance = read_f32(data, cursor)?;
560 let time_since_front = read_u64(data, cursor)?;
561
562 let trigger_count = read_u32(data, cursor)? as usize;
563 let mut triggers = Vec::new();
564 for _ in 0..trigger_count {
565 triggers.push(read_string(data, cursor)?);
566 }
567
568 let ability_count = read_u32(data, cursor)? as usize;
569 let mut abilities = HashSet::new();
570 for _ in 0..ability_count {
571 abilities.insert(read_string(data, cursor)?);
572 }
573
574 let preferred_reality = deserialize_reality_layer(data, cursor)?;
575 let memory_access = deserialize_memory_access(data, cursor)?;
576
577 Ok(Alter {
578 id,
579 name,
580 category,
581 state,
582 anima,
583 base_arousal,
584 base_dominance,
585 time_since_front,
586 triggers,
587 abilities,
588 preferred_reality,
589 memory_access,
590 })
591}
592
593fn serialize_anima_state(buffer: &mut Vec<u8>, anima: &AnimaState) {
598 buffer.extend_from_slice(&anima.pleasure.to_le_bytes());
599 buffer.extend_from_slice(&anima.arousal.to_le_bytes());
600 buffer.extend_from_slice(&anima.dominance.to_le_bytes());
601 buffer.extend_from_slice(&anima.expressiveness.to_le_bytes());
602 buffer.extend_from_slice(&anima.stability.to_le_bytes());
603}
604
605fn deserialize_anima_state(data: &[u8], cursor: &mut usize) -> Result<AnimaState, SaveError> {
606 Ok(AnimaState {
607 pleasure: read_f32(data, cursor)?,
608 arousal: read_f32(data, cursor)?,
609 dominance: read_f32(data, cursor)?,
610 expressiveness: read_f32(data, cursor)?,
611 stability: read_f32(data, cursor)?,
612 })
613}
614
615fn serialize_fronting_state(buffer: &mut Vec<u8>, state: &FrontingState) {
616 match state {
617 FrontingState::None => buffer.push(0),
618 FrontingState::Single(id) => {
619 buffer.push(1);
620 write_string(buffer, id);
621 }
622 FrontingState::Blended(ids) => {
623 buffer.push(2);
624 write_u32(buffer, ids.len() as u32);
625 for id in ids {
626 write_string(buffer, id);
627 }
628 }
629 FrontingState::Rapid(ids) => {
630 buffer.push(3);
631 write_u32(buffer, ids.len() as u32);
632 for id in ids {
633 write_string(buffer, id);
634 }
635 }
636 FrontingState::Unknown => buffer.push(4),
637 }
638}
639
640fn deserialize_fronting_state(data: &[u8], cursor: &mut usize) -> Result<FrontingState, SaveError> {
641 let tag = read_u8(data, cursor)?;
642 match tag {
643 0 => Ok(FrontingState::None),
644 1 => Ok(FrontingState::Single(read_string(data, cursor)?)),
645 2 => {
646 let count = read_u32(data, cursor)? as usize;
647 let mut ids = Vec::new();
648 for _ in 0..count {
649 ids.push(read_string(data, cursor)?);
650 }
651 Ok(FrontingState::Blended(ids))
652 }
653 3 => {
654 let count = read_u32(data, cursor)? as usize;
655 let mut ids = Vec::new();
656 for _ in 0..count {
657 ids.push(read_string(data, cursor)?);
658 }
659 Ok(FrontingState::Rapid(ids))
660 }
661 4 => Ok(FrontingState::Unknown),
662 _ => Err(SaveError::InvalidFormat(format!(
663 "Unknown FrontingState tag: {}",
664 tag
665 ))),
666 }
667}
668
669fn serialize_reality_layer(buffer: &mut Vec<u8>, layer: &RealityLayer) {
670 match layer {
671 RealityLayer::Grounded => buffer.push(0),
672 RealityLayer::Fractured => buffer.push(1),
673 RealityLayer::Shattered => buffer.push(2),
674 RealityLayer::Custom(name) => {
675 buffer.push(3);
676 write_string(buffer, name);
677 }
678 }
679}
680
681fn deserialize_reality_layer(data: &[u8], cursor: &mut usize) -> Result<RealityLayer, SaveError> {
682 let tag = read_u8(data, cursor)?;
683 match tag {
684 0 => Ok(RealityLayer::Grounded),
685 1 => Ok(RealityLayer::Fractured),
686 2 => Ok(RealityLayer::Shattered),
687 3 => Ok(RealityLayer::Custom(read_string(data, cursor)?)),
688 _ => Err(SaveError::InvalidFormat(format!(
689 "Unknown RealityLayer tag: {}",
690 tag
691 ))),
692 }
693}
694
695fn serialize_alter_category(buffer: &mut Vec<u8>, category: &AlterCategory) {
696 match category {
697 AlterCategory::Council => buffer.push(0),
698 AlterCategory::Servant => buffer.push(1),
699 AlterCategory::Fragment => buffer.push(2),
700 AlterCategory::Introject => buffer.push(3),
701 AlterCategory::Persecutor => buffer.push(4),
702 AlterCategory::TraumaHolder => buffer.push(5),
703 AlterCategory::Custom(name) => {
704 buffer.push(6);
705 write_string(buffer, name);
706 }
707 };
708}
709
710fn deserialize_alter_category(data: &[u8], cursor: &mut usize) -> Result<AlterCategory, SaveError> {
711 let tag = read_u8(data, cursor)?;
712 match tag {
713 0 => Ok(AlterCategory::Council),
714 1 => Ok(AlterCategory::Servant),
715 2 => Ok(AlterCategory::Fragment),
716 3 => Ok(AlterCategory::Introject),
717 4 => Ok(AlterCategory::Persecutor),
718 5 => Ok(AlterCategory::TraumaHolder),
719 6 => Ok(AlterCategory::Custom(read_string(data, cursor)?)),
720 _ => Err(SaveError::InvalidFormat(format!(
721 "Unknown AlterCategory tag: {}",
722 tag
723 ))),
724 }
725}
726
727fn serialize_alter_state(buffer: &mut Vec<u8>, state: &AlterPresenceState) {
728 let tag = match state {
729 AlterPresenceState::Dormant => 0,
730 AlterPresenceState::Stirring => 1,
731 AlterPresenceState::CoConscious => 2,
732 AlterPresenceState::Emerging => 3,
733 AlterPresenceState::Fronting => 4,
734 AlterPresenceState::Receding => 5,
735 AlterPresenceState::Triggered => 6,
736 AlterPresenceState::Dissociating => 7,
737 };
738 buffer.push(tag);
739}
740
741fn deserialize_alter_state(
742 data: &[u8],
743 cursor: &mut usize,
744) -> Result<AlterPresenceState, SaveError> {
745 let tag = read_u8(data, cursor)?;
746 match tag {
747 0 => Ok(AlterPresenceState::Dormant),
748 1 => Ok(AlterPresenceState::Stirring),
749 2 => Ok(AlterPresenceState::CoConscious),
750 3 => Ok(AlterPresenceState::Emerging),
751 4 => Ok(AlterPresenceState::Fronting),
752 5 => Ok(AlterPresenceState::Receding),
753 6 => Ok(AlterPresenceState::Triggered),
754 7 => Ok(AlterPresenceState::Dissociating),
755 _ => Err(SaveError::InvalidFormat(format!(
756 "Unknown AlterPresenceState tag: {}",
757 tag
758 ))),
759 }
760}
761
762fn serialize_memory_access(buffer: &mut Vec<u8>, access: &MemoryAccess) {
763 match access {
764 MemoryAccess::Full => buffer.push(0),
765 MemoryAccess::Partial(ids) => {
766 buffer.push(1);
767 write_u32(buffer, ids.len() as u32);
768 for id in ids {
769 write_string(buffer, id);
770 }
771 }
772 MemoryAccess::Own => buffer.push(2),
773 MemoryAccess::None => buffer.push(3),
774 }
775}
776
777fn deserialize_memory_access(data: &[u8], cursor: &mut usize) -> Result<MemoryAccess, SaveError> {
778 let tag = read_u8(data, cursor)?;
779 match tag {
780 0 => Ok(MemoryAccess::Full),
781 1 => {
782 let count = read_u32(data, cursor)? as usize;
783 let mut ids = Vec::new();
784 for _ in 0..count {
785 ids.push(read_string(data, cursor)?);
786 }
787 Ok(MemoryAccess::Partial(ids))
788 }
789 2 => Ok(MemoryAccess::Own),
790 3 => Ok(MemoryAccess::None),
791 _ => Err(SaveError::InvalidFormat(format!(
792 "Unknown MemoryAccess tag: {}",
793 tag
794 ))),
795 }
796}
797
798fn serialize_scene(buffer: &mut Vec<u8>, scene: &Scene) {
799 write_string(buffer, &scene.id);
800 write_string(buffer, &scene.name);
801 buffer.extend_from_slice(&scene.safety_level.to_le_bytes());
802 buffer.extend_from_slice(&scene.player_position.0.to_le_bytes());
803 buffer.extend_from_slice(&scene.player_position.1.to_le_bytes());
804 }
806
807fn deserialize_scene(data: &[u8], cursor: &mut usize) -> Result<Scene, SaveError> {
808 let id = read_string(data, cursor)?;
809 let name = read_string(data, cursor)?;
810 let safety_level = read_f32(data, cursor)?;
811 let x = read_f32(data, cursor)?;
812 let y = read_f32(data, cursor)?;
813
814 Ok(Scene {
815 id,
816 name,
817 safety_level,
818 player_position: (x, y),
819 entities: Vec::new(), trigger_zones: Vec::new(),
821 interactables: Vec::new(),
822 active_cutscene: None,
823 })
824}
825
826fn serialize_flag_value(buffer: &mut Vec<u8>, value: &FlagValue) {
827 match value {
828 FlagValue::Bool(b) => {
829 buffer.push(0);
830 buffer.push(if *b { 1 } else { 0 });
831 }
832 FlagValue::Int(i) => {
833 buffer.push(1);
834 buffer.extend_from_slice(&i.to_le_bytes());
835 }
836 FlagValue::String(s) => {
837 buffer.push(2);
838 write_string(buffer, s);
839 }
840 }
841}
842
843fn deserialize_flag_value(data: &[u8], cursor: &mut usize) -> Result<FlagValue, SaveError> {
844 let tag = read_u8(data, cursor)?;
845 match tag {
846 0 => Ok(FlagValue::Bool(read_u8(data, cursor)? != 0)),
847 1 => Ok(FlagValue::Int(read_i32(data, cursor)?)),
848 2 => Ok(FlagValue::String(read_string(data, cursor)?)),
849 _ => Err(SaveError::InvalidFormat(format!(
850 "Unknown FlagValue tag: {}",
851 tag
852 ))),
853 }
854}
855
856fn serialize_item(buffer: &mut Vec<u8>, item: &Item) {
857 write_string(buffer, &item.id);
858 write_string(buffer, &item.name);
859 write_string(buffer, &item.description);
860 let type_tag = match item.item_type {
861 ItemType::Key => 0,
862 ItemType::Consumable => 1,
863 ItemType::Document => 2,
864 ItemType::Memento => 3,
865 };
866 buffer.push(type_tag);
867}
868
869fn deserialize_item(data: &[u8], cursor: &mut usize) -> Result<Item, SaveError> {
870 let id = read_string(data, cursor)?;
871 let name = read_string(data, cursor)?;
872 let description = read_string(data, cursor)?;
873 let type_tag = read_u8(data, cursor)?;
874 let item_type = match type_tag {
875 0 => ItemType::Key,
876 1 => ItemType::Consumable,
877 2 => ItemType::Document,
878 3 => ItemType::Memento,
879 _ => {
880 return Err(SaveError::InvalidFormat(format!(
881 "Unknown ItemType tag: {}",
882 type_tag
883 )))
884 }
885 };
886
887 Ok(Item {
888 id,
889 name,
890 description,
891 item_type,
892 })
893}
894
895fn write_u32(buffer: &mut Vec<u8>, value: u32) {
900 buffer.extend_from_slice(&value.to_le_bytes());
901}
902
903fn read_u8(data: &[u8], cursor: &mut usize) -> Result<u8, SaveError> {
904 if *cursor >= data.len() {
905 return Err(SaveError::UnexpectedEof);
906 }
907 let value = data[*cursor];
908 *cursor += 1;
909 Ok(value)
910}
911
912fn read_u32(data: &[u8], cursor: &mut usize) -> Result<u32, 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(u32::from_le_bytes(bytes))
919}
920
921fn read_i32(data: &[u8], cursor: &mut usize) -> Result<i32, SaveError> {
922 if *cursor + 4 > data.len() {
923 return Err(SaveError::UnexpectedEof);
924 }
925 let bytes: [u8; 4] = data[*cursor..*cursor + 4].try_into().unwrap();
926 *cursor += 4;
927 Ok(i32::from_le_bytes(bytes))
928}
929
930fn read_u64(data: &[u8], cursor: &mut usize) -> Result<u64, SaveError> {
931 if *cursor + 8 > data.len() {
932 return Err(SaveError::UnexpectedEof);
933 }
934 let bytes: [u8; 8] = data[*cursor..*cursor + 8].try_into().unwrap();
935 *cursor += 8;
936 Ok(u64::from_le_bytes(bytes))
937}
938
939fn read_f32(data: &[u8], cursor: &mut usize) -> Result<f32, SaveError> {
940 if *cursor + 4 > data.len() {
941 return Err(SaveError::UnexpectedEof);
942 }
943 let bytes: [u8; 4] = data[*cursor..*cursor + 4].try_into().unwrap();
944 *cursor += 4;
945 Ok(f32::from_le_bytes(bytes))
946}
947
948fn write_string(buffer: &mut Vec<u8>, s: &str) {
949 let bytes = s.as_bytes();
950 write_u32(buffer, bytes.len() as u32);
951 buffer.extend_from_slice(bytes);
952}
953
954fn read_string(data: &[u8], cursor: &mut usize) -> Result<String, SaveError> {
955 let len = read_u32(data, cursor)? as usize;
956 if *cursor + len > data.len() {
957 return Err(SaveError::UnexpectedEof);
958 }
959 let bytes = &data[*cursor..*cursor + len];
960 *cursor += len;
961 String::from_utf8(bytes.to_vec()).map_err(|e| SaveError::InvalidFormat(e.to_string()))
962}
963
964fn write_option_string(buffer: &mut Vec<u8>, opt: &Option<String>) {
965 match opt {
966 Some(s) => {
967 buffer.push(1);
968 write_string(buffer, s);
969 }
970 None => buffer.push(0),
971 }
972}
973
974fn read_option_string(data: &[u8], cursor: &mut usize) -> Result<Option<String>, SaveError> {
975 let has_value = read_u8(data, cursor)?;
976 if has_value != 0 {
977 Ok(Some(read_string(data, cursor)?))
978 } else {
979 Ok(None)
980 }
981}
982
983fn current_timestamp() -> u64 {
988 std::time::SystemTime::now()
989 .duration_since(std::time::UNIX_EPOCH)
990 .map(|d| d.as_secs())
991 .unwrap_or(0)
992}
993
994fn calculate_completion(state: &GameState) -> u8 {
995 let trauma_progress = (state.processed_traumas.len() as f32 / 10.0 * 100.0).min(100.0);
998 trauma_progress as u8
999}
1000
1001#[derive(Debug)]
1007pub enum SaveError {
1008 InvalidSlot(usize),
1010 IoError(String),
1012 InvalidFormat(String),
1014 VersionMismatch { expected: u32, found: u32 },
1016 UnexpectedEof,
1018 Corrupted(String),
1020}
1021
1022impl std::fmt::Display for SaveError {
1023 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1024 match self {
1025 SaveError::InvalidSlot(slot) => write!(f, "Invalid save slot: {}", slot),
1026 SaveError::IoError(msg) => write!(f, "I/O error: {}", msg),
1027 SaveError::InvalidFormat(msg) => write!(f, "Invalid save format: {}", msg),
1028 SaveError::VersionMismatch { expected, found } => {
1029 write!(
1030 f,
1031 "Save version mismatch: expected {}, found {}",
1032 expected, found
1033 )
1034 }
1035 SaveError::UnexpectedEof => write!(f, "Unexpected end of save file"),
1036 SaveError::Corrupted(msg) => write!(f, "Save file corrupted: {}", msg),
1037 }
1038 }
1039}
1040
1041impl std::error::Error for SaveError {}
1042
1043#[cfg(test)]
1048mod tests {
1049 use super::*;
1050
1051 #[test]
1052 fn test_serialize_anima_state() {
1053 let anima = AnimaState::new(0.5, 0.3, 0.7);
1054 let mut buffer = Vec::new();
1055 serialize_anima_state(&mut buffer, &anima);
1056
1057 let mut cursor = 0;
1058 let result = deserialize_anima_state(&buffer, &mut cursor).unwrap();
1059
1060 assert!((result.pleasure - 0.5).abs() < 0.001);
1061 assert!((result.arousal - 0.3).abs() < 0.001);
1062 assert!((result.dominance - 0.7).abs() < 0.001);
1063 }
1064
1065 #[test]
1066 fn test_serialize_fronting_state() {
1067 let states = vec![
1068 FrontingState::None,
1069 FrontingState::Single("host".to_string()),
1070 FrontingState::Blended(vec!["a".to_string(), "b".to_string()]),
1071 FrontingState::Unknown,
1072 ];
1073
1074 for state in states {
1075 let mut buffer = Vec::new();
1076 serialize_fronting_state(&mut buffer, &state);
1077
1078 let mut cursor = 0;
1079 let result = deserialize_fronting_state(&buffer, &mut cursor).unwrap();
1080
1081 match (&state, &result) {
1082 (FrontingState::None, FrontingState::None) => {}
1083 (FrontingState::Single(a), FrontingState::Single(b)) => assert_eq!(a, b),
1084 (FrontingState::Blended(a), FrontingState::Blended(b)) => assert_eq!(a, b),
1085 (FrontingState::Unknown, FrontingState::Unknown) => {}
1086 _ => panic!("Mismatch: {:?} vs {:?}", state, result),
1087 }
1088 }
1089 }
1090
1091 #[test]
1092 fn test_serialize_reality_layer() {
1093 let layers = vec![
1094 RealityLayer::Grounded,
1095 RealityLayer::Fractured,
1096 RealityLayer::Shattered,
1097 RealityLayer::Custom("nightmare".to_string()),
1098 ];
1099
1100 for layer in layers {
1101 let mut buffer = Vec::new();
1102 serialize_reality_layer(&mut buffer, &layer);
1103
1104 let mut cursor = 0;
1105 let result = deserialize_reality_layer(&buffer, &mut cursor).unwrap();
1106
1107 match (&layer, &result) {
1108 (RealityLayer::Grounded, RealityLayer::Grounded) => {}
1109 (RealityLayer::Fractured, RealityLayer::Fractured) => {}
1110 (RealityLayer::Shattered, RealityLayer::Shattered) => {}
1111 (RealityLayer::Custom(a), RealityLayer::Custom(b)) => assert_eq!(a, b),
1112 _ => panic!("Mismatch: {:?} vs {:?}", layer, result),
1113 }
1114 }
1115 }
1116
1117 #[test]
1118 fn test_save_file_roundtrip() {
1119 let state = GameState::new();
1120 let manager = SaveManager::new("/tmp/test_saves");
1121
1122 let save_file = manager.create_save_file(&state, "Test Save").unwrap();
1123 let serialized = serialize_save_file(&save_file).unwrap();
1124 let deserialized = deserialize_save_file(&serialized).unwrap();
1125
1126 assert_eq!(save_file.version, deserialized.version);
1127 assert_eq!(save_file.metadata.name, deserialized.metadata.name);
1128 assert_eq!(save_file.data.game_time, deserialized.data.game_time);
1129 }
1130
1131 #[test]
1132 fn test_save_manager_slot_validation() {
1133 let manager = SaveManager::new("/tmp/test_saves");
1134
1135 let result = manager.save_to_slot(10, &GameState::new());
1137 assert!(matches!(result, Err(SaveError::InvalidSlot(_))));
1138 }
1139}