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
|