summary refs log tree commit diff stats
path: root/tools/validator
diff options
context:
space:
mode:
Diffstat (limited to 'tools/validator')
-rw-r--r--tools/validator/CMakeLists.txt11
-rw-r--r--tools/validator/human_processor.cpp425
-rw-r--r--tools/validator/human_processor.h14
-rw-r--r--tools/validator/main.cpp31
-rw-r--r--tools/validator/structs.h97
-rw-r--r--tools/validator/validator.cpp250
-rw-r--r--tools/validator/validator.h12
7 files changed, 840 insertions, 0 deletions
diff --git a/tools/validator/CMakeLists.txt b/tools/validator/CMakeLists.txt new file mode 100644 index 0000000..0ad58c2 --- /dev/null +++ b/tools/validator/CMakeLists.txt
@@ -0,0 +1,11 @@
1find_package(Protobuf REQUIRED)
2
3add_executable(validator
4 human_processor.cpp
5 main.cpp
6 validator.cpp
7)
8set_property(TARGET validator PROPERTY CXX_STANDARD 20)
9set_property(TARGET validator PROPERTY CXX_STANDARD_REQUIRED ON)
10target_include_directories(validator PUBLIC ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/tools)
11target_link_libraries(validator PUBLIC protos util protobuf::libprotobuf)
diff --git a/tools/validator/human_processor.cpp b/tools/validator/human_processor.cpp new file mode 100644 index 0000000..5382443 --- /dev/null +++ b/tools/validator/human_processor.cpp
@@ -0,0 +1,425 @@
1#include "human_processor.h"
2
3#include <google/protobuf/message.h>
4#include <google/protobuf/text_format.h>
5
6#include <filesystem>
7#include <fstream>
8#include <iostream>
9#include <map>
10#include <optional>
11#include <sstream>
12#include <string>
13
14#include "structs.h"
15
16namespace com::fourisland::lingo2_archipelago {
17namespace {
18
19template <typename T>
20T ReadMessageFromFile(const std::string& path) {
21 std::cout << "Processing " << path << std::endl;
22
23 std::ifstream file(path);
24 std::stringstream buffer;
25 buffer << file.rdbuf();
26
27 T message;
28 google::protobuf::TextFormat::ParseFromString(buffer.str(), &message);
29
30 return message;
31}
32
33class HumanProcessor {
34 public:
35 HumanProcessor(const std::string& mapdir, CollectedInfo& info)
36 : mapdir_(mapdir), info_(info) {}
37
38 void Run() {
39 std::filesystem::path datadir_path = mapdir_;
40
41 ProcessConnectionsFile(datadir_path / "connections.txtpb", std::nullopt);
42 ProcessMaps(datadir_path);
43 ProcessIdsFile(datadir_path / "ids.txtpb");
44 }
45
46 private:
47 void ProcessMaps(std::filesystem::path path) {
48 std::filesystem::path maps_dir = path / "maps";
49 for (auto const& dir_entry :
50 std::filesystem::directory_iterator(maps_dir)) {
51 ProcessMap(dir_entry.path());
52 }
53 }
54
55 void ProcessMap(std::filesystem::path path) {
56 std::string map_name = path.filename();
57
58 ProcessConnectionsFile(path / "connections.txtpb", map_name);
59 ProcessDoorsFile(path / "doors.txtpb", map_name);
60 ProcessRooms(path / "rooms", map_name);
61 }
62
63 void ProcessRooms(std::filesystem::path path,
64 const std::string& current_map_name) {
65 for (auto const& dir_entry : std::filesystem::directory_iterator(path)) {
66 auto room = ReadMessageFromFile<HumanRoom>(dir_entry.path().string());
67 ProcessRoom(room, current_map_name);
68 }
69 }
70
71 void ProcessRoom(const HumanRoom& h_room,
72 const std::string& current_map_name) {
73 RoomIdentifier room_identifier;
74 room_identifier.set_map(current_map_name);
75 room_identifier.set_name(h_room.name());
76
77 RoomInfo& room_info = info_.rooms[room_identifier];
78 room_info.definitions.push_back(h_room);
79
80 for (const HumanPanel& h_panel : h_room.panels()) {
81 ProcessPanel(h_panel, current_map_name, h_room.name());
82 }
83
84 for (const HumanPainting& h_painting : h_room.paintings()) {
85 ProcessPainting(h_painting, current_map_name, h_room.name());
86 }
87
88 for (const HumanPort& h_port : h_room.ports()) {
89 ProcessPort(h_port, current_map_name, h_room.name());
90 }
91
92 for (const HumanLetter& h_letter : h_room.letters()) {
93 ProcessLetter(h_letter, current_map_name, h_room.name());
94 }
95
96 for (const HumanMastery& h_mastery : h_room.masteries()) {
97 ProcessMastery(h_mastery, current_map_name, h_room.name());
98 }
99
100 for (const HumanKeyholder& h_keyholder : h_room.keyholders()) {
101 ProcessKeyholder(h_keyholder, current_map_name, h_room.name());
102 }
103 }
104
105 void ProcessPanel(const HumanPanel& h_panel,
106 const std::string& current_map_name,
107 const std::string& current_room_name) {
108 PanelIdentifier panel_identifier;
109 panel_identifier.set_map(current_map_name);
110 panel_identifier.set_room(current_room_name);
111 panel_identifier.set_name(h_panel.name());
112
113 PanelInfo& panel_info = info_.panels[panel_identifier];
114 panel_info.definitions.push_back(h_panel);
115 panel_info.proxies[h_panel.answer()].definitions.push_back(Proxy());
116
117 for (const Proxy& h_proxy : h_panel.proxies()) {
118 ProxyInfo& proxy_info = panel_info.proxies[h_proxy.answer()];
119 proxy_info.definitions.push_back(h_proxy);
120 }
121
122 if (h_panel.has_required_door()) {
123 DoorIdentifier required_door_identifier =
124 *GetCompleteDoorIdentifier(h_panel.required_door(), current_map_name);
125 DoorInfo& required_door_info = info_.doors[required_door_identifier];
126 required_door_info.panels_referenced_by.push_back(panel_identifier);
127 }
128
129 if (h_panel.has_required_room()) {
130 RoomIdentifier required_room_identifier =
131 *GetCompleteRoomIdentifier(h_panel.required_room(), current_map_name);
132 RoomInfo& required_room_info = info_.rooms[required_room_identifier];
133 required_room_info.panels_referenced_by.push_back(panel_identifier);
134 }
135 }
136
137 void ProcessPainting(const HumanPainting& h_painting,
138 const std::string& current_map_name,
139 const std::string& current_room_name) {
140 PaintingIdentifier painting_identifier;
141 painting_identifier.set_map(current_map_name);
142 painting_identifier.set_room(current_room_name);
143 painting_identifier.set_name(h_painting.name());
144
145 PaintingInfo& painting_info = info_.paintings[painting_identifier];
146 painting_info.definitions.push_back(h_painting);
147
148 if (h_painting.has_required_door()) {
149 DoorIdentifier required_door_identifier = *GetCompleteDoorIdentifier(
150 h_painting.required_door(), current_map_name);
151 DoorInfo& required_door_info = info_.doors[required_door_identifier];
152 required_door_info.paintings_referenced_by.push_back(painting_identifier);
153 }
154 }
155
156 void ProcessPort(const HumanPort& h_port, const std::string& current_map_name,
157 const std::string& current_room_name) {
158 PortIdentifier port_identifier;
159 port_identifier.set_map(current_map_name);
160 port_identifier.set_room(current_room_name);
161 port_identifier.set_name(h_port.name());
162
163 PortInfo& port_info = info_.ports[port_identifier];
164 port_info.definitions.push_back(h_port);
165
166 if (h_port.has_required_door()) {
167 DoorIdentifier required_door_identifier =
168 *GetCompleteDoorIdentifier(h_port.required_door(), current_map_name);
169 DoorInfo& required_door_info = info_.doors[required_door_identifier];
170 required_door_info.ports_referenced_by.push_back(port_identifier);
171 }
172 }
173
174 void ProcessLetter(const HumanLetter& h_letter,
175 const std::string& current_map_name,
176 const std::string& current_room_name) {
177 LetterIdentifier letter_identifier =
178 std::make_tuple(h_letter.key()[0], h_letter.level2());
179 LetterInfo& letter_info = info_.letters[letter_identifier];
180
181 RoomIdentifier room_identifier;
182 room_identifier.set_map(current_map_name);
183 room_identifier.set_name(current_room_name);
184 letter_info.defined_in.push_back(room_identifier);
185 }
186
187 void ProcessMastery(const HumanMastery& h_mastery,
188 const std::string& current_map_name,
189 const std::string& current_room_name) {
190 // Nothing really to validate about masteries yet.
191 }
192
193 void ProcessKeyholder(const HumanKeyholder& h_keyholder,
194 const std::string& current_map_name,
195 const std::string& current_room_name) {
196 KeyholderIdentifier keyholder_identifier;
197 keyholder_identifier.set_map(current_map_name);
198 keyholder_identifier.set_room(current_room_name);
199 keyholder_identifier.set_name(h_keyholder.name());
200
201 KeyholderInfo& keyholder_info = info_.keyholders[keyholder_identifier];
202 keyholder_info.definitions.push_back(h_keyholder);
203 }
204
205 void ProcessDoorsFile(std::filesystem::path path,
206 const std::string& current_map_name) {
207 if (!std::filesystem::exists(path)) {
208 return;
209 }
210
211 auto doors = ReadMessageFromFile<HumanDoors>(path.string());
212
213 for (const HumanDoor& door : doors.doors()) {
214 ProcessDoor(door, current_map_name);
215 }
216 }
217
218 void ProcessDoor(const HumanDoor& h_door,
219 const std::string& current_map_name) {
220 DoorIdentifier door_identifier;
221 door_identifier.set_map(current_map_name);
222 door_identifier.set_name(h_door.name());
223
224 DoorInfo& door_info = info_.doors[door_identifier];
225 door_info.definitions.push_back(h_door);
226
227 if (h_door.has_location_room()) {
228 RoomIdentifier location_room_identifier;
229 location_room_identifier.set_map(current_map_name);
230 location_room_identifier.set_name(h_door.location_room());
231 info_.rooms[location_room_identifier].doors_referenced_by.push_back(
232 door_identifier);
233 }
234
235 for (const PaintingIdentifier& pi : h_door.move_paintings()) {
236 auto complete_painting_identifier =
237 GetCompletePaintingIdentifier(pi, current_map_name, std::nullopt);
238 if (complete_painting_identifier) {
239 PaintingInfo& move_painting_info =
240 info_.paintings[*complete_painting_identifier];
241 move_painting_info.doors_referenced_by.push_back(door_identifier);
242 } else {
243 door_info.malformed_identifiers.paintings.push_back(pi);
244 }
245 }
246
247 for (const PanelIdentifier& pi : h_door.panels()) {
248 auto complete_panel_identifier = GetCompletePanelIdentifierWithoutAnswer(
249 pi, current_map_name, std::nullopt);
250 if (complete_panel_identifier) {
251 PanelInfo& panel_info = info_.panels[*complete_panel_identifier];
252 panel_info.doors_referenced_by.push_back(door_identifier);
253
254 if (pi.has_answer()) {
255 panel_info.proxies[pi.answer()].doors_referenced_by.push_back(
256 door_identifier);
257 }
258 } else {
259 door_info.malformed_identifiers.panels.push_back(pi);
260 }
261 }
262
263 for (const KeyholderIdentifier& ki : h_door.keyholders()) {
264 auto complete_keyholder_identifier =
265 GetCompleteKeyholderIdentifierWithoutKey(ki, current_map_name,
266 std::nullopt);
267 if (complete_keyholder_identifier) {
268 KeyholderInfo& keyholder_info =
269 info_.keyholders[*complete_keyholder_identifier];
270 keyholder_info.doors_referenced_by.push_back(door_identifier);
271 } else {
272 door_info.malformed_identifiers.keyholders.push_back(ki);
273 }
274 }
275
276 for (const RoomIdentifier& ri : h_door.rooms()) {
277 RoomIdentifier complete_room_identifier =
278 *GetCompleteRoomIdentifier(ri, current_map_name);
279 RoomInfo& room_info = info_.rooms[complete_room_identifier];
280 room_info.doors_referenced_by.push_back(door_identifier);
281 }
282
283 for (const DoorIdentifier& di : h_door.doors()) {
284 DoorIdentifier complete_door_identifier =
285 *GetCompleteDoorIdentifier(di, current_map_name);
286 DoorInfo& other_door_info = info_.doors[complete_door_identifier];
287 other_door_info.doors_referenced_by.push_back(door_identifier);
288 }
289 }
290
291 void ProcessConnectionsFile(std::filesystem::path path,
292 std::optional<std::string> current_map_name) {
293 if (!std::filesystem::exists(path)) {
294 return;
295 }
296
297 auto connections = ReadMessageFromFile<HumanConnections>(path.string());
298
299 for (const HumanConnection& connection : connections.connections()) {
300 ProcessConnection(connection, current_map_name);
301 }
302 }
303
304 void ProcessConnection(const HumanConnection& human_connection,
305 const std::optional<std::string>& current_map_name) {
306 if (human_connection.has_from_room()) {
307 if (current_map_name) {
308 RoomIdentifier room_identifier;
309 room_identifier.set_map(*current_map_name);
310 room_identifier.set_name(human_connection.from_room());
311
312 RoomInfo& room_info = info_.rooms[room_identifier];
313 room_info.connections_referenced_by.push_back(human_connection);
314 } else {
315 // Not sure where else to store this right now.
316 std::cout << "A global connection used from_room." << std::endl;
317 }
318 } else if (human_connection.has_from()) {
319 ProcessSingleConnection(human_connection, human_connection.from(),
320 current_map_name);
321 }
322
323 if (human_connection.has_to_room()) {
324 if (current_map_name) {
325 RoomIdentifier room_identifier;
326 room_identifier.set_map(*current_map_name);
327 room_identifier.set_name(human_connection.to_room());
328
329 RoomInfo& room_info = info_.rooms[room_identifier];
330 room_info.connections_referenced_by.push_back(human_connection);
331 } else {
332 // Not sure where else to store this right now.
333 std::cout << "A global connection used to_room." << std::endl;
334 }
335 } else if (human_connection.has_to()) {
336 ProcessSingleConnection(human_connection, human_connection.to(),
337 current_map_name);
338 }
339
340 if (human_connection.has_door()) {
341 auto door_identifier =
342 GetCompleteDoorIdentifier(human_connection.door(), current_map_name);
343 if (door_identifier) {
344 DoorInfo& door_info = info_.doors[*door_identifier];
345 door_info.connections_referenced_by.push_back(human_connection);
346 } else {
347 // Not sure where else to store this right now.
348 std::cout
349 << "A connection used the following malformed door identifier: "
350 << human_connection.door().ShortDebugString() << std::endl;
351 }
352 }
353 }
354
355 void ProcessSingleConnection(
356 const HumanConnection& human_connection,
357 const HumanConnection::Endpoint& endpoint,
358 const std::optional<std::string>& current_map_name) {
359 if (endpoint.has_room()) {
360 auto room_identifier =
361 GetCompleteRoomIdentifier(endpoint.room(), current_map_name);
362 if (room_identifier) {
363 RoomInfo& room_info = info_.rooms[*room_identifier];
364 room_info.connections_referenced_by.push_back(human_connection);
365 } else {
366 // Not sure where else to store this right now.
367 std::cout
368 << "A connection used the following malformed room identifier: "
369 << endpoint.room().ShortDebugString() << std::endl;
370 }
371 } else if (endpoint.has_painting()) {
372 auto painting_identifier = GetCompletePaintingIdentifier(
373 endpoint.painting(), current_map_name, std::nullopt);
374 if (painting_identifier) {
375 PaintingInfo& painting_info = info_.paintings[*painting_identifier];
376 painting_info.connections_referenced_by.push_back(human_connection);
377 } else {
378 // Not sure where else to store this right now.
379 std::cout
380 << "A connection used the following malformed painting identifier: "
381 << endpoint.painting().ShortDebugString() << std::endl;
382 }
383 } else if (endpoint.has_port()) {
384 auto port_identifier = GetCompletePortIdentifier(
385 endpoint.port(), current_map_name, std::nullopt);
386 if (port_identifier) {
387 PortInfo& port_info = info_.ports[*port_identifier];
388 port_info.connections_referenced_by.push_back(human_connection);
389 } else {
390 // Not sure where else to store this right now.
391 std::cout
392 << "A connection used the following malformed port identifier: "
393 << endpoint.port().ShortDebugString() << std::endl;
394 }
395 } else if (endpoint.has_panel()) {
396 auto panel_identifier = GetCompletePanelIdentifierWithoutAnswer(
397 endpoint.panel(), current_map_name, std::nullopt);
398 if (panel_identifier) {
399 PanelInfo& panel_info = info_.panels[*panel_identifier];
400 panel_info.connections_referenced_by.push_back(human_connection);
401
402 if (endpoint.panel().has_answer()) {
403 panel_info.proxies[endpoint.panel().answer()]
404 .connections_referenced_by.push_back(human_connection);
405 }
406 }
407 }
408 }
409
410 void ProcessIdsFile(std::filesystem::path path) {
411 // Ignore this for now.
412 }
413
414 std::string mapdir_;
415 CollectedInfo& info_;
416};
417
418} // namespace
419
420void ProcessHumanData(const std::string& mapdir, CollectedInfo& info) {
421 HumanProcessor human_processor(mapdir, info);
422 human_processor.Run();
423}
424
425} // namespace com::fourisland::lingo2_archipelago
diff --git a/tools/validator/human_processor.h b/tools/validator/human_processor.h new file mode 100644 index 0000000..52f174f --- /dev/null +++ b/tools/validator/human_processor.h
@@ -0,0 +1,14 @@
1#ifndef TOOLS_VALIDATOR_HUMAN_PROCESSOR_H_
2#define TOOLS_VALIDATOR_HUMAN_PROCESSOR_H_
3
4#include <string>
5
6namespace com::fourisland::lingo2_archipelago {
7
8struct CollectedInfo;
9
10void ProcessHumanData(const std::string& mapdir, CollectedInfo& info);
11
12} // namespace com::fourisland::lingo2_archipelago
13
14#endif /* TOOLS_VALIDATOR_HUMAN_PROCESSOR_H_ */
diff --git a/tools/validator/main.cpp b/tools/validator/main.cpp new file mode 100644 index 0000000..af9842b --- /dev/null +++ b/tools/validator/main.cpp
@@ -0,0 +1,31 @@
1#include "human_processor.h"
2#include "structs.h"
3#include "validator.h"
4
5namespace com::fourisland::lingo2_archipelago {
6namespace {
7
8void Run(const std::string& mapdir) {
9 CollectedInfo info;
10
11 ProcessHumanData(mapdir, info);
12
13 ValidateCollectedInfo(info);
14}
15
16} // namespace
17} // namespace com::fourisland::lingo2_archipelago
18
19int main(int argc, char** argv) {
20 if (argc != 2) {
21 std::cout << "Incorrect argument count." << std::endl;
22 std::cout << "Usage: validator [path to map directory]" << std::endl;
23 return 1;
24 }
25
26 std::string mapdir = argv[1];
27
28 com::fourisland::lingo2_archipelago::Run(mapdir);
29
30 return 0;
31}
diff --git a/tools/validator/structs.h b/tools/validator/structs.h new file mode 100644 index 0000000..c3427f4 --- /dev/null +++ b/tools/validator/structs.h
@@ -0,0 +1,97 @@
1#ifndef TOOLS_VALIDATOR_STRUCTS_H_
2#define TOOLS_VALIDATOR_STRUCTS_H_
3
4#include <map>
5#include <string>
6#include <vector>
7
8#include "proto/human.pb.h"
9#include "util/identifiers.h"
10
11namespace com::fourisland::lingo2_archipelago {
12
13struct MalformedIdentifiers {
14 std::vector<PaintingIdentifier> paintings;
15 std::vector<PanelIdentifier> panels;
16 std::vector<KeyholderIdentifier> keyholders;
17
18 bool HasAny() const {
19 return !paintings.empty() || !panels.empty() || !keyholders.empty();
20 }
21};
22
23struct RoomInfo {
24 std::vector<HumanRoom> definitions;
25
26 std::vector<DoorIdentifier> doors_referenced_by;
27 std::vector<PanelIdentifier> panels_referenced_by;
28 std::vector<HumanConnection> connections_referenced_by;
29};
30
31struct DoorInfo {
32 std::vector<HumanDoor> definitions;
33
34 std::vector<HumanConnection> connections_referenced_by;
35 std::vector<DoorIdentifier> doors_referenced_by;
36 std::vector<PanelIdentifier> panels_referenced_by;
37 std::vector<PaintingIdentifier> paintings_referenced_by;
38 std::vector<PortIdentifier> ports_referenced_by;
39
40 MalformedIdentifiers malformed_identifiers;
41};
42
43struct PortInfo {
44 std::vector<HumanPort> definitions;
45
46 std::vector<HumanConnection> connections_referenced_by;
47};
48
49struct PaintingInfo {
50 std::vector<HumanPainting> definitions;
51
52 std::vector<HumanConnection> connections_referenced_by;
53 std::vector<DoorIdentifier> doors_referenced_by;
54};
55
56struct ProxyInfo {
57 std::vector<Proxy> definitions;
58
59 std::vector<HumanConnection> connections_referenced_by;
60 std::vector<DoorIdentifier> doors_referenced_by;
61};
62
63struct PanelInfo {
64 std::vector<HumanPanel> definitions;
65
66 std::vector<HumanConnection> connections_referenced_by;
67 std::vector<DoorIdentifier> doors_referenced_by;
68
69 std::map<std::string, ProxyInfo> proxies;
70};
71
72struct KeyholderInfo {
73 std::vector<HumanKeyholder> definitions;
74
75 std::vector<DoorIdentifier> doors_referenced_by;
76};
77
78using LetterIdentifier = std::tuple<char, bool>;
79
80struct LetterInfo {
81 std::vector<RoomIdentifier> defined_in;
82};
83
84struct CollectedInfo {
85 std::map<RoomIdentifier, RoomInfo, RoomIdentifierLess> rooms;
86 std::map<DoorIdentifier, DoorInfo, DoorIdentifierLess> doors;
87 std::map<PortIdentifier, PortInfo, PortIdentifierLess> ports;
88 std::map<PaintingIdentifier, PaintingInfo, PaintingIdentifierLess> paintings;
89 std::map<PanelIdentifier, PanelInfo, PanelIdentifierLess> panels;
90 std::map<KeyholderIdentifier, KeyholderInfo, KeyholderIdentifierLess>
91 keyholders;
92 std::map<LetterIdentifier, LetterInfo> letters;
93};
94
95} // namespace com::fourisland::lingo2_archipelago
96
97#endif /* TOOLS_VALIDATOR_STRUCTS_H_ */
diff --git a/tools/validator/validator.cpp b/tools/validator/validator.cpp new file mode 100644 index 0000000..3381ed2 --- /dev/null +++ b/tools/validator/validator.cpp
@@ -0,0 +1,250 @@
1#include "validator.h"
2
3#include <iostream>
4
5#include "proto/human.pb.h"
6#include "structs.h"
7#include "util/identifiers.h"
8
9namespace com::fourisland::lingo2_archipelago {
10namespace {
11
12void ValidateRoom(const RoomIdentifier& room_identifier,
13 const RoomInfo& room_info) {
14 if (room_info.definitions.empty()) {
15 std::cout << "Room " << room_identifier.ShortDebugString()
16 << " has no definition, but was referenced:" << std::endl;
17
18 for (const DoorIdentifier& door_identifier :
19 room_info.doors_referenced_by) {
20 std::cout << " DOOR " << door_identifier.ShortDebugString()
21 << std::endl;
22 }
23
24 for (const PanelIdentifier& panel_identifier :
25 room_info.panels_referenced_by) {
26 std::cout << " PANEL " << panel_identifier.ShortDebugString()
27 << std::endl;
28 }
29
30 for (const HumanConnection& connection :
31 room_info.connections_referenced_by) {
32 std::cout << " CONNECTION " << connection.ShortDebugString()
33 << std::endl;
34 }
35 } else if (room_info.definitions.size() > 1) {
36 std::cout << "Room " << room_identifier.ShortDebugString()
37 << " was defined multiple times." << std::endl;
38 }
39}
40
41void ValidateDoor(const DoorIdentifier& door_identifier,
42 const DoorInfo& door_info) {
43 if (door_info.definitions.empty()) {
44 std::cout << "Door " << door_identifier.ShortDebugString()
45 << " has no definition, but was referenced:" << std::endl;
46
47 for (const DoorIdentifier& other_door_identifier :
48 door_info.doors_referenced_by) {
49 std::cout << " DOOR " << other_door_identifier.ShortDebugString()
50 << std::endl;
51 }
52
53 for (const PanelIdentifier& panel_identifier :
54 door_info.panels_referenced_by) {
55 std::cout << " PANEL " << panel_identifier.ShortDebugString()
56 << std::endl;
57 }
58
59 for (const PaintingIdentifier& painting_identifier :
60 door_info.paintings_referenced_by) {
61 std::cout << " PAINTING " << painting_identifier.ShortDebugString()
62 << std::endl;
63 }
64
65 for (const PortIdentifier& port_identifier :
66 door_info.ports_referenced_by) {
67 std::cout << " PORT " << port_identifier.ShortDebugString()
68 << std::endl;
69 }
70
71 for (const HumanConnection& connection :
72 door_info.connections_referenced_by) {
73 std::cout << " CONNECTION " << connection.ShortDebugString()
74 << std::endl;
75 }
76 } else if (door_info.definitions.size() > 1) {
77 std::cout << "Door " << door_identifier.ShortDebugString()
78 << " was defined multiple times." << std::endl;
79 }
80
81 if (door_info.malformed_identifiers.HasAny()) {
82 std::cout << "Door " << door_identifier.ShortDebugString()
83 << " has malformed identifiers:" << std::endl;
84
85 for (const PaintingIdentifier& painting_identifier :
86 door_info.malformed_identifiers.paintings) {
87 std::cout << " PAINTING " << painting_identifier.ShortDebugString()
88 << std::endl;
89 }
90
91 for (const PanelIdentifier& panel_identifier :
92 door_info.malformed_identifiers.panels) {
93 std::cout << " PANEL " << panel_identifier.ShortDebugString()
94 << std::endl;
95 }
96
97 for (const KeyholderIdentifier& keyholder_identifier :
98 door_info.malformed_identifiers.keyholders) {
99 std::cout << " KEYHOLDER " << keyholder_identifier.ShortDebugString()
100 << std::endl;
101 }
102 }
103}
104
105void ValidatePort(const PortIdentifier& port_identifier,
106 const PortInfo& port_info) {
107 if (port_info.definitions.empty()) {
108 std::cout << "Port " << port_identifier.ShortDebugString()
109 << " has no definition, but was referenced:" << std::endl;
110
111 for (const HumanConnection& connection :
112 port_info.connections_referenced_by) {
113 std::cout << " CONNECTION " << connection.ShortDebugString()
114 << std::endl;
115 }
116 } else if (port_info.definitions.size() > 1) {
117 std::cout << "Port " << port_identifier.ShortDebugString()
118 << " was defined multiple times." << std::endl;
119 }
120}
121
122void ValidatePainting(const PaintingIdentifier& painting_identifier,
123 const PaintingInfo& painting_info) {
124 if (painting_info.definitions.empty()) {
125 std::cout << "Painting " << painting_identifier.ShortDebugString()
126 << " has no definition, but was referenced:" << std::endl;
127
128 for (const DoorIdentifier& door_identifier :
129 painting_info.doors_referenced_by) {
130 std::cout << " DOOR " << door_identifier.ShortDebugString()
131 << std::endl;
132 }
133
134 for (const HumanConnection& connection :
135 painting_info.connections_referenced_by) {
136 std::cout << " CONNECTION " << connection.ShortDebugString()
137 << std::endl;
138 }
139 } else if (painting_info.definitions.size() > 1) {
140 std::cout << "Painting " << painting_identifier.ShortDebugString()
141 << " was defined multiple times." << std::endl;
142 }
143}
144
145void ValidatePanel(const PanelIdentifier& panel_identifier,
146 const PanelInfo& panel_info) {
147 if (panel_info.definitions.empty()) {
148 std::cout << "Panel " << panel_identifier.ShortDebugString()
149 << " has no definition, but was referenced:" << std::endl;
150
151 for (const DoorIdentifier& door_identifier :
152 panel_info.doors_referenced_by) {
153 std::cout << " DOOR " << door_identifier.ShortDebugString()
154 << std::endl;
155 }
156
157 for (const HumanConnection& connection :
158 panel_info.connections_referenced_by) {
159 std::cout << " CONNECTION " << connection.ShortDebugString()
160 << std::endl;
161 }
162 } else if (panel_info.definitions.size() > 1) {
163 std::cout << "Panel " << panel_identifier.ShortDebugString()
164 << " was defined multiple times." << std::endl;
165 }
166
167 for (const auto& [answer, proxy_info] : panel_info.proxies) {
168 if (proxy_info.definitions.empty()) {
169 std::cout << "Panel " << panel_identifier.ShortDebugString()
170 << " with answer \"" << answer
171 << "\" has no definition, but was referenced:" << std::endl;
172
173 for (const DoorIdentifier& door_identifier :
174 proxy_info.doors_referenced_by) {
175 std::cout << " DOOR " << door_identifier.ShortDebugString()
176 << std::endl;
177 }
178
179 for (const HumanConnection& connection :
180 proxy_info.connections_referenced_by) {
181 std::cout << " CONNECTION " << connection.ShortDebugString()
182 << std::endl;
183 }
184 } else if (proxy_info.definitions.size() > 1) {
185 std::cout << "Panel " << panel_identifier.ShortDebugString()
186 << " with answer \"" << answer
187 << "\" was defined multiple times." << std::endl;
188 }
189 }
190}
191
192void ValidateKeyholder(const KeyholderIdentifier& keyholder_identifier,
193 const KeyholderInfo& keyholder_info) {
194 if (keyholder_info.definitions.empty()) {
195 std::cout << "Keyholder " << keyholder_identifier.ShortDebugString()
196 << " has no definition, but was referenced:" << std::endl;
197
198 for (const DoorIdentifier& door_identifier :
199 keyholder_info.doors_referenced_by) {
200 std::cout << " DOOR " << door_identifier.ShortDebugString()
201 << std::endl;
202 }
203 } else if (keyholder_info.definitions.size() > 1) {
204 std::cout << "Keyholder " << keyholder_identifier.ShortDebugString()
205 << " was defined multiple times." << std::endl;
206 }
207}
208
209void ValidateLetter(const LetterIdentifier& letter_identifier,
210 const LetterInfo& letter_info) {
211 std::string letter_name = std::string(1, std::get<0>(letter_identifier)) +
212 (std::get<1>(letter_identifier) ? "2" : "1");
213
214 if (letter_info.defined_in.size() > 1) {
215 std::cout << "Letter " << letter_name
216 << " was defined in multiple places:" << std::endl;
217
218 for (const RoomIdentifier& room_identifier : letter_info.defined_in) {
219 std::cout << " " << room_identifier.ShortDebugString() << std::endl;
220 }
221 }
222}
223
224} // namespace
225
226void ValidateCollectedInfo(const CollectedInfo& info) {
227 for (const auto& [room_identifier, room_info] : info.rooms) {
228 ValidateRoom(room_identifier, room_info);
229 }
230 for (const auto& [door_identifier, door_info] : info.doors) {
231 ValidateDoor(door_identifier, door_info);
232 }
233 for (const auto& [port_identifier, port_info] : info.ports) {
234 ValidatePort(port_identifier, port_info);
235 }
236 for (const auto& [painting_identifier, painting_info] : info.paintings) {
237 ValidatePainting(painting_identifier, painting_info);
238 }
239 for (const auto& [panel_identifier, panel_info] : info.panels) {
240 ValidatePanel(panel_identifier, panel_info);
241 }
242 for (const auto& [keyholder_identifier, keyholder_info] : info.keyholders) {
243 ValidateKeyholder(keyholder_identifier, keyholder_info);
244 }
245 for (const auto& [letter_identifier, letter_info] : info.letters) {
246 ValidateLetter(letter_identifier, letter_info);
247 }
248}
249
250} // namespace com::fourisland::lingo2_archipelago
diff --git a/tools/validator/validator.h b/tools/validator/validator.h new file mode 100644 index 0000000..b710429 --- /dev/null +++ b/tools/validator/validator.h
@@ -0,0 +1,12 @@
1#ifndef TOOLS_VALIDATOR_VALIDATOR_H_
2#define TOOLS_VALIDATOR_VALIDATOR_H
3
4namespace com::fourisland::lingo2_archipelago {
5
6struct CollectedInfo;
7
8void ValidateCollectedInfo(const CollectedInfo& info);
9
10} // namespace com::fourisland::lingo2_archipelago
11
12#endif /* TOOLS_VALIDATOR_VALIDATOR_H */