Add GDExtension support to Script

* Ability to create script languages from GDExtension
* Some additions to gdnative_extension.h to make this happen
* Moved the GDExtension binder to core

This now allows creating scripting languages from GDExtension, with the same ease as if it was a module. It replaces the old PluginScript from Godot 3.x.
Warning: GodotCPP will need to be updated to support this (it may be a bit of work as ScriptInstance needs to be created over there again).
This commit is contained in:
reduz 2022-03-26 16:48:43 +01:00
parent a5eed70fa2
commit 360dea5348
38 changed files with 2019 additions and 267 deletions

View file

@ -2,6 +2,12 @@
Import("env")
import make_wrappers
from platform_methods import run_in_subprocess
env.CommandNoCache(["ext_wrappers.gen.inc"], "make_wrappers.py", run_in_subprocess(make_wrappers.run))
env_extension = env.Clone()
env_extension.add_source_files(env.core_sources, "*.cpp")

View file

@ -32,6 +32,7 @@
#include "core/config/engine.h"
#include "core/object/class_db.h"
#include "core/object/script_language_extension.h"
#include "core/os/memory.h"
#include "core/variant/variant.h"
#include "core/version.h"
@ -864,6 +865,13 @@ static GDObjectInstanceID gdnative_object_get_instance_id(const GDNativeObjectPt
return (GDObjectInstanceID)o->get_instance_id();
}
static GDNativeScriptInstancePtr gdnative_script_instance_create(const GDNativeExtensionScriptInstanceInfo *p_info, GDNativeExtensionScriptInstanceDataPtr p_instance_data) {
ScriptInstanceExtension *script_instance_extension = memnew(ScriptInstanceExtension);
script_instance_extension->instance = p_instance_data;
script_instance_extension->native_info = p_info;
return reinterpret_cast<GDNativeScriptInstancePtr>(script_instance_extension);
}
static GDNativeMethodBindPtr gdnative_classdb_get_method_bind(const char *p_classname, const char *p_methodname, GDNativeInt p_hash) {
MethodBind *mb = ClassDB::get_method(StringName(p_classname), StringName(p_methodname));
ERR_FAIL_COND_V(!mb, nullptr);
@ -1032,6 +1040,10 @@ void gdnative_setup_interface(GDNativeInterface *p_interface) {
gdni.object_get_instance_from_id = gdnative_object_get_instance_from_id;
gdni.object_get_instance_id = gdnative_object_get_instance_id;
/* SCRIPT INSTANCE */
gdni.script_instance_create = gdnative_script_instance_create;
/* CLASSDB */
gdni.classdb_construct_object = gdnative_classdb_construct_object;

View file

@ -205,6 +205,17 @@ typedef struct {
uint32_t usage;
} GDNativePropertyInfo;
typedef struct {
const char *name;
GDNativePropertyInfo return_value;
uint32_t flags; // From GDNativeExtensionClassMethodFlags
int32_t id;
GDNativePropertyInfo *arguments;
uint32_t argument_count;
GDNativeVariantPtr default_arguments;
uint32_t default_argument_count;
} GDNativeMethodInfo;
typedef const GDNativePropertyInfo *(*GDNativeExtensionClassGetPropertyList)(GDExtensionClassInstancePtr p_instance, uint32_t *r_count);
typedef void (*GDNativeExtensionClassFreePropertyList)(GDExtensionClassInstancePtr p_instance, const GDNativePropertyInfo *p_list);
typedef void (*GDNativeExtensionClassNotification)(GDExtensionClassInstancePtr p_instance, int32_t p_what);
@ -289,6 +300,79 @@ typedef struct {
GDNativeVariantPtr *default_arguments;
} GDNativeExtensionClassMethodInfo;
/* SCRIPT INSTANCE EXTENSION */
typedef void *GDNativeExtensionScriptInstanceDataPtr; // Pointer to custom ScriptInstance native implementation
typedef GDNativeBool (*GDNativeExtensionScriptInstanceSet)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name, const GDNativeVariantPtr p_value);
typedef GDNativeBool (*GDNativeExtensionScriptInstanceGet)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret);
typedef const GDNativePropertyInfo *(*GDNativeExtensionScriptInstanceGetPropertyList)(GDNativeExtensionScriptInstanceDataPtr p_instance, uint32_t *r_count);
typedef void (*GDNativeExtensionScriptInstanceFreePropertyList)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativePropertyInfo *p_list);
typedef GDNativeVariantType (*GDNativeExtensionScriptInstanceGetPropertyType)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name, GDNativeBool *r_is_valid);
typedef GDNativeObjectPtr (*GDNativeExtensionScriptInstanceGetOwner)(GDNativeExtensionScriptInstanceDataPtr p_instance);
typedef void (*GDNativeExtensionScriptInstancePropertyStateAdd)(const GDNativeStringNamePtr p_name, const GDNativeVariantPtr p_value, void *p_userdata);
typedef void (*GDNativeExtensionScriptInstanceGetPropertyState)(GDNativeExtensionScriptInstanceDataPtr p_instance, GDNativeExtensionScriptInstancePropertyStateAdd p_add_func, void *p_userdata);
typedef const GDNativeMethodInfo *(*GDNativeExtensionScriptInstanceGetMethodList)(GDNativeExtensionScriptInstanceDataPtr p_instance, uint32_t *r_count);
typedef void (*GDNativeExtensionScriptInstanceFreeMethodList)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeMethodInfo *p_list);
typedef GDNativeBool (*GDNativeExtensionScriptInstanceHasMethod)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name);
typedef void (*GDNativeExtensionScriptInstanceCall)(GDNativeExtensionScriptInstanceDataPtr p_self, const GDNativeStringNamePtr p_method, const GDNativeVariantPtr *p_args, const GDNativeInt p_argument_count, GDNativeVariantPtr r_return, GDNativeCallError *r_error);
typedef void (*GDNativeExtensionScriptInstanceNotification)(GDNativeExtensionScriptInstanceDataPtr p_instance, int32_t p_what);
typedef const char *(*GDNativeExtensionScriptInstanceToString)(GDNativeExtensionScriptInstanceDataPtr p_instance, GDNativeBool *r_is_valid);
typedef void (*GDNativeExtensionScriptInstanceRefCountIncremented)(GDNativeExtensionScriptInstanceDataPtr p_instance);
typedef GDNativeBool (*GDNativeExtensionScriptInstanceRefCountDecremented)(GDNativeExtensionScriptInstanceDataPtr p_instance);
typedef GDNativeObjectPtr (*GDNativeExtensionScriptInstanceGetScript)(GDNativeExtensionScriptInstanceDataPtr p_instance);
typedef GDNativeBool (*GDNativeExtensionScriptInstanceIsPlaceholder)(GDNativeExtensionScriptInstanceDataPtr p_instance);
typedef void *GDNativeExtensionScriptLanguagePtr;
typedef GDNativeExtensionScriptLanguagePtr (*GDNativeExtensionScriptInstanceGetLanguage)(GDNativeExtensionScriptInstanceDataPtr p_instance);
typedef void (*GDNativeExtensionScriptInstanceFree)(GDNativeExtensionScriptInstanceDataPtr p_instance);
typedef void *GDNativeScriptInstancePtr; // Pointer to ScriptInstance.
typedef struct {
GDNativeExtensionScriptInstanceSet set_func;
GDNativeExtensionScriptInstanceGet get_func;
GDNativeExtensionScriptInstanceGetPropertyList get_property_list_func;
GDNativeExtensionScriptInstanceFreePropertyList free_property_list_func;
GDNativeExtensionScriptInstanceGetPropertyType get_property_type_func;
GDNativeExtensionScriptInstanceGetOwner get_owner_func;
GDNativeExtensionScriptInstanceGetPropertyState get_property_state_func;
GDNativeExtensionScriptInstanceGetMethodList get_method_list_func;
GDNativeExtensionScriptInstanceFreeMethodList free_method_list_func;
GDNativeExtensionScriptInstanceHasMethod has_method_func;
GDNativeExtensionScriptInstanceCall call_func;
GDNativeExtensionScriptInstanceNotification notification_func;
GDNativeExtensionScriptInstanceToString to_string_func;
GDNativeExtensionScriptInstanceRefCountIncremented refcount_incremented_func;
GDNativeExtensionScriptInstanceRefCountDecremented refcount_decremented_func;
GDNativeExtensionScriptInstanceGetScript get_script_func;
GDNativeExtensionScriptInstanceIsPlaceholder is_placeholder_func;
GDNativeExtensionScriptInstanceSet set_fallback_func;
GDNativeExtensionScriptInstanceGet get_fallback_func;
GDNativeExtensionScriptInstanceGetLanguage get_language_func;
GDNativeExtensionScriptInstanceFree free_func;
} GDNativeExtensionScriptInstanceInfo;
/* INTERFACE */
typedef struct {
@ -441,6 +525,10 @@ typedef struct {
GDNativeObjectPtr (*object_get_instance_from_id)(GDObjectInstanceID p_instance_id);
GDObjectInstanceID (*object_get_instance_id)(const GDNativeObjectPtr p_object);
/* SCRIPT INSTANCE */
GDNativeScriptInstancePtr (*script_instance_create)(const GDNativeExtensionScriptInstanceInfo *p_info, GDNativeExtensionScriptInstanceDataPtr p_instance_data);
/* CLASSDB */
GDNativeObjectPtr (*classdb_construct_object)(const char *p_classname); /* The passed class must be a built-in godot class, or an already-registered extension class. In both case, object_set_instance should be called to fully initialize the object. */
GDNativeMethodBindPtr (*classdb_get_method_bind)(const char *p_classname, const char *p_methodname, GDNativeInt p_hash);

View file

@ -0,0 +1,93 @@
proto = """
#define EXBIND$VER($RETTYPE m_name$ARG) \\
GDVIRTUAL$VER($RETTYPE_##m_name$ARG)\\
virtual $RETVAL m_name($FUNCARGS) $CONST override { \\
$RETPRE\\
GDVIRTUAL_REQUIRED_CALL(_##m_name$CALLARGS$RETREF);\\
$RETPOST\\
}
"""
def generate_version(argcount, const=False, returns=False):
s = proto
sproto = str(argcount)
method_info = ""
if returns:
sproto += "R"
s = s.replace("$RETTYPE", "m_ret, ")
s = s.replace("$RETVAL", "m_ret")
s = s.replace("$RETPRE", "m_ret ret; ZeroInitializer<m_ret>::initialize(ret);\\\n")
s = s.replace("$RETPOST", "return ret;\\\n")
else:
s = s.replace("$RETTYPE", "")
s = s.replace("$RETVAL", "void")
s = s.replace("$RETPRE", "")
s = s.replace("$RETPOST", "return;")
if const:
sproto += "C"
s = s.replace("$CONST", "const")
else:
s = s.replace("$CONST", "")
s = s.replace("$VER", sproto)
argtext = ""
funcargs = ""
callargs = ""
for i in range(argcount):
if i > 0:
funcargs += ", "
argtext += ", m_type" + str(i + 1)
funcargs += "m_type" + str(i + 1) + " arg" + str(i + 1)
callargs += ", arg" + str(i + 1)
if argcount:
s = s.replace("$ARG", argtext)
s = s.replace("$FUNCARGS", funcargs)
s = s.replace("$CALLARGS", callargs)
else:
s = s.replace("$ARG", "")
s = s.replace("$FUNCARGS", funcargs)
s = s.replace("$CALLARGS", callargs)
if returns:
s = s.replace("$RETREF", ", ret")
else:
s = s.replace("$RETREF", "")
return s
def run(target, source, env):
max_versions = 12
txt = """
#ifndef GDEXTENSION_WRAPPERS_GEN_H
#define GDEXTENSION_WRAPPERS_GEN_H
"""
for i in range(max_versions + 1):
txt += "/* " + str(i) + " Arguments */\n\n"
txt += generate_version(i, False, False)
txt += generate_version(i, False, True)
txt += generate_version(i, True, False)
txt += generate_version(i, True, True)
txt += "#endif"
with open(target[0], "w") as f:
f.write(txt)
if __name__ == "__main__":
from platform_methods import subprocess_main
subprocess_main(globals())