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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
/*
* Copyright (C) 2002-2018 by the Widelands Development Team
*
* 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.
*
*/
#include "game_io/game_cmd_queue_packet.h"
#include "base/macros.h"
#include "io/fileread.h"
#include "io/filewrite.h"
#include "logic/cmd_queue.h"
#include "logic/game.h"
#include "logic/game_data_error.h"
#include "logic/queue_cmd_factory.h"
namespace Widelands {
constexpr uint16_t kCurrentPacketVersion = 2;
void GameCmdQueuePacket::read(FileSystem& fs, Game& game, MapObjectLoader* const ol) {
try {
FileRead fr;
fr.open(fs, "binary/cmd_queue");
uint16_t const packet_version = fr.unsigned_16();
if (packet_version == kCurrentPacketVersion) {
CmdQueue& cmdq = game.cmdqueue();
// nothing to be done for game_
// Next serial
cmdq.nextserial_ = fr.unsigned_32();
// Erase all currently pending commands in the queue
cmdq.flush();
for (;;) {
uint32_t const packet_id = fr.unsigned_16();
if (!packet_id)
break;
CmdQueue::CmdItem item;
item.category = fr.signed_32();
item.serial = fr.unsigned_32();
GameLogicCommand& cmd = QueueCmdFactory::create_correct_queue_command(
static_cast<QueueCommandTypes>(packet_id));
cmd.read(fr, game, *ol);
item.cmd = &cmd;
cmdq.cmds_[cmd.duetime() % kCommandQueueBucketSize].push(item);
++cmdq.ncmds_;
}
} else {
throw UnhandledVersionError("GameCmdQueuePacket", packet_version, kCurrentPacketVersion);
}
} catch (const WException& e) {
throw GameDataError("command queue: %s", e.what());
}
}
void GameCmdQueuePacket::write(FileSystem& fs, Game& game, MapObjectSaver* const os) {
FileWrite fw;
fw.unsigned_16(kCurrentPacketVersion);
const CmdQueue& cmdq = game.cmdqueue();
// nothing to be done for game_
// Next serial
fw.unsigned_32(cmdq.nextserial_);
// Write all commands
// Find all the items in the current cmdqueue
uint32_t time = game.get_gametime();
size_t nhandled = 0;
while (nhandled < cmdq.ncmds_) {
// Make a copy, so we can pop stuff
std::priority_queue<CmdQueue::CmdItem> p = cmdq.cmds_[time % kCommandQueueBucketSize];
while (!p.empty()) {
const CmdQueue::CmdItem& it = p.top();
if (it.cmd->duetime() == time) {
if (upcast(GameLogicCommand, cmd, it.cmd)) {
// The id (aka command type)
fw.unsigned_16(static_cast<uint16_t>(cmd->id()));
// Serial number
fw.signed_32(it.category);
fw.unsigned_32(it.serial);
// Now the command itself
cmd->write(fw, game, *os);
}
++nhandled;
}
// DONE: next command
p.pop();
}
++time;
}
fw.unsigned_16(0); // end of command queue
fw.write(fs, "binary/cmd_queue");
}
} // namespace Widelands
|