about summary refs log tree commit diff stats
path: root/tools/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/util')
-rw-r--r--tools/util/CMakeLists.txt8
-rw-r--r--tools/util/godot_scene.cpp207
-rw-r--r--tools/util/godot_scene.h57
-rw-r--r--tools/util/identifiers.cpp102
-rw-r--r--tools/util/identifiers.h85
-rw-r--r--tools/util/ids_yaml_format.cpp190
-rw-r--r--tools/util/ids_yaml_format.h16
-rw-r--r--tools/util/naming.cpp4
-rw-r--r--tools/util/naming.h4
9 files changed, 673 insertions, 0 deletions
diff --git a/tools/util/CMakeLists.txt b/tools/util/CMakeLists.txt index 8eb8d3b..0859a58 100644 --- a/tools/util/CMakeLists.txt +++ b/tools/util/CMakeLists.txt
@@ -1,5 +1,13 @@
1find_package(Protobuf REQUIRED)
2find_package(yaml-cpp REQUIRED)
3
1add_library(util 4add_library(util
5 godot_scene.cpp
6 identifiers.cpp
7 ids_yaml_format.cpp
2 naming.cpp 8 naming.cpp
3) 9)
4set_property(TARGET util PROPERTY CXX_STANDARD 20) 10set_property(TARGET util PROPERTY CXX_STANDARD 20)
5set_property(TARGET util PROPERTY CXX_STANDARD_REQUIRED ON) 11set_property(TARGET util PROPERTY CXX_STANDARD_REQUIRED ON)
12target_include_directories(util PUBLIC ${CMAKE_BINARY_DIR})
13target_link_libraries(util PUBLIC protos protobuf::libprotobuf yaml-cpp::yaml-cpp)
diff --git a/tools/util/godot_scene.cpp b/tools/util/godot_scene.cpp new file mode 100644 index 0000000..f788d21 --- /dev/null +++ b/tools/util/godot_scene.cpp
@@ -0,0 +1,207 @@
1#include "godot_scene.h"
2
3#include <fstream>
4#include <sstream>
5#include <string_view>
6#include <variant>
7
8namespace com::fourisland::lingo2_archipelago {
9
10namespace {
11
12struct Heading {
13 std::string type;
14
15 std::string id;
16 std::string path;
17 std::string resource_type;
18
19 std::string name;
20 std::string parent;
21 GodotInstanceType instance_type;
22};
23
24Heading ParseTscnHeading(std::string_view line) {
25 std::string original_line(line);
26 Heading heading;
27
28 if (line[0] != '[') {
29 std::ostringstream errormsg;
30 errormsg << "Heading must start with [." << std::endl
31 << "Bad heading: " << original_line;
32 throw std::invalid_argument(errormsg.str());
33 }
34
35 line.remove_prefix(1);
36 int divider = line.find_first_of(" ]");
37 if (divider == std::string_view::npos) {
38 std::ostringstream errormsg;
39 errormsg << "Malformatted heading: " << line << std::endl
40 << "Original line: " << original_line;
41 throw std::invalid_argument(errormsg.str());
42 }
43
44 heading.type = std::string(line.substr(0, divider));
45 line.remove_prefix(divider + 1);
46
47 while (!line.empty()) {
48 divider = line.find_first_of("=");
49 if (divider == std::string_view::npos) {
50 std::ostringstream errormsg;
51 errormsg << "Malformatted heading: " << line << std::endl
52 << "Original line: " << original_line;
53 throw std::invalid_argument(errormsg.str());
54 }
55
56 std::string key(line.substr(0, divider));
57 line.remove_prefix(divider + 1);
58
59 if (line[0] == '"') {
60 line.remove_prefix(1);
61 divider = line.find_first_of("\"");
62
63 if (divider == std::string_view::npos) {
64 std::ostringstream errormsg;
65 errormsg << "Malformatted heading: " << line << std::endl
66 << "Original line: " << original_line;
67 throw std::invalid_argument(errormsg.str());
68 }
69
70 std::string strval(line.substr(0, divider));
71 line.remove_prefix(divider + 2);
72
73 if (key == "name") {
74 heading.name = strval;
75 } else if (key == "parent") {
76 heading.parent = strval;
77 } else if (key == "path") {
78 heading.path = strval;
79 } else if (key == "type") {
80 heading.resource_type = strval;
81 } else if (key == "id") {
82 heading.id = strval;
83 }
84 } else if (line[0] == 'S' || line[0] == 'E') {
85 GodotInstanceType rrval;
86 char internal = line[0];
87
88 line.remove_prefix(13); // SubResource("
89 divider = line.find_first_of("\"");
90
91 if (divider == std::string_view::npos) {
92 std::ostringstream errormsg;
93 errormsg << "Malformatted heading: " << line << std::endl
94 << "Original line: " << original_line;
95 throw std::invalid_argument(errormsg.str());
96 }
97
98 std::string refid = std::string(line.substr(0, divider));
99 line.remove_prefix(divider + 3);
100
101 GodotInstanceType instance_type;
102 if (internal == 'E') {
103 instance_type = GodotExtResourceRef{.id = refid};
104 } else {
105 // SubResource is not supported right now.
106 }
107
108 if (key == "instance") {
109 heading.instance_type = instance_type;
110 } else {
111 // Other keys aren't supported right now.
112 }
113 } else {
114 divider = line.find_first_of(" ]");
115
116 if (divider == std::string_view::npos) {
117 std::ostringstream errormsg;
118 errormsg << "Malformatted heading: " << line << std::endl
119 << "Original line: " << original_line;
120 throw std::invalid_argument(errormsg.str());
121 }
122
123 int numval = std::atoi(line.substr(0, divider).data());
124 line.remove_prefix(divider + 1);
125
126 // keyvals_[key] = numval;
127 }
128 }
129
130 return heading;
131}
132
133} // namespace
134
135std::string GodotNode::GetPath() const {
136 if (parent.empty() || parent == ".") {
137 return name;
138 } else {
139 return parent + "/" + name;
140 }
141}
142
143GodotScene ReadGodotSceneFromFile(const std::string& path) {
144 std::map<std::string, GodotExtResource> ext_resources;
145 std::vector<GodotNode> nodes;
146
147 std::ifstream input(path);
148
149 std::string line;
150 bool section_started = false;
151 Heading cur_heading;
152 std::ostringstream cur_value;
153 bool value_started = false;
154 auto handle_end_of_section = [&]() {
155 section_started = false;
156 value_started = false;
157
158 if (cur_heading.type == "sub_resource") {
159 // sub_resources_[std::get<int>(cur_heading.GetKeyval("id"))] =
160 // {cur_heading, cur_value.str(), ""};
161 } else {
162 // other_.emplace_back(cur_heading, cur_value.str());
163 }
164
165 cur_value = {};
166 };
167 while (std::getline(input, line)) {
168 if (section_started && (line.empty() || line[0] == '[')) {
169 handle_end_of_section();
170 }
171 if (!line.empty() && line[0] == '[') {
172 Heading heading = ParseTscnHeading(line);
173 if (heading.type == "gd_scene") {
174 // file_descriptor_ = heading;
175 } else if (heading.type == "ext_resource") {
176 GodotExtResource ext_resource;
177 ext_resource.path = heading.path;
178 ext_resource.type = heading.resource_type;
179
180 ext_resources[heading.id] = ext_resource;
181 } else if (heading.type == "node") {
182 if (heading.parent != "") {
183 nodes.push_back(GodotNode{.name = heading.name,
184 .parent = heading.parent,
185 .instance_type = heading.instance_type});
186 }
187 } else {
188 cur_heading = heading;
189 section_started = true;
190 }
191 } else if (!line.empty()) {
192 if (value_started) {
193 cur_value << std::endl;
194 } else {
195 value_started = true;
196 }
197 cur_value << line;
198 }
199 }
200 if (section_started) {
201 handle_end_of_section();
202 }
203
204 return GodotScene(std::move(ext_resources), std::move(nodes));
205}
206
207} // namespace com::fourisland::lingo2_archipelago
diff --git a/tools/util/godot_scene.h b/tools/util/godot_scene.h new file mode 100644 index 0000000..17f3f50 --- /dev/null +++ b/tools/util/godot_scene.h
@@ -0,0 +1,57 @@
1#ifndef TOOLS_UTIL_TSCN_H_
2#define TOOLS_UTIL_TSCN_H_
3
4#include <map>
5#include <memory>
6#include <string>
7#include <utility>
8#include <variant>
9#include <vector>
10
11namespace com::fourisland::lingo2_archipelago {
12
13struct GodotExtResource {
14 std::string type;
15 std::string path;
16};
17
18struct GodotExtResourceRef {
19 std::string id;
20};
21
22using GodotInstanceType = std::variant<std::monostate, GodotExtResourceRef>;
23
24struct GodotNode {
25 std::string name;
26 std::string parent;
27 GodotInstanceType instance_type;
28
29 std::string GetPath() const;
30};
31
32class GodotScene {
33 public:
34 GodotScene(std::map<std::string, GodotExtResource> ext_resources,
35 std::vector<GodotNode> nodes)
36 : ext_resources_(std::move(ext_resources)), nodes_(std::move(nodes)) {}
37
38 const GodotExtResource* GetExtResource(const std::string& id) const {
39 auto it = ext_resources_.find(id);
40 if (it != ext_resources_.end()) {
41 return &it->second;
42 } else {
43 return nullptr;
44 }
45 }
46 const std::vector<GodotNode>& GetNodes() const { return nodes_; }
47
48 private:
49 std::map<std::string, GodotExtResource> ext_resources_;
50 std::vector<GodotNode> nodes_;
51};
52
53GodotScene ReadGodotSceneFromFile(const std::string& path);
54
55} // namespace com::fourisland::lingo2_archipelago
56
57#endif /* TOOLS_UTIL_TSCN_H_ */
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/ids_yaml_format.cpp b/tools/util/ids_yaml_format.cpp new file mode 100644 index 0000000..71bfd63 --- /dev/null +++ b/tools/util/ids_yaml_format.cpp
@@ -0,0 +1,190 @@
1#include "ids_yaml_format.h"
2
3#include <yaml-cpp/yaml.h>
4
5#include <fstream>
6#include <functional>
7
8namespace com::fourisland::lingo2_archipelago {
9namespace {
10
11template <typename T>
12void OperateOnSortedMap(
13 const T& map, std::function<void(const std::string& name,
14 const typename T::mapped_type& value)>
15 callback) {
16 std::vector<std::string> names;
17 for (const auto& it : map) {
18 names.push_back(it.first);
19 }
20
21 std::sort(names.begin(), names.end());
22
23 for (const std::string& name : names) {
24 callback(name, map.at(name));
25 }
26}
27
28} // namespace
29
30IdMappings ReadIdsFromYaml(const std::string& filename) {
31 IdMappings result;
32
33 YAML::Node document = YAML::LoadFile(filename);
34
35 if (document["maps"]) {
36 for (const auto& map_it : document["maps"]) {
37 IdMappings::MapIds& map_ids =
38 (*result.mutable_maps())[map_it.first.as<std::string>()];
39
40 if (map_it.second["rooms"]) {
41 for (const auto& room_it : map_it.second["rooms"]) {
42 IdMappings::RoomIds& room_ids =
43 (*map_ids.mutable_rooms())[room_it.first.as<std::string>()];
44
45 if (room_it.second["panels"]) {
46 for (const auto& panel_it : room_it.second["panels"]) {
47 (*room_ids.mutable_panels())[panel_it.first.as<std::string>()] =
48 panel_it.second.as<uint64_t>();
49 }
50 }
51
52 if (room_it.second["masteries"]) {
53 for (const auto& mastery_it : room_it.second["masteries"]) {
54 (*room_ids
55 .mutable_masteries())[mastery_it.first.as<std::string>()] =
56 mastery_it.second.as<uint64_t>();
57 }
58 }
59
60 if (room_it.second["keyholders"]) {
61 for (const auto& keyholder_it : room_it.second["keyholders"]) {
62 (*room_ids.mutable_keyholders())[keyholder_it.first
63 .as<std::string>()] =
64 keyholder_it.second.as<uint64_t>();
65 }
66 }
67 }
68 }
69
70 if (map_it.second["doors"]) {
71 for (const auto& door_it : map_it.second["doors"]) {
72 (*map_ids.mutable_doors())[door_it.first.as<std::string>()] =
73 door_it.second.as<uint64_t>();
74 }
75 }
76 }
77 }
78
79 if (document["letters"]) {
80 for (const auto& letter_it : document["letters"]) {
81 (*result.mutable_letters())[letter_it.first.as<std::string>()] =
82 letter_it.second.as<uint64_t>();
83 }
84 }
85
86 if (document["endings"]) {
87 for (const auto& ending_it : document["endings"]) {
88 (*result.mutable_endings())[ending_it.first.as<std::string>()] =
89 ending_it.second.as<uint64_t>();
90 }
91 }
92
93 if (document["special"]) {
94 for (const auto& special_it : document["special"]) {
95 (*result.mutable_special())[special_it.first.as<std::string>()] =
96 special_it.second.as<uint64_t>();
97 }
98 }
99
100 if (document["progressives"]) {
101 for (const auto& prog_it : document["progressives"]) {
102 (*result.mutable_progressives())[prog_it.first.as<std::string>()] =
103 prog_it.second.as<uint64_t>();
104 }
105 }
106
107 if (document["door_groups"]) {
108 for (const auto& group_it : document["door_groups"]) {
109 (*result.mutable_door_groups())[group_it.first.as<std::string>()] =
110 group_it.second.as<uint64_t>();
111 }
112 }
113
114 return result;
115}
116
117void WriteIdsAsYaml(const IdMappings& ids, const std::string& filename) {
118 YAML::Node result;
119
120 OperateOnSortedMap(ids.maps(), [&result](const std::string& map_name,
121 const IdMappings::MapIds& map_ids) {
122 YAML::Node map_node;
123
124 OperateOnSortedMap(
125 map_ids.rooms(), [&map_node](const std::string& room_name,
126 const IdMappings::RoomIds& room_ids) {
127 YAML::Node room_node;
128
129 OperateOnSortedMap(
130 room_ids.panels(),
131 [&room_node](const std::string& panel_name, uint64_t panel_id) {
132 room_node["panels"][panel_name] = panel_id;
133 });
134
135 OperateOnSortedMap(room_ids.masteries(),
136 [&room_node](const std::string& mastery_name,
137 uint64_t mastery_id) {
138 room_node["masteries"][mastery_name] =
139 mastery_id;
140 });
141
142 OperateOnSortedMap(room_ids.keyholders(),
143 [&room_node](const std::string& keyholder_name,
144 uint64_t keyholder_id) {
145 room_node["keyholders"][keyholder_name] =
146 keyholder_id;
147 });
148
149 map_node["rooms"][room_name] = std::move(room_node);
150 });
151
152 OperateOnSortedMap(
153 map_ids.doors(),
154 [&map_node](const std::string& door_name, uint64_t door_id) {
155 map_node["doors"][door_name] = door_id;
156 });
157
158 result["maps"][map_name] = std::move(map_node);
159 });
160
161 OperateOnSortedMap(ids.letters(), [&result](const std::string& letter_name,
162 uint64_t letter_id) {
163 result["letters"][letter_name] = letter_id;
164 });
165
166 OperateOnSortedMap(ids.endings(), [&result](const std::string& ending_name,
167 uint64_t ending_id) {
168 result["endings"][ending_name] = ending_id;
169 });
170
171 OperateOnSortedMap(ids.special(), [&result](const std::string& special_name,
172 uint64_t special_id) {
173 result["special"][special_name] = special_id;
174 });
175
176 OperateOnSortedMap(ids.progressives(),
177 [&result](const std::string& prog_name, uint64_t prog_id) {
178 result["progressives"][prog_name] = prog_id;
179 });
180
181 OperateOnSortedMap(ids.door_groups(), [&result](const std::string& group_name,
182 uint64_t group_id) {
183 result["door_groups"][group_name] = group_id;
184 });
185
186 std::ofstream output_stream(filename);
187 output_stream << result << std::endl;
188}
189
190} // namespace com::fourisland::lingo2_archipelago
diff --git a/tools/util/ids_yaml_format.h b/tools/util/ids_yaml_format.h new file mode 100644 index 0000000..d926369 --- /dev/null +++ b/tools/util/ids_yaml_format.h
@@ -0,0 +1,16 @@
1#ifndef TOOLS_UTIL_IDS_YAML_FORMAT_H_
2#define TOOLS_UTIL_IDS_YAML_FORMAT_H_
3
4#include <string>
5
6#include "proto/human.pb.h"
7
8namespace com::fourisland::lingo2_archipelago {
9
10IdMappings ReadIdsFromYaml(const std::string& filename);
11
12void WriteIdsAsYaml(const IdMappings& ids, const std::string& filename);
13
14} // namespace com::fourisland::lingo2_archipelago
15
16#endif /* TOOLS_UTIL_IDS_YAML_FORMAT_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_ */