summaryrefslogtreecommitdiffstats
path: root/src/game_state/serialize.rs
blob: ef3b5c999218356057b948a589644d068292672b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// -*- coding: utf-8 -*-
//
// Copyright 2021 Michael Buesch <m@bues.ch>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//

use anyhow as ah;
use crate::net::protocol::{Message, MsgType, message_from_bytes};
use std::fs::OpenOptions;
use std::io::{Read, Write};
use std::path::Path;
use super::GameState;

impl GameState {
    pub fn save_game(&self, filename: &Path) -> ah::Result<()> {
        let mut file = OpenOptions::new()
                            .write(true)
                            .create(true)
                            .open(filename)?;
        file.write_all(&self.serialize()?)?;
        file.sync_all()?;
        Ok(())
    }

    pub fn load_game(&mut self, filename: &Path) -> ah::Result<()> {
        let mut file = OpenOptions::new()
                            .read(true)
                            .open(filename)?;
        let mut buf = vec![];
        file.read_to_end(&mut buf)?;
        self.deserialize(&buf)?;
        Ok(())
    }

    fn serialize(&self) -> ah::Result<Vec<u8>> {
        let game_state_msg = self.make_state_message();
        Ok(game_state_msg.to_bytes())
    }

    fn deserialize(&mut self, data: &[u8]) -> ah::Result<()> {
        let mut offset = 0;
        let mut messages = vec![];
        loop {
            let (size, msg) = message_from_bytes(&data[offset..])?;
            if size == 0 {
                break;
            }
            if let Some(msg) = msg {
                offset += size;

                // Check if this is a supported message.
                match msg.get_message() {
                    MsgType::GameState(_) => (),
                    invalid => return Err(ah::format_err!(
                        "File data contains unsupported packet {:?}", invalid)),
                }

                messages.push(msg);
            } else {
                break;
            }
        }
        if messages.is_empty() {
            return Err(ah::format_err!("File data does not contain valid game state."));
        }

        // Set the local game state to the message contents.
        self.reset_game(true);
        for msg in messages {
            match msg.get_message() {
                MsgType::GameState(msg) => { self.read_state_message(&msg, true)?; },
                _ => (),
            }
        }
        // Send the local game state to the server (if any).
        self.client_send_full_gamestate()?;

        Ok(())
    }
}

// vim: ts=4 sw=4 expandtab
bues.ch cgit interface