Skip to content

Commit

Permalink
Structs can now be bound to ClassDB
Browse files Browse the repository at this point in the history
  • Loading branch information
nlupugla committed Sep 25, 2023
1 parent d1dc7b1 commit 57543b9
Show file tree
Hide file tree
Showing 11 changed files with 313 additions and 62 deletions.
42 changes: 42 additions & 0 deletions core/core_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1508,6 +1508,44 @@ StringName ClassDB::class_get_integer_constant_enum(const StringName &p_class, c
return ::ClassDB::get_integer_constant_enum(p_class, p_name, p_no_inheritance);
}

bool ClassDB::class_has_struct(const StringName &p_class, const StringName &p_struct, bool p_no_inheritance) const {
return ::ClassDB::has_struct(p_class, p_struct, p_no_inheritance);
}

TypedArray<Dictionary> ClassDB::class_get_struct_list(const StringName &p_class, bool p_no_inheritance) const {
List<StructInfo> structs;
TypedArray<Dictionary> ret;
::ClassDB::get_struct_list(p_class, &structs, p_no_inheritance);
for (const StructInfo &struct_info : structs) {
Dictionary struct_dict;
for (uint32_t i = 0; i < struct_info.count; i++) {
Dictionary member_dict;
member_dict[SNAME("name")] = struct_info.names[i];
member_dict[SNAME("type")] = struct_info.types[i];
member_dict[SNAME("class_name")] = struct_info.class_names[i];
member_dict[SNAME("default_value")] = struct_info.default_values[i];
struct_dict[struct_info.name] = member_dict;
}
ret.push_back(struct_dict);
}
return ret;
}

TypedArray<Dictionary> ClassDB::class_get_struct_members(const StringName &p_class, const StringName &p_struct, bool p_no_inheritance) const {
List<StructMember> members;
TypedArray<Dictionary> ret;
::ClassDB::get_struct_members(p_class, p_struct, &members, p_no_inheritance);
for (const StructMember &member : members) {
Dictionary dict;
dict[SNAME("name")] = member.name;
dict[SNAME("type")] = member.type;
dict[SNAME("class_name")] = member.class_name;
dict[SNAME("default_value")] = member.default_value;
ret.push_back(dict);
}
return ret;
}

bool ClassDB::is_class_enabled(StringName p_class) const {
return ::ClassDB::is_class_enabled(p_class);
}
Expand Down Expand Up @@ -1543,6 +1581,10 @@ void ClassDB::_bind_methods() {
::ClassDB::bind_method(D_METHOD("class_get_enum_constants", "class", "enum", "no_inheritance"), &ClassDB::class_get_enum_constants, DEFVAL(false));
::ClassDB::bind_method(D_METHOD("class_get_integer_constant_enum", "class", "name", "no_inheritance"), &ClassDB::class_get_integer_constant_enum, DEFVAL(false));

::ClassDB::bind_method(D_METHOD("class_has_struct", "class", "struct", "no_inheritance"), &ClassDB::class_has_struct, DEFVAL(false));
::ClassDB::bind_method(D_METHOD("class_get_struct_list", "class", "no_inheritance"), &ClassDB::class_get_struct_list, DEFVAL(false));
::ClassDB::bind_method(D_METHOD("class_get_struct_members", "class", "struct", "no_inheritance"), &ClassDB::class_get_struct_members, DEFVAL(false));

::ClassDB::bind_method(D_METHOD("is_class_enabled", "class"), &ClassDB::is_class_enabled);
}

Expand Down
4 changes: 4 additions & 0 deletions core/core_bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,10 @@ class ClassDB : public Object {
PackedStringArray class_get_enum_constants(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance = false) const;
StringName class_get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false) const;

bool class_has_struct(const StringName &p_class, const StringName &p_struct, bool p_no_inheritance = false) const;
TypedArray<Dictionary> class_get_struct_list(const StringName &p_class, bool p_no_inheritance = false) const;
TypedArray<Dictionary> class_get_struct_members(const StringName &p_class, const StringName &p_struct, bool p_no_inheritance = false) const;

bool is_class_enabled(StringName p_class) const;

ClassDB() {}
Expand Down
88 changes: 88 additions & 0 deletions core/object/class_db.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,8 @@ uint32_t ClassDB::get_api_hash(APIType p_api) {
hash = hash_murmur3_one_64(F.hint_string.hash(), hash);
hash = hash_murmur3_one_64(F.usage, hash);
}

// TODO: do I need to incorporate the structs into the hash?
}

hash = hash_fmix32(hash);
Expand Down Expand Up @@ -849,6 +851,83 @@ bool ClassDB::is_enum_bitfield(const StringName &p_class, const StringName &p_na
return false;
}

