summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gdextension/gdextension_interface.h25
-rw-r--r--include/godot_cpp/core/method_bind.hpp2
-rw-r--r--include/godot_cpp/godot.hpp7
-rw-r--r--src/godot.cpp52
-rw-r--r--test/SConstruct4
-rw-r--r--test/doc_classes/Example.xml25
-rw-r--r--test/project/project.godot2
-rw-r--r--tools/godotcpp.py48
8 files changed, 163 insertions, 2 deletions
diff --git a/gdextension/gdextension_interface.h b/gdextension/gdextension_interface.h
index 60ec8d4..b9a6a25 100644
--- a/gdextension/gdextension_interface.h
+++ b/gdextension/gdextension_interface.h
@@ -2835,6 +2835,31 @@ typedef void (*GDExtensionInterfaceEditorAddPlugin)(GDExtensionConstStringNamePt
*/
typedef void (*GDExtensionInterfaceEditorRemovePlugin)(GDExtensionConstStringNamePtr p_class_name);
+/**
+ * @name editor_help_load_xml_from_utf8_chars
+ * @since 4.3
+ *
+ * Loads new XML-formatted documentation data in the editor.
+ *
+ * The provided pointer can be immediately freed once the function returns.
+ *
+ * @param p_data A pointer to a UTF-8 encoded C string (null terminated).
+ */
+typedef void (*GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars)(const char *p_data);
+
+/**
+ * @name editor_help_load_xml_from_utf8_chars_and_len
+ * @since 4.3
+ *
+ * Loads new XML-formatted documentation data in the editor.
+ *
+ * The provided pointer can be immediately freed once the function returns.
+ *
+ * @param p_data A pointer to a UTF-8 encoded C string.
+ * @param p_size The number of bytes (not code units).
+ */
+typedef void (*GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen)(const char *p_data, GDExtensionInt p_size);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/godot_cpp/core/method_bind.hpp b/include/godot_cpp/core/method_bind.hpp
index 4afd7b8..eabd6ec 100644
--- a/include/godot_cpp/core/method_bind.hpp
+++ b/include/godot_cpp/core/method_bind.hpp
@@ -412,6 +412,7 @@ public:
method = p_method;
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
+ set_const(true);
}
};
@@ -578,6 +579,7 @@ public:
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
set_return(true);
+ set_const(true);
}
};
diff --git a/include/godot_cpp/godot.hpp b/include/godot_cpp/godot.hpp
index 5a62930..4bb7915 100644
--- a/include/godot_cpp/godot.hpp
+++ b/include/godot_cpp/godot.hpp
@@ -190,6 +190,13 @@ extern "C" GDExtensionInterfaceClassdbUnregisterExtensionClass gdextension_inter
extern "C" GDExtensionInterfaceGetLibraryPath gdextension_interface_get_library_path;
extern "C" GDExtensionInterfaceEditorAddPlugin gdextension_interface_editor_add_plugin;
extern "C" GDExtensionInterfaceEditorRemovePlugin gdextension_interface_editor_remove_plugin;
+extern "C" GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars gdextension_interface_editor_help_load_xml_from_utf8_chars;
+extern "C" GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen gdextension_interface_editor_help_load_xml_from_utf8_chars_and_len;
+
+class DocDataRegistration {
+public:
+ DocDataRegistration(const char *p_hash, int p_uncompressed_size, int p_compressed_size, const unsigned char *p_data);
+};
} // namespace internal
diff --git a/src/godot.cpp b/src/godot.cpp
index 8a031be..01977de 100644
--- a/src/godot.cpp
+++ b/src/godot.cpp
@@ -196,6 +196,38 @@ GDExtensionInterfaceClassdbUnregisterExtensionClass gdextension_interface_classd
GDExtensionInterfaceGetLibraryPath gdextension_interface_get_library_path = nullptr;
GDExtensionInterfaceEditorAddPlugin gdextension_interface_editor_add_plugin = nullptr;
GDExtensionInterfaceEditorRemovePlugin gdextension_interface_editor_remove_plugin = nullptr;
+GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars gdextension_interface_editor_help_load_xml_from_utf8_chars = nullptr;
+GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen gdextension_interface_editor_help_load_xml_from_utf8_chars_and_len = nullptr;
+
+struct DocData {
+ const char *hash = nullptr;
+ int uncompressed_size = 0;
+ int compressed_size = 0;
+ const unsigned char *data = nullptr;
+
+ inline bool is_valid() const {
+ return hash != nullptr && uncompressed_size > 0 && compressed_size > 0 && data != nullptr;
+ }
+
+ void load_data() const;
+};
+
+static DocData &get_doc_data() {
+ static DocData doc_data;
+ return doc_data;
+}
+
+DocDataRegistration::DocDataRegistration(const char *p_hash, int p_uncompressed_size, int p_compressed_size, const unsigned char *p_data) {
+ DocData &doc_data = get_doc_data();
+ if (doc_data.is_valid()) {
+ printf("ERROR: Attempting to register documentation data when we already have some - discarding.\n");
+ return;
+ }
+ doc_data.hash = p_hash;
+ doc_data.uncompressed_size = p_uncompressed_size;
+ doc_data.compressed_size = p_compressed_size;
+ doc_data.data = p_data;
+}
} // namespace internal
@@ -436,6 +468,8 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
LOAD_PROC_ADDRESS(get_library_path, GDExtensionInterfaceGetLibraryPath);
LOAD_PROC_ADDRESS(editor_add_plugin, GDExtensionInterfaceEditorAddPlugin);
LOAD_PROC_ADDRESS(editor_remove_plugin, GDExtensionInterfaceEditorRemovePlugin);
+ LOAD_PROC_ADDRESS(editor_help_load_xml_from_utf8_chars, GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars);
+ LOAD_PROC_ADDRESS(editor_help_load_xml_from_utf8_chars_and_len, GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen);
r_initialization->initialize = initialize_level;
r_initialization->deinitialize = deinitialize_level;
@@ -465,6 +499,13 @@ void GDExtensionBinding::initialize_level(void *p_userdata, GDExtensionInitializ
ClassDB::initialize(p_level);
}
level_initialized[p_level]++;
+
+ if ((ModuleInitializationLevel)p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
+ const internal::DocData &doc_data = internal::get_doc_data();
+ if (doc_data.is_valid()) {
+ doc_data.load_data();
+ }
+ }
}
void GDExtensionBinding::deinitialize_level(void *p_userdata, GDExtensionInitializationLevel p_level) {
@@ -531,4 +572,15 @@ GDExtensionBool GDExtensionBinding::InitObject::init() const {
return GDExtensionBinding::init(get_proc_address, library, init_data, initialization);
}
+void internal::DocData::load_data() const {
+ PackedByteArray compressed;
+ compressed.resize(compressed_size);
+ memcpy(compressed.ptrw(), data, compressed_size);
+
+ // FileAccess::COMPRESSION_DEFLATE = 1
+ PackedByteArray decompressed = compressed.decompress(uncompressed_size, 1);
+
+ internal::gdextension_interface_editor_help_load_xml_from_utf8_chars_and_len(reinterpret_cast<const char *>(decompressed.ptr()), uncompressed_size);
+}
+
} // namespace godot
diff --git a/test/SConstruct b/test/SConstruct
index 9c25917..7cb25be 100644
--- a/test/SConstruct
+++ b/test/SConstruct
@@ -16,6 +16,10 @@ env = SConscript("../SConstruct")
env.Append(CPPPATH=["src/"])
sources = Glob("src/*.cpp")
+if env["target"] in ["editor", "template_debug"]:
+ doc_data = env.GodotCPPDocData("src/gen/doc_data.gen.cpp", source=Glob("doc_classes/*.xml"))
+ sources.append(doc_data)
+
if env["platform"] == "macos":
library = env.SharedLibrary(
"project/bin/libgdexample.{}.{}.framework/libgdexample.{}.{}".format(
diff --git a/test/doc_classes/Example.xml b/test/doc_classes/Example.xml
new file mode 100644
index 0000000..457709d
--- /dev/null
+++ b/test/doc_classes/Example.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="Example" inherits="Control" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/godotengine/godot/master/doc/class.xsd">
+ <brief_description>
+ A test control defined in GDExtension.
+ </brief_description>
+ <description>
+ A control used for the automated GDExtension tests.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="simple_func">
+ <return type="void" />
+ <description>
+ Tests a simple function call.
+ </description>
+ </method>
+ </methods>
+ <members>
+ </members>
+ <signals>
+ </signals>
+ <constants>
+ </constants>
+</class>
diff --git a/test/project/project.godot b/test/project/project.godot
index 4f51c07..df3dd70 100644
--- a/test/project/project.godot
+++ b/test/project/project.godot
@@ -12,7 +12,7 @@ config_version=5
config/name="GDExtension Test Project"
run/main_scene="res://main.tscn"
-config/features=PackedStringArray("4.2")
+config/features=PackedStringArray("4.3")
config/icon="res://icon.png"
[native_extensions]
diff --git a/tools/godotcpp.py b/tools/godotcpp.py
index 13a57e9..2e61e2b 100644
--- a/tools/godotcpp.py
+++ b/tools/godotcpp.py
@@ -325,6 +325,51 @@ def options(opts, env):
tool.options(opts)
+def make_doc_source(target, source, env):
+ import zlib
+
+ dst = str(target[0])
+ g = open(dst, "w", encoding="utf-8")
+ buf = ""
+ docbegin = ""
+ docend = ""
+ for src in source:
+ src_path = str(src)
+ if not src_path.endswith(".xml"):
+ continue
+ with open(src_path, "r", encoding="utf-8") as f:
+ content = f.read()
+ buf += content
+
+ buf = (docbegin + buf + docend).encode("utf-8")
+ decomp_size = len(buf)
+
+ # Use maximum zlib compression level to further reduce file size
+ # (at the cost of initial build times).
+ buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION)
+
+ g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
+ g.write("\n")
+ g.write("#include <godot_cpp/godot.hpp>\n")
+ g.write("\n")
+
+ g.write('static const char *_doc_data_hash = "' + str(hash(buf)) + '";\n')
+ g.write("static const int _doc_data_uncompressed_size = " + str(decomp_size) + ";\n")
+ g.write("static const int _doc_data_compressed_size = " + str(len(buf)) + ";\n")
+ g.write("static const unsigned char _doc_data_compressed[] = {\n")
+ for i in range(len(buf)):
+ g.write("\t" + str(buf[i]) + ",\n")
+ g.write("};\n")
+ g.write("\n")
+
+ g.write(
+ "static godot::internal::DocDataRegistration _doc_data_registration(_doc_data_hash, _doc_data_uncompressed_size, _doc_data_compressed_size, _doc_data_compressed);\n"
+ )
+ g.write("\n")
+
+ g.close()
+
+
def generate(env):
# Default num_jobs to local cpu count if not user specified.
# SCons has a peculiarity where user-specified options won't be overridden
@@ -451,7 +496,8 @@ def generate(env):
# Builders
env.Append(
BUILDERS={
- "GodotCPPBindings": Builder(action=Action(scons_generate_bindings, "$GENCOMSTR"), emitter=scons_emit_files)
+ "GodotCPPBindings": Builder(action=Action(scons_generate_bindings, "$GENCOMSTR"), emitter=scons_emit_files),
+ "GodotCPPDocData": Builder(action=make_doc_source),
}
)
env.AddMethod(_godot_cpp, "GodotCPP")