def pybind_get_template_source_code(handle, class_name, base_class_name): class_name = godot_string_to_pyobj(class_name) or "MyExportedCls" base_class_name = godot_string_to_pyobj(base_class_name) src = """from godot import exposed, export from godot.bindings import * from godot.globals import * @exposed class %s(%s): # member variables here, example: a = export(int) b = export(str, default='foo') def _ready(self): \"\"\" Called every time the node is added to the scene. Initialization here. \"\"\" pass """ % ( class_name, base_class_name, ) return godot_string_from_pyobj_for_ffi_return(src)[0]
def pybind_instance_call_method(handle, p_method, p_args, p_argcount, r_error): instance = ffi.from_handle(handle) # TODO: improve this by using a dict lookup using string_name method = lib.godot_string_name_get_name(p_method) methname = godot_string_to_pyobj(ffi.addressof(method)) lib.godot_string_destroy(ffi.addressof(method)) try: meth = getattr(instance, methname) except AttributeError: r_error.error = lib.GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD # TODO: Keep this object cached instead of recreating everytime return pyobj_to_variant(None, for_ffi_return=True)[0] # print('[GD->PY] Calling %s on %s ==> %s' % (methname, instance, meth)) pyargs = [variant_to_pyobj(p_args[i]) for i in range(p_argcount)] try: pyret = meth(*pyargs) ret = pyobj_to_variant(pyret, for_ffi_return=True) r_error.error = lib.GODOT_CALL_ERROR_CALL_OK # print('[GD->PY] result: %s (%s)' % (pyret, ret[0])) return ret[0] except NotImplementedError: # print('[GD->PY] not implemented !') r_error.error = lib.GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD except TypeError: traceback.print_exc() # TODO: handle errors here r_error.error = lib.GODOT_CALL_ERROR_CALL_ERROR_INVALID_ARGUMENT r_error.argument = 1 r_error.expected = lib.GODOT_VARIANT_TYPE_NIL # Something bad occured, return a default None variant # TODO: Keep this object cached instead of recreating it everytime return pyobj_to_variant(None, for_ffi_return=True)[0]
def pybind_script_init(handle, path, source, r_error): path = godot_string_to_pyobj(path) if verbose: print("Loading python script from %s" % path) if not path.startswith("res://") or not path.rsplit( ".", 1)[-1] in ("py", "pyc", "pyo", "pyd"): print( "Bad python script path `%s`, must starts by `res://` and ends with `.py/pyc/pyo/pyd`" % path) r_error[0] = lib.GODOT_ERR_FILE_BAD_PATH return ffi.NULL # TODO: possible bug if res:// is not part of PYTHONPATH # Remove `res://`, `.py` and replace / by . modname = path[6:].rsplit(".", 1)[0].replace("/", ".") try: __import__(modname) # Force lazy loading of the module # TODO: make sure script reloading works cls = get_exposed_class_per_module(modname) except Exception: # If we are here it could be because the file doesn't exists # or (more possibly) the file content is not a valid python (or # miss an exposed class) print("Got exception loading %s (%s): %s" % (path, modname, traceback.format_exc())) r_error[0] = lib.GODOT_ERR_PARSE_ERROR # Obliged to return the structure, but no need in init it return ffi.new("godot_pluginscript_script_manifest*")[0] r_error[0] = lib.GODOT_OK return _build_script_manifest(cls)[0]
def pybind_make_function(handle, class_, name, args): args = PoolStringArray.build_from_gdobj(args, steal=True) name = godot_string_to_pyobj(name) src = ['def %s(' % name] src.append(', '.join([arg.split(':', 1)[0] for arg in args])) src.append('):\n pass') return ''.join(src)
def pybind_make_function(handle, class_, name, args): args = PoolStringArray.build_from_gdobj(args, steal=True) name = godot_string_to_pyobj(name) src = ["def %s(" % name] src.append(", ".join([arg.split(":", 1)[0] for arg in args])) src.append("):\n pass") return "".join(src)
def pybind_instance_get_prop(instance_handle, p_name, r_ret): instance = ffi.from_handle(instance_handle) try: name = godot_string_to_pyobj(p_name) pyret = getattr(instance, name) pyobj_to_variant(pyret, r_ret) return True except Exception: traceback.print_exc() return False
def pybind_instance_set_prop(instance_handle, p_name, p_value): instance = ffi.from_handle(instance_handle) try: pyval = variant_to_pyobj(p_value) name = godot_string_to_pyobj(p_name) # print('[GD->PY] Set %s to %s (%s)' % (name, pyval, p_value)) setattr(instance, name, pyval) return True except Exception: traceback.print_exc() return False
def pybind_auto_indent_code(handle, code, from_line, to_line): try: import autopep8 except ImportError: print("[Pythonscript] Auto indent requires module `autopep8`, " "install it with `pip install autopep8`") pycode = godot_string_to_pyobj(code).splitlines() before = '\n'.join(pycode[:from_line]) to_fix = '\n'.join(pycode[from_line:to_line]) after = '\n'.join(pycode[to_line:]) fixed = autopep8.fix_code(to_fix) final_code = '\n'.join((before, fixed, after)) # TODO: modify code instead of replace it when binding on godot_string # operation is available lib.godot_string_destroy(code) lib.godot_string_new_unicode_data(code, final_code, len(final_code))
def get_subname(self, idx): self._check_param_type("idx", idx, int) subname = lib.godot_node_path_get_subname(self._gd_ptr, idx) return godot_string_to_pyobj(ffi.addressof(subname))
def get_concatenated_subnames(self): concatenated = lib.godot_node_path_get_concatenated_subnames( self._gd_ptr) return godot_string_to_pyobj(ffi.addressof(concatenated))
def _string_gd_to_py(self, value): return godot_string_to_pyobj(ffi.addressof(value))
def to_json(self): raw = lib.godot_dictionary_to_json(self._gd_ptr) return godot_string_to_pyobj(ffi.addressof(raw))
def pybind_add_global_constant(handle, name, value): name = godot_string_to_pyobj(name) value = variant_to_pyobj(value) globals()[name] = value
def test_godot_string_to_pyobj(arg): gdstr = pyobj_to_gdobj(arg) ret_arg = godot_string_to_pyobj(gdstr) assert ret_arg == arg
def pybind_add_global_constant(handle, name, value): name = godot_string_to_pyobj(name) value = variant_to_pyobj(value) # Update `godot.globals` module here godot.globals.__dict__[name] = value