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,
13    MemoryAccess, 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.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    /// Create GameState from SaveFile
257    fn create_game_state(&self, save_file: SaveFile) -> Result<GameState, SaveError> {
258        // Version check
259        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    /// Write save file to disk
270    fn write_save_file(&self, path: &str, save_file: &SaveFile) -> Result<(), SaveError> {
271        // Ensure directory exists
272        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        // Serialize to binary format
278        let data = serialize_save_file(save_file)?;
279
280        // Write to file
281        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    /// Read save file from disk
291    fn read_save_file(&self, path: &str) -> Result<SaveFile, SaveError> {
292        // Read from file
293        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 from binary format
301        deserialize_save_file(&data)
302    }
303}
304
305// ============================================================================
306// SERIALIZATION
307// ============================================================================
308
309/// Serialize a SaveFile to binary
310fn serialize_save_file(save_file: &SaveFile) -> Result<Vec<u8>, SaveError> {
311    let mut buffer = Vec::new();
312
313    // Write magic bytes
314    buffer.extend_from_slice(SAVE_MAGIC);
315
316    // Write version
317    buffer.extend_from_slice(&save_file.version.to_le_bytes());
318
319    // Write metadata
320    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    // Write data
328    serialize_save_data(&mut buffer, &save_file.data)?;
329
330    Ok(buffer)
331}
332
333/// Deserialize a SaveFile from binary
334fn deserialize_save_file(data: &[u8]) -> Result<SaveFile, SaveError> {
335    let mut cursor = 0;
336
337    // Read and verify magic bytes
338    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    // Read version
344    let version = read_u32(data, &mut cursor)?;
345
346    // Read metadata
347    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    // Read data
364    let save_data = deserialize_save_data(data, &mut cursor)?;
365
366    Ok(SaveFile {
367        version,
368        metadata,
369        data: save_data,
370    })
371}
372
373/// Serialize SaveData
374fn serialize_save_data(buffer: &mut Vec<u8>, data: &SaveData) -> Result<(), SaveError> {
375    // Serialize PluralSystem
376    serialize_plural_system(buffer, &data.system)?;
377
378    // Serialize Scene
379    serialize_scene(buffer, &data.scene);
380
381    // Game time
382    buffer.extend_from_slice(&data.game_time.to_le_bytes());
383
384    // Flags
385    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    // Inventory
392    write_u32(buffer, data.inventory.len() as u32);
393    for item in &data.inventory {
394        serialize_item(buffer, item);
395    }
396
397    // Unlocked abilities
398    write_u32(buffer, data.unlocked_abilities.len() as u32);
399    for ability in &data.unlocked_abilities {
400        write_string(buffer, ability);
401    }
402
403    // Processed traumas
404    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
412/// Deserialize SaveData
413fn deserialize_save_data(data: &[u8], cursor: &mut usize) -> Result<SaveData, SaveError> {
414    // Deserialize PluralSystem
415    let system = deserialize_plural_system(data, cursor)?;
416
417    // Deserialize Scene
418    let scene = deserialize_scene(data, cursor)?;
419
420    // Game time
421    let game_time = read_u64(data, cursor)?;
422
423    // Flags
424    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    // Inventory
433    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    // Unlocked abilities
440    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    // Processed traumas
447    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
464/// Serialize PluralSystem
465fn serialize_plural_system(buffer: &mut Vec<u8>, system: &PluralSystem) -> Result<(), SaveError> {
466    // Name
467    write_option_string(buffer, &system.name);
468
469    // Alters
470    write_u32(buffer, system.alters.len() as u32);
471    for alter in system.alters.values() {
472        serialize_alter(buffer, alter)?;
473    }
474
475    // Fronting state
476    serialize_fronting_state(buffer, &system.fronting);
477
478    // Anima
479    serialize_anima_state(buffer, &system.anima);
480
481    // Reality layer
482    serialize_reality_layer(buffer, &system.reality_layer);
483
484    // Dissociation and stability
485    buffer.extend_from_slice(&system.dissociation.to_le_bytes());
486    buffer.extend_from_slice(&system.stability.to_le_bytes());
487
488    Ok(())
489}
490
491/// Deserialize PluralSystem
492fn 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(), // Not persisted
515        headspace: super::runtime::HeadspaceState::default(),
516        dissociation,
517        stability,
518    })
519}
520
521/// Serialize Alter
522fn 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    // Triggers
533    write_u32(buffer, alter.triggers.len() as u32);
534    for trigger in &alter.triggers {
535        write_string(buffer, trigger);
536    }
537
538    // Abilities
539    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
550/// Deserialize Alter
551fn 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
592// ============================================================================
593// SERIALIZATION HELPERS
594// ============================================================================
595
596fn 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    // Other scene data would be loaded from scene definitions, not saved
786}
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(), // Loaded from scene definitions
801        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
868// ============================================================================
869// BINARY READ/WRITE PRIMITIVES
870// ============================================================================
871
872fn 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
957// ============================================================================
958// UTILITY FUNCTIONS
959// ============================================================================
960
961fn 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    // Simple completion calculation based on processed traumas
970    // In a real game, this would be more sophisticated
971    let trauma_progress = (state.processed_traumas.len() as f32 / 10.0 * 100.0).min(100.0);
972    trauma_progress as u8
973}
974
975// ============================================================================
976// ERRORS
977// ============================================================================
978
979/// Errors that can occur during save operations
980#[derive(Debug)]
981pub enum SaveError {
982    /// Invalid save slot
983    InvalidSlot(usize),
984    /// I/O error
985    IoError(String),
986    /// Invalid save format
987    InvalidFormat(String),
988    /// Version mismatch
989    VersionMismatch { expected: u32, found: u32 },
990    /// Unexpected end of file
991    UnexpectedEof,
992    /// Save file corrupted
993    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// ============================================================================
1014// TESTS
1015// ============================================================================
1016
1017#[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        // Invalid slot should fail
1106        let result = manager.save_to_slot(10, &GameState::new());
1107        assert!(matches!(result, Err(SaveError::InvalidSlot(_))));
1108    }
1109}