added type tags and safe object casting
parent
37abbe0c09
commit
dabc96ebd9
|
@ -34,6 +34,9 @@ def generate_bindings(path):
|
||||||
icall_source_file = open("src/gen/__icalls.cpp", "w+")
|
icall_source_file = open("src/gen/__icalls.cpp", "w+")
|
||||||
icall_source_file.write(generate_icall_implementation(icalls))
|
icall_source_file.write(generate_icall_implementation(icalls))
|
||||||
|
|
||||||
|
register_types_file = open("src/gen/__register_types.cpp", "w+")
|
||||||
|
register_types_file.write(generate_type_registry(classes))
|
||||||
|
|
||||||
|
|
||||||
def is_reference_type(t):
|
def is_reference_type(t):
|
||||||
for c in classes:
|
for c in classes:
|
||||||
|
@ -79,6 +82,8 @@ def generate_class_header(used_classes, c):
|
||||||
# so don't include it here because it's not needed
|
# so don't include it here because it's not needed
|
||||||
if class_name != "Object" and class_name != "Reference":
|
if class_name != "Object" and class_name != "Reference":
|
||||||
source.append("#include <core/Ref.hpp>")
|
source.append("#include <core/Ref.hpp>")
|
||||||
|
else:
|
||||||
|
source.append("#include <TagDB.hpp>")
|
||||||
|
|
||||||
|
|
||||||
included = []
|
included = []
|
||||||
|
@ -100,7 +105,6 @@ def generate_class_header(used_classes, c):
|
||||||
if c["base_class"] != "":
|
if c["base_class"] != "":
|
||||||
source.append("#include \"" + strip_name(c["base_class"]) + ".hpp\"")
|
source.append("#include \"" + strip_name(c["base_class"]) + ".hpp\"")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
source.append("namespace godot {")
|
source.append("namespace godot {")
|
||||||
source.append("")
|
source.append("")
|
||||||
|
@ -118,18 +122,13 @@ def generate_class_header(used_classes, c):
|
||||||
vararg_templates = ""
|
vararg_templates = ""
|
||||||
|
|
||||||
# generate the class definition here
|
# generate the class definition here
|
||||||
source.append("class " + class_name + ("" if c["base_class"] == "" else (" : public " + strip_name(c["base_class"])) ) + " {")
|
source.append("class " + class_name + (" : public _Wrapped" if c["base_class"] == "" else (" : public " + strip_name(c["base_class"])) ) + " {")
|
||||||
|
|
||||||
if c["base_class"] == "":
|
if c["base_class"] == "":
|
||||||
# this is Object
|
source.append("public: enum { ___CLASS_IS_SCRIPT = 0, };")
|
||||||
|
source.append("private:")
|
||||||
source.append("")
|
source.append("")
|
||||||
source.append("public:")
|
|
||||||
source.append("\tgodot_object *_owner;")
|
|
||||||
source.append("")
|
|
||||||
# TODO decide what to do about virtual methods
|
|
||||||
# source.append("static void _register_methods();")
|
|
||||||
# source.append("")
|
|
||||||
|
|
||||||
if c["singleton"]:
|
if c["singleton"]:
|
||||||
source.append("\tstatic " + class_name + " *_singleton;")
|
source.append("\tstatic " + class_name + " *_singleton;")
|
||||||
source.append("")
|
source.append("")
|
||||||
|
@ -140,6 +139,10 @@ def generate_class_header(used_classes, c):
|
||||||
source.append("public:")
|
source.append("public:")
|
||||||
source.append("")
|
source.append("")
|
||||||
|
|
||||||
|
source.append("\tstatic void *___get_type_tag();")
|
||||||
|
source.append("\tstatic void *___get_base_type_tag();")
|
||||||
|
|
||||||
|
|
||||||
if c["singleton"]:
|
if c["singleton"]:
|
||||||
source.append("\tstatic inline " + class_name + " *get_singleton()")
|
source.append("\tstatic inline " + class_name + " *get_singleton()")
|
||||||
source.append("\t{")
|
source.append("\t{")
|
||||||
|
@ -180,6 +183,14 @@ def generate_class_header(used_classes, c):
|
||||||
source.append("\tstatic " + class_name + " *_new();")
|
source.append("\tstatic " + class_name + " *_new();")
|
||||||
|
|
||||||
source.append("\n\t// methods")
|
source.append("\n\t// methods")
|
||||||
|
|
||||||
|
|
||||||
|
if class_name == "Object":
|
||||||
|
source.append("#ifndef GODOT_CPP_NO_OBJECT_CAST")
|
||||||
|
source.append("\ttemplate<class T>")
|
||||||
|
source.append("\tstatic T *cast_to(const Object *obj);")
|
||||||
|
source.append("#endif")
|
||||||
|
source.append("")
|
||||||
|
|
||||||
for method in c["methods"]:
|
for method in c["methods"]:
|
||||||
|
|
||||||
|
@ -264,11 +275,10 @@ def generate_class_header(used_classes, c):
|
||||||
source.append("")
|
source.append("")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
source.append("}")
|
source.append("}")
|
||||||
source.append("")
|
source.append("")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
source.append("#endif")
|
source.append("#endif")
|
||||||
|
|
||||||
|
|
||||||
|
@ -314,6 +324,21 @@ def generate_class_implementation(icalls, used_classes, c):
|
||||||
|
|
||||||
source.append("")
|
source.append("")
|
||||||
source.append("")
|
source.append("")
|
||||||
|
|
||||||
|
source.append("void *" + class_name + "::___get_type_tag()")
|
||||||
|
source.append("{")
|
||||||
|
source.append("\treturn (void *) &" + class_name + "::___get_type_tag;")
|
||||||
|
source.append("}")
|
||||||
|
source.append("")
|
||||||
|
|
||||||
|
source.append("void *" + class_name + "::___get_base_type_tag()")
|
||||||
|
source.append("{")
|
||||||
|
if c["base_class"] != "":
|
||||||
|
source.append("\treturn (void *) &" + strip_name(c["base_class"]) + "::___get_type_tag;")
|
||||||
|
else:
|
||||||
|
source.append("\treturn (void *) nullptr;")
|
||||||
|
source.append("}")
|
||||||
|
source.append("")
|
||||||
|
|
||||||
if c["singleton"]:
|
if c["singleton"]:
|
||||||
source.append("" + class_name + " *" + class_name + "::_singleton = NULL;")
|
source.append("" + class_name + " *" + class_name + "::_singleton = NULL;")
|
||||||
|
@ -640,8 +665,34 @@ def generate_icall_implementation(icalls):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def generate_type_registry(classes):
|
||||||
|
source = []
|
||||||
|
|
||||||
|
source.append("#include \"TagDB.hpp\"")
|
||||||
|
source.append("")
|
||||||
|
|
||||||
|
for c in classes:
|
||||||
|
source.append("#include <" + strip_name(c["name"]) + ".hpp>")
|
||||||
|
|
||||||
|
source.append("")
|
||||||
|
source.append("")
|
||||||
|
|
||||||
|
source.append("namespace godot {")
|
||||||
|
|
||||||
|
source.append("void ___register_types()")
|
||||||
|
source.append("{")
|
||||||
|
|
||||||
|
for c in classes:
|
||||||
|
class_name = strip_name(c["name"])
|
||||||
|
source.append("\tgodot::_TagDB::register_global_type(\"" + class_name + "\", " + class_name + "::___get_type_tag(), " + class_name + "::___get_base_type_tag());")
|
||||||
|
|
||||||
|
source.append("}")
|
||||||
|
|
||||||
|
source.append("")
|
||||||
|
source.append("}")
|
||||||
|
|
||||||
|
|
||||||
|
return "\n".join(source)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,5 +21,7 @@
|
||||||
#include "Vector2.hpp"
|
#include "Vector2.hpp"
|
||||||
#include "Vector3.hpp"
|
#include "Vector3.hpp"
|
||||||
|
|
||||||
|
#include "Wrapped.hpp"
|
||||||
|
|
||||||
|
|
||||||
#endif // CORETYPES_H
|
#endif // CORETYPES_H
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "CoreTypes.hpp"
|
#include "CoreTypes.hpp"
|
||||||
#include "Variant.hpp"
|
#include "Variant.hpp"
|
||||||
#include "Ref.hpp"
|
#include "Ref.hpp"
|
||||||
|
#include "TagDB.hpp"
|
||||||
|
|
||||||
#include "Object.hpp"
|
#include "Object.hpp"
|
||||||
|
|
||||||
|
@ -23,7 +24,7 @@ namespace godot {
|
||||||
|
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
T *as(Object *obj)
|
T *as(const Object *obj)
|
||||||
{
|
{
|
||||||
return (T *) godot::nativescript_api->godot_nativescript_get_userdata(obj->_owner);
|
return (T *) godot::nativescript_api->godot_nativescript_get_userdata(obj->_owner);
|
||||||
}
|
}
|
||||||
|
@ -37,9 +38,12 @@ T *get_wrapper(godot_object *obj)
|
||||||
|
|
||||||
#define GODOT_CLASS(Name, Base) \
|
#define GODOT_CLASS(Name, Base) \
|
||||||
public: inline static const char *___get_type_name() { return static_cast<const char *>(#Name); } \
|
public: inline static const char *___get_type_name() { return static_cast<const char *>(#Name); } \
|
||||||
|
enum { ___CLASS_IS_SCRIPT = 1, }; \
|
||||||
inline static Name *_new() { godot::NativeScript *script = godot::NativeScript::_new(); script->set_library(godot::get_wrapper<godot::GDNativeLibrary>((godot_object *) godot::gdnlib)); script->set_class_name(#Name); Name *instance = godot::as<Name>(script->new_()); return instance; } \
|
inline static Name *_new() { godot::NativeScript *script = godot::NativeScript::_new(); script->set_library(godot::get_wrapper<godot::GDNativeLibrary>((godot_object *) godot::gdnlib)); script->set_class_name(#Name); Name *instance = godot::as<Name>(script->new_()); return instance; } \
|
||||||
inline static const char *___get_base_type_name() { return Base::___get_class_name(); } \
|
inline static const char *___get_base_type_name() { return Base::___get_class_name(); } \
|
||||||
inline static Object *___get_from_variant(godot::Variant a) { return (godot::Object *) godot::as<Name>(godot::Object::___get_from_variant(a)); } \
|
inline static Object *___get_from_variant(godot::Variant a) { return (godot::Object *) godot::as<Name>(godot::Object::___get_from_variant(a)); } \
|
||||||
|
inline static void *___get_type_tag() { return (void *) &Name::___get_type_tag; } \
|
||||||
|
inline static void *___get_base_type_tag() { return (void *) &Base::___get_type_tag; } \
|
||||||
private:
|
private:
|
||||||
|
|
||||||
#define GODOT_SUBCLASS(Name, Base) \
|
#define GODOT_SUBCLASS(Name, Base) \
|
||||||
|
@ -83,6 +87,7 @@ void *_godot_class_instance_func(godot_object *p, void *method_data)
|
||||||
{
|
{
|
||||||
T *d = new T();
|
T *d = new T();
|
||||||
d->_owner = p;
|
d->_owner = p;
|
||||||
|
d->_type_tag = T::___get_type_tag();
|
||||||
d->_init();
|
d->_init();
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
@ -104,8 +109,10 @@ void register_class()
|
||||||
godot_instance_destroy_func destroy = {};
|
godot_instance_destroy_func destroy = {};
|
||||||
destroy.destroy_func = _godot_class_destroy_func<T>;
|
destroy.destroy_func = _godot_class_destroy_func<T>;
|
||||||
|
|
||||||
|
_TagDB::register_type(T::___get_type_tag(), T::___get_base_type_tag());
|
||||||
|
|
||||||
godot::nativescript_api->godot_nativescript_register_class(godot::_RegisterState::nativescript_handle, T::___get_type_name(), T::___get_base_type_name(), create, destroy);
|
godot::nativescript_api->godot_nativescript_register_class(godot::_RegisterState::nativescript_handle, T::___get_type_name(), T::___get_base_type_name(), create, destroy);
|
||||||
|
godot::nativescript_1_1_api->godot_nativescript_set_type_tag(godot::_RegisterState::nativescript_handle, T::___get_type_name(), T::___get_type_tag());
|
||||||
T::_register_methods();
|
T::_register_methods();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,8 +125,10 @@ void register_tool_class()
|
||||||
godot_instance_destroy_func destroy = {};
|
godot_instance_destroy_func destroy = {};
|
||||||
destroy.destroy_func = _godot_class_destroy_func<T>;
|
destroy.destroy_func = _godot_class_destroy_func<T>;
|
||||||
|
|
||||||
|
_TagDB::register_type(T::___get_type_tag(), T::___get_base_type_tag());
|
||||||
|
|
||||||
godot::nativescript_api->godot_nativescript_register_tool_class(godot::_RegisterState::nativescript_handle, T::___get_type_name(), T::___get_base_type_name(), create, destroy);
|
godot::nativescript_api->godot_nativescript_register_tool_class(godot::_RegisterState::nativescript_handle, T::___get_type_name(), T::___get_base_type_name(), create, destroy);
|
||||||
|
godot::nativescript_1_1_api->godot_nativescript_set_type_tag(godot::_RegisterState::nativescript_handle, T::___get_type_name(), T::___get_type_tag());
|
||||||
T::_register_methods();
|
T::_register_methods();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,6 +487,23 @@ void register_signal(String name, Args... varargs)
|
||||||
register_signal<T>(name, Dictionary::make(varargs...));
|
register_signal<T>(name, Dictionary::make(varargs...));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef GODOT_CPP_NO_OBJECT_CAST
|
||||||
|
template<class T>
|
||||||
|
T *Object::cast_to(const Object *obj)
|
||||||
|
{
|
||||||
|
if (godot::_TagDB::is_type_compatible(T::___get_type_tag(), obj->_type_tag)) {
|
||||||
|
return (T::___CLASS_IS_SCRIPT) ? godot::as<T>(obj) : (T *) obj;
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // GODOT_H
|
#endif // GODOT_H
|
||||||
|
|
|
@ -107,7 +107,7 @@ public:
|
||||||
void operator=(const Variant &p_variant) {
|
void operator=(const Variant &p_variant) {
|
||||||
|
|
||||||
// TODO We need a safe cast
|
// TODO We need a safe cast
|
||||||
Reference *refb = (Reference *) Object::___get_from_variant(p_variant);
|
Reference *refb = (Reference *) T::___get_from_variant(p_variant);
|
||||||
if (!refb) {
|
if (!refb) {
|
||||||
unref();
|
unref();
|
||||||
return;
|
return;
|
||||||
|
@ -156,7 +156,7 @@ public:
|
||||||
|
|
||||||
reference = nullptr;
|
reference = nullptr;
|
||||||
// TODO We need a safe cast
|
// TODO We need a safe cast
|
||||||
Reference *refb = (Reference *) Object::___get_from_variant(p_variant);
|
Reference *refb = (Reference *) T::___get_from_variant(p_variant);
|
||||||
if (!refb) {
|
if (!refb) {
|
||||||
unref();
|
unref();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef TAGDB_HPP
|
||||||
|
#define TAGDB_HPP
|
||||||
|
|
||||||
|
namespace godot {
|
||||||
|
|
||||||
|
namespace _TagDB {
|
||||||
|
|
||||||
|
void register_type(const void *type_tag, const void *base_type_tag);
|
||||||
|
void register_global_type(const char *name, const void *type_tag, const void *base_type_tag);
|
||||||
|
|
||||||
|
bool is_type_compatible(const void *type_tag, const void *base_type_tag);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // TAGDB_HPP
|
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef WRAPPED_HPP
|
||||||
|
#define WRAPPED_HPP
|
||||||
|
|
||||||
|
#include <gdnative/gdnative.h>
|
||||||
|
|
||||||
|
namespace godot {
|
||||||
|
|
||||||
|
class _Wrapped {
|
||||||
|
public:
|
||||||
|
godot_object *_owner;
|
||||||
|
const void *_type_tag;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // WRAPPED_HPP
|
|
@ -2,18 +2,18 @@
|
||||||
|
|
||||||
#include "String.hpp"
|
#include "String.hpp"
|
||||||
|
|
||||||
static GDCALLINGCONV void *wrapper_create(void *data, godot_object *instance)
|
#include "Wrapped.hpp"
|
||||||
|
|
||||||
|
static GDCALLINGCONV void *wrapper_create(void *data, const void *type_tag, godot_object *instance)
|
||||||
{
|
{
|
||||||
void *wrapper_memory = godot::api->godot_alloc(sizeof(instance));
|
godot::_Wrapped *wrapper_memory = (godot::_Wrapped *) godot::api->godot_alloc(sizeof(godot::_Wrapped));
|
||||||
|
|
||||||
if (!wrapper_memory)
|
if (!wrapper_memory)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
wrapper_memory->_owner = instance;
|
||||||
|
wrapper_memory->_type_tag = type_tag;
|
||||||
|
|
||||||
godot_object **wrapper = (godot_object **) wrapper_memory;
|
return (void *) wrapper_memory;
|
||||||
|
|
||||||
*wrapper = instance;
|
|
||||||
|
|
||||||
return wrapper;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GDCALLINGCONV void wrapper_destroy(void *data, void *wrapper)
|
static GDCALLINGCONV void wrapper_destroy(void *data, void *wrapper)
|
||||||
|
@ -71,6 +71,8 @@ void Godot::print_error(const String& description, const String& function, const
|
||||||
if (c_file != nullptr) godot::api->godot_free(c_file);
|
if (c_file != nullptr) godot::api->godot_free(c_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ___register_types();
|
||||||
|
|
||||||
void Godot::gdnative_init(godot_gdnative_init_options *options)
|
void Godot::gdnative_init(godot_gdnative_init_options *options)
|
||||||
{
|
{
|
||||||
godot::api = options->api_struct;
|
godot::api = options->api_struct;
|
||||||
|
@ -91,11 +93,12 @@ void Godot::gdnative_init(godot_gdnative_init_options *options)
|
||||||
|
|
||||||
extension = extension->next;
|
extension = extension->next;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
default: {
|
default: break;
|
||||||
}break;
|
}
|
||||||
};
|
}
|
||||||
};
|
|
||||||
|
___register_types();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Godot::gdnative_terminate(godot_gdnative_terminate_options *options)
|
void Godot::gdnative_terminate(godot_gdnative_terminate_options *options)
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
#include "TagDB.hpp"
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include <GodotGlobal.hpp>
|
||||||
|
|
||||||
|
namespace godot {
|
||||||
|
|
||||||
|
namespace _TagDB {
|
||||||
|
|
||||||
|
std::unordered_map<const void *, const void *> parent_to;
|
||||||
|
|
||||||
|
void register_type(const void *type_tag, const void *base_type_tag)
|
||||||
|
{
|
||||||
|
parent_to[type_tag] = base_type_tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_global_type(const char *name, const void *type_tag, const void *base_type_tag)
|
||||||
|
{
|
||||||
|
|
||||||
|
godot::nativescript_1_1_api->godot_nativescript_set_global_type_tag(godot::_RegisterState::language_index, name, type_tag);
|
||||||
|
|
||||||
|
register_type(type_tag, base_type_tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_type_compatible(const void *type_tag, const void *base_type_tag)
|
||||||
|
{
|
||||||
|
if (type_tag == nullptr || base_type_tag == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (type_tag == base_type_tag)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const void *tag = type_tag;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (tag == base_type_tag) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tag == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = parent_to[tag];
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue