summary refs log tree commit diff stats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/util/CMakeLists.txt5
-rw-r--r--tools/util/identifiers.cpp102
-rw-r--r--tools/util/identifiers.h85
-rw-r--r--tools/util/naming.cpp4
-rw-r--r--tools/util/naming.h4
-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
12 files changed, 1040 insertions, 0 deletions
diff --git a/tools/util/CMakeLists.txt b/tools/util/CMakeLists.txt index 8eb8d3b..f086e10 100644 --- a/tools/util/CMakeLists.txt +++ b/tools/util/CMakeLists.txt
@@ -1,5 +1,10 @@
1find_package(Protobuf REQUIRED)
2
1add_library(util 3add_library(util
4 identifiers.cpp
2 naming.cpp 5 naming.cpp
3) 6)
4set_property(TARGET util PROPERTY CXX_STANDARD 20) 7set_property(TARGET util PROPERTY CXX_STANDARD 20)
5set_property(TARGET util PROPERTY CXX_STANDARD_REQUIRED ON) 8set_property(TARGET util PROPERTY CXX_STANDARD_REQUIRED ON)
9target_include_directories(util PUBLIC ${CMAKE_BINARY_DIR})
10target_link_libraries(util PUBLIC protos protobuf::libprotobuf)
diff --git a/tools/util/identifiers.cpp b/tools/util/identifiers.cpp new file mode 100644 index 0000000..5b51c57 --- /dev/null +++ b/tools/util/identifiers.cpp
@@ -0,0 +1,102 @@
1#include "identifiers.h"
2
3#include <string>
4
5#include "proto/human.pb.h"
6
7namespace com::fourisland::lingo2_archipelago {
8
9std::optional<RoomIdentifier> GetCompleteRoomIdentifier(
10 RoomIdentifier identifier, std::optional<std::string> map_name) {
11 if (!identifier.has_map()) {
12 if (!map_name) {
13 return std::nullopt;
14 }
15 identifier.set_map(*map_name);
16 }
17 return identifier;
18}
19
20std::optional<DoorIdentifier> GetCompleteDoorIdentifier(
21 DoorIdentifier identifier, std::optional<std::string> map_name) {
22 if (!identifier.has_map()) {
23 if (!map_name) {
24 return std::nullopt;
25 }
26 identifier.set_map(*map_name);
27 }
28 return identifier;
29}
30
31std::optional<PortIdentifier> GetCompletePortIdentifier(
32 PortIdentifier identifier, std::optional<std::string> map_name,
33 std::optional<std::string> room_name) {
34 if (!identifier.has_map()) {
35 if (!map_name) {
36 return std::nullopt;
37 }
38 identifier.set_map(*map_name);
39 }
40 if (!identifier.has_room()) {
41 if (!room_name) {
42 return std::nullopt;
43 }
44 identifier.set_room(*room_name);
45 }
46 return identifier;
47}
48
49std::optional<PaintingIdentifier> GetCompletePaintingIdentifier(
50 PaintingIdentifier identifier, std::optional<std::string> map_name,
51 std::optional<std::string> room_name) {
52 if (!identifier.has_map()) {
53 if (!map_name) {
54 return std::nullopt;
55 }
56 identifier.set_map(*map_name);
57 }
58 if (!identifier.has_room()) {
59 if (!room_name) {
60 return std::nullopt;
61 }
62 identifier.set_room(*room_name);
63 }
64 return identifier;
65}
66
67std::optional<PanelIdentifier> GetCompletePanelIdentifierWithoutAnswer(
68 PanelIdentifier identifier, std::optional<std::string> map_name,
69 std::optional<std::string> room_name) {
70 if (!identifier.has_map()) {
71 if (!map_name) {
72 return std::nullopt;
73 }
74 identifier.set_map(*map_name);
75 }
76 if (!identifier.has_room()) {
77 if (!room_name) {
78 return std::nullopt;
79 }
80 identifier.set_room(*room_name);
81 }
82 identifier.clear_answer();
83 return identifier;
84}
85
86std::optional<KeyholderIdentifier> GetCompleteKeyholderIdentifierWithoutKey(
87 KeyholderIdentifier identifier, const std::string& map_name,
88 std::optional<std::string> room_name) {
89 if (!identifier.has_map()) {
90 identifier.set_map(map_name);
91 }
92 if (!identifier.has_room()) {
93 if (!room_name) {
94 return std::nullopt;
95 }
96 identifier.set_room(*room_name);
97 }
98 identifier.clear_key();
99 return identifier;
100}
101
102} // namespace com::fourisland::lingo2_archipelago
diff --git a/tools/util/identifiers.h b/tools/util/identifiers.h new file mode 100644 index 0000000..341dee1 --- /dev/null +++ b/tools/util/identifiers.h
@@ -0,0 +1,85 @@
1#ifndef TOOLS_UTIL_IDENTIFIERS_H_
2#define TOOLS_UTIL_IDENTIFIERS_H_
3
4#include <optional>
5#include <string>
6#include <utility>
7
8#include "proto/human.pb.h"
9
10namespace com::fourisland::lingo2_archipelago {
11
12class RoomIdentifierLess {
13 public:
14 bool operator()(const RoomIdentifier& lhs, const RoomIdentifier& rhs) const {
15 return std::tie(lhs.map(), lhs.name()) < std::tie(rhs.map(), rhs.name());
16 }
17};
18
19class DoorIdentifierLess {
20 public:
21 bool operator()(const DoorIdentifier& lhs, const DoorIdentifier& rhs) const {
22 return std::tie(lhs.map(), lhs.name()) < std::tie(rhs.map(), rhs.name());
23 }
24};
25
26class PortIdentifierLess {
27 public:
28 bool operator()(const PortIdentifier& lhs, const PortIdentifier& rhs) const {
29 return std::tie(lhs.map(), lhs.room(), lhs.name()) <
30 std::tie(rhs.map(), rhs.room(), rhs.name());
31 }
32};
33
34class PaintingIdentifierLess {
35 public:
36 bool operator()(const PaintingIdentifier& lhs,
37 const PaintingIdentifier& rhs) const {
38 return std::tie(lhs.map(), lhs.room(), lhs.name()) <
39 std::tie(rhs.map(), rhs.room(), rhs.name());
40 }
41};
42
43class PanelIdentifierLess {
44 public:
45 bool operator()(const PanelIdentifier& lhs,
46 const PanelIdentifier& rhs) const {
47 return std::tie(lhs.map(), lhs.room(), lhs.name(), lhs.answer()) <
48 std::tie(rhs.map(), rhs.room(), rhs.name(), rhs.answer());
49 }
50};
51
52class KeyholderIdentifierLess {
53 public:
54 bool operator()(const KeyholderIdentifier& lhs,
55 const KeyholderIdentifier& rhs) const {
56 return std::tie(lhs.map(), lhs.room(), lhs.name(), lhs.key()) <
57 std::tie(rhs.map(), rhs.room(), rhs.name(), rhs.key());
58 }
59};
60
61std::optional<RoomIdentifier> GetCompleteRoomIdentifier(
62 RoomIdentifier identifier, std::optional<std::string> map_name);
63
64std::optional<DoorIdentifier> GetCompleteDoorIdentifier(
65 DoorIdentifier identifier, std::optional<std::string> map_name);
66
67std::optional<PortIdentifier> GetCompletePortIdentifier(
68 PortIdentifier identifier, std::optional<std::string> map_name,
69 std::optional<std::string> room_name);
70
71std::optional<PaintingIdentifier> GetCompletePaintingIdentifier(
72 PaintingIdentifier identifier, std::optional<std::string> map_name,
73 std::optional<std::string> room_name);
74
75std::optional<PanelIdentifier> GetCompletePanelIdentifierWithoutAnswer(
76 PanelIdentifier identifier, std::optional<std::string> map_name,
77 std::optional<std::string> room_name);
78
79std::optional<KeyholderIdentifier> GetCompleteKeyholderIdentifierWithoutKey(
80 KeyholderIdentifier identifier, const std::string& map_name,
81 std::optional<std::string> room_name);
82
83} // namespace com::fourisland::lingo2_archipelago
84
85#endif /* TOOLS_UTIL_IDENTIFIERS_H_ */
diff --git a/tools/util/naming.cpp b/tools/util/naming.cpp index 0ae99f6..8229c6d 100644 --- a/tools/util/naming.cpp +++ b/tools/util/naming.cpp
@@ -2,6 +2,8 @@
2 2
3#include <sstream> 3#include <sstream>
4 4
5namespace com::fourisland::lingo2_archipelago {
6
5std::string GetLetterName(std::string key, bool level2) { 7std::string GetLetterName(std::string key, bool level2) {
6 std::ostringstream lettername_s; 8 std::ostringstream lettername_s;
7 lettername_s << key; 9 lettername_s << key;
@@ -9,3 +11,5 @@ std::string GetLetterName(std::string key, bool level2) {
9 11
10 return lettername_s.str(); 12 return lettername_s.str();
11} 13}
14
15} // namespace com::fourisland::lingo2_archipelago
diff --git a/tools/util/naming.h b/tools/util/naming.h index 9a68851..85e2db0 100644 --- a/tools/util/naming.h +++ b/tools/util/naming.h
@@ -3,6 +3,10 @@
3 3
4#include <string> 4#include <string>
5 5
6namespace com::fourisland::lingo2_archipelago {
7
6std::string GetLetterName(std::string key, bool level2); 8std::string GetLetterName(std::string key, bool level2);
7 9
10} // namespace com::fourisland::lingo2_archipelago
11
8#endif /* TOOLS_UTIL_NAMING_H_ */ 12#endif /* TOOLS_UTIL_NAMING_H_ */
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 */