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.txt5
-rw-r--r--tools/util/godot_scene.cpp207
-rw-r--r--tools/util/godot_scene.h57
-rw-r--r--tools/util/ids_yaml_format.cpp203
-rw-r--r--tools/util/ids_yaml_format.h16
5 files changed, 487 insertions, 1 deletions
diff --git a/tools/util/CMakeLists.txt b/tools/util/CMakeLists.txt index f086e10..0859a58 100644 --- a/tools/util/CMakeLists.txt +++ b/tools/util/CMakeLists.txt
@@ -1,10 +1,13 @@
1find_package(Protobuf REQUIRED) 1find_package(Protobuf REQUIRED)
2find_package(yaml-cpp REQUIRED)
2 3
3add_library(util 4add_library(util
5 godot_scene.cpp
4 identifiers.cpp 6 identifiers.cpp
7 ids_yaml_format.cpp
5 naming.cpp 8 naming.cpp
6) 9)
7set_property(TARGET util PROPERTY CXX_STANDARD 20) 10set_property(TARGET util PROPERTY CXX_STANDARD 20)
8set_property(TARGET util PROPERTY CXX_STANDARD_REQUIRED ON) 11set_property(TARGET util PROPERTY CXX_STANDARD_REQUIRED ON)
9target_include_directories(util PUBLIC ${CMAKE_BINARY_DIR}) 12target_include_directories(util PUBLIC ${CMAKE_BINARY_DIR})
10target_link_libraries(util PUBLIC protos protobuf::libprotobuf) 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/ids_yaml_format.cpp b/tools/util/ids_yaml_format.cpp new file mode 100644 index 0000000..5b9113b --- /dev/null +++ b/tools/util/ids_yaml_format.cpp
@@ -0,0 +1,203 @@
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 if (room_it.second["ports"]) {
69 for (const auto& port_it : room_it.second["ports"]) {
70 (*room_ids.mutable_ports())[port_it.first.as<std::string>()] =
71 port_it.second.as<uint64_t>();
72 }
73 }
74 }
75 }
76
77 if (map_it.second["doors"]) {
78 for (const auto& door_it : map_it.second["doors"]) {
79 (*map_ids.mutable_doors())[door_it.first.as<std::string>()] =
80 door_it.second.as<uint64_t>();
81 }
82 }
83 }
84 }
85
86 if (document["letters"]) {
87 for (const auto& letter_it : document["letters"]) {
88 (*result.mutable_letters())[letter_it.first.as<std::string>()] =
89 letter_it.second.as<uint64_t>();
90 }
91 }
92
93 if (document["endings"]) {
94 for (const auto& ending_it : document["endings"]) {
95 (*result.mutable_endings())[ending_it.first.as<std::string>()] =
96 ending_it.second.as<uint64_t>();
97 }
98 }
99
100 if (document["special"]) {
101 for (const auto& special_it : document["special"]) {
102 (*result.mutable_special())[special_it.first.as<std::string>()] =
103 special_it.second.as<uint64_t>();
104 }
105 }
106
107 if (document["progressives"]) {
108 for (const auto& prog_it : document["progressives"]) {
109 (*result.mutable_progressives())[prog_it.first.as<std::string>()] =
110 prog_it.second.as<uint64_t>();
111 }
112 }
113
114 if (document["door_groups"]) {
115 for (const auto& group_it : document["door_groups"]) {
116 (*result.mutable_door_groups())[group_it.first.as<std::string>()] =
117 group_it.second.as<uint64_t>();
118 }
119 }
120
121 return result;
122}
123
124void WriteIdsAsYaml(const IdMappings& ids, const std::string& filename) {
125 YAML::Node result;
126
127 OperateOnSortedMap(ids.maps(), [&result](const std::string& map_name,
128 const IdMappings::MapIds& map_ids) {
129 YAML::Node map_node;
130
131 OperateOnSortedMap(
132 map_ids.rooms(), [&map_node](const std::string& room_name,
133 const IdMappings::RoomIds& room_ids) {
134 YAML::Node room_node;
135
136 OperateOnSortedMap(
137 room_ids.panels(),
138 [&room_node](const std::string& panel_name, uint64_t panel_id) {
139 room_node["panels"][panel_name] = panel_id;
140 });
141
142 OperateOnSortedMap(room_ids.masteries(),
143 [&room_node](const std::string& mastery_name,
144 uint64_t mastery_id) {
145 room_node["masteries"][mastery_name] =
146 mastery_id;
147 });
148
149 OperateOnSortedMap(room_ids.keyholders(),
150 [&room_node](const std::string& keyholder_name,
151 uint64_t keyholder_id) {
152 room_node["keyholders"][keyholder_name] =
153 keyholder_id;
154 });
155
156 OperateOnSortedMap(
157 room_ids.ports(),
158 [&room_node](const std::string& port_name, uint64_t port_id) {
159 room_node["ports"][port_name] = port_id;
160 });
161
162 map_node["rooms"][room_name] = std::move(room_node);
163 });
164
165 OperateOnSortedMap(
166 map_ids.doors(),
167 [&map_node](const std::string& door_name, uint64_t door_id) {
168 map_node["doors"][door_name] = door_id;
169 });
170
171 result["maps"][map_name] = std::move(map_node);
172 });
173
174 OperateOnSortedMap(ids.letters(), [&result](const std::string& letter_name,
175 uint64_t letter_id) {
176 result["letters"][letter_name] = letter_id;
177 });
178
179 OperateOnSortedMap(ids.endings(), [&result](const std::string& ending_name,
180 uint64_t ending_id) {
181 result["endings"][ending_name] = ending_id;
182 });
183
184 OperateOnSortedMap(ids.special(), [&result](const std::string& special_name,
185 uint64_t special_id) {
186 result["special"][special_name] = special_id;
187 });
188
189 OperateOnSortedMap(ids.progressives(),
190 [&result](const std::string& prog_name, uint64_t prog_id) {
191 result["progressives"][prog_name] = prog_id;
192 });
193
194 OperateOnSortedMap(ids.door_groups(), [&result](const std::string& group_name,
195 uint64_t group_id) {
196 result["door_groups"][group_name] = group_id;
197 });
198
199 std::ofstream output_stream(filename);
200 output_stream << result << std::endl;
201}
202
203} // 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_ */