class ClassDB: _instance = lib.godot_global_get_singleton(b"ClassDB") _meth_instance = lib.godot_method_bind_get_method(b"_ClassDB", b"instance") _meth_get_class_list = lib.godot_method_bind_get_method( b"_ClassDB", b"get_class_list") _meth_get_method_list = lib.godot_method_bind_get_method( b"_ClassDB", b"class_get_method_list") _meth_get_parent_class = lib.godot_method_bind_get_method( b"_ClassDB", b"get_parent_class") _meth_get_property_list = lib.godot_method_bind_get_method( b"_ClassDB", b"class_get_property_list") _meth_get_property = lib.godot_method_bind_get_method( b"_ClassDB", b"class_get_property") _meth_set_property = lib.godot_method_bind_get_method( b"_ClassDB", b"class_set_property") _meth_get_integer_constant_list = lib.godot_method_bind_get_method( b"_ClassDB", b"class_get_integer_constant_list") _meth_get_integer_constant = lib.godot_method_bind_get_method( b"_ClassDB", b"class_get_integer_constant") @classmethod def get_class_list(cls): ret = godot_pool_string_array_alloc() lib.godot_method_bind_ptrcall(cls._meth_get_class_list, cls._instance, ffi.NULL, ret) # Convert Godot return into Python civilized stuff unordered = [] for i in range(lib.godot_pool_string_array_size(ret)): godot_str = lib.godot_pool_string_array_get(ret, i) raw_str = lib.godot_string_wide_str(ffi.addressof(godot_str)) unordered.append(ffi.string(raw_str)) # Order class to have a parent defined before their children classes = [] while len(unordered) != len(classes): for classname in unordered: parentname = cls.get_parent_class(classname) if not parentname or parentname in classes: if classname not in classes: classes.append(classname) return classes @classmethod def get_class_constructor(cls, classname): def constructor(self): gd_classname = godot_string_from_pyobj(classname) # TODO: alloc this on the stack (using _malloca ?) args = ffi.new("void*[]", [gd_classname]) ret = godot_variant_alloc() lib.godot_method_bind_ptrcall(cls._meth_instance, cls._instance, args, ret) objret = lib.godot_variant_as_object(ret) # Quick'n dirty fix to prevent Ressource objects from beeing automatically # freed when the variant is destroyed given it holds the only ref on it self._gd_var = ret return objret return constructor @classmethod def get_class_methods(cls, classname): methods = [] ret = godot_array_alloc() lib.godot_array_new(ret) gd_classname = godot_string_from_pyobj(classname) gd_true = godot_bool_alloc(True) args = ffi.new("void*[2]", [gd_classname, gd_true]) # 2nd arg should be false, which is what we get by not initializing it lib.godot_method_bind_ptrcall(cls._meth_get_method_list, cls._instance, args, ret) for i in range(lib.godot_array_size(ret)): var = lib.godot_array_get(ret, i) gddict = lib.godot_variant_as_dictionary(ffi.addressof(var)) methdict = Dictionary.build_from_gdobj(gddict) methods.append(methdict) return methods @classmethod def build_property_getset(cls, prop): propname = prop['name'] gd_propname = godot_string_from_pyobj(propname) def getter(self): ret = godot_variant_alloc() lib.godot_variant_new_nil(ret) args = ffi.new("void*[]", [self._gd_ptr, gd_propname]) lib.godot_method_bind_ptrcall(cls._meth_get_property, cls._instance, args, ret) return variant_to_pyobj(ret) def setter(self, value): gd_value = pyobj_to_variant(value) args = ffi.new("void*[]", [self._gd_ptr, gd_propname, gd_value]) ret = godot_variant_alloc() lib.godot_variant_new_nil(ret) lib.godot_method_bind_ptrcall(cls._meth_set_property, cls._instance, args, ret) return variant_to_pyobj(ret) return getter, setter @classmethod def get_class_properties(cls, classname): properties = [] ret = godot_array_alloc() lib.godot_array_new(ret) gd_classname = godot_string_from_pyobj(classname) gd_true = godot_bool_alloc(True) args = ffi.new("void*[2]", [gd_classname, gd_true]) # 2nd arg should be false, which what we get by not initializing it lib.godot_method_bind_ptrcall(cls._meth_get_property_list, cls._instance, args, ret) for i in range(lib.godot_array_size(ret)): var = lib.godot_array_get(ret, i) gddict = lib.godot_variant_as_dictionary(ffi.addressof(var)) propdict = Dictionary.build_from_gdobj(gddict) properties.append(propdict) return properties @classmethod def get_class_consts(cls, classname): consts = [] ret = godot_pool_string_array_alloc() lib.godot_pool_string_array_new(ret) gd_classname = godot_string_from_pyobj(classname) gd_true = godot_bool_alloc(True) args = ffi.new("void*[2]", [gd_classname, gd_true]) # 2nd arg should be false, which what we get by not initializing it lib.godot_method_bind_ptrcall(cls._meth_get_integer_constant_list, cls._instance, args, ret) for i in range(lib.godot_pool_string_array_size(ret)): godot_str = lib.godot_pool_string_array_get(ret, i) raw_str = lib.godot_string_wide_str(ffi.addressof(godot_str)) consts.append(ffi.string(raw_str)) return consts @classmethod def get_integer_constant(cls, classname, constname): ret = godot_int_alloc() gd_classname = godot_string_from_pyobj(classname) gd_constname = godot_string_from_pyobj(constname) args = ffi.new("void*[2]", [gd_classname, gd_constname]) # 2nd arg should be false, which what we get by not initializing it lib.godot_method_bind_ptrcall(cls._meth_get_integer_constant, cls._instance, args, ret) return int(ret[0]) @classmethod def get_parent_class(cls, classname): ret = godot_string_alloc() lib.godot_string_new(ret) gd_classname = godot_string_from_pyobj(classname) args = ffi.new("godot_string**", gd_classname) lib.godot_method_bind_ptrcall(cls._meth_get_parent_class, cls._instance, ffi.cast("void**", args), ret) raw_str = lib.godot_string_wide_str(ret) return ffi.string(raw_str)
def build_global(godot_bindings_module, name, clsname): return getattr(godot_bindings_module, clsname)(lib.godot_global_get_singleton(name.encode()))