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.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):
|
||||
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
|
||||
if class_name != "Object" and class_name != "Reference":
|
||||
source.append("#include <core/Ref.hpp>")
|
||||
else:
|
||||
source.append("#include <TagDB.hpp>")
|
||||
|
||||
|
||||
included = []
|
||||
|
@ -100,7 +105,6 @@ def generate_class_header(used_classes, c):
|
|||
if c["base_class"] != "":
|
||||
source.append("#include \"" + strip_name(c["base_class"]) + ".hpp\"")
|
||||
|
||||
|
||||
|
||||
source.append("namespace godot {")
|
||||
source.append("")
|
||||
|
@ -118,18 +122,13 @@ def generate_class_header(used_classes, c):
|
|||
vararg_templates = ""
|
||||
|
||||
# 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"] == "":
|
||||
# this is Object
|
||||
source.append("public: enum { ___CLASS_IS_SCRIPT = 0, };")
|
||||
source.append("private:")
|
||||
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"]:
|
||||
source.append("\tstatic " + class_name + " *_singleton;")
|
||||
source.append("")
|
||||
|
@ -140,6 +139,10 @@ def generate_class_header(used_classes, c):
|
|||
source.append("public:")
|
||||
source.append("")
|
||||
|
||||
source.append("\tstatic void *___get_type_tag();")
|
||||
source.append("\tstatic void *___get_base_type_tag();")
|
||||
|
||||
|
||||
if c["singleton"]:
|
||||
source.append("\tstatic inline " + class_name + " *get_singleton()")
|
||||
source.append("\t{")
|
||||
|
@ -180,6 +183,14 @@ def generate_class_header(used_classes, c):
|
|||
source.append("\tstatic " + class_name + " *_new();")
|
||||
|
||||
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"]:
|
||||
|
||||
|
@ -264,11 +275,10 @@ def generate_class_header(used_classes, c):
|
|||
source.append("")
|
||||
|
||||
|
||||
|
||||
source.append("}")
|
||||
source.append("")
|
||||
|
||||
|
||||
|
||||
source.append("#endif")
|
||||
|
||||
|
||||
|
@ -314,6 +324,21 @@ def generate_class_implementation(icalls, used_classes, c):
|
|||
|
||||
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"]:
|
||||
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 "Vector3.hpp"
|
||||
|
||||
#include "Wrapped.hpp"
|
||||
|
||||
|
||||
#endif // CORETYPES_H
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "CoreTypes.hpp"
|
||||
#include "Variant.hpp"
|
||||
#include "Ref.hpp"
|
||||
#include "TagDB.hpp"
|
||||
|
||||
#include "Object.hpp"
|
||||
|
||||
|
@ -23,7 +24,7 @@ namespace godot {
|
|||
|
||||
|
||||
template<class T>
|
||||
T *as(Object *obj)
|
||||
T *as(const Object *obj)
|
||||
{
|
||||
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) \
|
||||
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 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 void *___get_type_tag() { return (void *) &Name::___get_type_tag; } \
|
||||
inline static void *___get_base_type_tag() { return (void *) &Base::___get_type_tag; } \
|
||||
private:
|
||||
|
||||
#define GODOT_SUBCLASS(Name, Base) \
|
||||
|
@ -83,6 +87,7 @@ void *_godot_class_instance_func(godot_object *p, void *method_data)
|
|||
{
|
||||
T *d = new T();
|
||||
d->_owner = p;
|
||||
d->_type_tag = T::___get_type_tag();
|
||||
d->_init();
|
||||
return d;
|
||||
}
|
||||
|
@ -104,8 +109,10 @@ void register_class()
|
|||
godot_instance_destroy_func destroy = {};
|
||||
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_1_1_api->godot_nativescript_set_type_tag(godot::_RegisterState::nativescript_handle, T::___get_type_name(), T::___get_type_tag());
|
||||
T::_register_methods();
|
||||
}
|
||||
|
||||
|
@ -118,8 +125,10 @@ void register_tool_class()
|
|||
godot_instance_destroy_func destroy = {};
|
||||
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_1_1_api->godot_nativescript_set_type_tag(godot::_RegisterState::nativescript_handle, T::___get_type_name(), T::___get_type_tag());
|
||||
T::_register_methods();
|
||||
}
|
||||
|
||||
|
@ -478,6 +487,23 @@ void register_signal(String name, Args... 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
|
||||
|
|
|
@ -107,7 +107,7 @@ public:
|
|||
void operator=(const Variant &p_variant) {
|
||||
|
||||
// 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) {
|
||||
unref();
|
||||
return;
|
||||
|
@ -156,7 +156,7 @@ public:
|
|||
|
||||
reference = nullptr;
|
||||
// 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) {
|
||||
unref();
|
||||
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"
|
||||
|
||||
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)
|
||||
return NULL;
|
||||
wrapper_memory->_owner = instance;
|
||||
wrapper_memory->_type_tag = type_tag;
|
||||
|
||||
godot_object **wrapper = (godot_object **) wrapper_memory;
|
||||
|
||||
*wrapper = instance;
|
||||
|
||||
return wrapper;
|
||||
return (void *) wrapper_memory;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void ___register_types();
|
||||
|
||||
void Godot::gdnative_init(godot_gdnative_init_options *options)
|
||||
{
|
||||
godot::api = options->api_struct;
|
||||
|
@ -91,11 +93,12 @@ void Godot::gdnative_init(godot_gdnative_init_options *options)
|
|||
|
||||
extension = extension->next;
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
}break;
|
||||
};
|
||||
};
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
___register_types();
|
||||
}
|
||||
|
||||
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