From cb269bf9a21ef3be09f7dc1da5c20c839b8a0d30 Mon Sep 17 00:00:00 2001 From: Relintai Date: Sat, 16 Jul 2022 18:06:33 +0200 Subject: [PATCH] Added the gdscript to cpp converter addon. --- gdc_converter/gdc_class_bind_generator.gd | 422 +++++++++ gdc_converter/gdc_code_converter.gd | 1010 +++++++++++++++++++++ gdc_converter/gdc_scene_converter.gd | 186 ++++ gdc_converter/plugin.cfg | 7 + gdc_converter/plugin.gd | 63 ++ 5 files changed, 1688 insertions(+) create mode 100644 gdc_converter/gdc_class_bind_generator.gd create mode 100644 gdc_converter/gdc_code_converter.gd create mode 100644 gdc_converter/gdc_scene_converter.gd create mode 100644 gdc_converter/plugin.cfg create mode 100644 gdc_converter/plugin.gd diff --git a/gdc_converter/gdc_class_bind_generator.gd b/gdc_converter/gdc_class_bind_generator.gd new file mode 100644 index 0000000..081f050 --- /dev/null +++ b/gdc_converter/gdc_class_bind_generator.gd @@ -0,0 +1,422 @@ +tool +extends Reference + +class GDSStaticClassParser: + var scope_data : String = "" + var raw_scope_data : String = "" + var static_methods : PoolStringArray = PoolStringArray() + + func convert_to_string(current_scope_level : int = 0) -> String: + var s : String = scope_data + "- (" + raw_scope_data + ")---GDSScope---\n" + + for m in static_methods: + s += m + "\n" + + s += "\n" + + return s + + func get_cpp_header_string() -> String: + var s : String = "" + + s += "class _" + scope_data + " : public Object {\n" + s += " GDCLASS(" + scope_data + ", Object);\n\n" + + s += " public:\n" + + s += "\n" + + for m in static_methods: + s += " " + transform_method_to_cpp(m) + ";\n" + + s += "\n" + s += " static _" + scope_data + "* get_singleton();\n" + s += "\n" + s += " " + scope_data + "();\n" + s += " ~" + scope_data + "();\n" + s += "\n" + s += " protected:\n" + s += " static void _bind_methods();\n" + + s += "\n" + s += " static _" + scope_data + "* self;\n" + + s += "\n" + s += "};" + s += "\n" + + return s + + func get_cpp_impl_string(current_scope_level : int = 0, owner_class_name : String = "") -> String: + var s : String = "" + + s += "\n" + + for m in static_methods: + #scope_data + + s += transform_method_to_cpp(m, "_" + scope_data + "::", false) + " {\n" + s += " " + transform_method_to_cpp_call(m, scope_data + "::") + ";\n" + s += "}\n\n" + + s += "_" + scope_data + "* _" + scope_data + "::get_singleton() {\n" + s += " return self;\n" + s += "}\n\n" + + s += "\n" + + s += "_" + scope_data + "::_" + scope_data + "() {\n" + s += " self = this;\n" + s += "}\n\n" + + s += "_" + scope_data + "::~_" + scope_data + "() {\n" + s += " self = nullptr;\n" + s += "}\n\n" + s += "\n" + s += "static void _" + scope_data + "::_bind_methods() {\n" + + s += create_cpp_binds_string() + + s += "}\n\n" + + s += "_" + scope_data + "* _" + scope_data + "::self = nullptr;\n" + + return s + + func create_cpp_binds_string() -> String: + var s : String = "" + + for m in static_methods: + s += " " + transform_method_to_cpp_binding(m, "_" + scope_data) + ";\n" + + s += "\n" + + return s + + func transform_method_to_cpp(func_raw_data : String, name_prefix : String = "", default_params : bool = true) -> String: + var func_data : String = func_raw_data + var func_ret_type : String = "void" + + var indx : int = func_raw_data.find(" -> ") + + if indx != -1: + func_ret_type = func_raw_data.substr(indx + 4) + func_data = func_raw_data.substr(0, indx) + + var func_final : String = func_ret_type + " " + indx = func_data.find("(") + var func_name : String = func_data.substr(0, indx) + func_final += name_prefix + func_name + "(" + + var func_params : String = func_data.substr(indx + 1, func_data.length() - indx - 2) + + if func_params != "": + var params : PoolStringArray = func_params.split(",", false) + + for i in range(params.size()): + var p : String = params[i] + + var default_value_indx : int = p.find("=") + var default_value : String + + if default_value_indx != -1: + default_value = p.substr(default_value_indx + 1).strip_edges() + p = p.substr(0, default_value_indx).strip_edges() + + var type_indx : int = p.find(":") + + if type_indx != -1: + var param_type : String = p.substr(type_indx + 1).strip_edges() + p = p.substr(0, type_indx).strip_edges() + + if param_type == "int" || param_type == "float" || param_type == "bool" || param_type == "RID": + func_final += "const " + param_type + " " + else: + func_final += "const " + param_type + " &" + else: + func_final += "const Variant &" + + func_final += p + + if default_params && default_value_indx != -1: + func_final += " = " + default_value + + if i + 1 < params.size(): + func_final += ", " + + func_final += ")" + + return func_final + + func transform_method_to_cpp_call(func_raw_data : String, name_prefix : String = "") -> String: + var func_data : String = func_raw_data + var func_ret_type : String = "void" + + var indx : int = func_raw_data.find(" -> ") + + if indx != -1: + func_ret_type = func_raw_data.substr(indx + 4) + func_data = func_raw_data.substr(0, indx) + + var func_final : String = "" + + if func_ret_type != "void": + func_final += "return " + + indx = func_data.find("(") + var func_name : String = func_data.substr(0, indx) + func_final += name_prefix + func_name + "(" + + var func_params : String = func_data.substr(indx + 1, func_data.length() - indx - 2) + + if func_params != "": + var params : PoolStringArray = func_params.split(",", false) + + for i in range(params.size()): + var p : String = params[i] + + var default_value_indx : int = p.find("=") + var default_value : String + + if default_value_indx != -1: + default_value = p.substr(default_value_indx + 1).strip_edges() + p = p.substr(0, default_value_indx).strip_edges() + + var type_indx : int = p.find(":") + + if type_indx != -1: + var param_type : String = p.substr(type_indx + 1).strip_edges() + p = p.substr(0, type_indx).strip_edges() + + func_final += p + + if i + 1 < params.size(): + func_final += ", " + + func_final += ")" + + return func_final + + func transform_method_to_cpp_binding(func_raw_data : String, name_prefix : String) -> String: + var func_data : String = func_raw_data + var func_ret_type : String = "void" + + var indx : int = func_raw_data.find(" -> ") + + if indx != -1: + func_ret_type = func_raw_data.substr(indx + 4) + func_data = func_raw_data.substr(0, indx) + + var ret_final : String = "ClassDB::bind_method(D_METHOD(\"" + + indx = func_data.find("(") + var func_name : String = func_data.substr(0, indx) + ret_final += func_name + "\"" + + var func_params : String = func_data.substr(indx + 1, func_data.length() - indx - 2) + + var default_values : PoolStringArray = PoolStringArray() + + if func_params != "": + var params : PoolStringArray = func_params.split(",", false) + + for i in range(params.size()): + ret_final += ", " + + var p : String = params[i] + + var default_value_indx : int = p.find("=") + var default_value : String + + if default_value_indx != -1: + default_value = p.substr(default_value_indx + 1).strip_edges() + p = p.substr(0, default_value_indx).strip_edges() + default_values.push_back(default_value) + + var type_indx : int = p.find(":") + + if type_indx != -1: + var param_type : String = p.substr(type_indx + 1).strip_edges() + p = p.substr(0, type_indx).strip_edges() + + ret_final += "\"" + p + "\"" + + ret_final += "), &" + name_prefix + "::" + func_name + + for i in range(default_values.size()): + ret_final += ", " + default_values[i] + + ret_final += ");" + + return ret_final + + func camel_case_scope_data() -> void: + scope_data = camel_case_name(scope_data) + + func camel_case_name(cname : String) -> String: + var ret : String = "" + + var next_upper : bool = true + for i in range(cname.length()): + if cname[i] == "_": + next_upper = true + continue + + if next_upper: + ret += cname[i].to_upper() + next_upper = false + else: + ret += cname[i] + + return ret + + func _to_string(): + return convert_to_string() + + func parse(contentsstr : String, file_name : String) -> void: + raw_scope_data = file_name + scope_data = file_name.get_file().trim_suffix(".gd") + camel_case_scope_data() + + var contents : PoolStringArray = split_preprocess_content(contentsstr) + + for current_index in range(contents.size()): + var cl : String = contents[current_index] + + if cl.begins_with("class_name "): + raw_scope_data = cl + scope_data = cl.trim_prefix("class_name ") + continue + + if cl.begins_with("#"): + continue + + var clstripped : String = cl.strip_edges(true, false) + + if clstripped.begins_with("static func "): + static_methods.push_back(clstripped.trim_prefix("static func ").trim_suffix(":")) + + + func split_preprocess_content(contents : String) -> PoolStringArray: + var ret : PoolStringArray = PoolStringArray() + + contents = contents.replace("\r\n", "\n") + + var sp : PoolStringArray = contents.split("\n") + + var pl : String = "" + var accum : bool = false + for i in range(sp.size()): + var l : String = sp[i] + l = l.strip_edges(false, true) + + var lfstrip : String = l.strip_edges(true, false) + if lfstrip == "": + continue + + if lfstrip.begins_with("#"): + ret.append(lfstrip) + continue + + if lfstrip.begins_with("export"): + var indx = lfstrip.find("var") + var expstr : String = lfstrip.substr(0, indx) + + ret.append("#" + expstr) + l = l.replace(expstr, "") + + var setget_indx = l.find(" setget ") + if setget_indx != -1: + var setget_str : String = l.substr(setget_indx) + ret.append("#" + setget_str) + l = l.substr(0, setget_indx).strip_edges(false, true) + + var hash_symbol_index = l.find("#") + if hash_symbol_index != -1: + var comment_str : String = l.substr(hash_symbol_index) + ret.append(comment_str) + l = l.substr(0, hash_symbol_index).strip_edges(false, true) + + if l.ends_with("\\"): + if !accum: + accum = true + pl = l + else: + pl += l.substr(0, l.length() - 1).strip_edges() + else: + if accum: + accum = false + ret.append(pl) + pl = "" + else: + ret.append(l) + + return ret + + func get_final_cpp_header_string(file_name : String) -> String: + var include_guard_name : String = file_name.get_file() + include_guard_name = include_guard_name.to_upper() + include_guard_name = include_guard_name.trim_suffix(".GD") + include_guard_name += "_BIND_H" + + var s : String = "#ifndef " + include_guard_name + "\n" + s += "#define " + include_guard_name + "\n" + s += "\n\n" + + s += get_cpp_header_string() + + s += "\n\n" + s += "#endif" + s += "\n" + + s = s.replace(";;", ";") + + return s + + func get_final_cpp_impl_string(file_name : String) -> String: + var include_name : String = file_name.get_file() + include_name = include_name.to_lower() + include_name = include_name.trim_suffix(".gd") + include_name += "_bind.h" + + var s : String = "\n" + s += "#include \"" + include_name + "\"\n" + s += "\n\n" + + s += get_cpp_impl_string() + + s += "\n\n" + + s = s.replace(";;", ";") + + return s + +func process_file(file_name : String) -> void: + var file : File = File.new() + file.open(file_name, File.READ) + var contents : String = file.get_as_text() + file.close() + + var parser : GDSStaticClassParser = GDSStaticClassParser.new() + parser.parse(contents, file_name) + #print(parser) + #print(parser.get_cpp_header_string(file_name)) + #print(parser.get_cpp_impl_string(file_name)) + + var save_base_file_path : String = file_name.get_base_dir() + var save_base_file_name : String = file_name.get_file().to_lower().trim_suffix(".gd") + + var header_file : String = save_base_file_path + "/" + save_base_file_name + "_bind.h" + var impl_file : String = save_base_file_path + "/" + save_base_file_name + "_bind.cpp" + + var header_data : String = parser.get_final_cpp_header_string(file_name) + var impl_data : String = parser.get_final_cpp_impl_string(file_name) + + file.open(header_file, File.WRITE) + file.store_string(header_data) + file.close() + + file.open(impl_file, File.WRITE) + file.store_string(impl_data) + file.close() + diff --git a/gdc_converter/gdc_code_converter.gd b/gdc_converter/gdc_code_converter.gd new file mode 100644 index 0000000..5223b8a --- /dev/null +++ b/gdc_converter/gdc_code_converter.gd @@ -0,0 +1,1010 @@ +tool +extends Reference + +enum GDScopeType { + GDSCOPE_TYPE_GENERIC = 0, + GDSCOPE_TYPE_CLASS, + GDSCOPE_TYPE_IF, + GDSCOPE_TYPE_ELIF, + GDSCOPE_TYPE_ELSE, + GDSCOPE_TYPE_FUNC, + GDSCOPE_TYPE_FOR, + GDSCOPE_TYPE_WHILE, + GDSCOPE_TYPE_ENUM, +}; + +enum GDScopeLineType { + GDSCOPE_TYPE_LINE = 0, + GDSCOPE_TYPE_SCOPE, +}; + +class GDSScope: + var type : int = GDScopeType.GDSCOPE_TYPE_GENERIC + var scope_data : String = "" + var raw_scope_data : String = "" + var scope_data_alt : String = "" + var raw_scope_data_alt : String = "" + var subscopes : Array = Array() + var scope_lines : PoolStringArray = PoolStringArray() + var is_static : bool = false + var scope_line_order : PoolIntArray + + var comment_accumulator : PoolStringArray = PoolStringArray() + + func apply_comments() -> void: + for i in range(comment_accumulator.size()): + scope_lines.append(comment_accumulator[i]) + scope_line_order.push_back(GDScopeLineType.GDSCOPE_TYPE_LINE) + scope_line_order.push_back(scope_lines.size() - 1) + + comment_accumulator.resize(0) + + func parse(contents : PoolStringArray, current_index : int = 0, current_indent : int = 0) -> int: + while current_index < contents.size(): + var cl : String = contents[current_index] + + if cl == "tool": + scope_lines.append("#" + cl) + scope_line_order.push_back(GDScopeLineType.GDSCOPE_TYPE_LINE) + scope_line_order.push_back(scope_lines.size() - 1) + current_index += 1 + continue + + if cl.begins_with("class_name "): + type = GDScopeType.GDSCOPE_TYPE_CLASS + raw_scope_data = cl + scope_data = cl.trim_prefix("class_name ") + current_index += 1 + continue + + if cl.begins_with("extends "): + type = GDScopeType.GDSCOPE_TYPE_CLASS + raw_scope_data_alt = cl + scope_data_alt = cl.trim_prefix("extends ") + current_index += 1 + continue + + if cl.begins_with("#"): + comment_accumulator.append(cl) + current_index += 1 + continue + + var curr_line_indent : int = get_indent_count(cl) + var clstripped : String = cl.strip_edges(true, false) + + if curr_line_indent < current_indent: + return current_index + + apply_comments() + + if cl.ends_with(":") || cl.begins_with("enum "): + var scope : GDSScope = GDSScope.new() + scope.parse_scope_data(clstripped) + current_index += 1 + current_index = scope.parse(contents, current_index, curr_line_indent + 1) + + subscopes.append(scope) + scope_line_order.push_back(GDScopeLineType.GDSCOPE_TYPE_SCOPE) + scope_line_order.push_back(subscopes.size() - 1) + + comment_accumulator = scope.comment_accumulator + scope.comment_accumulator.resize(0) + apply_comments() + + #don't + #current_index += 1 + continue + + scope_lines.append(clstripped) + scope_line_order.push_back(GDScopeLineType.GDSCOPE_TYPE_LINE) + scope_line_order.push_back(scope_lines.size() - 1) + current_index += 1 + + return current_index + + func parse_scope_data(s : String) -> void: + raw_scope_data = s + + if raw_scope_data.begins_with("static "): + is_static = true + raw_scope_data = raw_scope_data.trim_prefix("static ") + + if raw_scope_data.begins_with("if "): + type = GDScopeType.GDSCOPE_TYPE_IF + scope_data = raw_scope_data.trim_prefix("if ").trim_suffix(":") + elif raw_scope_data.begins_with("elif "): + type = GDScopeType.GDSCOPE_TYPE_ELIF + scope_data = raw_scope_data.trim_prefix("elif ").trim_suffix(":") + elif raw_scope_data.begins_with("else"): + type = GDScopeType.GDSCOPE_TYPE_ELSE + elif raw_scope_data.begins_with("class "): + type = GDScopeType.GDSCOPE_TYPE_CLASS + scope_data = raw_scope_data.trim_prefix("class ").trim_suffix(":") + elif raw_scope_data.begins_with("enum "): + type = GDScopeType.GDSCOPE_TYPE_ENUM + scope_data = raw_scope_data.trim_prefix("enum ").trim_suffix("{") + elif raw_scope_data.begins_with("func "): + type = GDScopeType.GDSCOPE_TYPE_FUNC + scope_data = raw_scope_data.trim_prefix("func ").trim_suffix(":") + elif raw_scope_data.begins_with("for "): + type = GDScopeType.GDSCOPE_TYPE_FOR + scope_data = raw_scope_data.trim_prefix("for ").trim_suffix(":") + elif raw_scope_data.begins_with("while "): + type = GDScopeType.GDSCOPE_TYPE_WHILE + scope_data = raw_scope_data.trim_prefix("while ").trim_suffix(":") + + func get_indent_count(s : String) -> int: + var c : int = 0 + + for ch in s: + if ch == "\t": + c += 1 + else: + break + + return c + + func convert_to_string(current_scope_level : int = 0) -> String: + var indents : String = "" + + for i in range(current_scope_level): + indents += " " + + var s : String = indents + "---GDSScope---\n" + + s += indents + raw_scope_data + " -- " + type_to_print_string() + " " + s += scope_data + + if scope_data_alt != "": + s += " " + scope_data_alt + + s += "\n" + + indents += " " + + for i in range(0, scope_line_order.size(), 2): + if scope_line_order[i] == GDScopeLineType.GDSCOPE_TYPE_LINE: + s += indents + scope_lines[scope_line_order[i + 1]] + "\n" + else: + s += "\n" + s += subscopes[scope_line_order[i + 1]].convert_to_string(current_scope_level + 1) + + s += "\n" + + return s + + + func type_to_print_string() -> String: + if type == GDScopeType.GDSCOPE_TYPE_CLASS: + return "(CLASS)" + elif type == GDScopeType.GDSCOPE_TYPE_IF: + return "(IF)" + elif type == GDScopeType.GDSCOPE_TYPE_ELIF: + return "(ELIF)" + elif type == GDScopeType.GDSCOPE_TYPE_ELSE: + return "(ELSE)" + elif type == GDScopeType.GDSCOPE_TYPE_FUNC: + return "(FUNC)" + elif type == GDScopeType.GDSCOPE_TYPE_FOR: + return "(FOR)" + elif type == GDScopeType.GDSCOPE_TYPE_WHILE: + return "(WHILE)" + elif type == GDScopeType.GDSCOPE_TYPE_ENUM: + return "(ENUM)" + elif type == GDScopeType.GDSCOPE_TYPE_GENERIC: + return "(GEN)" + + return "(UNKN)" + + func type_to_cpp_entity() -> String: + if type == GDScopeType.GDSCOPE_TYPE_CLASS: + return "class " + elif type == GDScopeType.GDSCOPE_TYPE_IF: + return "if " + elif type == GDScopeType.GDSCOPE_TYPE_ELIF: + return "else if " + elif type == GDScopeType.GDSCOPE_TYPE_ELSE: + return "else " + elif type == GDScopeType.GDSCOPE_TYPE_FUNC: + return "" + elif type == GDScopeType.GDSCOPE_TYPE_FOR: + return "for " + elif type == GDScopeType.GDSCOPE_TYPE_WHILE: + return "while " + elif type == GDScopeType.GDSCOPE_TYPE_ENUM: + return "enum " + elif type == GDScopeType.GDSCOPE_TYPE_GENERIC: + return "" + + return "" + + func get_cpp_header_string(current_scope_level : int = 0) -> String: + if type == GDScopeType.GDSCOPE_TYPE_IF: + return "" + elif type == GDScopeType.GDSCOPE_TYPE_ELIF: + return "" + elif type == GDScopeType.GDSCOPE_TYPE_ELSE: + return "" + elif type == GDScopeType.GDSCOPE_TYPE_FOR: + return "" + elif type == GDScopeType.GDSCOPE_TYPE_WHILE: + return "" + elif type == GDScopeType.GDSCOPE_TYPE_GENERIC: + return "" + + var indents : String = "" + + for i in range(current_scope_level): + indents += " " + + var s : String = "" + + s += indents + type_to_cpp_entity() + + if type == GDScopeType.GDSCOPE_TYPE_CLASS: + s += scope_data + + if scope_data_alt != "": + s += " : public " + scope_data_alt + + s += " {\n" + + if scope_data_alt != "": + s += indents + " GDCLASS(" + scope_data + ", " + scope_data_alt + ");\n\n" + + s += indents + " public:\n" + + elif type == GDScopeType.GDSCOPE_TYPE_FUNC: + if is_static: + s += "static " + + s += transform_method_to_cpp() + ";" + return s + elif type == GDScopeType.GDSCOPE_TYPE_ENUM: + s += scope_data + " {" + + s += "\n" + + indents += " " + + if type == GDScopeType.GDSCOPE_TYPE_CLASS: + for l in scope_lines: + var gs : String = create_cpp_getter_setter(l, true, indents) + + if gs != "": + s += gs + "\n" + + for subs in subscopes: + var scstr : String = subs.get_cpp_header_string(current_scope_level + 1) + + if scstr != "": + s += scstr + s += "\n" + + if type == GDScopeType.GDSCOPE_TYPE_CLASS: + s += "\n" + s += indents + scope_data + "();\n" + s += indents + "~" + scope_data + "();\n" + s += "\n" + s += indents + "protected:\n" + s += indents + "static void _bind_methods();\n" + + s += "\n" + + if type != GDScopeType.GDSCOPE_TYPE_ENUM: + for l in scope_lines: + if l.begins_with("#"): + l = l.replace("#", "//") + s += indents + l + "\n" + continue + + if l.begins_with("var "): + s += indents + transform_variable_to_cpp(l) + ";\n" + else: + s += indents + l + ";\n" + else: + for l in scope_lines: + if l.begins_with("#"): + l = l.replace("#", "//") + s += indents + l + "\n" + continue + + s += indents + l + "\n" + + if type == GDScopeType.GDSCOPE_TYPE_CLASS || type == GDScopeType.GDSCOPE_TYPE_ENUM: + s += "};" + else: + s += "}" + + s += "\n" + + return s + + func get_cpp_impl_string(current_scope_level : int = 0, owner_class_name : String = "") -> String: + if type == GDScopeType.GDSCOPE_TYPE_ENUM: + return "" + + var indents : String = "" + + for i in range(current_scope_level): + indents += " " + + var s : String = "" + + s += indents + + if type == GDScopeType.GDSCOPE_TYPE_IF: + scope_data = scope_data.replace(" and ", " && ") + scope_data = scope_data.replace(" or ", " || ") + + s += "if (" + scope_data + ") {" + elif type == GDScopeType.GDSCOPE_TYPE_ELIF: + scope_data = scope_data.replace(" and ", " && ") + scope_data = scope_data.replace(" or ", " || ") + + s += "else if (" + scope_data + ") {" + elif type == GDScopeType.GDSCOPE_TYPE_ELSE: + s += "else {" + elif type == GDScopeType.GDSCOPE_TYPE_FOR: + var range_indx : int = scope_data.find("range(") + if range_indx != -1: + var var_end_indx : int = scope_data.find(" in ") + if var_end_indx != -1: + var var_str : String = scope_data.substr(0, var_end_indx) + var range_str : String = scope_data.substr(range_indx + 6, scope_data.length() - range_indx - 1 - 6) + var ranges : PoolStringArray = range_str.split(",") + + if ranges.size() == 1: + s += "for (int " + var_str + " = 0; " + var_str + " < " + ranges[0] + "; ++" + var_str + ") { //" + scope_data + elif ranges.size() == 2: + s += "for (int " + var_str + " = " + ranges[0] + "; " + var_str + " < " + ranges[1] + "; ++" + var_str + ") { //" + scope_data + elif ranges.size() == 3: + s += "for (int " + var_str + " = " + ranges[0] + "; " + var_str + " > " + ranges[1] + "; " + var_str + " += " + ranges[2] + ") { //" + scope_data + else: + s += "for (" + scope_data + ") {" + else: + s += "for (" + scope_data + ") {" + else: + s += "for (" + scope_data + ") {" + elif type == GDScopeType.GDSCOPE_TYPE_WHILE: + scope_data = scope_data.replace(" and ", " && ") + scope_data = scope_data.replace(" or ", " || ") + + s += "while (" + scope_data + ") {" + elif type == GDScopeType.GDSCOPE_TYPE_GENERIC: + s += scope_data + " {" + elif type == GDScopeType.GDSCOPE_TYPE_FUNC: + s += transform_method_to_cpp(owner_class_name, false) + " {" + elif type == GDScopeType.GDSCOPE_TYPE_CLASS: + owner_class_name = scope_data + "::" + + for l in scope_lines: + var gs : String = create_cpp_getter_setter(l, false, indents, owner_class_name) + + if gs != "": + s += gs + "\n" + + s += "\n" + indents += " " + + for i in range(0, scope_line_order.size(), 2): + if scope_line_order[i] == GDScopeLineType.GDSCOPE_TYPE_LINE: + var l : String = scope_lines[scope_line_order[i + 1]] + + if l.begins_with("#"): + l = l.replace("#", "//") + s += indents + l + ";\n" + continue + + if l.begins_with("var "): + if l.find("preload") != -1: + s += indents + "//" + l + ";\n" + continue + + s += indents + " " + transform_variable_to_cpp(l) + ";\n" + else: + s += indents + l + ";\n" + else: + var scstr : String = subscopes[scope_line_order[i + 1]].get_cpp_impl_string(current_scope_level + 1, owner_class_name) + + if scstr != "": + s += "\n" + s += scstr + s += "\n" + + s += "}\n" + + + if type == GDScopeType.GDSCOPE_TYPE_CLASS: + s += "\n" + s += indents + scope_data + "::" + scope_data + "() {\n" + + for l in scope_lines: + if l.find("preload") != -1: + s += indents + "//" + l + ";\n" + elif l.begins_with("var "): + var vcpp : String = transform_variable_to_cpp(l) + var index_fs : int = vcpp.find(" ") + if index_fs != -1: + vcpp = vcpp.substr(index_fs + 1) + + s += indents + " " + vcpp + ";\n" + + s += indents + "}\n\n" + s += indents + scope_data + "::~" + scope_data + "() {\n" + s += indents + "}\n\n" + s += "\n" + s += indents + "static void " + scope_data + "::_bind_methods() {\n" + + for l in scope_lines: + var gs : String = create_cpp_getter_setter_bind(l, indents + " ", scope_data) + + if gs != "": + s += gs + "\n" + + s += create_cpp_binds_string(indents.length() + 1) + + s += indents + "}\n\n" + + return s + + func create_cpp_binds_string(current_scope_level : int = 0) -> String: + if type != GDScopeType.GDSCOPE_TYPE_CLASS: + return "" + + var indents : String = "" + + for i in range(current_scope_level): + indents += " " + + var s : String = "" + + for subs in subscopes: + if subs.type != GDScopeType.GDSCOPE_TYPE_FUNC: + continue + + if subs.is_static: + continue + + var scstr : String = subs.transform_method_to_cpp_binding(scope_data) + + if scstr != "": + s += indents + scstr + s += "\n" + + s += "\n" + + return s + + func create_cpp_getter_setter(line : String, header : bool, indent : String, class_prefix : String = "") -> String: + if !line.begins_with("var "): + return "" + + var cpp_var : String = transform_variable_to_cpp(line) + + var equals_index = cpp_var.find("=") + if equals_index != -1: + cpp_var = cpp_var.substr(0, equals_index) + + cpp_var = cpp_var.strip_edges() + + var name_start_index : int = cpp_var.find_last(" ") + var var_type : String = cpp_var.substr(0, name_start_index).strip_edges() + var var_name : String = cpp_var.substr(name_start_index + 1).strip_edges() + + var ret_final : String = "" + + if var_type == "int" || var_type == "float" || var_type == "bool" || var_type == "RID": + ret_final += indent + var_type + " " + class_prefix + "get_" + var_name + "() const" + + if !header: + ret_final += " {\n"; + ret_final += indent + " return " + var_name + ";\n" + ret_final += indent + "}\n\n"; + else: + ret_final += ";\n" + + ret_final += indent + "void " + class_prefix + "set_" + var_name + "(const " + var_type + " val)" + + if !header: + ret_final += " {\n"; + ret_final += indent + var_name + " = val;\n" + ret_final += indent + "}\n\n"; + else: + ret_final += ";\n" + else: + ret_final += indent + var_type + " " + class_prefix + "get_" + var_name + "()" + + if !header: + ret_final += " {\n"; + ret_final += indent + " return " + var_name + ";\n" + ret_final += indent + "}\n\n"; + else: + ret_final += ";\n" + + ret_final += indent + "void " + class_prefix + "set_" + var_name + "(const " + var_type + " &val)" + + if !header: + ret_final += " {\n"; + ret_final += indent + var_name + " = val;\n" + ret_final += indent + "}\n\n"; + else: + ret_final += ";\n" + + return ret_final + + func create_cpp_getter_setter_bind(line : String, indent : String, owner_class_name : String) -> String: + if !line.begins_with("var "): + return "" + + var cpp_var : String = transform_variable_to_cpp(line) + + var equals_index = cpp_var.find("=") + if equals_index != -1: + cpp_var = cpp_var.substr(0, equals_index) + + cpp_var = cpp_var.strip_edges() + + var name_start_index : int = cpp_var.find_last(" ") + var var_type : String = cpp_var.substr(0, name_start_index).strip_edges() + var var_name : String = cpp_var.substr(name_start_index + 1).strip_edges() + + var ret_final : String = "" + + ret_final += indent + " ClassDB::bind_method(D_METHOD(\"get_" + var_name + "\"), &" + owner_class_name + "::get_" + var_name + ");\n" + ret_final += indent + " ClassDB::bind_method(D_METHOD(\"set_" + var_name + "\", \"value\"), &" + owner_class_name + "::set_" + var_name + ");\n" + + ret_final += indent + " ADD_PROPERTY(PropertyInfo(Variant::" + + var is_object : bool = false + + if var_type == "bool": + ret_final += "BOOL" + elif var_type == "int": + ret_final += "INT" + elif var_type == "float" || var_type == "double": + ret_final += "REAL" + elif var_type == "String": + ret_final += "STRING" + elif var_type == "Vector2": + ret_final += "VECTOR2" + elif var_type == "Vector2i": + ret_final += "VECTOR2I" + elif var_type == "Rect2": + ret_final += "RECT2" + elif var_type == "Rect2i": + ret_final += "RECT2I" + elif var_type == "Vector3": + ret_final += "VECTOR3" + elif var_type == "Vector3i": + ret_final += "VECTOR3I" + elif var_type == "Transform2D": + ret_final += "TRANSFORM2D" + elif var_type == "Plane": + ret_final += "PLANE" + elif var_type == "Quat": + ret_final += "QUAT" + elif var_type == "AABB": + ret_final += "AABB" + elif var_type == "Basis": + ret_final += "BASIS" + elif var_type == "Transform": + ret_final += "TRANSFORM" + elif var_type == "Color": + ret_final += "COLOR" + elif var_type == "NodePath": + ret_final += "NODE_PATH" + elif var_type == "RID": + ret_final += "_RID" + elif var_type == "Object": + ret_final += "OBJECT" + is_object = true + elif var_type == "StringName": + ret_final += "STRING_NAME" + elif var_type == "Dictionary": + ret_final += "DICTIONARY" + elif var_type == "Array": + ret_final += "ARRAY" + elif var_type == "PoolByteArray": + ret_final += "POOL_BYTE_ARRAY" + elif var_type == "PoolIntArray": + ret_final += "POOL_INT_ARRAY" + elif var_type == "PoolRealArray": + ret_final += "POOL_REAL_ARRAY" + elif var_type == "PoolStringArray": + ret_final += "POOL_STRING_ARRAY" + elif var_type == "PoolVector2Array": + ret_final += "POOL_VECTOR2_ARRAY" + elif var_type == "PoolVector2iArray": + ret_final += "POOL_VECTOR2I_ARRAY" + elif var_type == "PoolVector3Array": + ret_final += "POOL_VECTOR3_ARRAY" + elif var_type == "PoolVector3iArray": + ret_final += "POOL_VECTOR3I_ARRAY" + elif var_type == "PoolColorArray": + ret_final += "POOL_COLOR_ARRAY" + else: + ret_final += "OBJECT" + is_object = true + + if is_object: + ret_final += ", \"" + var_name + "\", PROPERTY_HINT_RESOURCE_TYPE, \"" + var_type + "\"), \"set_" + var_name + "\", \"get_" + var_name + "\");" + else: + ret_final += ", \"" + var_name + "\"), \"set_" + var_name + "\", \"get_" + var_name + "\");" + + ret_final += "\n\n" + + return ret_final + + func transform_variable_assign(line : String) -> String: + + if !line.ends_with(" as "): + return line + + #This should hadnle primitive types like int + if !line.ends_with(".new()"): + return line + + return line + + func transform_variable_to_cpp(line : String) -> String: + line = line.replace("var ", "") + + var var_final : String = "" + + var param_type : String + var var_name : String + var assigned_value : String + + var assigned_value_indx : int = line.find("=") + + if assigned_value_indx != -1: + assigned_value = line.substr(assigned_value_indx + 1).strip_edges() + line = line.substr(0, assigned_value_indx).strip_edges() + assigned_value = transform_variable_assign(assigned_value) + + var type_indx : int = line.find(":") + if type_indx != -1: + param_type = line.substr(type_indx + 1).strip_edges() + var_name = line.substr(0, type_indx).strip_edges() + if param_type == "int" || param_type == "float" || param_type == "bool" || param_type == "RID": + var_final += param_type + " " + var_name + " = " + assigned_value + elif param_type == "Vector2" || param_type == "Vector2i": + var_final += param_type + " " + var_name + " = " + assigned_value + elif param_type == "Vector3" || param_type == "Vector3i": + var_final += param_type + " " + var_name + " = " + assigned_value + elif param_type == "Rect2" || param_type == "Rect2i": + var_final += param_type + " " + var_name + " = " + assigned_value + elif param_type == "Transform" || param_type == "Transform2D": + var_final += param_type + " " + var_name + " = " + assigned_value + elif param_type == "String" || param_type == "StringName": + var_final += param_type + " " + var_name + " = " + assigned_value + elif param_type == "Quat" || param_type == "Plane": + var_final += param_type + " " + var_name + " = " + assigned_value + elif param_type == "NodePath" || param_type == "Dictionary": + var_final += param_type + " " + var_name + " = " + assigned_value + elif param_type == "Color" || param_type == "Basis": + var_final += param_type + " " + var_name + " = " + assigned_value + elif param_type == "Array" || param_type == "AABB": + var_final += param_type + " " + var_name + " = " + assigned_value + elif param_type == "PoolByteArray" || param_type == "PoolColorArray": + var_final += param_type + " " + var_name + " = " + assigned_value + elif param_type == "PoolIntArray" || param_type == "PoolRealArray": + var_final += param_type + " " + var_name + " = " + assigned_value + elif param_type == "PoolVector2Array" || param_type == "PoolVector2iArray": + var_final += param_type + " " + var_name + " = " + assigned_value + elif param_type == "PoolVector3Array" || param_type == "PoolVector3iArray": + var_final += param_type + " " + var_name + " = " + assigned_value + elif param_type == "PoolStringArray": + var_final += param_type + " " + var_name + " = " + assigned_value + elif param_type != "": + if ClassDB.class_exists(param_type): + #check if it's a reference + var is_ref : bool = false + var pcls : String = param_type + while pcls != "Object": + pcls = ClassDB.get_parent_class(pcls) + + if pcls == "Reference": + is_ref = true + break + + if is_ref: + var_final += "Ref<" + param_type + "> " + var_name + else: + var_final += param_type + " *" + var_name + + if assigned_value != "": + var_final += " = " + assigned_value + else: + #Assume it needs a pointer + var_final += param_type + " *" + var_name + + if assigned_value != "": + var_final += " = " + assigned_value + else: + var_final += "Variant " + var_name + + if assigned_value != "": + var_final += " = " + assigned_value + + return var_final + + func transform_method_to_cpp(name_prefix : String = "", default_params : bool = true) -> String: + if type != GDScopeType.GDSCOPE_TYPE_FUNC: + return "" + + var func_data : String = scope_data + var func_ret_type : String = "void" + + var indx : int = scope_data.find(" -> ") + + if indx != -1: + func_ret_type = scope_data.substr(indx + 4) + func_data = scope_data.substr(0, indx) + + var func_final : String = func_ret_type + " " + indx = func_data.find("(") + var func_name : String = func_data.substr(0, indx) + func_final += name_prefix + func_name + "(" + + var func_params : String = func_data.substr(indx + 1, func_data.length() - indx - 2) + + if func_params != "": + var params : PoolStringArray = func_params.split(",", false) + + for i in range(params.size()): + var p : String = params[i] + + var default_value_indx : int = p.find("=") + var default_value : String + + if default_value_indx != -1: + default_value = p.substr(default_value_indx + 1).strip_edges() + p = p.substr(0, default_value_indx).strip_edges() + + var type_indx : int = p.find(":") + + if type_indx != -1: + var param_type : String = p.substr(type_indx + 1).strip_edges() + p = p.substr(0, type_indx).strip_edges() + + if param_type == "int" || param_type == "float" || param_type == "bool" || param_type == "RID": + func_final += "const " + param_type + " " + else: + func_final += "const " + param_type + " &" + else: + func_final += "const Variant &" + + func_final += p + + if default_params && default_value_indx != -1: + func_final += " = " + default_value + + if i + 1 < params.size(): + func_final += ", " + + func_final += ")" + + return func_final + + func transform_method_to_cpp_binding(name_prefix : String) -> String: + if type != GDScopeType.GDSCOPE_TYPE_FUNC: + return "" + + var func_data : String = scope_data + var func_ret_type : String = "void" + + var indx : int = scope_data.find(" -> ") + + if indx != -1: + func_ret_type = scope_data.substr(indx + 4) + func_data = scope_data.substr(0, indx) + + var ret_final : String = "ClassDB::bind_method(D_METHOD(\"" + + indx = func_data.find("(") + var func_name : String = func_data.substr(0, indx) + ret_final += func_name + "\"" + + var func_params : String = func_data.substr(indx + 1, func_data.length() - indx - 2) + + var default_values : PoolStringArray = PoolStringArray() + + if func_params != "": + var params : PoolStringArray = func_params.split(",", false) + + for i in range(params.size()): + ret_final += ", " + + var p : String = params[i] + + var default_value_indx : int = p.find("=") + var default_value : String + + if default_value_indx != -1: + default_value = p.substr(default_value_indx + 1).strip_edges() + p = p.substr(0, default_value_indx).strip_edges() + default_values.push_back(default_value) + + var type_indx : int = p.find(":") + + if type_indx != -1: + var param_type : String = p.substr(type_indx + 1).strip_edges() + p = p.substr(0, type_indx).strip_edges() + + ret_final += "\"" + p + "\"" + + ret_final += "), &" + name_prefix + "::" + func_name + + for i in range(default_values.size()): + ret_final += ", " + default_values[i] + + ret_final += ");" + + return ret_final + + func camel_case_scope_data() -> void: + scope_data = camel_case_name(scope_data) + + func camel_case_name(cname : String) -> String: + var ret : String = "" + + var next_upper : bool = true + for i in range(cname.length()): + if cname[i] == "_": + next_upper = true + continue + + if next_upper: + ret += cname[i].to_upper() + next_upper = false + else: + ret += cname[i] + + return ret + + func _to_string(): + return convert_to_string() + + + +class GDSParser: + var root : GDSScope + + func parse(contents : String, file_name : String) -> void: + root = GDSScope.new() + root.raw_scope_data = file_name + root.scope_data = file_name.get_file().trim_suffix(".gd") + root.camel_case_scope_data() + var c : PoolStringArray = split_preprocess_content(contents) + root.parse(c) + root.apply_comments() + + + func split_preprocess_content(contents : String) -> PoolStringArray: + var ret : PoolStringArray = PoolStringArray() + + contents = contents.replace("\r\n", "\n") + + var sp : PoolStringArray = contents.split("\n") + + var pl : String = "" + var accum : bool = false + for i in range(sp.size()): + var l : String = sp[i] + l = l.strip_edges(false, true) + + var lfstrip : String = l.strip_edges(true, false) + if lfstrip == "": + continue + + if lfstrip.begins_with("#"): + ret.append(lfstrip) + continue + + if lfstrip.begins_with("export"): + var indx = lfstrip.find("var") + var expstr : String = lfstrip.substr(0, indx) + + ret.append("#" + expstr) + l = l.replace(expstr, "") + + var setget_indx = l.find(" setget ") + if setget_indx != -1: + var setget_str : String = l.substr(setget_indx) + ret.append("#" + setget_str) + l = l.substr(0, setget_indx).strip_edges(false, true) + + var hash_symbol_index = l.find("#") + if hash_symbol_index != -1: + var comment_str : String = l.substr(hash_symbol_index).strip_edges(true, false) + ret.append(comment_str) + l = l.substr(0, hash_symbol_index).strip_edges(false, true) + + if l.ends_with("\\"): + if !accum: + accum = true + pl = l + else: + pl += l.substr(0, l.length() - 1).strip_edges() + else: + if accum: + accum = false + ret.append(pl) + pl = "" + else: + ret.append(l) + + return ret + + func _to_string(): + return str(root) + + func get_cpp_header_string(file_name : String) -> String: + var include_guard_name : String = file_name.get_file() + include_guard_name = include_guard_name.to_upper() + include_guard_name = include_guard_name.trim_suffix(".GD") + include_guard_name += "_H" + + var s : String = "#ifndef " + include_guard_name + "\n" + s += "#define " + include_guard_name + "\n" + s += "\n\n" + + s += root.get_cpp_header_string() + + s += "\n\n" + s += "#endif" + s += "\n" + + s = s.replace(";;", ";") + + return s + + func get_cpp_impl_string(file_name : String) -> String: + var include_name : String = file_name.get_file() + include_name = include_name.to_lower() + include_name = include_name.trim_suffix(".gd") + include_name += ".h" + + var s : String = "\n" + s += "#include \"" + include_name + "\"\n" + s += "\n\n" + + s += root.get_cpp_impl_string() + + s += "\n\n" + + s = s.replace(";;", ";") + + return s + +func process_file(file_name : String) -> void: + var file : File = File.new() + file.open(file_name, File.READ) + var contents : String = file.get_as_text() + file.close() + + var parser : GDSParser = GDSParser.new() + parser.parse(contents, file_name) + #print(parser) + #print(parser.get_cpp_header_string(file_name)) + #print(parser.get_cpp_impl_string(file_name)) + + var save_base_file_path : String = file_name.get_base_dir() + var save_base_file_name : String = file_name.get_file().to_lower().trim_suffix(".gd") + + var header_file : String = save_base_file_path + "/" + save_base_file_name + ".h" + var impl_file : String = save_base_file_path + "/" + save_base_file_name + ".cpp" + + var header_data : String = parser.get_cpp_header_string(file_name) + var impl_data : String = parser.get_cpp_impl_string(file_name) + + file.open(header_file, File.WRITE) + file.store_string(header_data) + file.close() + + file.open(impl_file, File.WRITE) + file.store_string(impl_data) + file.close() + diff --git a/gdc_converter/gdc_scene_converter.gd b/gdc_converter/gdc_scene_converter.gd new file mode 100644 index 0000000..1dac6b9 --- /dev/null +++ b/gdc_converter/gdc_scene_converter.gd @@ -0,0 +1,186 @@ +tool +extends Reference + +class GDSSceneParser: + var result : String + + func parse(file_name : String) -> void: + var ps : PackedScene = ResourceLoader.load(file_name, "PackedScene") + + if !ps: + print("ERROR! !ps :" + file_name) + return + + var node : Node = ps.instance() + + process_node(node) + + + func process_node(node : Node) -> void: + var node_name : String = node.get_name() + + var nn : Node = node.get_parent() + while nn: + node_name += "_" + nn.get_name() + nn = nn.get_parent() + + node_name = node_name.to_lower() + + var nscript : Script = node.get_script() + + if nscript: + result += "//Script: " + nscript.resource_path + "\n" + + result += node.get_class() + " *" + node_name + " = memnew(" + node.get_class() + ");\n" + result += node_name + "->set_name(\"" + node.get_name() + "\");\n" + var node_parent : Node = node.get_parent() + if node_parent: + var node_parent_name : String = node_parent.get_name() + + var nnp : Node = node_parent.get_parent() + while nnp: + node_parent_name += "_" + nnp.get_name() + nnp = nnp.get_parent() + + node_parent_name = node_parent_name.to_lower() + result += node_parent_name + "->add_child(" + node_name + ");\n" + + var node_def_copy : Node = ClassDB.instance(node.get_class()) + node_def_copy.set_script(node.get_script()) + + result += "\n" + + var props : Array = node.get_property_list() + + for p in props: + var property_name : String = p["name"] + + var prop_value = node.get(property_name) + if prop_value != node_def_copy.get(property_name): + var property_type : int = p["type"] + + if property_type == TYPE_BOOL || property_type == TYPE_INT || property_type == TYPE_REAL: + result += node_name + "->set_" + property_name + "(" + str(prop_value) + ");\n" + result += "//" + node_name + "->set(\"" + property_name + "\", " + str(prop_value) + ");\n" + elif property_type == TYPE_STRING: + result += node_name + "->set_" + property_name + "(\"" + prop_value + "\");\n" + result += "//" + node_name + "->set(\"" + property_name + "\", \"" + prop_value + "\");\n" + elif property_type == TYPE_VECTOR2: + result += node_name + "->set_" + property_name + "(Vector2(" + str(prop_value.x) + ", " + str(prop_value.y) + "));\n" + result += "//" + node_name + "->set(\"" + property_name + "\", Vector2(" + str(prop_value.x) + ", " + str(prop_value.y) + "));\n" + elif property_type == TYPE_VECTOR2I: + result += node_name + "->set_" + property_name + "(Vector2i(" + str(prop_value.x) + ", " + str(prop_value.y) + "));\n" + result += "//" + node_name + "->set(\"" + property_name + "\", Vector2i(" + str(prop_value.x) + ", " + str(prop_value.y) + "));\n" + elif property_type == TYPE_RECT2: + result += node_name + "->set_" + property_name + "(Rect2(" + str(prop_value.position.x) + ", " + str(prop_value.position.y) + ", " + str(prop_value.size.y) + ", " + str(prop_value.size.y) + "));\n" + result += "//" + node_name + "->set(\"" + property_name + "\", Rect2(" + str(prop_value.position.x) + ", " + str(prop_value.position.y) + ", " + str(prop_value.size.y) + ", " + str(prop_value.size.y) + "));\n" + elif property_type == TYPE_RECT2I: + result += node_name + "->set_" + property_name + "(Rect2i(" + str(prop_value.position.x) + ", " + str(prop_value.position.y) + ", " + str(prop_value.size.y) + ", " + str(prop_value.size.y) + "));\n" + result += "//" + node_name + "->set(\"" + property_name + "\", Rect2i(" + str(prop_value.position.x) + ", " + str(prop_value.position.y) + ", " + str(prop_value.size.y) + ", " + str(prop_value.size.y) + "));\n" + elif property_type == TYPE_VECTOR3: + result += node_name + "->set_" + property_name + "(Vector3(" + str(prop_value.x) + ", " + str(prop_value.y) + ", " + str(prop_value.z) + "));\n" + result += "//" + node_name + "->set(\"" + property_name + "\", Vector3(" + str(prop_value.x) + ", " + str(prop_value.y) + ", " + str(prop_value.z) + "));\n" + elif property_type == TYPE_VECTOR3I: + result += node_name + "->set_" + property_name + "(Vector3i(" + str(prop_value.x) + ", " + str(prop_value.y) + ", " + str(prop_value.z) + "));\n" + result += "//" + node_name + "->set(\"" + property_name + "\", Vector3i(" + str(prop_value.x) + ", " + str(prop_value.y) + ", " + str(prop_value.z) + "));\n" + elif property_type == TYPE_TRANSFORM2D: + result += "//" + node_name + " property " + property_name + " TYPE_TRANSFORM2D value: " + str(prop_value) + "\n" + elif property_type == TYPE_PLANE: + result += "//" + node_name + " property " + property_name + " TYPE_PLANE value: " + str(prop_value) + "\n" + elif property_type == TYPE_QUAT: + result += "//" + node_name + " property " + property_name + " TYPE_QUAT value: " + str(prop_value) + "\n" + elif property_type == TYPE_AABB: + result += "//" + node_name + " property " + property_name + " TYPE_AABB value: " + str(prop_value) + "\n" + elif property_type == TYPE_BASIS: + result += "//" + node_name + " property " + property_name + " TYPE_BASIS value: " + str(prop_value) + "\n" + elif property_type == TYPE_TRANSFORM: + result += "//" + node_name + " property " + property_name + " TYPE_TRANSFORM value: " + str(prop_value) + "\n" + elif property_type == TYPE_COLOR: + result += node_name + "->set_" + property_name + "(Color(" + str(prop_value.r) + ", " + str(prop_value.g) + ", " + str(prop_value.b) + ", " + str(prop_value.a) + "));\n" + result += "//" + node_name + "->set(\"" + property_name + "\", Color(" + str(prop_value.r) + ", " + str(prop_value.g) + ", " + str(prop_value.b) + ", " + str(prop_value.a) + "));\n" + elif property_type == TYPE_NODE_PATH: + result += "//" + node_name + " property " + property_name + " TYPE_NODE_PATH value: " + str(prop_value) + "\n" + elif property_type == TYPE_RID: + result += "//" + node_name + " property " + property_name + " TYPE_RID value: " + str(prop_value) + "\n" + elif property_type == TYPE_STRING_NAME: + result += node_name + "->set_" + property_name + "(\"" + prop_value + "\");\n" + result += "//" + node_name + "->set(\"" + property_name + "\", " + prop_value + "));\n" + elif property_type == TYPE_DICTIONARY: + result += "//" + node_name + " property " + property_name + " TYPE_DICTIONARY value: " + str(prop_value) + "\n" + elif property_type == TYPE_ARRAY: + result += "//" + node_name + " property " + property_name + " TYPE_ARRAY value: " + str(prop_value) + "\n" + elif property_type == TYPE_RAW_ARRAY: + result += "//" + node_name + " property " + property_name + " TYPE_RAW_ARRAY value: " + str(prop_value) + "\n" + elif property_type == TYPE_INT_ARRAY: + result += "//" + node_name + " property " + property_name + " TYPE_INT_ARRAY value: " + str(prop_value) + "\n" + elif property_type == TYPE_REAL_ARRAY: + result += "//" + node_name + " property " + property_name + " TYPE_REAL_ARRAY value: " + str(prop_value) + "\n" + elif property_type == TYPE_STRING_ARRAY: + result += "//" + node_name + " property " + property_name + " TYPE_STRING_ARRAY value: " + str(prop_value) + "\n" + elif property_type == TYPE_VECTOR2_ARRAY: + result += "//" + node_name + " property " + property_name + " TYPE_VECTOR2_ARRAY value: " + str(prop_value) + "\n" + elif property_type == TYPE_VECTOR2I_ARRAY: + result += "//" + node_name + " property " + property_name + " TYPE_VECTOR2I_ARRAY value: " + str(prop_value) + "\n" + elif property_type == TYPE_VECTOR3_ARRAY: + result += "//" + node_name + " property " + property_name + " TYPE_VECTOR3_ARRAY value: " + str(prop_value) + "\n" + elif property_type == TYPE_VECTOR3I_ARRAY: + result += "//" + node_name + " property " + property_name + " TYPE_VECTOR3I_ARRAY value: " + str(prop_value) + "\n" + elif property_type == TYPE_COLOR_ARRAY: + result += "//" + node_name + " property " + property_name + " TYPE_COLOR_ARRAY value: " + str(prop_value) + "\n" + elif property_type == TYPE_OBJECT: + result += "//" + node_name + " property " + property_name + " TYPE_OBJECT value: " + str(prop_value) + "\n" + if prop_value: + var is_reference : bool = false + var curr_pclass : String = prop_value.get_class() + while curr_pclass != "Object": + if curr_pclass == "Reference": + is_reference = true + break + + curr_pclass = ClassDB.get_parent_class(curr_pclass) + + if is_reference: + result += "Ref<" + prop_value.get_class() + "> " + node_name + "_prop_" + property_name + ";\n" + result += node_name + "_prop_" + property_name + ".instance();\n" + result += node_name + "->set_" + property_name + "(" + node_name + "_prop_" + property_name + ");\n" + result += "//" + node_name + "->set(\"" + property_name + "\", " + node_name + "_prop_" + property_name + ");\n" + else: + result += node_name + "->set_" + property_name + "(nullptr);\n" + result += "//" + node_name + "->set(\"" + property_name + "\", nullptr);\n" + else: + result += "//" + node_name + " property " + property_name + " value: " + str(prop_value) + "\n" + + result += "\n" + + result += "\n\n" + + for n in node.get_children(): + process_node(n) + + func _to_string(): + return result + + func get_cpp_impl_string() -> String: + var s : String = "\n" + s += "void construct() {\n" + s += "\n" + s += result + s += "\n}\n" + + return s + +func process_file(file_name : String) -> void: + var parser : GDSSceneParser = GDSSceneParser.new() + parser.parse(file_name) + + var save_base_file_path : String = file_name.get_base_dir() + var save_base_file_name : String = file_name.get_file().to_lower().trim_suffix(".tscn") + + var impl_file : String = save_base_file_path + "/" + save_base_file_name + ".ctscn" + var impl_data : String = parser.get_cpp_impl_string() + + #print(impl_data) + var file : File = File.new() + file.open(impl_file, File.WRITE) + file.store_string(impl_data) + file.close() diff --git a/gdc_converter/plugin.cfg b/gdc_converter/plugin.cfg new file mode 100644 index 0000000..abfee2b --- /dev/null +++ b/gdc_converter/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="GDCConverter" +description="GDScript to CPP converter addon." +author="Relintai" +version="1.0" +script="plugin.gd" diff --git a/gdc_converter/plugin.gd b/gdc_converter/plugin.gd new file mode 100644 index 0000000..3342f44 --- /dev/null +++ b/gdc_converter/plugin.gd @@ -0,0 +1,63 @@ +tool +extends EditorPlugin + +func _enter_tree(): + add_tool_menu_item("Convert Scripts to Cpp", self, "on_convert_script_menu_clicked") + add_tool_menu_item("Generate Cpp Class Bind for Scripts", self, "on_generate_class_binds_menu_clicked") + add_tool_menu_item("Convert Scenes to Cpp", self, "on_convert_scene_menu_clicked") + +func _exit_tree(): + remove_tool_menu_item("Convert Scripts to Cpp") + remove_tool_menu_item("Generate Cpp Class Bind for Scripts") + remove_tool_menu_item("Convert Scenes to Cpp") + +func on_convert_script_menu_clicked(val) -> void: + var GDSParser = load("res://addons/gdc_converter/gdc_code_converter.gd") + var parser = GDSParser.new() + + var dir = Directory.new() + var dir_name = get_editor_interface().get_selected_path() + if dir.open(dir_name) == OK: + dir.list_dir_begin() + var file_name = dir.get_next() + while file_name != "": + + if !dir.current_is_dir(): + if file_name.get_extension() == "gd": + parser.process_file(dir_name + file_name) + + file_name = dir.get_next() + +func on_generate_class_binds_menu_clicked(val) -> void: + var GDSParser = load("res://addons/gdc_converter/gdc_class_bind_generator.gd") + var parser = GDSParser.new() + + var dir = Directory.new() + var dir_name = get_editor_interface().get_selected_path() + if dir.open(dir_name) == OK: + dir.list_dir_begin() + var file_name = dir.get_next() + while file_name != "": + + if !dir.current_is_dir(): + if file_name.get_extension() == "gd": + parser.process_file(dir_name + file_name) + + file_name = dir.get_next() + +func on_convert_scene_menu_clicked(val) -> void: + var GDSParser = load("res://addons/gdc_converter/gdc_scene_converter.gd") + var parser = GDSParser.new() + + var dir = Directory.new() + var dir_name = get_editor_interface().get_selected_path() + if dir.open(dir_name) == OK: + dir.list_dir_begin() + var file_name = dir.get_next() + while file_name != "": + + if !dir.current_is_dir(): + if file_name.get_extension() == "tscn": + parser.process_file(dir_name + file_name) + + file_name = dir.get_next()