sigil_parser/plurality/
save_system.rs

1//! # Save System for DAEMONIORUM
2//!
3//! Handles serialization and persistence of game state, including
4//! plural system state, progression, and narrative flags.
5
6use 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
16// ============================================================================
17// SAVE FORMAT VERSION
18// ============================================================================
19
20/// Current save format version for compatibility checking
21pub const SAVE_FORMAT_VERSION: u32 = 1;
22
23/// Magic bytes to identify save files
24pub const SAVE_MAGIC: &[u8; 8] = b"DAEMNGM\0";
25
26// ============================================================================
27// SAVE FILE STRUCTURE
28// ============================================================================
29
30/// Complete save file structure
31#[derive(Debug, Clone)]
32pub struct SaveFile {
33    /// Save format version
34    pub version: u32,
35    /// Save slot metadata
36    pub metadata: SaveMetadata,
37    /// The actual save data
38    pub data: SaveData,
39}
40
41/// Metadata about the save
42#[derive(Debug, Clone)]
43pub struct SaveMetadata {
44    /// Save slot name
45    pub name: String,
46    /// Unix timestamp of save creation
47    pub timestamp: u64,
48    /// Play time in seconds
49    pub play_time: u64,
50    /// Current location name for display
51    pub location_name: String,
52    /// Current fronter name for display
53    pub fronter_name: String,
54    /// Completion percentage (0-100)
55    pub completion: u8,
56}
57
58// ============================================================================
59// SERIALIZATION FORMATS
60// ============================================================================
61
62/// Serializable representation of PluralSystem
63#[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/// Serializable representation of Alter
75#[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/// Serializable AnimaState
92#[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/// Serializable FrontingState
102#[derive(Debug, Clone)]
103pub enum SerializedFrontingState {
104    None,
105    Single(String),
106    Blended(Vec<String>),
107    Rapid(Vec<String>),
108    Unknown,
109}
110
111/// Serializable MemoryAccess
112#[derive(Debug, Clone)]
113pub enum SerializedMemoryAccess {
114    Full,
115    Partial(Vec<String>),
116    Own,
117    None,
118}
119
120// ============================================================================
121// SAVE MANAGER
122// ============================================================================
123
124/// Manages save operations
125pub struct SaveManager {
126    /// Base directory for saves
127    save_dir: String,
128    /// Number of available slots
129    num_slots: usize,
130    /// Auto-save enabled
131    auto_save_enabled: bool,
132    /// Auto-save interval in seconds
133    auto_save_interval: u64,
134}
135
136impl SaveManager {
137    /// Create a new save manager
138    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, // 5 minutes
144        }
145    }
146
147    /// Get the path for a save slot
148    fn slot_path(&self, slot: usize) -> String {
149        format!("{}/save_{}.daem", self.save_dir, slot)
150    }
151
152    /// Get the auto-save path
153    fn auto_save_path(&self) -> String {
154        format!("{}/autosave.daem", self.save_dir)
155    }
156
157    /// Save game to a slot
158    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    /// Load game from a slot
169    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    /// Auto-save the game
180    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    /// Load auto-save
191    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    /// Check if a slot has save data
198    pub fn slot_exists(&self, slot: usize) -> bool {
199        let path = self.slot_path(slot);
200        Path::new(&path).exists()
201    }
202
203    /// Get metadata for a slot without loading full data
204    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    /// Delete a save slot
215    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    /// Create a SaveFile from GameState
225    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    /// Create GameState from SaveFile
260    fn create_game_state(&self, save_file: SaveFile) -> Result<GameState, SaveError> {
261        // Version check
262        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    /// Write save file to disk
273    fn write_save_file(&self, path: &str, save_file: &SaveFile) -> Result<(), SaveError> {
274        // Ensure directory exists
275        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        // Serialize to binary format
280        let data = serialize_save_file(save_file)?;
281
282        // Write to file
283        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    /// Read save file from disk
293    fn read_save_file(&self, path: &str) -> Result<SaveFile, SaveError> {
294        // Read from file
295        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 from binary format
302        deserialize_save_file(&data)
303    }
304}
305
306// ============================================================================
307// SERIALIZATION
308// ============================================================================
309
310/// Serialize a SaveFile to binary
311fn serialize_save_file(save_file: &SaveFile) -> Result<Vec<u8>, SaveError> {
312    let mut buffer = Vec::new();
313
314    // Write magic bytes
315    buffer.extend_from_slice(SAVE_MAGIC);
316
317    // Write version
318    buffer.extend_from_slice(&save_file.version.to_le_bytes());
319
320    // Write metadata
321    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    // Write data
329    serialize_save_data(&mut buffer, &save_file.data)?;
330
331    Ok(buffer)
332}
333
334/// Deserialize a SaveFile from binary
335fn deserialize_save_file(data: &[u8]) -> Result<SaveFile, SaveError> {
336    let mut cursor = 0;
337
338    // Read and verify magic bytes
339    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    // Read version
345    let version = read_u32(data, &mut cursor)?;
346
347    // Read metadata
348    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    // Read data
365    let save_data = deserialize_save_data(data, &mut cursor)?;
366
367    Ok(SaveFile {
368        version,
369        metadata,
370        data: save_data,
371    })
372}
373
374/// Serialize SaveData
375fn serialize_save_data(buffer: &mut Vec<u8>, data: &SaveData) -> Result<(), SaveError> {
376    // Serialize PluralSystem
377    serialize_plural_system(buffer, &data.system)?;
378
379    // Serialize Scene
380    serialize_scene(buffer, &data.scene);
381
382    // Game time
383    buffer.extend_from_slice(&data.game_time.to_le_bytes());
384
385    // Flags
386    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    // Inventory
393    write_u32(buffer, data.inventory.len() as u32);
394    for item in &data.inventory {
395        serialize_item(buffer, item);
396    }
397
398    // Unlocked abilities
399    write_u32(buffer, data.unlocked_abilities.len() as u32);
400    for ability in &data.unlocked_abilities {
401        write_string(buffer, ability);
402    }
403
404    // Processed traumas
405    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
413/// Deserialize SaveData
414fn deserialize_save_data(data: &[u8], cursor: &mut usize) -> Result<SaveData, SaveError> {
415    // Deserialize PluralSystem
416    let system = deserialize_plural_system(data, cursor)?;
417
418    // Deserialize Scene
419    let scene = deserialize_scene(data, cursor)?;
420
421    // Game time
422    let game_time = read_u64(data, cursor)?;
423
424    // Flags
425    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    // Inventory
434    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    // Unlocked abilities
441    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    // Processed traumas
448    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
465/// Serialize PluralSystem
466fn serialize_plural_system(buffer: &mut Vec<u8>, system: &PluralSystem) -> Result<(), SaveError> {
467    // Name
468    write_option_string(buffer, &system.name);
469
470    // Alters
471    write_u32(buffer, system.alters.len() as u32);
472    for alter in system.alters.values() {
473        serialize_alter(buffer, alter)?;
474    }
475
476    // Fronting state
477    serialize_fronting_state(buffer, &system.fronting);
478
479    // Anima
480    serialize_anima_state(buffer, &system.anima);
481
482    // Reality layer
483    serialize_reality_layer(buffer, &system.reality_layer);
484
485    // Dissociation and stability
486    buffer.extend_from_slice(&system.dissociation.to_le_bytes());
487    buffer.extend_from_slice(&system.stability.to_le_bytes());
488
489    Ok(())
490}
491
492/// Deserialize PluralSystem
493fn 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(), // Not persisted
516        headspace: super::runtime::HeadspaceState::default(),
517        dissociation,
518        stability,
519    })
520}
521
522/// Serialize Alter
523fn 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    // Triggers
534    write_u32(buffer, alter.triggers.len() as u32);
535    for trigger in &alter.triggers {
536        write_string(buffer, trigger);
537    }
538
539    // Abilities
540    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
551/// Deserialize Alter
552fn 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
593// ============================================================================
594// SERIALIZATION HELPERS
595// ============================================================================
596
597fn 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    // Other scene data would be loaded from scene definitions, not saved
805}
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(), // Loaded from scene definitions
820        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
895// ============================================================================
896// BINARY READ/WRITE PRIMITIVES
897// ============================================================================
898
899fn 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
983// ============================================================================
984// UTILITY FUNCTIONS
985// ============================================================================
986
987fn 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    // Simple completion calculation based on processed traumas
996    // In a real game, this would be more sophisticated
997    let trauma_progress = (state.processed_traumas.len() as f32 / 10.0 * 100.0).min(100.0);
998    trauma_progress as u8
999}
1000
1001// ============================================================================
1002// ERRORS
1003// ============================================================================
1004
1005/// Errors that can occur during save operations
1006#[derive(Debug)]
1007pub enum SaveError {
1008    /// Invalid save slot
1009    InvalidSlot(usize),
1010    /// I/O error
1011    IoError(String),
1012    /// Invalid save format
1013    InvalidFormat(String),
1014    /// Version mismatch
1015    VersionMismatch { expected: u32, found: u32 },
1016    /// Unexpected end of file
1017    UnexpectedEof,
1018    /// Save file corrupted
1019    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// ============================================================================
1044// TESTS
1045// ============================================================================
1046
1047#[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        // Invalid slot should fail
1136        let result = manager.save_to_slot(10, &GameState::new());
1137        assert!(matches!(result, Err(SaveError::InvalidSlot(_))));
1138    }
1139}