about summary refs log tree commit diff stats
path: root/tools/validator/validator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/validator/validator.cpp')
-rw-r--r--tools/validator/validator.cpp675
1 files changed, 500 insertions, 175 deletions
diff --git a/tools/validator/validator.cpp b/tools/validator/validator.cpp index f2ec280..fe36be7 100644 --- a/tools/validator/validator.cpp +++ b/tools/validator/validator.cpp
@@ -9,254 +9,579 @@
9namespace com::fourisland::lingo2_archipelago { 9namespace com::fourisland::lingo2_archipelago {
10namespace { 10namespace {
11 11
12void ValidateMap(const std::string& map_name, const MapInfo& map_info) { 12class Validator {
13 for (const auto& [node_path, node_info] : map_info.game_nodes) { 13 public:
14 if (node_info.uses > 1) { 14 explicit Validator(const CollectedInfo& info) : info_(info) {}
15 std::cout << "Map " << map_name << " node " << node_path 15
16 << " is used in multiple places." << std::endl; 16 void Validate() const {
17 for (const auto& [map_name, map_info] : info_.maps) {
18 ValidateMap(map_name, map_info);
19 }
20 for (const auto& [room_identifier, room_info] : info_.rooms) {
21 ValidateRoom(room_identifier, room_info);
22 }
23 for (const auto& [door_identifier, door_info] : info_.doors) {
24 ValidateDoor(door_identifier, door_info);
25 }
26 for (const auto& [port_identifier, port_info] : info_.ports) {
27 ValidatePort(port_identifier, port_info);
28 }
29 for (const auto& [painting_identifier, painting_info] : info_.paintings) {
30 ValidatePainting(painting_identifier, painting_info);
31 }
32 for (const auto& [panel_identifier, panel_info] : info_.panels) {
33 ValidatePanel(panel_identifier, panel_info);
34 }
35 for (const auto& [keyholder_identifier, keyholder_info] :
36 info_.keyholders) {
37 ValidateKeyholder(keyholder_identifier, keyholder_info);
38 }
39 for (const auto& [letter_identifier, letter_info] : info_.letters) {
40 ValidateLetter(letter_identifier, letter_info);
41 }
42 for (const auto& [ending_name, ending_info] : info_.endings) {
43 ValidateEnding(ending_name, ending_info);
44 }
45 for (const auto& [panel_name, panel_info] : info_.panel_names) {
46 ValidatePanelName(panel_name, panel_info);
47 }
48 for (const auto& [prog_name, prog_info] : info_.progressives) {
49 ValidateProgressive(prog_name, prog_info);
50 }
51 for (const auto& [group_name, group_info] : info_.door_groups) {
52 ValidateDoorGroup(group_name, group_info);
17 } 53 }
18 } 54 }
19}
20 55
21void ValidateRoom(const RoomIdentifier& room_identifier, 56 private:
22 const RoomInfo& room_info) { 57 void ValidateMap(const std::string& map_name, const MapInfo& map_info) const {
23 if (room_info.definitions.empty()) { 58 for (const auto& [node_path, node_info] : map_info.game_nodes) {
24 std::cout << "Room " << room_identifier.ShortDebugString() 59 if (node_info.uses > 1) {
25 << " has no definition, but was referenced:" << std::endl; 60 std::cout << "Map " << map_name << " node " << node_path
61 << " is used in multiple places." << std::endl;
62 } else if (node_info.uses == 0) {
63 std::cout << "Map " << map_name << " node " << node_path
64 << " is not used." << std::endl;
65 }
26 66
27 for (const DoorIdentifier& door_identifier : 67 if (!node_info.defined) {
28 room_info.doors_referenced_by) { 68 std::cout << "Map " << map_name << " node " << node_path
29 std::cout << " DOOR " << door_identifier.ShortDebugString() 69 << " is not defined in the game file." << std::endl;
30 << std::endl; 70 }
31 } 71 }
32 72
33 for (const PanelIdentifier& panel_identifier : 73 if (map_info.malformed_worldport_entrance) {
34 room_info.panels_referenced_by) { 74 std::cout << "The worldport entrance for map " << map_name
35 std::cout << " PANEL " << panel_identifier.ShortDebugString() 75 << " is malformed." << std::endl;
36 << std::endl;
37 } 76 }
77 }
38 78
39 for (const HumanConnection& connection : 79 void ValidateRoom(const RoomIdentifier& room_identifier,
40 room_info.connections_referenced_by) { 80 const RoomInfo& room_info) const {
41 std::cout << " CONNECTION " << connection.ShortDebugString() 81 if (room_info.definitions.empty()) {
42 << std::endl; 82 std::cout << "Room " << room_identifier.ShortDebugString()
83 << " has no definition, but was referenced:" << std::endl;
84
85 for (const DoorIdentifier& door_identifier :
86 room_info.doors_referenced_by) {
87 std::cout << " DOOR " << door_identifier.ShortDebugString()
88 << std::endl;
89 }
90
91 for (const PanelIdentifier& panel_identifier :
92 room_info.panels_referenced_by) {
93 std::cout << " PANEL " << panel_identifier.ShortDebugString()
94 << std::endl;
95 }
96
97 for (const HumanConnection& connection :
98 room_info.connections_referenced_by) {
99 std::cout << " CONNECTION " << connection.ShortDebugString()
100 << std::endl;
101 }
102 } else if (room_info.definitions.size() > 1) {
103 std::cout << "Room " << room_identifier.ShortDebugString()
104 << " was defined multiple times." << std::endl;
43 } 105 }
44 } else if (room_info.definitions.size() > 1) {
45 std::cout << "Room " << room_identifier.ShortDebugString()
46 << " was defined multiple times." << std::endl;
47 } 106 }
48}
49
50void ValidateDoor(const DoorIdentifier& door_identifier,
51 const DoorInfo& door_info) {
52 if (door_info.definitions.empty()) {
53 std::cout << "Door " << door_identifier.ShortDebugString()
54 << " has no definition, but was referenced:" << std::endl;
55 107
56 for (const DoorIdentifier& other_door_identifier : 108 bool DoesDoorNeedLocationName(const HumanDoor& h_door,
57 door_info.doors_referenced_by) { 109 const std::string& map_name) const {
58 std::cout << " DOOR " << other_door_identifier.ShortDebugString() 110 if (h_door.type() != DoorType::STANDARD) {
59 << std::endl; 111 return false;
60 } 112 }
61 113
62 for (const PanelIdentifier& panel_identifier : 114 if (h_door.keyholders_size() > 0 || h_door.white_ending() ||
63 door_info.panels_referenced_by) { 115 h_door.complete_at() > 0) {
64 std::cout << " PANEL " << panel_identifier.ShortDebugString() 116 return true;
65 << std::endl;
66 } 117 }
67 118
68 for (const PaintingIdentifier& painting_identifier : 119 if (h_door.panels_size() > 4) {
69 door_info.paintings_referenced_by) { 120 return true;
70 std::cout << " PAINTING " << painting_identifier.ShortDebugString()
71 << std::endl;
72 } 121 }
73 122
74 for (const PortIdentifier& port_identifier : 123 std::set<std::string> map_areas;
75 door_info.ports_referenced_by) { 124 for (const PanelIdentifier& pi : h_door.panels()) {
76 std::cout << " PORT " << port_identifier.ShortDebugString() 125 auto full_pi =
77 << std::endl; 126 GetCompletePanelIdentifierWithoutAnswer(pi, map_name, std::nullopt);
127 if (full_pi) {
128 auto panel_info_it = info_.panels.find(*full_pi);
129 if (panel_info_it != info_.panels.end()) {
130 const PanelInfo& panel_info = panel_info_it->second;
131
132 map_areas.insert(panel_info.map_area_name);
133 }
134 }
78 } 135 }
79 136
80 for (const HumanConnection& connection : 137 if (map_areas.size() > 1) {
81 door_info.connections_referenced_by) { 138 return true;
82 std::cout << " CONNECTION " << connection.ShortDebugString()
83 << std::endl;
84 } 139 }
85 } else if (door_info.definitions.size() > 1) { 140
86 std::cout << "Door " << door_identifier.ShortDebugString() 141 return false;
87 << " was defined multiple times." << std::endl;
88 } 142 }
89 143
90 if (door_info.malformed_identifiers.HasAny()) { 144 void ValidateDoor(const DoorIdentifier& door_identifier,
91 std::cout << "Door " << door_identifier.ShortDebugString() 145 const DoorInfo& door_info) const {
92 << " has malformed identifiers:" << std::endl; 146 if (door_info.definitions.empty()) {
147 std::cout << "Door " << door_identifier.ShortDebugString()
148 << " has no definition, but was referenced:" << std::endl;
93 149
94 for (const PaintingIdentifier& painting_identifier : 150 for (const DoorIdentifier& other_door_identifier :
95 door_info.malformed_identifiers.paintings) { 151 door_info.doors_referenced_by) {
96 std::cout << " PAINTING " << painting_identifier.ShortDebugString() 152 std::cout << " DOOR " << other_door_identifier.ShortDebugString()
97 << std::endl; 153 << std::endl;
98 } 154 }
99 155
100 for (const PanelIdentifier& panel_identifier : 156 for (const PanelIdentifier& panel_identifier :
101 door_info.malformed_identifiers.panels) { 157 door_info.panels_referenced_by) {
102 std::cout << " PANEL " << panel_identifier.ShortDebugString() 158 std::cout << " PANEL " << panel_identifier.ShortDebugString()
103 << std::endl; 159 << std::endl;
160 }
161
162 for (const PaintingIdentifier& painting_identifier :
163 door_info.paintings_referenced_by) {
164 std::cout << " PAINTING " << painting_identifier.ShortDebugString()
165 << std::endl;
166 }
167
168 for (const PortIdentifier& port_identifier :
169 door_info.ports_referenced_by) {
170 std::cout << " PORT " << port_identifier.ShortDebugString()
171 << std::endl;
172 }
173
174 for (const HumanConnection& connection :
175 door_info.connections_referenced_by) {
176 std::cout << " CONNECTION " << connection.ShortDebugString()
177 << std::endl;
178 }
179
180 for (const std::string& prog_name :
181 door_info.progressives_referenced_by) {
182 std::cout << " PROGRESSIVE " << prog_name << std::endl;
183 }
184
185 for (const std::string& group_name :
186 door_info.door_groups_referenced_by) {
187 std::cout << " DOOR GROUP " << group_name << std::endl;
188 }
189
190 if (door_info.has_id) {
191 std::cout << " An AP ID is present." << std::endl;
192 }
193 } else if (door_info.definitions.size() > 1) {
194 std::cout << "Door " << door_identifier.ShortDebugString()
195 << " was defined multiple times." << std::endl;
104 } 196 }
105 197
106 for (const KeyholderIdentifier& keyholder_identifier : 198 if (door_info.malformed_identifiers.HasAny()) {
107 door_info.malformed_identifiers.keyholders) { 199 std::cout << "Door " << door_identifier.ShortDebugString()
108 std::cout << " KEYHOLDER " << keyholder_identifier.ShortDebugString() 200 << " has malformed identifiers:" << std::endl;
109 << std::endl; 201
202 for (const PaintingIdentifier& painting_identifier :
203 door_info.malformed_identifiers.paintings) {
204 std::cout << " PAINTING " << painting_identifier.ShortDebugString()
205 << std::endl;
206 }
207
208 for (const PanelIdentifier& panel_identifier :
209 door_info.malformed_identifiers.panels) {
210 std::cout << " PANEL " << panel_identifier.ShortDebugString()
211 << std::endl;
212 }
213
214 for (const KeyholderIdentifier& keyholder_identifier :
215 door_info.malformed_identifiers.keyholders) {
216 std::cout << " KEYHOLDER " << keyholder_identifier.ShortDebugString()
217 << std::endl;
218 }
110 } 219 }
111 }
112}
113 220
114void ValidatePort(const PortIdentifier& port_identifier, 221 for (const HumanDoor& h_door : door_info.definitions) {
115 const PortInfo& port_info) { 222 if (DoesDoorNeedLocationName(h_door, door_identifier.map()) &&
116 if (port_info.definitions.empty()) { 223 !h_door.has_location_name()) {
117 std::cout << "Port " << port_identifier.ShortDebugString() 224 std::cout << "Door " << door_identifier.ShortDebugString()
118 << " has no definition, but was referenced:" << std::endl; 225 << " needs an explicit location name." << std::endl;
226 }
227
228 if (h_door.type() == DoorType::STANDARD ||
229 h_door.type() == DoorType::LOCATION_ONLY ||
230 h_door.type() == DoorType::GRAVESTONE || h_door.legacy_location()) {
231 if (h_door.double_letters()) {
232 std::cout << "Door " << door_identifier.ShortDebugString()
233 << " is a location that depends on double_letters."
234 << std::endl;
235 }
236
237 if (!h_door.has_location_room()) {
238 std::cout << "Door " << door_identifier.ShortDebugString()
239 << " is missing a location_room." << std::endl;
240 }
241 }
119 242
120 for (const HumanConnection& connection : 243 bool needs_id = (h_door.type() != DoorType::EVENT || h_door.latch() ||
121 port_info.connections_referenced_by) { 244 h_door.legacy_location());
122 std::cout << " CONNECTION " << connection.ShortDebugString() 245 if (door_info.has_id != needs_id) {
123 << std::endl; 246 if (needs_id) {
247 std::cout << "Door " << door_identifier.ShortDebugString()
248 << " is missing an AP ID." << std::endl;
249 } else {
250 std::cout << "Door " << door_identifier.ShortDebugString()
251 << " should not have an AP ID." << std::endl;
252 }
253 }
124 } 254 }
125 } else if (port_info.definitions.size() > 1) {
126 std::cout << "Port " << port_identifier.ShortDebugString()
127 << " was defined multiple times." << std::endl;
128 } 255 }
129}
130 256
131void ValidatePainting(const PaintingIdentifier& painting_identifier, 257 void ValidatePort(const PortIdentifier& port_identifier,
132 const PaintingInfo& painting_info) { 258 const PortInfo& port_info) const {
133 if (painting_info.definitions.empty()) { 259 if (port_info.definitions.empty()) {
134 std::cout << "Painting " << painting_identifier.ShortDebugString() 260 std::cout << "Port " << port_identifier.ShortDebugString()
135 << " has no definition, but was referenced:" << std::endl; 261 << " has no definition, but was referenced:" << std::endl;
136 262
137 for (const DoorIdentifier& door_identifier : 263 for (const HumanConnection& connection :
138 painting_info.doors_referenced_by) { 264 port_info.connections_referenced_by) {
139 std::cout << " DOOR " << door_identifier.ShortDebugString() 265 std::cout << " CONNECTION " << connection.ShortDebugString()
140 << std::endl; 266 << std::endl;
267 }
268
269 for (const std::string& map_name : port_info.map_worldport_entrances) {
270 std::cout << " MAP (worldport_entrance) " << map_name << std::endl;
271 }
272
273 if (port_info.has_id) {
274 std::cout << " An AP ID is present." << std::endl;
275 }
276 } else if (port_info.definitions.size() > 1) {
277 std::cout << "Port " << port_identifier.ShortDebugString()
278 << " was defined multiple times." << std::endl;
141 } 279 }
142 280
143 for (const HumanConnection& connection : 281 if (!port_info.target_connections_referenced_by.empty()) {
144 painting_info.connections_referenced_by) { 282 for (const HumanPort& port : port_info.definitions) {
145 std::cout << " CONNECTION " << connection.ShortDebugString() 283 if (port.has_required_door()) {
146 << std::endl; 284 std::cout << "Port " << port_identifier.ShortDebugString()
285 << " has a required door but is the target of a connection:"
286 << std::endl;
287
288 for (const HumanConnection& connection :
289 port_info.target_connections_referenced_by) {
290 std::cout << " CONNECTION " << connection.ShortDebugString()
291 << std::endl;
292 }
293 }
294 }
295 }
296
297 for (const HumanPort& port : port_info.definitions) {
298 if (!port.no_shuffle()) {
299 if (!port.has_destination()) {
300 std::cout << "Port " << port_identifier.ShortDebugString()
301 << " is shuffleable and missing a destination."
302 << std::endl;
303 }
304 if (!port.has_rotation()) {
305 std::cout << "Port " << port_identifier.ShortDebugString()
306 << " is shuffleable and missing a rotation." << std::endl;
307 }
308 if (!port_info.has_id) {
309 std::cout << "Port " << port_identifier.ShortDebugString()
310 << " is missing an AP ID." << std::endl;
311 }
312 } else {
313 if (port_info.has_id) {
314 std::cout << "Port " << port_identifier.ShortDebugString()
315 << " should not have an AP ID." << std::endl;
316 }
317 }
147 } 318 }
148 } else if (painting_info.definitions.size() > 1) {
149 std::cout << "Painting " << painting_identifier.ShortDebugString()
150 << " was defined multiple times." << std::endl;
151 } 319 }
152}
153 320
154void ValidatePanel(const PanelIdentifier& panel_identifier, 321 void ValidatePainting(const PaintingIdentifier& painting_identifier,
155 const PanelInfo& panel_info) { 322 const PaintingInfo& painting_info) const {
156 if (panel_info.definitions.empty()) { 323 if (painting_info.definitions.empty()) {
157 std::cout << "Panel " << panel_identifier.ShortDebugString() 324 std::cout << "Painting " << painting_identifier.ShortDebugString()
158 << " has no definition, but was referenced:" << std::endl; 325 << " has no definition, but was referenced:" << std::endl;
159 326
160 for (const DoorIdentifier& door_identifier : 327 for (const DoorIdentifier& door_identifier :
161 panel_info.doors_referenced_by) { 328 painting_info.doors_referenced_by) {
162 std::cout << " DOOR " << door_identifier.ShortDebugString() 329 std::cout << " DOOR " << door_identifier.ShortDebugString()
163 << std::endl; 330 << std::endl;
331 }
332
333 for (const HumanConnection& connection :
334 painting_info.connections_referenced_by) {
335 std::cout << " CONNECTION " << connection.ShortDebugString()
336 << std::endl;
337 }
338 } else if (painting_info.definitions.size() > 1) {
339 std::cout << "Painting " << painting_identifier.ShortDebugString()
340 << " was defined multiple times." << std::endl;
164 } 341 }
165 342
166 for (const HumanConnection& connection : 343 if (!painting_info.target_connections_referenced_by.empty()) {
167 panel_info.connections_referenced_by) { 344 for (const HumanPainting& painting : painting_info.definitions) {
168 std::cout << " CONNECTION " << connection.ShortDebugString() 345 if (painting.has_required_door()) {
169 << std::endl; 346 std::cout << "Painting " << painting_identifier.ShortDebugString()
347 << " has a required door but is the target of a connection:"
348 << std::endl;
349
350 for (const HumanConnection& connection :
351 painting_info.target_connections_referenced_by) {
352 std::cout << " CONNECTION " << connection.ShortDebugString()
353 << std::endl;
354 }
355 }
356 }
170 } 357 }
171 } else if (panel_info.definitions.size() > 1) {
172 std::cout << "Panel " << panel_identifier.ShortDebugString()
173 << " was defined multiple times." << std::endl;
174 } 358 }
175 359
176 for (const auto& [answer, proxy_info] : panel_info.proxies) { 360 void ValidatePanel(const PanelIdentifier& panel_identifier,
177 if (proxy_info.definitions.empty()) { 361 const PanelInfo& panel_info) const {
362 if (panel_identifier.name().empty()) {
178 std::cout << "Panel " << panel_identifier.ShortDebugString() 363 std::cout << "Panel " << panel_identifier.ShortDebugString()
179 << " with answer \"" << answer 364 << " has no name." << std::endl;
180 << "\" has no definition, but was referenced:" << std::endl; 365 }
366
367 if (panel_info.definitions.empty()) {
368 std::cout << "Panel " << panel_identifier.ShortDebugString()
369 << " has no definition, but was referenced:" << std::endl;
181 370
182 for (const DoorIdentifier& door_identifier : 371 for (const DoorIdentifier& door_identifier :
183 proxy_info.doors_referenced_by) { 372 panel_info.doors_referenced_by) {
184 std::cout << " DOOR " << door_identifier.ShortDebugString() 373 std::cout << " DOOR " << door_identifier.ShortDebugString()
185 << std::endl; 374 << std::endl;
186 } 375 }
187 376
188 for (const HumanConnection& connection : 377 for (const HumanConnection& connection :
189 proxy_info.connections_referenced_by) { 378 panel_info.connections_referenced_by) {
190 std::cout << " CONNECTION " << connection.ShortDebugString() 379 std::cout << " CONNECTION " << connection.ShortDebugString()
191 << std::endl; 380 << std::endl;
192 } 381 }
193 } else if (proxy_info.definitions.size() > 1) { 382
383 if (panel_info.has_id) {
384 std::cout << " An AP ID is present." << std::endl;
385 }
386 } else if (panel_info.definitions.size() > 1) {
194 std::cout << "Panel " << panel_identifier.ShortDebugString() 387 std::cout << "Panel " << panel_identifier.ShortDebugString()
195 << " with answer \"" << answer 388 << " was defined multiple times." << std::endl;
196 << "\" was defined multiple times." << std::endl;
197 } 389 }
198 }
199}
200 390
201void ValidateKeyholder(const KeyholderIdentifier& keyholder_identifier, 391 for (const auto& [answer, proxy_info] : panel_info.proxies) {
202 const KeyholderInfo& keyholder_info) { 392 if (proxy_info.definitions.empty()) {
203 if (keyholder_info.definitions.empty()) { 393 std::cout << "Panel " << panel_identifier.ShortDebugString()
204 std::cout << "Keyholder " << keyholder_identifier.ShortDebugString() 394 << " with answer \"" << answer
205 << " has no definition, but was referenced:" << std::endl; 395 << "\" has no definition, but was referenced:" << std::endl;
396
397 for (const DoorIdentifier& door_identifier :
398 proxy_info.doors_referenced_by) {
399 std::cout << " DOOR " << door_identifier.ShortDebugString()
400 << std::endl;
401 }
402
403 for (const HumanConnection& connection :
404 proxy_info.connections_referenced_by) {
405 std::cout << " CONNECTION " << connection.ShortDebugString()
406 << std::endl;
407 }
408 } else if (proxy_info.definitions.size() > 1) {
409 std::cout << "Panel " << panel_identifier.ShortDebugString()
410 << " with answer \"" << answer
411 << "\" was defined multiple times." << std::endl;
412 }
413 }
206 414
207 for (const DoorIdentifier& door_identifier : 415 if (!panel_info.has_id) {
208 keyholder_info.doors_referenced_by) { 416 std::cout << "Panel " << panel_identifier.ShortDebugString()
209 std::cout << " DOOR " << door_identifier.ShortDebugString() 417 << " is missing an AP ID." << std::endl;
210 << std::endl; 418 }
419
420 if (!panel_info.target_connections_referenced_by.empty()) {
421 for (const HumanPanel& panel : panel_info.definitions) {
422 if (panel.has_required_door()) {
423 std::cout << "Panel " << panel_identifier.ShortDebugString()
424 << " has a required door but is the target of a connection:"
425 << std::endl;
426
427 for (const HumanConnection& connection :
428 panel_info.target_connections_referenced_by) {
429 std::cout << " CONNECTION " << connection.ShortDebugString()
430 << std::endl;
431 }
432 }
433 }
211 } 434 }
212 } else if (keyholder_info.definitions.size() > 1) {
213 std::cout << "Keyholder " << keyholder_identifier.ShortDebugString()
214 << " was defined multiple times." << std::endl;
215 } 435 }
216}
217 436
218void ValidateLetter(const LetterIdentifier& letter_identifier, 437 void ValidateKeyholder(const KeyholderIdentifier& keyholder_identifier,
219 const LetterInfo& letter_info) { 438 const KeyholderInfo& keyholder_info) const {
220 std::string letter_name = std::string(1, std::get<0>(letter_identifier)) + 439 if (keyholder_info.definitions.empty()) {
221 (std::get<1>(letter_identifier) ? "2" : "1"); 440 std::cout << "Keyholder " << keyholder_identifier.ShortDebugString()
441 << " has no definition, but was referenced:" << std::endl;
222 442
223 if (letter_info.defined_in.size() > 1) { 443 for (const DoorIdentifier& door_identifier :
224 std::cout << "Letter " << letter_name 444 keyholder_info.doors_referenced_by) {
225 << " was defined in multiple places:" << std::endl; 445 std::cout << " DOOR " << door_identifier.ShortDebugString()
446 << std::endl;
447 }
226 448
227 for (const RoomIdentifier& room_identifier : letter_info.defined_in) { 449 if (keyholder_info.has_id) {
228 std::cout << " " << room_identifier.ShortDebugString() << std::endl; 450 std::cout << " An AP ID is present." << std::endl;
451 }
452 } else if (keyholder_info.definitions.size() > 1) {
453 std::cout << "Keyholder " << keyholder_identifier.ShortDebugString()
454 << " was defined multiple times." << std::endl;
455 }
456
457 for (const HumanKeyholder& h_keyholder : keyholder_info.definitions) {
458 bool needs_id = (h_keyholder.has_key());
459
460 if (needs_id != keyholder_info.has_id) {
461 if (needs_id) {
462 std::cout << "Keyholder " << keyholder_identifier.ShortDebugString()
463 << " is missing an AP ID." << std::endl;
464 } else {
465 std::cout << "Keyholder " << keyholder_identifier.ShortDebugString()
466 << " should not have an AP ID." << std::endl;
467 }
468 }
229 } 469 }
230 } 470 }
231}
232 471
233} // namespace 472 void ValidateLetter(const LetterIdentifier& letter_identifier,
473 const LetterInfo& letter_info) const {
474 std::string letter_name = std::string(1, std::get<0>(letter_identifier)) +
475 (std::get<1>(letter_identifier) ? "2" : "1");
234 476
235void ValidateCollectedInfo(const CollectedInfo& info) { 477 if (letter_info.defined_in.empty()) {
236 for (const auto& [map_name, map_info] : info.maps) { 478 std::cout << "Letter " << letter_name
237 ValidateMap(map_name, map_info); 479 << " has no definition, but was referenced:" << std::endl;
238 } 480
239 for (const auto& [room_identifier, room_info] : info.rooms) { 481 if (letter_info.has_id) {
240 ValidateRoom(room_identifier, room_info); 482 std::cout << " An AP ID is present." << std::endl;
241 } 483 }
242 for (const auto& [door_identifier, door_info] : info.doors) { 484 } else if (letter_info.defined_in.size() > 1) {
243 ValidateDoor(door_identifier, door_info); 485 std::cout << "Letter " << letter_name
244 } 486 << " was defined in multiple places:" << std::endl;
245 for (const auto& [port_identifier, port_info] : info.ports) { 487
246 ValidatePort(port_identifier, port_info); 488 for (const RoomIdentifier& room_identifier : letter_info.defined_in) {
489 std::cout << " " << room_identifier.ShortDebugString() << std::endl;
490 }
491 }
492
493 if (!letter_info.has_id) {
494 std::cout << "Letter " << letter_name << " is missing an AP ID."
495 << std::endl;
496 }
247 } 497 }
248 for (const auto& [painting_identifier, painting_info] : info.paintings) { 498
249 ValidatePainting(painting_identifier, painting_info); 499 void ValidateEnding(const std::string& ending_name,
500 const EndingInfo& ending_info) const {
501 if (ending_info.defined_in.empty()) {
502 std::cout << "Ending " << ending_name
503 << " has no definition, but was referenced:" << std::endl;
504
505 if (ending_info.has_id) {
506 std::cout << " An AP ID is present." << std::endl;
507 }
508 } else if (ending_info.defined_in.size() > 1) {
509 std::cout << "Ending " << ending_name
510 << " was defined in multiple places:" << std::endl;
511
512 for (const RoomIdentifier& room_identifier : ending_info.defined_in) {
513 std::cout << " " << room_identifier.ShortDebugString() << std::endl;
514 }
515 }
516
517 if (!ending_info.has_id) {
518 std::cout << "Ending " << ending_name << " is missing an AP ID."
519 << std::endl;
520 }
250 } 521 }
251 for (const auto& [panel_identifier, panel_info] : info.panels) { 522
252 ValidatePanel(panel_identifier, panel_info); 523 void ValidatePanelName(const std::string& panel_name,
524 const PanelNameInfo& panel_info) const {
525 if (panel_info.panels_used_by.size() > 1) {
526 std::cout << "The location name \"" << panel_name
527 << "\" is used by multiple panels:" << std::endl;
528
529 for (const PanelIdentifier& panel_identifier :
530 panel_info.panels_used_by) {
531 std::cout << " PANEL " << panel_identifier.ShortDebugString()
532 << std::endl;
533 }
534 }
253 } 535 }
254 for (const auto& [keyholder_identifier, keyholder_info] : info.keyholders) { 536
255 ValidateKeyholder(keyholder_identifier, keyholder_info); 537 void ValidateProgressive(const std::string& prog_name,
538 const ProgressiveInfo& prog_info) const {
539 if (prog_info.definitions.empty()) {
540 std::cout << "Progressive \"" << prog_name
541 << "\" has no definition, but was referenced:" << std::endl;
542
543 if (prog_info.has_id) {
544 std::cout << " An AP ID is present." << std::endl;
545 }
546 } else if (prog_info.definitions.size() > 1) {
547 std::cout << "Progressive \"" << prog_name
548 << "\" has multiple definitions." << std::endl;
549 }
550
551 if (!prog_info.has_id) {
552 std::cout << "Progressive \"" << prog_name << "\" is missing an AP ID."
553 << std::endl;
554 }
256 } 555 }
257 for (const auto& [letter_identifier, letter_info] : info.letters) { 556
258 ValidateLetter(letter_identifier, letter_info); 557 void ValidateDoorGroup(const std::string& group_name,
558 const DoorGroupInfo& group_info) const {
559 if (group_info.definitions.empty()) {
560 std::cout << "Door group \"" << group_name
561 << "\" has no definition, but was referenced:" << std::endl;
562
563 if (group_info.has_id) {
564 std::cout << " An AP ID is present." << std::endl;
565 }
566 } else if (group_info.definitions.size() > 1) {
567 std::cout << "Door group \"" << group_name
568 << "\" has multiple definitions." << std::endl;
569 }
570
571 if (!group_info.has_id) {
572 std::cout << "Door group \"" << group_name << "\" is missing an AP ID."
573 << std::endl;
574 }
259 } 575 }
576
577 const CollectedInfo& info_;
578};
579
580} // namespace
581
582void ValidateCollectedInfo(const CollectedInfo& info) {
583 Validator validator(info);
584 validator.Validate();
260} 585}
261 586
262} // namespace com::fourisland::lingo2_archipelago 587} // namespace com::fourisland::lingo2_archipelago