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])
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 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
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
def pybind_profiling_get_frame_data(handle, info, info_max): print('get_frame_data') # Sort function to make sure we can display the most consuming ones sorted_and_limited = sorted( profiler.per_meth_profiling.items(), key=lambda x: -x[1].last_frame_self_time)[:info_max] for i, item in enumerate(sorted_and_limited): signature, profile = item # TODO: should be able to use lib.godot_string_new_with_wide_string directly lib.godot_string_name_new(ffi.addressof(info[i].signature), godot_string_from_pyobj(signature)) info[i].call_count = profile.last_frame_call_count info[i].total_time = int(profile.last_frame_total_time * 1e6) info[i].self_time = int(profile.last_frame_self_time * 1e6) return len(sorted_and_limited)
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
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
def flush(self): if self.buffer: g_b = godot_string_from_pyobj(self.buffer) self.godot_func(g_b) self.buffer = ""
def write(self, b): self.buffer += b if "\n" in self.buffer: *to_print, self.buffer = self.buffer.split("\n") g_b = godot_string_from_pyobj("\n".join(to_print)) self.godot_func(g_b)
def write(self, b): self.buffer += b if '\n' in self.buffer: *to_print, self.buffer = self.buffer.split('\n') g_b = godot_string_from_pyobj('\n'.join(to_print)) self.godot_func(g_b)
def _build_script_manifest(cls): def _build_signal_info(signal): methinfo = Dictionary() methinfo["name"] = signal.name # Dummy data, only name is important here methinfo["args"] = Array() methinfo["default_args"] = Array() methinfo["return"] = None methinfo["flags"] = lib.METHOD_FLAG_FROM_SCRIPT return methinfo def _build_method_info(meth, methname): spec = inspect.getfullargspec(meth) methinfo = Dictionary() methinfo["name"] = methname # TODO: Handle classmethod/staticmethod methinfo["args"] = Array(spec.args) methinfo["default_args"] = Array() # TODO # TODO: use annotation to determine return type ? methinfo["return"] = None methinfo["flags"] = lib.METHOD_FLAG_FROM_SCRIPT methinfo["rpc_mode"] = getattr(meth, "__rpc", lib.GODOT_METHOD_RPC_MODE_DISABLED) return methinfo def _build_property_info(prop): propinfo = Dictionary() propinfo["name"] = prop.name propinfo["type"] = py_to_gd_type(prop.type) propinfo["hint"] = prop.hint propinfo["hint_string"] = prop.hint_string propinfo["usage"] = prop.usage propinfo["default_value"] = prop.default propinfo["rset_mode"] = prop.rpc return propinfo manifest = ffi.new("godot_pluginscript_script_manifest*") manifest.data = connect_handle(cls) # TODO: should be able to use lib.godot_string_new_with_wide_string directly gdname = godot_string_from_pyobj(cls.__name__) lib.godot_string_name_new(ffi.addressof(manifest.name), gdname) if cls.__bases__: # Only one Godot parent class (checked at class definition time) godot_parent_class = next( (b for b in cls.__bases__ if issubclass(b, BaseObject))) if godot_parent_class.__dict__.get("__is_godot_native_class"): path = godot_parent_class.__name__ else: # Pluginscript wants us to return the parent as a path path = "res://%s.py" % "/".join( cls.__bases__[0].__module__.split(".")) gdbase = godot_string_from_pyobj(path) lib.godot_string_name_new(ffi.addressof(manifest.base), gdbase) manifest.is_tool = cls.__tool lib.godot_dictionary_new(ffi.addressof(manifest.member_lines)) lib.godot_array_new(ffi.addressof(manifest.methods)) methods = Array() # TODO: include inherited in exposed methods ? Expose Godot base class' ones ? # for methname in vars(cls): for methname in dir(cls): meth = getattr(cls, methname) if not inspect.isfunction(meth) or meth.__name__.startswith("__"): continue methinfo = _build_method_info(meth, methname) methods.append(methinfo) signals = Array() for signal in cls.__signals.values(): signalinfo = _build_signal_info(signal) signals.append(signalinfo) properties = Array() for prop in cls.__exported.values(): property_info = _build_property_info(prop) properties.append(property_info) lib.godot_array_new_copy(ffi.addressof(manifest.methods), methods._gd_ptr) lib.godot_array_new_copy(ffi.addressof(manifest.signals), signals._gd_ptr) lib.godot_array_new_copy(ffi.addressof(manifest.properties), properties._gd_ptr) return manifest