about summary refs log tree commit diff stats
path: root/tools/util/godot_scene.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/util/godot_scene.cpp')
-rw-r--r--tools/util/godot_scene.cpp207
1 files changed, 207 insertions, 0 deletions
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