void ClassDB::bind_struct(const StringName &p_class, const StructInfo &p_info) {
OBJTYPE_WLOCK;

ClassInfo *type = classes.getptr(p_class);

ERR_FAIL_NULL(type);

if (type->struct_map.has(p_info.name)) {
ERR_FAIL();
}

type->struct_map.insert(p_info.name, p_info);
}

void ClassDB::get_struct_list(const StringName &p_class, List<StructInfo> *r_structs, bool p_no_inheritance) {
OBJTYPE_RLOCK;

ClassInfo *type = classes.getptr(p_class);

while (type) {
for (const KeyValue<StringName, StructInfo> &E : type->struct_map) {
r_structs->push_back(E.value);
}

if (p_no_inheritance) {
break;
}

type = type->inherits_ptr;
}
}

void ClassDB::get_struct_members(const StringName &p_class, const StringName &p_struct, List<StructMember> *r_members, bool p_no_inheritance) {
OBJTYPE_RLOCK;

ClassInfo *type = classes.getptr(p_class);

while (type) {
const StructInfo *struct_info = type->struct_map.getptr(p_struct);

if (struct_info) {
for (uint32_t i = 0; i < struct_info->count; i++) {
r_members->push_back(StructMember(
struct_info->names[i],
(Variant::Type)struct_info->types[i],
struct_info->class_names[i],
struct_info->default_values[i]));
}
}

if (p_no_inheritance) {
break;
}

type = type->inherits_ptr;
}
}

bool ClassDB::has_struct(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) {
OBJTYPE_RLOCK;

ClassInfo *type = classes.getptr(p_class);

while (type) {
if (type->struct_map.has(p_name)) {
return true;
}
if (p_no_inheritance) {
return false;
}

type = type->inherits_ptr;
}

return false;
}

