summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--data/connections.txtpb20
-rw-r--r--data/ids.txtpb20
-rw-r--r--data/maps/four_rooms/doors.txtpb8
-rw-r--r--data/maps/four_rooms/rooms/Examples Room.txtpb8
-rw-r--r--data/maps/the_butterfly/doors.txtpb2
-rw-r--r--data/maps/the_double_sided/connections.txtpb2
-rw-r--r--data/maps/the_great/rooms/Main Area.txtpb7
-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
20 files changed, 1080 insertions, 28 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index f15a970..e76d0db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -6,3 +6,4 @@ add_subdirectory(proto)
6add_subdirectory(tools/util) 6add_subdirectory(tools/util)
7add_subdirectory(tools/assign_ids) 7add_subdirectory(tools/assign_ids)
8add_subdirectory(tools/datapacker) 8add_subdirectory(tools/datapacker)
9add_subdirectory(tools/validator)
diff --git a/data/connections.txtpb b/data/connections.txtpb index 3cfbe6a..9d72467 100644 --- a/data/connections.txtpb +++ b/data/connections.txtpb
@@ -1,4 +1,5 @@
1# TODO 1# TODO
2# the_entry/Starting Room/HI/thewords
2# the_entry/Lime Room/DAEDALUS 3# the_entry/Lime Room/DAEDALUS
3# the_entry/Lime Room/REVITALIZED 4# the_entry/Lime Room/REVITALIZED
4# the_entry/Shop Entrance/SHOP 5# the_entry/Shop Entrance/SHOP
@@ -38,23 +39,6 @@
38# the_liberated/Painting Room/PYRAMID 39# the_liberated/Painting Room/PYRAMID
39connections { 40connections {
40 from { 41 from {
41 panel {
42 map: "the_entry"
43 room: "Starting Room"
44 name: "HI"
45 answer: "thewords"
46 }
47 }
48 to {
49 room {
50 map: "the_words"
51 name: "Entrance"
52 }
53 }
54 oneway: true
55}
56connections {
57 from {
58 port { 42 port {
59 map: "the_entry" 43 map: "the_entry"
60 room: "Gallery Return" 44 room: "Gallery Return"
@@ -171,7 +155,7 @@ connections {
171 from { 155 from {
172 painting { 156 painting {
173 map: "the_bearer" 157 map: "the_bearer"
174 room: "Butterfly" 158 room: "Butterfly Room"
175 name: "BUTTERFLY" 159 name: "BUTTERFLY"
176 } 160 }
177 } 161 }
diff --git a/data/ids.txtpb b/data/ids.txtpb index 7d1d9d0..49e035a 100644 --- a/data/ids.txtpb +++ b/data/ids.txtpb
@@ -37,10 +37,26 @@ maps {
37 value: 265 37 value: 265
38 } 38 }
39 panels { 39 panels {
40 key: "EMOTION (1)"
41 value: 738
42 }
43 panels {
44 key: "EMOTION (2)"
45 value: 740
46 }
47 panels {
40 key: "SIZE" 48 key: "SIZE"
41 value: 264 49 value: 264
42 } 50 }
43 panels { 51 panels {
52 key: "SIZE (1)"
53 value: 737
54 }
55 panels {
56 key: "SIZE (2)"
57 value: 739
58 }
59 panels {
44 key: "SONNET" 60 key: "SONNET"
45 value: 267 61 value: 267
46 } 62 }
@@ -2740,6 +2756,10 @@ maps {
2740 value: 518 2756 value: 518
2741 } 2757 }
2742 panels { 2758 panels {
2759 key: "CURT"
2760 value: 736
2761 }
2762 panels {
2743 key: "DEW" 2763 key: "DEW"
2744 value: 505 2764 value: 505
2745 } 2765 }
diff --git a/data/maps/four_rooms/doors.txtpb b/data/maps/four_rooms/doors.txtpb index 46d0abe..f0bf060 100644 --- a/data/maps/four_rooms/doors.txtpb +++ b/data/maps/four_rooms/doors.txtpb
@@ -16,10 +16,10 @@ doors {
16 name: "Examples Door" 16 name: "Examples Door"
17 type: STANDARD 17 type: STANDARD
18 receivers: "Components/Doors/entry_2" 18 receivers: "Components/Doors/entry_2"
19 panels { room: "Examples Room" name: "SIZE" } 19 panels { room: "Examples Room" name: "SIZE (1)" }
20 panels { room: "Examples Room" name: "EMOTION" } 20 panels { room: "Examples Room" name: "EMOTION (1)" }
21 panels { room: "Examples Room" name: "SIZE" } 21 panels { room: "Examples Room" name: "SIZE (2)" }
22 panels { room: "Examples Room" name: "EMOTION" } 22 panels { room: "Examples Room" name: "EMOTION (2)" }
23 panels { room: "Examples Room" name: "SUPERLATIVE" } 23 panels { room: "Examples Room" name: "SUPERLATIVE" }
24 panels { room: "Examples Room" name: "SONNET" } 24 panels { room: "Examples Room" name: "SONNET" }
25 panels { room: "Examples Room" name: "URN" } 25 panels { room: "Examples Room" name: "URN" }
diff --git a/data/maps/four_rooms/rooms/Examples Room.txtpb b/data/maps/four_rooms/rooms/Examples Room.txtpb index ffbe74d..bec3a23 100644 --- a/data/maps/four_rooms/rooms/Examples Room.txtpb +++ b/data/maps/four_rooms/rooms/Examples Room.txtpb
@@ -1,28 +1,28 @@
1name: "Examples Room" 1name: "Examples Room"
2display_name: "Examples Room" 2display_name: "Examples Room"
3panels { 3panels {
4 name: "SIZE" 4 name: "SIZE (1)"
5 path: "Panels/Room 2 Examples/entry_1" 5 path: "Panels/Room 2 Examples/entry_1"
6 clue: "size" 6 clue: "size"
7 answer: "tiny" 7 answer: "tiny"
8 symbols: "example" 8 symbols: "example"
9} 9}
10panels { 10panels {
11 name: "EMOTION" 11 name: "EMOTION (1)"
12 path: "Panels/Room 2 Examples/entry_2" 12 path: "Panels/Room 2 Examples/entry_2"
13 clue: "emotion" 13 clue: "emotion"
14 answer: "love" 14 answer: "love"
15 symbols: "example" 15 symbols: "example"
16} 16}
17panels { 17panels {
18 name: "SIZE" 18 name: "SIZE (2)"
19 path: "Panels/Room 2 Examples/entry_3" 19 path: "Panels/Room 2 Examples/entry_3"
20 clue: "size" 20 clue: "size"
21 answer: "huge" 21 answer: "huge"
22 symbols: "example" 22 symbols: "example"
23} 23}
24panels { 24panels {
25 name: "EMOTION" 25 name: "EMOTION (2)"
26 path: "Panels/Room 2 Examples/entry_4" 26 path: "Panels/Room 2 Examples/entry_4"
27 clue: "emotion" 27 clue: "emotion"
28 answer: "fear" 28 answer: "fear"
diff --git a/data/maps/the_butterfly/doors.txtpb b/data/maps/the_butterfly/doors.txtpb index 1994d2f..987c269 100644 --- a/data/maps/the_butterfly/doors.txtpb +++ b/data/maps/the_butterfly/doors.txtpb
@@ -4,7 +4,7 @@ doors {
4 type: EVENT 4 type: EVENT
5 panels { room: "Main Area" name: "SPECIES" } 5 panels { room: "Main Area" name: "SPECIES" }
6 panels { room: "Main Area" name: "PERSONALITY" } 6 panels { room: "Main Area" name: "PERSONALITY" }
7 panels { room: "Main Area" name: "CONSTITUION" } 7 panels { room: "Main Area" name: "CONSTITUTION" }
8 panels { room: "Main Area" name: "GAME" } 8 panels { room: "Main Area" name: "GAME" }
9 panels { room: "Main Area" name: "SCIENCE" } 9 panels { room: "Main Area" name: "SCIENCE" }
10 panels { room: "Main Area" name: "SCHOOL" } 10 panels { room: "Main Area" name: "SCHOOL" }
diff --git a/data/maps/the_double_sided/connections.txtpb b/data/maps/the_double_sided/connections.txtpb index c21049d..3c404e2 100644 --- a/data/maps/the_double_sided/connections.txtpb +++ b/data/maps/the_double_sided/connections.txtpb
@@ -94,7 +94,7 @@ connections {
94 door { name: "Obverse Black/Pink Door" } 94 door { name: "Obverse Black/Pink Door" }
95} 95}
96connections { 96connections {
97 from_room: "Flipped Yellow Area" 97 from_room: "Flipped Yellow Front Area"
98 to_room: "Flipped Black Area" 98 to_room: "Flipped Black Area"
99 door { name: "Flipped Yellow/Black Door" } 99 door { name: "Flipped Yellow/Black Door" }
100} 100}
diff --git a/data/maps/the_great/rooms/Main Area.txtpb b/data/maps/the_great/rooms/Main Area.txtpb index a70b011..b014b16 100644 --- a/data/maps/the_great/rooms/Main Area.txtpb +++ b/data/maps/the_great/rooms/Main Area.txtpb
@@ -119,6 +119,13 @@ panels {
119 symbols: "sun" 119 symbols: "sun"
120 symbols: "zero" 120 symbols: "zero"
121} 121}
122panels {
123 name: "CURT"
124 path: "Panels/Maze/entry_1"
125 clue: "curt"
126 answer: "court"
127 symbols: "sparkles"
128}
122ports { 129ports {
123 name: "ENTRY" 130 name: "ENTRY"
124 path: "Components/Warps/worldport" 131 path: "Components/Warps/worldport"
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 */