diff options
| author | Star Rauchenberger <fefferburbia@gmail.com> | 2023-11-23 01:47:18 +0000 |
|---|---|---|
| committer | Star Rauchenberger <fefferburbia@gmail.com> | 2023-11-23 01:47:18 +0000 |
| commit | 4e206fae5be6093b36c7779ba2a4a3679f0e754b (patch) | |
| tree | 3a1377ae7781debeb04c17464f9eab13f7e47131 | |
| download | godot3-tscn-compactor-4e206fae5be6093b36c7779ba2a4a3679f0e754b.tar.gz godot3-tscn-compactor-4e206fae5be6093b36c7779ba2a4a3679f0e754b.tar.bz2 godot3-tscn-compactor-4e206fae5be6093b36c7779ba2a4a3679f0e754b.zip | |
something
| -rw-r--r-- | .clang-format | 2 | ||||
| -rw-r--r-- | .gitignore | 11 | ||||
| -rw-r--r-- | CMakeLists.txt | 8 | ||||
| -rw-r--r-- | heading.cpp | 121 | ||||
| -rw-r--r-- | heading.h | 41 | ||||
| -rw-r--r-- | main.cpp | 98 | ||||
| -rw-r--r-- | scene.cpp | 139 | ||||
| -rw-r--r-- | scene.h | 34 | ||||
| -rw-r--r-- | script.cpp | 106 | ||||
| -rw-r--r-- | script.h | 36 |
10 files changed, 596 insertions, 0 deletions
| diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..8de7fe6 --- /dev/null +++ b/.clang-format | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | --- | ||
| 2 | BasedOnStyle: Google | ||
| diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f85f339 --- /dev/null +++ b/.gitignore | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | build | ||
| 2 | CMakeFiles | ||
| 3 | cmake_install.cmake | ||
| 4 | CMakeCache.txt | ||
| 5 | compile_commands.json | ||
| 6 | Makefile | ||
| 7 | [._]*.s[a-v][a-z] | ||
| 8 | [._]*.sw[a-p] | ||
| 9 | [._]s[a-rt-v][a-z] | ||
| 10 | [._]ss[a-gi-z] | ||
| 11 | [._]sw[a-p] | ||
| diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..b4f5e05 --- /dev/null +++ b/CMakeLists.txt | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | cmake_minimum_required (VERSION 3.9) | ||
| 2 | project (godot3_tscn_compactor) | ||
| 3 | |||
| 4 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) | ||
| 5 | |||
| 6 | add_executable(godot3_tscn_compactor main.cpp heading.cpp scene.cpp script.cpp) | ||
| 7 | set_property(TARGET godot3_tscn_compactor PROPERTY CXX_STANDARD 17) | ||
| 8 | set_property(TARGET godot3_tscn_compactor PROPERTY CXX_STANDARD_REQUIRED ON) | ||
| diff --git a/heading.cpp b/heading.cpp new file mode 100644 index 0000000..ff4a1a6 --- /dev/null +++ b/heading.cpp | |||
| @@ -0,0 +1,121 @@ | |||
| 1 | #include <stdlib.h> | ||
| 2 | |||
| 3 | #include <sstream> | ||
| 4 | #include <stdexcept> | ||
| 5 | #include <string> | ||
| 6 | #include <string_view> | ||
| 7 | |||
| 8 | #include "heading.h" | ||
| 9 | |||
| 10 | Heading::Heading(std::string_view line) { | ||
| 11 | std::string original_line(line); | ||
| 12 | |||
| 13 | if (line[0] != '[') { | ||
| 14 | std::ostringstream errormsg; | ||
| 15 | errormsg << "Heading must start with [." << std::endl | ||
| 16 | << "Bad heading: " << original_line; | ||
| 17 | throw std::invalid_argument(errormsg.str()); | ||
| 18 | } | ||
| 19 | |||
| 20 | line.remove_prefix(1); | ||
| 21 | int divider = line.find_first_of(" ]"); | ||
| 22 | if (divider == std::string_view::npos) { | ||
| 23 | std::ostringstream errormsg; | ||
| 24 | errormsg << "Malformatted heading: " << line << std::endl | ||
| 25 | << "Original line: " << original_line; | ||
| 26 | throw std::invalid_argument(errormsg.str()); | ||
| 27 | } | ||
| 28 | |||
| 29 | type_ = line.substr(0, divider); | ||
| 30 | line.remove_prefix(divider + 1); | ||
| 31 | |||
| 32 | while (!line.empty()) { | ||
| 33 | divider = line.find_first_of("="); | ||
| 34 | if (divider == std::string_view::npos) { | ||
| 35 | std::ostringstream errormsg; | ||
| 36 | errormsg << "Malformatted heading: " << line << std::endl | ||
| 37 | << "Original line: " << original_line; | ||
| 38 | throw std::invalid_argument(errormsg.str()); | ||
| 39 | } | ||
| 40 | |||
| 41 | std::string key(line.substr(0, divider)); | ||
| 42 | line.remove_prefix(divider + 1); | ||
| 43 | |||
| 44 | if (line[0] == '"') { | ||
| 45 | line.remove_prefix(1); | ||
| 46 | divider = line.find_first_of("\""); | ||
| 47 | |||
| 48 | if (divider == std::string_view::npos) { | ||
| 49 | std::ostringstream errormsg; | ||
| 50 | errormsg << "Malformatted heading: " << line << std::endl | ||
| 51 | << "Original line: " << original_line; | ||
| 52 | throw std::invalid_argument(errormsg.str()); | ||
| 53 | } | ||
| 54 | |||
| 55 | std::string strval(line.substr(0, divider)); | ||
| 56 | line.remove_prefix(divider + 2); | ||
| 57 | |||
| 58 | keyvals_[key] = strval; | ||
| 59 | } else if (line[0] == 'S' || line[0] == 'E') { | ||
| 60 | ResourceRef rrval; | ||
| 61 | rrval.internal = (line[0] == 'S'); | ||
| 62 | |||
| 63 | line.remove_prefix(13); // SubResource(# | ||
| 64 | divider = line.find_first_of(" "); | ||
| 65 | |||
| 66 | if (divider == std::string_view::npos) { | ||
| 67 | std::ostringstream errormsg; | ||
| 68 | errormsg << "Malformatted heading: " << line << std::endl | ||
| 69 | << "Original line: " << original_line; | ||
| 70 | throw std::invalid_argument(errormsg.str()); | ||
| 71 | } | ||
| 72 | |||
| 73 | rrval.id = std::atoi(line.substr(0, divider).data()); | ||
| 74 | line.remove_prefix(divider + 3); | ||
| 75 | |||
| 76 | keyvals_[key] = rrval; | ||
| 77 | } else { | ||
| 78 | divider = line.find_first_of(" ]"); | ||
| 79 | |||
| 80 | if (divider == std::string_view::npos) { | ||
| 81 | std::ostringstream errormsg; | ||
| 82 | errormsg << "Malformatted heading: " << line << std::endl | ||
| 83 | << "Original line: " << original_line; | ||
| 84 | throw std::invalid_argument(errormsg.str()); | ||
| 85 | } | ||
| 86 | |||
| 87 | int numval = std::atoi(line.substr(0, divider).data()); | ||
| 88 | line.remove_prefix(divider + 1); | ||
| 89 | |||
| 90 | keyvals_[key] = numval; | ||
| 91 | } | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | std::string Heading::ToString() const { | ||
| 96 | std::ostringstream output; | ||
| 97 | output << "["; | ||
| 98 | output << type_; | ||
| 99 | |||
| 100 | for (const auto& [key, value] : keyvals_) { | ||
| 101 | output << " " << key << "="; | ||
| 102 | |||
| 103 | if (std::holds_alternative<int>(value)) { | ||
| 104 | output << std::get<int>(value); | ||
| 105 | } else if (std::holds_alternative<ResourceRef>(value)) { | ||
| 106 | const auto& rrval = std::get<ResourceRef>(value); | ||
| 107 | if (rrval.internal) { | ||
| 108 | output << "Sub"; | ||
| 109 | } else { | ||
| 110 | output << "Ext"; | ||
| 111 | } | ||
| 112 | output << "Resource( " << rrval.id << " )"; | ||
| 113 | } else { | ||
| 114 | output << "\"" << std::get<std::string>(value) << "\""; | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | output << "]" << std::endl; | ||
| 119 | |||
| 120 | return output.str(); | ||
| 121 | } | ||
| diff --git a/heading.h b/heading.h new file mode 100644 index 0000000..1b1781b --- /dev/null +++ b/heading.h | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | #ifndef HEADING_H | ||
| 2 | #define HEADING_H | ||
| 3 | |||
| 4 | #include <map> | ||
| 5 | #include <string> | ||
| 6 | #include <string_view> | ||
| 7 | #include <variant> | ||
| 8 | |||
| 9 | struct ResourceRef { | ||
| 10 | bool internal = false; | ||
| 11 | int id; | ||
| 12 | }; | ||
| 13 | |||
| 14 | class Heading { | ||
| 15 | public: | ||
| 16 | using keyval_t = std::variant<std::string, int, ResourceRef>; | ||
| 17 | |||
| 18 | Heading() = default; | ||
| 19 | |||
| 20 | explicit Heading(std::string_view line); | ||
| 21 | |||
| 22 | const std::string& type() const { return type_; } | ||
| 23 | |||
| 24 | void set_type(std::string_view type) { type_ = std::string(type); } | ||
| 25 | |||
| 26 | const keyval_t& GetKeyval(std::string_view key) const { | ||
| 27 | return keyvals_.at(std::string(key)); | ||
| 28 | } | ||
| 29 | |||
| 30 | void SetKeyval(std::string_view key, const keyval_t& value) { | ||
| 31 | keyvals_[std::string(key)] = value; | ||
| 32 | } | ||
| 33 | |||
| 34 | std::string ToString() const; | ||
| 35 | |||
| 36 | private: | ||
| 37 | std::string type_; | ||
| 38 | std::map<std::string, keyval_t> keyvals_; | ||
| 39 | }; | ||
| 40 | |||
| 41 | #endif /* HEADING_H */ | ||
| diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..9da0c40 --- /dev/null +++ b/main.cpp | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | #include <filesystem> | ||
| 2 | #include <fstream> | ||
| 3 | #include <iostream> | ||
| 4 | #include <list> | ||
| 5 | #include <utility> | ||
| 6 | |||
| 7 | #include "heading.h" | ||
| 8 | #include "scene.h" | ||
| 9 | #include "script.h" | ||
| 10 | |||
| 11 | struct EmbeddedScript { | ||
| 12 | Script script; | ||
| 13 | bool internal = false; // true if referred from within another script | ||
| 14 | int id = -1; // if internal is false, ExtResource id | ||
| 15 | std::string path; // if internal is true | ||
| 16 | }; | ||
| 17 | |||
| 18 | void show_usage() { | ||
| 19 | std::cout << "godot3_tscn_compactor [path to root tscn] [file prefix]" | ||
| 20 | << std::endl; | ||
| 21 | } | ||
| 22 | |||
| 23 | int main(int argc, char** argv) { | ||
| 24 | if (argc != 3) { | ||
| 25 | show_usage(); | ||
| 26 | return 0; | ||
| 27 | } | ||
| 28 | |||
| 29 | std::filesystem::path root_tscn_path(argv[1]); | ||
| 30 | std::string file_prefix(argv[2]); | ||
| 31 | |||
| 32 | Scene root_tscn(root_tscn_path); | ||
| 33 | |||
| 34 | std::vector<EmbeddedScript> sub_scripts; | ||
| 35 | |||
| 36 | for (const auto& [id, heading] : root_tscn.ext_resources()) { | ||
| 37 | std::string resource_filename = | ||
| 38 | std::get<std::string>(heading.GetKeyval("path")); | ||
| 39 | if (resource_filename.substr(0, file_prefix.size()) == file_prefix) { | ||
| 40 | std::filesystem::path relative_filename = | ||
| 41 | resource_filename.substr(file_prefix.size()); | ||
| 42 | std::filesystem::path resource_path = | ||
| 43 | root_tscn_path.parent_path() / relative_filename; | ||
| 44 | |||
| 45 | EmbeddedScript embedded_script; | ||
| 46 | embedded_script.script = Script(resource_path, file_prefix); | ||
| 47 | embedded_script.id = id; | ||
| 48 | |||
| 49 | sub_scripts.push_back(std::move(embedded_script)); | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | std::list<EmbeddedScript> all_scripts; | ||
| 54 | std::vector<EmbeddedScript> scripts_to_check = sub_scripts; | ||
| 55 | while (!scripts_to_check.empty()) { | ||
| 56 | std::vector<EmbeddedScript> cur_scripts; | ||
| 57 | cur_scripts.swap(scripts_to_check); | ||
| 58 | |||
| 59 | for (const EmbeddedScript& embedded_script : cur_scripts) { | ||
| 60 | all_scripts.push_front(embedded_script); | ||
| 61 | |||
| 62 | for (const std::string& loaded_script_path : | ||
| 63 | embedded_script.script.loaded_scripts()) { | ||
| 64 | std::filesystem::path resource_path = | ||
| 65 | root_tscn_path.parent_path() / loaded_script_path; | ||
| 66 | |||
| 67 | EmbeddedScript embedded_script; | ||
| 68 | embedded_script.script = Script(resource_path, file_prefix); | ||
| 69 | embedded_script.internal = true; | ||
| 70 | embedded_script.path = loaded_script_path; | ||
| 71 | |||
| 72 | scripts_to_check.push_back(std::move(embedded_script)); | ||
| 73 | } | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | std::map<std::string, int> new_sub_scripts; | ||
| 78 | for (EmbeddedScript embedded_script : all_scripts) { | ||
| 79 | embedded_script.script.ReplaceScriptReferences(new_sub_scripts); | ||
| 80 | int sub_resource_id = root_tscn.AddSubResource(embedded_script.script); | ||
| 81 | |||
| 82 | if (embedded_script.internal) { | ||
| 83 | new_sub_scripts[embedded_script.path] = sub_resource_id; | ||
| 84 | } else { | ||
| 85 | root_tscn.RemoveExtResource(embedded_script.id); | ||
| 86 | root_tscn.ReplaceScriptReferences(embedded_script.id, sub_resource_id); | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | std::filesystem::path output_name = root_tscn_path; | ||
| 91 | output_name.replace_filename(std::string(output_name.stem()) + | ||
| 92 | "_compiled.tscn"); | ||
| 93 | |||
| 94 | std::ofstream output_stream(output_name); | ||
| 95 | output_stream << root_tscn.ToString(); | ||
| 96 | |||
| 97 | return 0; | ||
| 98 | } | ||
| diff --git a/scene.cpp b/scene.cpp new file mode 100644 index 0000000..6eae537 --- /dev/null +++ b/scene.cpp | |||
| @@ -0,0 +1,139 @@ | |||
| 1 | #include <filesystem> | ||
| 2 | #include <fstream> | ||
| 3 | #include <iomanip> | ||
| 4 | #include <iostream> | ||
| 5 | #include <map> | ||
| 6 | #include <sstream> | ||
| 7 | #include <stdexcept> | ||
| 8 | #include <string_view> | ||
| 9 | #include <variant> | ||
| 10 | |||
| 11 | #include "heading.h" | ||
| 12 | #include "scene.h" | ||
| 13 | |||
| 14 | Scene::Scene(const std::filesystem::path& path) { | ||
| 15 | std::ifstream input(path.c_str()); | ||
| 16 | std::string line; | ||
| 17 | bool section_started = false; | ||
| 18 | Heading cur_heading; | ||
| 19 | std::ostringstream cur_value; | ||
| 20 | bool value_started = false; | ||
| 21 | auto handle_end_of_section = [&]() { | ||
| 22 | section_started = false; | ||
| 23 | value_started = false; | ||
| 24 | |||
| 25 | if (cur_heading.type() == "sub_resource") { | ||
| 26 | sub_resources_[std::get<int>(cur_heading.GetKeyval("id"))] = { | ||
| 27 | cur_heading, cur_value.str()}; | ||
| 28 | } else { | ||
| 29 | other_.emplace_back(cur_heading, cur_value.str()); | ||
| 30 | } | ||
| 31 | |||
| 32 | cur_value = {}; | ||
| 33 | }; | ||
| 34 | while (std::getline(input, line)) { | ||
| 35 | if (section_started && (line.empty() || line[0] == '[')) { | ||
| 36 | handle_end_of_section(); | ||
| 37 | } | ||
| 38 | if (!line.empty() && line[0] == '[') { | ||
| 39 | Heading heading(line); | ||
| 40 | if (heading.type() == "gd_scene") { | ||
| 41 | file_descriptor_ = heading; | ||
| 42 | } else if (heading.type() == "ext_resource") { | ||
| 43 | ext_resources_[std::get<int>(heading.GetKeyval("id"))] = heading; | ||
| 44 | } else { | ||
| 45 | cur_heading = heading; | ||
| 46 | section_started = true; | ||
| 47 | } | ||
| 48 | } else if (!line.empty()) { | ||
| 49 | if (value_started) { | ||
| 50 | cur_value << std::endl; | ||
| 51 | } else { | ||
| 52 | value_started = true; | ||
| 53 | } | ||
| 54 | cur_value << line; | ||
| 55 | } | ||
| 56 | } | ||
| 57 | if (section_started) { | ||
| 58 | handle_end_of_section(); | ||
| 59 | } | ||
| 60 | |||
| 61 | for (const auto& [id, stuff] : sub_resources_) { | ||
| 62 | if (id >= next_sub_id_) { | ||
| 63 | next_sub_id_ = id + 1; | ||
| 64 | } | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | int Scene::AddSubResource(const Script& script) { | ||
| 69 | int new_id = next_sub_id_++; | ||
| 70 | |||
| 71 | std::ostringstream resource_contents; | ||
| 72 | for (const auto& [variable, value] : script.exports()) { | ||
| 73 | resource_contents << variable << " = SubResource( " << value << " )" | ||
| 74 | << std::endl; | ||
| 75 | } | ||
| 76 | resource_contents << "script/source = " << std::quoted(script.ToString()); | ||
| 77 | |||
| 78 | Heading heading; | ||
| 79 | heading.set_type("sub_resource"); | ||
| 80 | heading.SetKeyval("type", "GDScript"); | ||
| 81 | heading.SetKeyval("id", new_id); | ||
| 82 | |||
| 83 | sub_resources_[new_id] = {heading, resource_contents.str()}; | ||
| 84 | |||
| 85 | return new_id; | ||
| 86 | } | ||
| 87 | |||
| 88 | void Scene::RemoveExtResource(int id) { ext_resources_.erase(id); } | ||
| 89 | |||
| 90 | void Scene::ReplaceScriptReferences(int ext_id, int sub_id) { | ||
| 91 | auto replace_refs = [&](std::string& text) { | ||
| 92 | std::ostringstream search_str; | ||
| 93 | search_str << "ExtResource( " << ext_id << " )"; | ||
| 94 | std::string search = search_str.str(); | ||
| 95 | |||
| 96 | std::ostringstream new_text; | ||
| 97 | std::string_view corpus = text; | ||
| 98 | int location; | ||
| 99 | while ((location = corpus.find(search)) != std::string_view::npos) { | ||
| 100 | new_text << corpus.substr(0, location) << "SubResource( " << sub_id | ||
| 101 | << " )"; | ||
| 102 | corpus.remove_prefix(location + search.size()); | ||
| 103 | } | ||
| 104 | new_text << corpus; | ||
| 105 | |||
| 106 | text = new_text.str(); | ||
| 107 | }; | ||
| 108 | |||
| 109 | for (auto& [id, stuff] : sub_resources_) { | ||
| 110 | auto& [heading, text] = stuff; | ||
| 111 | replace_refs(text); | ||
| 112 | } | ||
| 113 | |||
| 114 | for (auto& [heading, text] : other_) { | ||
| 115 | replace_refs(text); | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | std::string Scene::ToString() const { | ||
| 120 | std::ostringstream output; | ||
| 121 | output << file_descriptor_.ToString() << std::endl; | ||
| 122 | |||
| 123 | for (const auto& [id, heading] : ext_resources_) { | ||
| 124 | output << heading.ToString(); | ||
| 125 | } | ||
| 126 | |||
| 127 | output << std::endl; | ||
| 128 | |||
| 129 | for (const auto& [id, resource] : sub_resources_) { | ||
| 130 | const auto& [heading, value] = resource; | ||
| 131 | output << heading.ToString() << value << std::endl << std::endl; | ||
| 132 | } | ||
| 133 | |||
| 134 | for (const auto& [heading, value] : other_) { | ||
| 135 | output << heading.ToString() << value << std::endl << std::endl; | ||
| 136 | } | ||
| 137 | |||
| 138 | return output.str(); | ||
| 139 | } | ||
| diff --git a/scene.h b/scene.h new file mode 100644 index 0000000..0ee9450 --- /dev/null +++ b/scene.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | #ifndef SCENE_H | ||
| 2 | #define SCENE_H | ||
| 3 | |||
| 4 | #include <filesystem> | ||
| 5 | #include <map> | ||
| 6 | #include <tuple> | ||
| 7 | #include <vector> | ||
| 8 | |||
| 9 | #include "heading.h" | ||
| 10 | #include "script.h" | ||
| 11 | |||
| 12 | class Scene { | ||
| 13 | public: | ||
| 14 | explicit Scene(const std::filesystem::path& path); | ||
| 15 | |||
| 16 | const std::map<int, Heading>& ext_resources() const { return ext_resources_; } | ||
| 17 | |||
| 18 | int AddSubResource(const Script& script); | ||
| 19 | |||
| 20 | void RemoveExtResource(int id); | ||
| 21 | |||
| 22 | void ReplaceScriptReferences(int ext_id, int sub_id); | ||
| 23 | |||
| 24 | std::string ToString() const; | ||
| 25 | |||
| 26 | private: | ||
| 27 | Heading file_descriptor_; | ||
| 28 | std::map<int, Heading> ext_resources_; | ||
| 29 | std::map<int, std::tuple<Heading, std::string>> sub_resources_; | ||
| 30 | std::vector<std::tuple<Heading, std::string>> other_; | ||
| 31 | int next_sub_id_ = 0; | ||
| 32 | }; | ||
| 33 | |||
| 34 | #endif /* SCENE_H */ | ||
| diff --git a/script.cpp b/script.cpp new file mode 100644 index 0000000..509d4a7 --- /dev/null +++ b/script.cpp | |||
| @@ -0,0 +1,106 @@ | |||
| 1 | #include <filesystem> | ||
| 2 | #include <fstream> | ||
| 3 | #include <map> | ||
| 4 | #include <sstream> | ||
| 5 | #include <stdexcept> | ||
| 6 | #include <string> | ||
| 7 | #include <string_view> | ||
| 8 | |||
| 9 | #include "script.h" | ||
| 10 | |||
| 11 | Script::Script(const std::filesystem::path& path, std::string_view file_prefix) | ||
| 12 | : file_prefix_(file_prefix) { | ||
| 13 | { | ||
| 14 | std::ifstream script_file(path); | ||
| 15 | std::string line; | ||
| 16 | std::ostringstream text_stream; | ||
| 17 | while (std::getline(script_file, line)) { | ||
| 18 | text_stream << line << std::endl; | ||
| 19 | } | ||
| 20 | text_ = text_stream.str(); | ||
| 21 | } | ||
| 22 | |||
| 23 | std::string search = std::string("load(\"") + std::string(file_prefix); | ||
| 24 | std::string_view corpus = text_; | ||
| 25 | int location; | ||
| 26 | while ((location = corpus.find(search)) != std::string_view::npos) { | ||
| 27 | corpus.remove_prefix(location + search.size()); | ||
| 28 | int divider = corpus.find_first_of("\""); | ||
| 29 | if (divider == std::string_view::npos) { | ||
| 30 | throw std::invalid_argument( | ||
| 31 | "I don't know how this is happening but I guess I gotta report it."); | ||
| 32 | } | ||
| 33 | std::string script_path(corpus.substr(0, divider)); | ||
| 34 | corpus.remove_prefix(divider + 1); | ||
| 35 | loaded_scripts_.push_back(script_path); | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | void Script::ReplaceScriptReferences( | ||
| 40 | const std::map<std::string, int>& script_ids) { | ||
| 41 | std::ostringstream new_text; | ||
| 42 | std::string_view corpus = text_; | ||
| 43 | int divider = corpus.find_first_of("\n"); | ||
| 44 | if (divider == std::string_view::npos) { | ||
| 45 | throw std::invalid_argument("Script is one line??"); | ||
| 46 | } | ||
| 47 | new_text << corpus.substr(0, divider + 1) << std::endl; | ||
| 48 | ; | ||
| 49 | corpus.remove_prefix(divider + 1); | ||
| 50 | |||
| 51 | std::map<std::string, std::string> path_to_export; | ||
| 52 | for (const std::string& loaded_script : loaded_scripts_) { | ||
| 53 | std::ostringstream export_str; | ||
| 54 | export_str << "COMPACTED"; | ||
| 55 | |||
| 56 | std::filesystem::path name_path(loaded_script); | ||
| 57 | name_path.replace_filename(name_path.stem()); | ||
| 58 | for (const auto& segment : name_path) { | ||
| 59 | std::string segment_str(segment); | ||
| 60 | export_str << "_" << segment_str; | ||
| 61 | } | ||
| 62 | |||
| 63 | std::string export_name = export_str.str(); | ||
| 64 | exports_.emplace_back(export_name, script_ids.at(loaded_script)); | ||
| 65 | |||
| 66 | new_text << "export(Resource) var " << export_name << std::endl; | ||
| 67 | |||
| 68 | path_to_export[loaded_script] = export_name; | ||
| 69 | } | ||
| 70 | |||
| 71 | new_text << std::endl; | ||
| 72 | |||
| 73 | std::string search = std::string("load(\"") + file_prefix_; | ||
| 74 | std::string search_alt1 = std::string("preload(\"") + file_prefix_; | ||
| 75 | std::string search_alt2 = | ||
| 76 | std::string("ResourceLoader.load(\"") + file_prefix_; | ||
| 77 | int location; | ||
| 78 | while ((location = corpus.find(search)) != std::string_view::npos) { | ||
| 79 | int alt1 = corpus.find(search_alt1); | ||
| 80 | int alt2 = corpus.find(search_alt2); | ||
| 81 | int remove_size = search.size(); | ||
| 82 | |||
| 83 | if (alt1 != std::string_view::npos && alt1 < location) { | ||
| 84 | location = alt1; | ||
| 85 | remove_size = search_alt1.size(); | ||
| 86 | } else if (alt2 != std::string_view::npos && alt2 < location) { | ||
| 87 | location = alt2; | ||
| 88 | remove_size = search_alt2.size(); | ||
| 89 | } | ||
| 90 | |||
| 91 | new_text << corpus.substr(0, location); | ||
| 92 | corpus.remove_prefix(location + remove_size); | ||
| 93 | |||
| 94 | int divider = corpus.find_first_of("\""); | ||
| 95 | // TODO: ehhh error reporting | ||
| 96 | std::string referenced_path(corpus.substr(0, divider)); | ||
| 97 | corpus.remove_prefix(divider + 2); // the quote and the close paren | ||
| 98 | new_text << path_to_export.at(referenced_path); | ||
| 99 | } | ||
| 100 | |||
| 101 | new_text << corpus; | ||
| 102 | |||
| 103 | text_ = new_text.str(); | ||
| 104 | } | ||
| 105 | |||
| 106 | std::string Script::ToString() const { return text_; } | ||
| diff --git a/script.h b/script.h new file mode 100644 index 0000000..fabf531 --- /dev/null +++ b/script.h | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | #ifndef SCRIPT_H | ||
| 2 | #define SCRIPT_H | ||
| 3 | |||
| 4 | #include <filesystem> | ||
| 5 | #include <map> | ||
| 6 | #include <string> | ||
| 7 | #include <string_view> | ||
| 8 | #include <tuple> | ||
| 9 | #include <vector> | ||
| 10 | |||
| 11 | class Script { | ||
| 12 | public: | ||
| 13 | Script() = default; | ||
| 14 | |||
| 15 | Script(const std::filesystem::path& path, std::string_view file_prefix); | ||
| 16 | |||
| 17 | const std::vector<std::string>& loaded_scripts() const { | ||
| 18 | return loaded_scripts_; | ||
| 19 | } | ||
| 20 | |||
| 21 | const std::vector<std::tuple<std::string, int>>& exports() const { | ||
| 22 | return exports_; | ||
| 23 | } | ||
| 24 | |||
| 25 | void ReplaceScriptReferences(const std::map<std::string, int>& script_ids); | ||
| 26 | |||
| 27 | std::string ToString() const; | ||
| 28 | |||
| 29 | private: | ||
| 30 | std::string text_; | ||
| 31 | std::string file_prefix_; | ||
| 32 | std::vector<std::string> loaded_scripts_; | ||
| 33 | std::vector<std::tuple<std::string, int>> exports_; | ||
| 34 | }; | ||
| 35 | |||
| 36 | #endif /* SCRIPT_H */ | ||