void ClassDB::add_signal(const StringName &p_class, const MethodInfo &p_signal) {
OBJTYPE_WLOCK;

Expand Down Expand Up @@ -961,6 +1040,15 @@ void ClassDB::add_property_array(const StringName &p_class, const StringName &p_
type->property_list.push_back(PropertyInfo(Variant::NIL, p_path, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, p_array_element_prefix));
}

// TODO: This probably isn't right, I just copied the function above.
void ClassDB::add_property_struct(const StringName &p_class, const StringName &p_path, const String &p_array_element_prefix) {
OBJTYPE_WLOCK; // TODO: I'm not sure what this does but it's in the one above so I figure I need it
ClassInfo *type = classes.getptr(p_class);
ERR_FAIL_NULL(type);

type->property_list.push_back(PropertyInfo(Variant::NIL, p_path, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, p_array_element_prefix));
}

// NOTE: For implementation simplicity reasons, this method doesn't allow setters to have optional arguments at the end.
void ClassDB::add_property(const StringName &p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index) {
lock.read_lock();
Expand Down
12 changes: 12 additions & 0 deletions core/object/class_db.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
#include "core/object/method_bind.h"
#include "core/object/object.h"
#include "core/string/print_string.h"
// TODO: It would be nice to not have to include struct.h, but I seem to need it for HashMap<StringName, StructInfo>
#include "core/variant/struct.h"

// Makes callable_mp readily available in all classes connecting signals.
// Needs to come after method_bind and object have been included.
Expand Down Expand Up @@ -113,6 +115,7 @@ class ClassDB {
};

HashMap<StringName, EnumInfo> enum_map;
HashMap<StringName, StructInfo> struct_map;
HashMap<StringName, MethodInfo> signal_map;
List<PropertyInfo> property_list;
HashMap<StringName, PropertyInfo> property_map;
Expand Down Expand Up @@ -380,6 +383,7 @@ class ClassDB {
static void add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix = "", int p_indent_depth = 0);
static void add_property_array_count(const StringName &p_class, const String &p_label, const StringName &p_count_property, const StringName &p_count_setter, const StringName &p_count_getter, const String &p_array_element_prefix, uint32_t p_count_usage = PROPERTY_USAGE_DEFAULT);
static void add_property_array(const StringName &p_class, const StringName &p_path, const String &p_array_element_prefix);
static void add_property_struct(const StringName &p_class, const StringName &p_path, const String &p_array_element_prefix);
static void add_property(const StringName &p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index = -1);
static void set_property_default_value(const StringName &p_class, const StringName &p_name, const Variant &p_default);
static void add_linked_property(const StringName &p_class, const String &p_property, const String &p_linked_property);
Expand Down Expand Up @@ -418,6 +422,11 @@ class ClassDB {
static bool has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false);
static bool is_enum_bitfield(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false);

static void bind_struct(const StringName &p_class, const StructInfo &p_info);
static void get_struct_list(const StringName &p_class, List<StructInfo> *r_structs, bool p_no_inheritance = false);
static void get_struct_members(const StringName &p_class, const StringName &p_struct, List<StructMember> *r_members, bool p_no_inheritance = false);
static bool has_struct(const StringName &p_class, const StringName &p_struct, bool p_no_inheritance = false);

static void set_method_error_return_values(const StringName &p_class, const StringName &p_method, const Vector<Error> &p_values);
static Vector<Error> get_method_error_return_values(const StringName &p_class, const StringName &p_method);
static Variant class_get_default_property_value(const StringName &p_class, const StringName &p_property, bool *r_valid = nullptr);
Expand Down Expand Up @@ -455,6 +464,9 @@ class ClassDB {
#define BIND_CONSTANT(m_constant) \
::ClassDB::bind_integer_constant(get_class_static(), StringName(), #m_constant, m_constant);

#define BIND_STRUCT(m_struct) \
::ClassDB::bind_struct(get_class_static(), StructInfo(m_struct::get_name(), m_struct::member_count, m_struct::get_members()));

#ifdef DEBUG_METHODS_ENABLED

_FORCE_INLINE_ void errarray_add_str(Vector<Error> &arr) {
Expand Down
7 changes: 5 additions & 2 deletions core/object/object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "core/string/print_string.h"
#include "core/string/translation.h"
#include "core/templates/local_vector.h"
#include "core/variant/struct.h"
#include "core/variant/typed_array.h"

#ifdef DEBUG_ENABLED
Expand All @@ -63,7 +64,7 @@ struct _ObjectDebugLock {

#endif

STRUCT_LAYOUT(PropertyInfoLayout, 5,
STRUCT_LAYOUT(PropertyInfoLayout, "PropertyInfo", 5,
STRUCT_MEMBER("name", Variant::STRING),
STRUCT_MEMBER("type", Variant::INT),
STRUCT_MEMBER("hint", Variant::INT),
Expand Down Expand Up @@ -1004,7 +1005,7 @@ TypedArray<Dictionary> Object::_get_property_list_bind() const {
Struct<PropertyInfoLayout> Object::_get_property_struct(uint32_t p_index) const {
List<PropertyInfo> lpi;
get_property_list(&lpi);
return Struct<PropertyInfoLayout>((Variant) lpi[p_index]);
return Struct<PropertyInfoLayout>((Variant)lpi[p_index]);
}

TypedArray<Dictionary> Object::_get_method_list_bind() const {
Expand Down Expand Up @@ -1691,6 +1692,8 @@ void Object::_bind_methods() {
BIND_ENUM_CONSTANT(CONNECT_PERSIST);
BIND_ENUM_CONSTANT(CONNECT_ONE_SHOT);
BIND_ENUM_CONSTANT(CONNECT_REFERENCE_COUNTED);

BIND_STRUCT(PropertyInfoLayout);
}

void Object::set_deferred(const StringName &p_property, const Variant &p_value) {
Expand Down
6 changes: 4 additions & 2 deletions core/object/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
#include "core/templates/rb_map.h"
#include "core/templates/safe_refcount.h"
#include "core/variant/callable_bind.h"
#include "core/variant/struct.h"
#include "core/variant/variant.h"

template <typename T>
Expand Down Expand Up @@ -142,6 +141,8 @@ enum PropertyUsageFlags {
#define ADD_ARRAY_COUNT(m_label, m_count_property, m_count_property_setter, m_count_property_getter, m_prefix) ClassDB::add_property_array_count(get_class_static(), m_label, m_count_property, _scs_create(m_count_property_setter), _scs_create(m_count_property_getter), m_prefix)
#define ADD_ARRAY_COUNT_WITH_USAGE_FLAGS(m_label, m_count_property, m_count_property_setter, m_count_property_getter, m_prefix, m_property_usage_flags) ClassDB::add_property_array_count(get_class_static(), m_label, m_count_property, _scs_create(m_count_property_setter), _scs_create(m_count_property_getter), m_prefix, m_property_usage_flags)
#define ADD_ARRAY(m_array_path, m_prefix) ClassDB::add_property_array(get_class_static(), m_array_path, m_prefix)
// TODO: This probably doesn't work yet as is.
#define ADD_STRUCT(m_array_path, m_prefix) ClassDB::add_property_struct(get_class_static(), m_array_path, m_prefix)

// Helper macro to use with PROPERTY_HINT_ARRAY_TYPE for arrays of specific resources:
// PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, MAKE_RESOURCE_TYPE_HINT("Font")
Expand Down Expand Up @@ -592,8 +593,9 @@ class Object {
Connection(const Variant &p_variant);
};

// TODO: These methods are for testing purposes only and will be removed before release.
// TypedArray<Struct<PropertyInfoLayout>> _get_property_list_struct() const;
Struct<PropertyInfoLayout> _get_property_struct(uint32_t p_index) const;
Struct<PropertyInfoLayout> _get_property_struct(uint32_t p_index) const;

private:
#ifdef DEBUG_ENABLED
Expand Down
47 changes: 21 additions & 26 deletions core/variant/array.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "core/templates/vector.h"
#include "core/variant/callable.h"
#include "core/variant/dictionary.h"
#include "core/variant/struct.h"
#include "core/variant/variant.h"

class ArrayPrivate {
Expand All @@ -48,24 +49,21 @@ class ArrayPrivate {
Variant *read_only = nullptr; // If enabled, a pointer is used to a temporary value that is used to return read-only values.
ContainerTypeValidate typed;

/// structs

uint32_t struct_size = 0;
const StructMember *struct_members = nullptr;
StructInfo struct_info;

_FORCE_INLINE_ bool is_struct() const {
return struct_size > 0;
return struct_info.count > 0;
}

_FORCE_INLINE_ bool is_struct_array() const {
return struct_size > 0; // TODO: this seems fishy
return struct_info.count > 0; // TODO: this seems fishy
}

_FORCE_INLINE_ int32_t find_member_index(const StringName &p_member) const {
// TODO: is there a better way to do this than linear search?
for (uint32_t i = 0; i < struct_size; i++) {
if (p_member == struct_members[i].name) {
return (int32_t) i; // TODO: is this cast necessary?
for (uint32_t i = 0; i < struct_info.count; i++) {
if (p_member == struct_info.names[i]) {
return (int32_t)i; // TODO: is this cast necessary?
}
}
return -1;
Expand Down Expand Up @@ -469,7 +467,6 @@ const Variant &Array::get_named(const StringName &p_member) const {
return get(index);
}


Array Array::duplicate(bool p_deep) const {
return recursive_duplicate(p_deep, 0);
}
Expand Down Expand Up @@ -874,40 +871,38 @@ Array::Array(const Array &p_from) {
_ref(p_from);
}

Array::Array(const Array &p_from, const StructMember *p_members, uint32_t p_member_count) {
Array::Array(const Array &p_from, const StructInfo &p_info) {
_p = memnew(ArrayPrivate);
_p->refcount.init(); // TODO: should this be _ref(p_from)?
assign(p_from);
set_struct(p_members, p_member_count);
set_struct_info(p_info);
}

Array::Array(const StructMember *p_members, uint32_t p_member_count) {
Array::Array(const StructInfo &p_info) {
_p = memnew(ArrayPrivate);
_p->refcount.init();
set_struct(p_members, p_member_count);
set_struct_info(p_info);
}

void Array::set_struct(const StructMember *p_members, uint32_t p_member_count) {
void Array::set_struct_info(const StructInfo &p_info) {
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");
ERR_FAIL_COND_MSG(_p->is_struct(), "Array is a struct."); // TODO: better error message
ERR_FAIL_COND_MSG(_p->array.size() > 0, "Type can only be set when array is empty.");
ERR_FAIL_COND_MSG(_p->refcount.get() > 1, "Type can only be set when array has no more than one user.");
ERR_FAIL_COND_MSG(_p->typed.type != Variant::NIL, "Type can only be set once.");

// TODO: figure out what to do with this commented out section
// ERR_FAIL_COND_MSG(p_class_name != StringName() && p_type != Variant::OBJECT, "Class names can only be set for type OBJECT");
// Ref<Script> script = p_script;
// ERR_FAIL_COND_MSG(script.is_valid() && p_class_name == StringName(), "Script class can only be set together with base class name");
//
// _p->typed.type = Variant::Type(p_type);
// _p->typed.class_name = p_class_name;
// _p->typed.script = script;
_p->array.resize(p_member_count);
// ERR_FAIL_COND_MSG(p_class_name != StringName() && p_type != Variant::OBJECT, "Class names can only be set for type OBJECT");
// Ref<Script> script = p_script;
// ERR_FAIL_COND_MSG(script.is_valid() && p_class_name == StringName(), "Script class can only be set together with base class name");
//
// _p->typed.type = Variant::Type(p_type);
// _p->typed.class_name = p_class_name;
// _p->typed.script = script;
_p->array.resize(p_info.count);
_p->typed.where = "Struct";

_p->struct_members = p_members;
_p->struct_size = p_member_count;

_p->struct_info = p_info;
}

Array::Array() {
Expand Down
Loading

0 comments on commit 57543b9

Please sign in to comment.