Implement native extension system

* Deprecates GDNative in favor of a simpler, lower level interface.
* New extension system allows registering core engine classes.
* Simple header interface in gdnative_interace.h
This commit is contained in:
reduz 2021-06-19 12:58:49 -03:00
parent c8444c3ee0
commit b1d15c51bc
50 changed files with 3316 additions and 224 deletions

View File

@ -186,6 +186,7 @@ SConscript("io/SCsub")
SConscript("debugger/SCsub")
SConscript("input/SCsub")
SConscript("variant/SCsub")
SConscript("extension/SCsub")
SConscript("object/SCsub")
SConscript("templates/SCsub")
SConscript("string/SCsub")

View File

@ -236,9 +236,10 @@ Engine::Engine() {
singleton = this;
}
Engine::Singleton::Singleton(const StringName &p_name, Object *p_ptr) :
Engine::Singleton::Singleton(const StringName &p_name, Object *p_ptr, const StringName &p_class_name) :
name(p_name),
ptr(p_ptr) {
ptr(p_ptr),
class_name(p_class_name) {
#ifdef DEBUG_ENABLED
RefCounted *rc = Object::cast_to<RefCounted>(p_ptr);
if (rc && !rc->is_referenced()) {

View File

@ -41,7 +41,8 @@ public:
struct Singleton {
StringName name;
Object *ptr;
Singleton(const StringName &p_name = StringName(), Object *p_ptr = nullptr);
StringName class_name; //used for binding generation hinting
Singleton(const StringName &p_name = StringName(), Object *p_ptr = nullptr, const StringName &p_class_name = StringName());
};
private:

7
core/extension/SCsub Normal file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env python
Import("env")
env_extension = env.Clone()
env_extension.add_source_files(env.core_sources, "*.cpp")

View File

@ -0,0 +1,805 @@
/*************************************************************************/
/* extension_api_dump.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "extension_api_dump.h"
#include "core/config/engine.h"
#include "core/core_constants.h"
#include "core/io/file_access.h"
#include "core/io/json.h"
#include "core/templates/pair.h"
#include "core/version.h"
#ifdef TOOLS_ENABLED
Dictionary NativeExtensionAPIDump::generate_extension_api() {
Dictionary api_dump;
{
//header
Dictionary header;
header["version_major"] = VERSION_MAJOR;
header["version_minor"] = VERSION_MINOR;
#if VERSION_PATCH
header["version_patch"] = VERSION_PATCH;
#else
header["version_patch"] = 0;
#endif
header["version_status"] = VERSION_STATUS;
header["version_build"] = VERSION_BUILD;
header["version_full_name"] = VERSION_FULL_NAME;
api_dump["header"] = header;
}
const uint32_t vec3_elems = 3;
const uint32_t ptrsize_32 = 4;
const uint32_t ptrsize_64 = 4;
static const char *build_config_name[4] = { "float_32", "float_64", "double_32", "double_64" };
{
//type sizes
struct {
Variant::Type type;
uint32_t size_32_bits_real_float;
uint32_t size_64_bits_real_float;
uint32_t size_32_bits_real_double;
uint32_t size_64_bits_real_double;
} type_size_array[Variant::VARIANT_MAX + 1] = {
{ Variant::NIL, 0, 0, 0, 0 },
{ Variant::BOOL, sizeof(uint32_t), sizeof(uint32_t), sizeof(uint32_t), sizeof(uint32_t) },
{ Variant::INT, sizeof(int64_t), sizeof(int64_t), sizeof(int64_t), sizeof(int64_t) },
{ Variant::FLOAT, sizeof(double), sizeof(double), sizeof(double), sizeof(double) },
{ Variant::STRING, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
{ Variant::VECTOR2, 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) },
{ Variant::VECTOR2I, 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t) },
{ Variant::RECT2, 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(double), 4 * sizeof(double) },
{ Variant::RECT2I, 4 * sizeof(int32_t), 4 * sizeof(int32_t), 4 * sizeof(int32_t), 4 * sizeof(int32_t) },
{ Variant::VECTOR3, vec3_elems * sizeof(float), vec3_elems * sizeof(float), vec3_elems * sizeof(double), vec3_elems * sizeof(double) },
{ Variant::VECTOR3I, 3 * sizeof(int32_t), 3 * sizeof(int32_t), 3 * sizeof(int32_t), 3 * sizeof(int32_t) },
{ Variant::TRANSFORM2D, 6 * sizeof(float), 6 * sizeof(float), 6 * sizeof(double), 6 * sizeof(double) },
{ Variant::PLANE, (vec3_elems + 1) * sizeof(float), (vec3_elems + 1) * sizeof(float), (vec3_elems + 1) * sizeof(double), (vec3_elems + 1) * sizeof(double) },
{ Variant::QUATERNION, 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(double), 4 * sizeof(double) },
{ Variant::AABB, (vec3_elems * 2) * sizeof(float), (vec3_elems * 2) * sizeof(float), (vec3_elems * 2) * sizeof(double), (vec3_elems * 2) * sizeof(double) },
{ Variant::BASIS, (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(double), (vec3_elems * 3) * sizeof(double) },
{ Variant::TRANSFORM3D, (vec3_elems * 4) * sizeof(float), (vec3_elems * 4) * sizeof(float), (vec3_elems * 4) * sizeof(double), (vec3_elems * 4) * sizeof(double) },
{ Variant::COLOR, 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(float) },
{ Variant::STRING_NAME, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
{ Variant::NODE_PATH, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
{ Variant::RID, sizeof(uint64_t), sizeof(uint64_t), sizeof(uint64_t), sizeof(uint64_t) },
{ Variant::OBJECT, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
{ Variant::CALLABLE, sizeof(Callable), sizeof(Callable), sizeof(Callable), sizeof(Callable) }, //harcoded align
{ Variant::SIGNAL, sizeof(Signal), sizeof(Signal), sizeof(Signal), sizeof(Signal) }, //harcoded align
{ Variant::DICTIONARY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
{ Variant::ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
{ Variant::PACKED_BYTE_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
{ Variant::PACKED_INT32_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
{ Variant::PACKED_INT64_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
{ Variant::PACKED_FLOAT32_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
{ Variant::PACKED_FLOAT64_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
{ Variant::PACKED_STRING_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
{ Variant::PACKED_VECTOR2_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
{ Variant::PACKED_VECTOR3_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
{ Variant::PACKED_COLOR_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
{ Variant::VARIANT_MAX, sizeof(uint64_t) + sizeof(float) * 4, sizeof(uint64_t) + sizeof(float) * 4, sizeof(uint64_t) + sizeof(double) * 4, sizeof(uint64_t) + sizeof(double) * 4 },
};
Array core_type_sizes;
for (int i = 0; i < 4; i++) {
Dictionary d;
d["build_configuration"] = build_config_name[i];
Array sizes;
for (int j = 0; j < Variant::VARIANT_MAX; j++) {
Variant::Type t = type_size_array[j].type;
String name = t == Variant::VARIANT_MAX ? String("Variant") : Variant::get_type_name(t);
Dictionary d2;
d2["name"] = name;
uint32_t size;
switch (i) {
case 0:
size = type_size_array[j].size_32_bits_real_float;
break;
case 1:
size = type_size_array[j].size_64_bits_real_float;
break;
case 2:
size = type_size_array[j].size_32_bits_real_double;
break;
case 3:
size = type_size_array[j].size_64_bits_real_double;
break;
}
d2["size"] = size;
sizes.push_back(d2);
}
d["sizes"] = sizes;
core_type_sizes.push_back(d);
}
api_dump["builtin_class_sizes"] = core_type_sizes;
}
{
//member offsets sizes
struct {
Variant::Type type;
const char *member;
uint32_t offset_32_bits_real_float;
uint32_t offset_64_bits_real_float;
uint32_t offset_32_bits_real_double;
uint32_t offset_64_bits_real_double;
} member_offset_array[] = {
{ Variant::VECTOR2, "x", 0, 0, 0, 0 },
{ Variant::VECTOR2, "y", sizeof(float), sizeof(float), sizeof(double), sizeof(double) },
{ Variant::VECTOR2I, "x", 0, 0, 0, 0 },
{ Variant::VECTOR2I, "y", sizeof(int32_t), sizeof(int32_t), sizeof(int32_t), sizeof(int32_t) },
{ Variant::RECT2, "position", 0, 0, 0, 0 },
{ Variant::RECT2, "size", 2 * sizeof(Vector2), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) },
{ Variant::RECT2I, "position", 0, 0, 0, 0 },
{ Variant::RECT2I, "size", 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t) },
{ Variant::VECTOR3, "x", 0, 0, 0, 0 },
{ Variant::VECTOR3, "y", sizeof(float), sizeof(float), sizeof(double), sizeof(double) },
{ Variant::VECTOR3, "z", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) },
{ Variant::VECTOR3I, "x", 0, 0, 0, 0 },
{ Variant::VECTOR3I, "y", sizeof(int32_t), sizeof(int32_t), sizeof(int32_t), sizeof(int32_t) },
{ Variant::VECTOR3I, "z", 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t) },
{ Variant::TRANSFORM2D, "x", 0, 0, 0, 0 },
{ Variant::TRANSFORM2D, "y", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) },
{ Variant::TRANSFORM2D, "origin", 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(double), 4 * sizeof(double) },
{ Variant::PLANE, "normal", 0, 0, 0, 0 },
{ Variant::PLANE, "d", vec3_elems * sizeof(float), vec3_elems * sizeof(float), vec3_elems * sizeof(double), vec3_elems * sizeof(double) },
{ Variant::QUATERNION, "x", 0, 0, 0, 0 },
{ Variant::QUATERNION, "y", sizeof(float), sizeof(float), sizeof(double), sizeof(double) },
{ Variant::QUATERNION, "z", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) },
{ Variant::QUATERNION, "w", 3 * sizeof(float), 3 * sizeof(float), 3 * sizeof(double), 3 * sizeof(double) },
{ Variant::AABB, "position", 0, 0, 0, 0 },
{ Variant::AABB, "size", vec3_elems * sizeof(float), vec3_elems * sizeof(float), vec3_elems * sizeof(double), vec3_elems * sizeof(double) },
//rememer that basis vectors are flipped!
{ Variant::BASIS, "x", 0, 0, 0, 0 },
{ Variant::BASIS, "y", vec3_elems * sizeof(float), vec3_elems * sizeof(float), vec3_elems * sizeof(double), vec3_elems * sizeof(double) },
{ Variant::BASIS, "z", vec3_elems * 2 * sizeof(float), vec3_elems * 2 * sizeof(float), vec3_elems * 2 * sizeof(double), vec3_elems * 2 * sizeof(double) },
{ Variant::TRANSFORM3D, "basis", 0, 0, 0, 0 },
{ Variant::TRANSFORM3D, "origin", (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(double), (vec3_elems * 3) * sizeof(double) },
{ Variant::COLOR, "x", 0, 0, 0, 0 },
{ Variant::COLOR, "y", sizeof(float), sizeof(float), sizeof(float), sizeof(float) },
{ Variant::COLOR, "z", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(float) },
{ Variant::COLOR, "w", 3 * sizeof(float), 3 * sizeof(float), 3 * sizeof(float), 3 * sizeof(float) },
{ Variant::NIL, nullptr, 0, 0, 0, 0 },
};
Array core_type_member_offsets;
for (int i = 0; i < 4; i++) {
Dictionary d;
d["build_configuration"] = build_config_name[i];
Array type_offsets;
uint32_t idx = 0;
Variant::Type last_type = Variant::NIL;
Dictionary d2;
Array members;
while (true) {
Variant::Type t = member_offset_array[idx].type;
if (t != last_type) {
if (last_type != Variant::NIL) {
d2["members"] = members;
type_offsets.push_back(d2);
}
if (t == Variant::NIL) {
break;
}
String name = t == Variant::VARIANT_MAX ? String("Variant") : Variant::get_type_name(t);
d2 = Dictionary();
members = Array();
d2["name"] = name;
last_type = t;
}
Dictionary d3;
uint32_t offset;
switch (i) {
case 0:
offset = member_offset_array[idx].offset_32_bits_real_float;
break;
case 1:
offset = member_offset_array[idx].offset_64_bits_real_float;
break;
case 2:
offset = member_offset_array[idx].offset_32_bits_real_double;
break;
case 3:
offset = member_offset_array[idx].offset_64_bits_real_double;
break;
}
d3["member"] = member_offset_array[idx].member;
d3["offset"] = offset;
members.push_back(d3);
idx++;
}
d["classes"] = type_offsets;
core_type_member_offsets.push_back(d);
}
api_dump["builtin_class_member_offsets"] = core_type_member_offsets;
}
{
// global enums and constants
Array constants;
Map<String, List<Pair<String, int>>> enum_list;
for (int i = 0; i < CoreConstants::get_global_constant_count(); i++) {
int value = CoreConstants::get_global_constant_value(i);
String enum_name = CoreConstants::get_global_constant_enum(i);
String name = CoreConstants::get_global_constant_name(i);
if (enum_name != String()) {
enum_list[enum_name].push_back(Pair<String, int>(name, value));
} else {
Dictionary d;
d["name"] = name;
d["value"] = value;
constants.push_back(d);
}
}
api_dump["global_constants"] = constants;
Array enums;
for (Map<String, List<Pair<String, int>>>::Element *E = enum_list.front(); E; E = E->next()) {
Dictionary d1;
d1["name"] = E->key();
Array values;
for (List<Pair<String, int>>::Element *F = E->get().front(); F; F = F->next()) {
Dictionary d2;
d2["name"] = F->get().first;
d2["value"] = F->get().second;
values.push_back(d2);
}
d1["values"] = values;
enums.push_back(d1);
}
api_dump["global_enums"] = enums;
}
{
Array utility_funcs;
List<StringName> utility_func_names;
Variant::get_utility_function_list(&utility_func_names);
for (List<StringName>::Element *E = utility_func_names.front(); E; E = E->next()) {
StringName name = E->get();
Dictionary func;
func["name"] = String(name);
if (Variant::has_utility_function_return_value(name)) {
Variant::Type rt = Variant::get_utility_function_return_type(name);
func["return_type"] = rt == Variant::NIL ? String("Variant") : Variant::get_type_name(rt);
}
switch (Variant::get_utility_function_type(name)) {
case Variant::UTILITY_FUNC_TYPE_MATH:
func["category"] = "math";
break;
case Variant::UTILITY_FUNC_TYPE_RANDOM:
func["category"] = "random";
break;
case Variant::UTILITY_FUNC_TYPE_GENERAL:
func["category"] = "general";
break;
}
bool vararg = Variant::is_utility_function_vararg(name);
func["is_vararg"] = Variant::is_utility_function_vararg(name);
func["hash"] = Variant::get_utility_function_hash(name);
Array arguments;
int argcount = Variant::get_utility_function_argument_count(name);
for (int i = 0; i < argcount; i++) {
Dictionary arg;
String argname = vararg ? "arg" + itos(i + 1) : Variant::get_utility_function_argument_name(name, i);
arg["name"] = argname;
Variant::Type argtype = Variant::get_utility_function_argument_type(name, i);
arg["type"] = argtype == Variant::NIL ? String("Variant") : Variant::get_type_name(argtype);
//no default value support in utility functions
arguments.push_back(arg);
}
if (arguments.size()) {
func["arguments"] = arguments;
}
utility_funcs.push_back(func);
}
api_dump["utility_functions"] = utility_funcs;
}
{
// builtin types
Array builtins;
for (int i = 0; i < Variant::VARIANT_MAX; i++) {
if (i == Variant::OBJECT) {
continue;
}
Variant::Type type = Variant::Type(i);
Dictionary d;
d["name"] = Variant::get_type_name(type);
if (Variant::has_indexing(type)) {
Variant::Type index_type = Variant::get_indexed_element_type(type);
d["indexing_return_type"] = index_type == Variant::NIL ? String("Variant") : Variant::get_type_name(index_type);
}
{
//members
Array members;
List<StringName> member_names;
Variant::get_member_list(type, &member_names);
for (List<StringName>::Element *E = member_names.front(); E; E = E->next()) {
StringName member_name = E->get();
Dictionary d2;
d2["name"] = String(member_name);
d2["type"] = Variant::get_type_name(Variant::get_member_type(type, member_name));
members.push_back(d2);
}
if (members.size()) {
d["members"] = members;
}
}
{
//constants
Array constants;
List<StringName> constant_names;
Variant::get_constants_for_type(type, &constant_names);
for (List<StringName>::Element *E = constant_names.front(); E; E = E->next()) {
StringName constant_name = E->get();
Dictionary d2;
d2["name"] = String(constant_name);
Variant constant = Variant::get_constant_value(type, constant_name);
d2["type"] = Variant::get_type_name(constant.get_type());
d2["value"] = constant.get_construct_string();
constants.push_back(d2);
}
if (constants.size()) {
d["constants"] = constants;
}
}
{
//operators
Array operators;
for (int j = 0; j < Variant::VARIANT_MAX; j++) {
for (int k = 0; k < Variant::OP_MAX; k++) {
Variant::Type rt = Variant::get_operator_return_type(Variant::Operator(k), type, Variant::Type(j));
if (rt != Variant::NIL) {
Dictionary d2;
d2["name"] = Variant::get_operator_name(Variant::Operator(k));
if (k != Variant::OP_NEGATE && k != Variant::OP_POSITIVE && k != Variant::OP_NOT && k != Variant::OP_BIT_NEGATE) {
d2["right_type"] = Variant::get_type_name(Variant::Type(j));
}
operators.push_back(d2);
}
}
}
if (operators.size()) {
d["operators"] = operators;
}
}
{
//methods
Array methods;
List<StringName> method_names;
Variant::get_builtin_method_list(type, &method_names);
for (List<StringName>::Element *E = method_names.front(); E; E = E->next()) {
StringName method_name = E->get();
Dictionary d2;
d2["name"] = String(method_name);
if (Variant::has_builtin_method_return_value(type, method_name)) {
Variant::Type ret_type = Variant::get_builtin_method_return_type(type, method_name);
d2["return_type"] = ret_type == Variant::NIL ? String("Variant") : Variant::get_type_name(ret_type);
}
d2["is_vararg"] = Variant::is_builtin_method_vararg(type, method_name);
d2["is_const"] = Variant::is_builtin_method_const(type, method_name);
d2["is_static"] = Variant::is_builtin_method_static(type, method_name);
d2["hash"] = Variant::get_builtin_method_hash(type, method_name);
Vector<Variant> default_args = Variant::get_builtin_method_default_arguments(type, method_name);
Array arguments;
int argcount = Variant::get_builtin_method_argument_count(type, method_name);
for (int j = 0; j < argcount; j++) {
Dictionary d3;
d3["name"] = Variant::get_builtin_method_argument_name(type, method_name, j);
Variant::Type argtype = Variant::get_builtin_method_argument_type(type, method_name, j);
d3["type"] = argtype == Variant::NIL ? String("Variant") : Variant::get_type_name(argtype);
if (j >= (argcount - default_args.size())) {
int dargidx = j - (argcount - default_args.size());
d3["default_value"] = default_args[dargidx].get_construct_string();
}
arguments.push_back(d3);
}
if (arguments.size()) {
d2["arguments"] = arguments;
}
methods.push_back(d2);
}
if (methods.size()) {
d["methods"] = methods;
}
}
{
//constructors
Array constructors;
for (int j = 0; j < Variant::get_constructor_count(type); j++) {
Dictionary d2;
d2["index"] = j;
Array arguments;
int argcount = Variant::get_constructor_argument_count(type, j);
for (int k = 0; k < argcount; k++) {
Dictionary d3;
d3["name"] = Variant::get_constructor_argument_name(type, j, k);
d3["type"] = Variant::get_type_name(Variant::get_constructor_argument_type(type, j, k));
arguments.push_back(d3);
}
if (arguments.size()) {
d2["arguments"] = arguments;
}
constructors.push_back(d2);
}
if (constructors.size()) {
d["constructors"] = constructors;
}
}
builtins.push_back(d);
}
api_dump["builtin_classes"] = builtins;
}
{
// classes
Array classes;
List<StringName> class_list;
ClassDB::get_class_list(&class_list);
class_list.sort_custom<StringName::AlphCompare>();
for (List<StringName>::Element *E = class_list.front(); E; E = E->next()) {
Dictionary d;
StringName class_name = E->get();
d["name"] = String(class_name);
d["is_refcounted"] = ClassDB::is_parent_class(class_name, "RefCounted");
d["is_instantiable"] = ClassDB::can_instantiate(class_name);
StringName parent_class = ClassDB::get_parent_class(class_name);
if (parent_class != StringName()) {
d["inherits"] = String(parent_class);
}
{
ClassDB::APIType api = ClassDB::get_api_type(class_name);
static const char *api_type[5] = { "core", "editor", "extension", "editor_extension" };
d["api_type"] = api_type[api];
}
{
//constants
Array constants;
List<String> constant_list;
ClassDB::get_integer_constant_list(class_name, &constant_list, true);
for (List<String>::Element *F = constant_list.front(); F; F = F->next()) {
StringName enum_name = ClassDB::get_integer_constant_enum(class_name, F->get());
if (enum_name != StringName()) {
continue; //enums will be handled on their own
}
Dictionary d2;
d2["name"] = String(F->get());
d2["value"] = ClassDB::get_integer_constant(class_name, F->get());
constants.push_back(d2);
}
if (constants.size()) {
d["constants"] = constants;
}
}
{
//enum
Array enums;
List<StringName> enum_list;
ClassDB::get_enum_list(class_name, &enum_list, true);
for (List<StringName>::Element *F = enum_list.front(); F; F = F->next()) {
Dictionary d2;
d2["name"] = String(F->get());
Array values;
List<StringName> enum_constant_list;
ClassDB::get_enum_constants(class_name, F->get(), &enum_constant_list, true);
for (List<StringName>::Element *G = enum_constant_list.front(); G; G = G->next()) {
Dictionary d3;
d3["name"] = String(G->get());
d3["value"] = ClassDB::get_integer_constant(class_name, G->get());
values.push_back(d3);
}
d2["values"] = values;
enums.push_back(d2);
}
if (enums.size()) {
d["enums"] = enums;
}
}
{
//methods
Array methods;
List<MethodInfo> method_list;
ClassDB::get_method_list(class_name, &method_list, true);
for (List<MethodInfo>::Element *F = method_list.front(); F; F = F->next()) {
StringName method_name = F->get().name;
if (F->get().flags & METHOD_FLAG_VIRTUAL) {
//virtual method
const MethodInfo &mi = F->get();
Dictionary d2;
d2["name"] = String(method_name);
d2["is_const"] = (F->get().flags & METHOD_FLAG_CONST) ? true : false;
d2["is_vararg"] = false;
d2["is_virtual"] = true;
// virtual functions have no hash since no MethodBind is involved
bool has_return = mi.return_val.type != Variant::NIL || (mi.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT);
Array arguments;
for (int i = (has_return ? -1 : 0); i < mi.arguments.size(); i++) {
PropertyInfo pinfo = i == -1 ? mi.return_val : mi.arguments[i];
Dictionary d3;
if (i >= 0) {
d3["name"] = pinfo.name;
}
if (pinfo.class_name != StringName()) {
d3["type"] = String(pinfo.class_name);
} else {
Variant::Type type = pinfo.type;
if (type == Variant::NIL) {
d3["type"] = "Variant";
} else {
d3["type"] = Variant::get_type_name(type);
}
}
if (i == -1) {
d2["return_value"] = d3;
} else {
arguments.push_back(d3);
}
}
if (arguments.size()) {
d2["arguments"] = arguments;
}
methods.push_back(d2);
} else if (F->get().name.begins_with("_")) {
//hidden method, ignore
} else {
Dictionary d2;
d2["name"] = String(method_name);
MethodBind *method = ClassDB::get_method(class_name, method_name);
if (!method) {
continue;
}
d2["is_const"] = method->is_const();
d2["is_vararg"] = method->is_vararg();
d2["is_virtual"] = false;
d2["hash"] = method->get_hash();
Vector<Variant> default_args = method->get_default_arguments();
Array arguments;
for (int i = (method->has_return() ? -1 : 0); i < method->get_argument_count(); i++) {
PropertyInfo pinfo = i == -1 ? method->get_return_info() : method->get_argument_info(i);
Dictionary d3;
if (i >= 0) {
d3["name"] = pinfo.name;
}
if (pinfo.class_name != StringName()) {
d3["type"] = String(pinfo.class_name);
} else {
Variant::Type type = pinfo.type;
if (type == Variant::NIL) {
d3["type"] = "Variant";
} else {
d3["type"] = Variant::get_type_name(type);
}
}
if (method->get_argument_meta(i) > 0) {
static const char *argmeta[11] = { "none", "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float", "double" };
d3["meta"] = argmeta[method->get_argument_meta(i)];
}
if (i >= 0 && i >= (method->get_argument_count() - default_args.size())) {
int dargidx = i - (method->get_argument_count() - default_args.size());
d3["default_value"] = default_args[dargidx].get_construct_string();
}
if (i == -1) {
d2["return_value"] = d3;
} else {
arguments.push_back(d3);
}
}
if (arguments.size()) {
d2["arguments"] = arguments;
}
methods.push_back(d2);
}
}
if (methods.size()) {
d["methods"] = methods;
}
}
{
//signals
Array signals;
List<MethodInfo> signal_list;
ClassDB::get_signal_list(class_name, &signal_list, true);
for (List<MethodInfo>::Element *F = signal_list.front(); F; F = F->next()) {
StringName signal_name = F->get().name;
Dictionary d2;
d2["name"] = String(signal_name);
Array arguments;
for (int i = 0; i < F->get().arguments.size(); i++) {
Dictionary d3;
d3["name"] = F->get().arguments[i].name;
Variant::Type type = F->get().arguments[i].type;
if (F->get().arguments[i].class_name != StringName()) {
d3["type"] = String(F->get().arguments[i].class_name);
} else if (type == Variant::NIL) {
d3["type"] = "Variant";
} else {
d3["type"] = Variant::get_type_name(type);
}
arguments.push_back(d3);
}
if (arguments.size()) {
d2["arguments"] = arguments;
}
signals.push_back(d2);
}
if (signals.size()) {
d["signals"] = signals;
}
}
{
//properties
Array properties;
List<PropertyInfo> property_list;
ClassDB::get_property_list(class_name, &property_list, true);
for (List<PropertyInfo>::Element *F = property_list.front(); F; F = F->next()) {
if (F->get().usage & PROPERTY_USAGE_CATEGORY || F->get().usage & PROPERTY_USAGE_GROUP || F->get().usage & PROPERTY_USAGE_SUBGROUP) {
continue; //not real properties
}
if (F->get().name.begins_with("_")) {
continue; //hidden property
}
StringName property_name = F->get().name;
Dictionary d2;
d2["name"] = String(property_name);
if (F->get().class_name != StringName()) {
d2["type"] = String(F->get().class_name);
} else if (F->get().type == Variant::NIL && F->get().usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
d2["type"] = "Variant";
} else {
d2["type"] = Variant::get_type_name(F->get().type);
}
d2["setter"] = ClassDB::get_property_setter(class_name, F->get().name);
d2["getter"] = ClassDB::get_property_getter(class_name, F->get().name);
d2["index"] = ClassDB::get_property_index(class_name, F->get().name);
properties.push_back(d2);
}
if (properties.size()) {
d["properties"] = properties;
}
}
classes.push_back(d);
}
api_dump["classes"] = classes;
}
{
// singletons
Array singletons;
List<Engine::Singleton> singleton_list;
Engine::get_singleton()->get_singletons(&singleton_list);
for (List<Engine::Singleton>::Element *E = singleton_list.front(); E; E = E->next()) {
const Engine::Singleton &s = E->get();
Dictionary d;
d["name"] = s.name;
if (s.class_name != StringName()) {
d["type"] = String(s.class_name);
} else {
d["type"] = String(s.ptr->get_class());
}
singletons.push_back(d);
}
if (singletons.size()) {
api_dump["singletons"] = singletons;
}
}
return api_dump;
}
void NativeExtensionAPIDump::generate_extension_json_file(const String &p_path) {
Dictionary api = generate_extension_api();
Ref<JSON> json;
json.instantiate();
String text = json->stringify(api, "\t", false);
FileAccessRef fa = FileAccess::open(p_path, FileAccess::WRITE);
CharString cs = text.ascii();
fa->store_buffer((const uint8_t *)cs.ptr(), cs.length());
fa->close();
}
#endif

View File

@ -0,0 +1,45 @@
/*************************************************************************/
/* extension_api_dump.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef API_DUMP_H
#define API_DUMP_H
#include "core/extension/native_extension.h"
#ifdef TOOLS_ENABLED
class NativeExtensionAPIDump {
public:
static Dictionary generate_extension_api();
static void generate_extension_json_file(const String &p_path);
};
#endif
#endif // API_DUMP_H

View File

@ -0,0 +1,688 @@
/*************************************************************************/
/* gdnative_interface.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "gdnative_interface.h"
#include "core/config/engine.h"
#include "core/object/class_db.h"
#include "core/os/memory.h"
#include "core/variant/variant.h"
#include "core/version.h"
// Memory Functions
static void *gdnative_alloc(size_t p_size) {
return memalloc(p_size);
}
static void *gdnative_realloc(void *p_mem, size_t p_size) {
return memrealloc(p_mem, p_size);
}
static void gdnative_free(void *p_mem) {
memfree(p_mem);
}
// Helper print functions.
static void gdnative_print_error(const char *p_description, const char *p_function, const char *p_file, int32_t p_line) {
_err_print_error(p_function, p_file, p_line, p_description, ERR_HANDLER_ERROR);
}
static void gdnative_print_warning(const char *p_description, const char *p_function, const char *p_file, int32_t p_line) {
_err_print_error(p_function, p_file, p_line, p_description, ERR_HANDLER_WARNING);
}
static void gdnative_print_script_error(const char *p_description, const char *p_function, const char *p_file, int32_t p_line) {
_err_print_error(p_function, p_file, p_line, p_description, ERR_HANDLER_SCRIPT);
}
// Variant functions
static void gdnative_variant_new_copy(GDNativeVariantPtr r_dest, const GDNativeVariantPtr p_src) {
memnew_placement(reinterpret_cast<Variant *>(r_dest), Variant(*reinterpret_cast<Variant *>(p_src)));
}
static void gdnative_variant_new_nil(GDNativeVariantPtr r_dest) {
memnew_placement(reinterpret_cast<Variant *>(r_dest), Variant);
}
static void gdnative_variant_destroy(GDNativeVariantPtr p_self) {
reinterpret_cast<Variant *>(p_self)->~Variant();
}
// variant type
#define memnew_placement_custom(m_placement, m_class, m_constr) _post_initialize(new (m_placement, sizeof(m_class), "") m_constr)
static void gdnative_variant_call(GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_method, const GDNativeVariantPtr *p_args, const GDNativeInt p_argcount, GDNativeVariantPtr r_return, GDNativeCallError *r_error) {
Variant *self = (Variant *)p_self;
const StringName *method = (const StringName *)p_method;
const Variant **args = (const Variant **)p_args;
Variant ret;
Callable::CallError error;
self->call(*method, args, p_argcount, ret, error);
memnew_placement_custom(r_return, Variant, Variant(ret));
if (r_error) {
r_error->error = (GDNativeCallErrorType)(error.error);
r_error->argument = error.argument;
r_error->expected = error.expected;
}
}
static void gdnative_variant_call_static(GDNativeVariantType p_type, const GDNativeStringNamePtr p_method, const GDNativeVariantPtr *p_args, const GDNativeInt p_argcount, GDNativeVariantPtr r_return, GDNativeCallError *r_error) {
Variant::Type type = (Variant::Type)p_type;
const StringName *method = (const StringName *)p_method;
const Variant **args = (const Variant **)p_args;
Variant ret;
Callable::CallError error;
Variant::call_static(type, *method, args, p_argcount, ret, error);
memnew_placement_custom(r_return, Variant, Variant(ret));
if (r_error) {
r_error->error = (GDNativeCallErrorType)error.error;
r_error->argument = error.argument;
r_error->expected = error.expected;
}
}
static void gdnative_variant_evaluate(GDNativeVariantOperator p_op, const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, GDNativeVariantPtr r_return, GDNativeBool *r_valid) {
Variant::Operator op = (Variant::Operator)p_op;
const Variant *a = (const Variant *)p_a;
const Variant *b = (const Variant *)p_b;
Variant *ret = (Variant *)r_return;
bool valid;
Variant::evaluate(op, *a, *b, *ret, valid);
*r_valid = valid;
}
static void gdnative_variant_set(GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, const GDNativeVariantPtr p_value, GDNativeBool *r_valid) {
Variant *self = (Variant *)p_self;
const Variant *key = (const Variant *)p_key;
const Variant *value = (const Variant *)p_value;
bool valid;
self->set(*key, *value, &valid);
*r_valid = valid;
}
static void gdnative_variant_set_named(GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_key, const GDNativeVariantPtr p_value, GDNativeBool *r_valid) {
Variant *self = (Variant *)p_self;
const StringName *key = (const StringName *)p_key;
const Variant *value = (const Variant *)p_value;
bool valid;
self->set_named(*key, *value, valid);
*r_valid = valid;
}
static void gdnative_variant_set_keyed(GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, const GDNativeVariantPtr p_value, GDNativeBool *r_valid) {
Variant *self = (Variant *)p_self;
const Variant *key = (const Variant *)p_key;
const Variant *value = (const Variant *)p_value;
bool valid;
self->set_keyed(*key, *value, valid);
*r_valid = valid;
}
static void gdnative_variant_set_indexed(GDNativeVariantPtr p_self, GDNativeInt p_index, const GDNativeVariantPtr p_value, GDNativeBool *r_valid, GDNativeBool *r_oob) {
Variant *self = (Variant *)p_self;
const Variant *value = (const Variant *)p_value;
bool valid;
bool oob;
self->set_indexed(p_index, value, valid, oob);
*r_valid = valid;
*r_oob = oob;
}
static void gdnative_variant_get(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, GDNativeVariantPtr r_ret, GDNativeBool *r_valid) {
const Variant *self = (const Variant *)p_self;
const Variant *key = (const Variant *)p_key;
bool valid;
memnew_placement_custom(r_ret, Variant, Variant(self->get(*key, &valid)));
*r_valid = valid;
}
static void gdnative_variant_get_named(const GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_key, GDNativeVariantPtr r_ret, GDNativeBool *r_valid) {
const Variant *self = (const Variant *)p_self;
const StringName *key = (const StringName *)p_key;
bool valid;
memnew_placement_custom(r_ret, Variant, Variant(self->get_named(*key, valid)));
*r_valid = valid;
}
static void gdnative_variant_get_keyed(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, GDNativeVariantPtr r_ret, GDNativeBool *r_valid) {
const Variant *self = (const Variant *)p_self;
const Variant *key = (const Variant *)p_key;
bool valid;
memnew_placement_custom(r_ret, Variant, Variant(self->get_keyed(*key, valid)));
*r_valid = valid;
}
static void gdnative_variant_get_indexed(const GDNativeVariantPtr p_self, GDNativeInt p_index, GDNativeVariantPtr r_ret, GDNativeBool *r_valid, GDNativeBool *r_oob) {
const Variant *self = (const Variant *)p_self;
bool valid;
bool oob;
memnew_placement_custom(r_ret, Variant, Variant(self->get_indexed(p_index, valid, oob)));
*r_valid = valid;
*r_oob = oob;
}
/// Iteration.
static GDNativeBool gdnative_variant_iter_init(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeBool *r_valid) {
const Variant *self = (const Variant *)p_self;
Variant *iter = (Variant *)r_iter;
bool valid;
bool ret = self->iter_init(*iter, valid);
*r_valid = valid;
return ret;
}
static GDNativeBool gdnative_variant_iter_next(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeBool *r_valid) {
const Variant *self = (const Variant *)p_self;
Variant *iter = (Variant *)r_iter;
bool valid;
bool ret = self->iter_next(*iter, valid);
*r_valid = valid;
return ret;
}
static void gdnative_variant_iter_get(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeVariantPtr r_ret, GDNativeBool *r_valid) {
const Variant *self = (const Variant *)p_self;
Variant *iter = (Variant *)r_iter;
bool valid;
memnew_placement_custom(r_ret, Variant, Variant(self->iter_next(*iter, valid)));
*r_valid = valid;
}
/// Variant functions.
static GDNativeBool gdnative_variant_hash_compare(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_other) {
const Variant *self = (const Variant *)p_self;
const Variant *other = (const Variant *)p_other;
return self->hash_compare(*other);
}
static GDNativeBool gdnative_variant_booleanize(const GDNativeVariantPtr p_self) {
const Variant *self = (const Variant *)p_self;
return self->booleanize();
}
static void gdnative_variant_blend(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst) {
const Variant *a = (const Variant *)p_a;
const Variant *b = (const Variant *)p_b;
memnew_placement(r_dst, Variant);
Variant::blend(*a, *b, p_c, *(Variant *)r_dst);
}
static void gdnative_variant_interpolate(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst) {
const Variant *a = (const Variant *)p_a;
const Variant *b = (const Variant *)p_b;
memnew_placement(r_dst, Variant);
Variant::interpolate(*a, *b, p_c, *(Variant *)r_dst);
}
static void gdnative_variant_duplicate(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_ret, GDNativeBool p_deep) {
const Variant *self = (const Variant *)p_self;
memnew_placement_custom(r_ret, Variant, Variant(self->duplicate(p_deep)));
}
static void gdnative_variant_stringify(const GDNativeVariantPtr p_self, GDNativeStringPtr r_ret) {
const Variant *self = (const Variant *)p_self;
memnew_placement_custom(r_ret, String, String(*self));
}
static GDNativeVariantType gdnative_variant_get_type(const GDNativeVariantPtr p_self) {
const Variant *self = (const Variant *)p_self;
return (GDNativeVariantType)self->get_type();
}
static GDNativeBool gdnative_variant_has_method(const GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_method) {
const Variant *self = (const Variant *)p_self;
const StringName *method = (const StringName *)p_method;
return self->has_method(*method);
}
static GDNativeBool gdnative_variant_has_member(GDNativeVariantType p_type, const GDNativeStringNamePtr p_member) {
return Variant::has_member((Variant::Type)p_type, *((const StringName *)p_member));
}
static GDNativeBool gdnative_variant_has_key(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, GDNativeBool *r_valid) {
const Variant *self = (const Variant *)p_self;
const Variant *key = (const Variant *)p_key;
bool valid;
return self->has_key(*key, valid);
*r_valid = valid;
}
static void gdnative_variant_get_type_name(GDNativeVariantType p_type, GDNativeStringPtr r_ret) {
String name = Variant::get_type_name((Variant::Type)p_type);
memnew_placement_custom(r_ret, String, String(name));
}
static GDNativeBool gdnative_variant_can_convert(GDNativeVariantType p_from, GDNativeVariantType p_to) {
return Variant::can_convert((Variant::Type)p_from, (Variant::Type)p_to);
}
static GDNativeBool gdnative_variant_can_convert_strict(GDNativeVariantType p_from, GDNativeVariantType p_to) {
return Variant::can_convert_strict((Variant::Type)p_from, (Variant::Type)p_to);
}
// ptrcalls
static GDNativePtrOperatorEvaluator gdnative_variant_get_ptr_operator_evaluator(GDNativeVariantOperator p_operator, GDNativeVariantType p_type_a, GDNativeVariantType p_type_b) {
return (GDNativePtrOperatorEvaluator)Variant::get_ptr_operator_evaluator(Variant::Operator(p_operator), Variant::Type(p_type_a), Variant::Type(p_type_b));
}
static GDNativePtrBuiltInMethod gdnative_variant_get_ptr_builtin_method(GDNativeVariantType p_type, const char *p_method, GDNativeInt p_hash) {
StringName method = p_method;
uint32_t hash = Variant::get_builtin_method_hash(Variant::Type(p_type), method);
if (hash != p_hash) {
ERR_PRINT_ONCE("Error getting method " + String(method) + ", hash mismatch.");
return nullptr;
}
return (GDNativePtrBuiltInMethod)Variant::get_ptr_builtin_method(Variant::Type(p_type), method);
}
static GDNativePtrConstructor gdnative_variant_get_ptr_constructor(GDNativeVariantType p_type, int32_t p_constructor) {
return (GDNativePtrConstructor)Variant::get_ptr_constructor(Variant::Type(p_type), p_constructor);
}
static void gdnative_variant_construct(GDNativeVariantType p_type, GDNativeVariantPtr p_base, const GDNativeVariantPtr *p_args, int32_t p_argument_count, GDNativeCallError *r_error) {
memnew_placement(p_base, Variant);
Callable::CallError error;
Variant::construct(Variant::Type(p_type), *(Variant *)p_base, (const Variant **)p_args, p_argument_count, error);
if (r_error) {
r_error->error = (GDNativeCallErrorType)(error.error);
r_error->argument = error.argument;
r_error->expected = error.expected;
}
}
static GDNativePtrSetter gdnative_variant_get_ptr_setter(GDNativeVariantType p_type, const char *p_member) {
return (GDNativePtrSetter)Variant::get_member_ptr_setter(Variant::Type(p_type), p_member);
}
static GDNativePtrGetter gdnative_variant_get_ptr_getter(GDNativeVariantType p_type, const char *p_member) {
return (GDNativePtrGetter)Variant::get_member_ptr_getter(Variant::Type(p_type), p_member);
}
static GDNativePtrIndexedSetter gdnative_variant_get_ptr_indexed_setter(GDNativeVariantType p_type) {
return (GDNativePtrIndexedSetter)Variant::get_member_ptr_indexed_setter(Variant::Type(p_type));
}
static GDNativePtrIndexedGetter gdnative_variant_get_ptr_indexed_getter(GDNativeVariantType p_type) {
return (GDNativePtrIndexedGetter)Variant::get_member_ptr_indexed_getter(Variant::Type(p_type));
}
static GDNativePtrKeyedSetter gdnative_variant_get_ptr_keyed_setter(GDNativeVariantType p_type) {
return (GDNativePtrKeyedSetter)Variant::get_member_ptr_keyed_setter(Variant::Type(p_type));
}
static GDNativePtrKeyedGetter gdnative_variant_get_ptr_keyed_getter(GDNativeVariantType p_type) {
return (GDNativePtrKeyedGetter)Variant::get_member_ptr_keyed_getter(Variant::Type(p_type));
}
static GDNativePtrKeyedChecker gdnative_variant_get_ptr_keyed_checker(GDNativeVariantType p_type) {
return (GDNativePtrKeyedChecker)Variant::get_member_ptr_keyed_checker(Variant::Type(p_type));
}
static void gdnative_variant_get_constant_value(GDNativeVariantType p_type, const char *p_constant, GDNativeVariantPtr r_ret) {
memnew_placement_custom(r_ret, Variant, Variant(Variant::get_constant_value(Variant::Type(p_type), p_constant)));
}
static GDNativePtrUtilityFunction gdnative_variant_get_ptr_utility_function(const char *p_function, GDNativeInt p_hash) {
StringName function = p_function;
uint32_t hash = Variant::get_utility_function_hash(function);
if (hash != p_hash) {
ERR_PRINT_ONCE("Error getting utility function " + String(function) + ", hash mismatch.");
return nullptr;
}
return (GDNativePtrUtilityFunction)Variant::get_ptr_utility_function(function);
}
//string helpers
static void gdnative_string_new_with_latin1_chars(GDNativeStringPtr r_dest, const char *p_contents) {
String *dest = (String *)r_dest;
memnew_placement(dest, String);
*dest = String(p_contents);
}
static void gdnative_string_new_with_utf8_chars(GDNativeStringPtr r_dest, const char *p_contents) {
String *dest = (String *)r_dest;
memnew_placement(dest, String);
dest->parse_utf8(p_contents);
}
static void gdnative_string_new_with_utf16_chars(GDNativeStringPtr r_dest, const char16_t *p_contents) {
String *dest = (String *)r_dest;
memnew_placement(dest, String);
dest->parse_utf16(p_contents);
}
static void gdnative_string_new_with_utf32_chars(GDNativeStringPtr r_dest, const char32_t *p_contents) {
String *dest = (String *)r_dest;
memnew_placement(dest, String);
*dest = String((const char32_t *)p_contents);
}
static void gdnative_string_new_with_wide_chars(GDNativeStringPtr r_dest, const wchar_t *p_contents) {
String *dest = (String *)r_dest;
if (sizeof(wchar_t) == 2) {
// wchar_t is 16 bit, parse.
memnew_placement(dest, String);
dest->parse_utf16((const char16_t *)p_contents);
} else {
// wchar_t is 32 bit, copy.
memnew_placement(dest, String);
*dest = String((const char32_t *)p_contents);
}
}
static void gdnative_string_new_with_latin1_chars_and_len(GDNativeStringPtr r_dest, const char *p_contents, const GDNativeInt p_size) {
String *dest = (String *)r_dest;
memnew_placement(dest, String);
*dest = String(p_contents, p_size);
}
static void gdnative_string_new_with_utf8_chars_and_len(GDNativeStringPtr r_dest, const char *p_contents, const GDNativeInt p_size) {
String *dest = (String *)r_dest;
memnew_placement(dest, String);
dest->parse_utf8(p_contents, p_size);
}
static void gdnative_string_new_with_utf16_chars_and_len(GDNativeStringPtr r_dest, const char16_t *p_contents, const GDNativeInt p_size) {
String *dest = (String *)r_dest;
memnew_placement(dest, String);
dest->parse_utf16(p_contents, p_size);
}
static void gdnative_string_new_with_utf32_chars_and_len(GDNativeStringPtr r_dest, const char32_t *p_contents, const GDNativeInt p_size) {
String *dest = (String *)r_dest;
memnew_placement(dest, String);
*dest = String((const char32_t *)p_contents, p_size);
}
static void gdnative_string_new_with_wide_chars_and_len(GDNativeStringPtr r_dest, const wchar_t *p_contents, const GDNativeInt p_size) {
String *dest = (String *)r_dest;
if (sizeof(wchar_t) == 2) {
// wchar_t is 16 bit, parse.
memnew_placement(dest, String);
dest->parse_utf16((const char16_t *)p_contents, p_size);
} else {
// wchar_t is 32 bit, copy.
memnew_placement(dest, String);
*dest = String((const char32_t *)p_contents, p_size);
}
}
static GDNativeInt gdnative_string_to_latin1_chars(const GDNativeStringPtr p_self, char *r_text, GDNativeInt p_max_write_length) {
String *self = (String *)p_self;
CharString cs = self->ascii(true);
GDNativeInt len = cs.length();
if (r_text) {
const char *s_text = cs.ptr();
for (GDNativeInt i = 0; i < MIN(len, p_max_write_length); i++) {
r_text[i] = s_text[i];
}
}
return len;
}
static GDNativeInt gdnative_string_to_utf8_chars(const GDNativeStringPtr p_self, char *r_text, GDNativeInt p_max_write_length) {
String *self = (String *)p_self;
CharString cs = self->utf8();
GDNativeInt len = cs.length();
if (r_text) {
const char *s_text = cs.ptr();
for (GDNativeInt i = 0; i < MIN(len, p_max_write_length); i++) {
r_text[i] = s_text[i];
}
}
return len;
}
static GDNativeInt gdnative_string_to_utf16_chars(const GDNativeStringPtr p_self, char16_t *r_text, GDNativeInt p_max_write_length) {
String *self = (String *)p_self;
Char16String cs = self->utf16();
GDNativeInt len = cs.length();
if (r_text) {
const char16_t *s_text = cs.ptr();
for (GDNativeInt i = 0; i < MIN(len, p_max_write_length); i++) {
r_text[i] = s_text[i];
}
}
return len;
}
static GDNativeInt gdnative_string_to_utf32_chars(const GDNativeStringPtr p_self, char32_t *r_text, GDNativeInt p_max_write_length) {
String *self = (String *)p_self;
GDNativeInt len = self->length();
if (r_text) {
const char32_t *s_text = self->ptr();
for (GDNativeInt i = 0; i < MIN(len, p_max_write_length); i++) {
r_text[i] = s_text[i];
}
}
return len;
}
static GDNativeInt gdnative_string_to_wide_chars(const GDNativeStringPtr p_self, wchar_t *r_text, GDNativeInt p_max_write_length) {
if (sizeof(wchar_t) == 4) {
return gdnative_string_to_utf32_chars(p_self, (char32_t *)r_text, p_max_write_length);
} else {
return gdnative_string_to_utf16_chars(p_self, (char16_t *)r_text, p_max_write_length);
}
}
static char32_t *gdnative_string_operator_index(GDNativeStringPtr p_self, GDNativeInt p_index) {
String *self = (String *)p_self;
ERR_FAIL_INDEX_V(p_index, self->length() + 1, nullptr);
return &self->ptrw()[p_index];
}
static const char32_t *gdnative_string_operator_index_const(const GDNativeStringPtr p_self, GDNativeInt p_index) {
const String *self = (const String *)p_self;
ERR_FAIL_INDEX_V(p_index, self->length() + 1, nullptr);
return &self->ptr()[p_index];
}
/* OBJECT API */
static void gdnative_object_method_bind_ptrcall(GDNativeMethodBindPtr p_method_bind, GDNativeObjectPtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr p_ret) {
MethodBind *mb = (MethodBind *)p_method_bind;
Object *o = (Object *)p_instance;
mb->ptrcall(o, (const void **)p_args, p_ret);
}
static void gdnative_object_destroy(GDNativeObjectPtr p_o) {
memdelete((Object *)p_o);
}
static GDNativeObjectPtr gdnative_global_get_singleton(const char *p_name) {
return (GDNativeObjectPtr)Engine::get_singleton()->get_singleton_object(String(p_name));
}
static GDNativeObjectPtr gdnative_object_get_instance_from_id(GDObjectInstanceID p_instance_id) {
return (GDNativeObjectPtr)ObjectDB::get_instance(ObjectID(p_instance_id));
}
static GDNativeObjectPtr gdnative_object_cast_to(const GDNativeObjectPtr p_object, void *p_class_tag) {
if (!p_object) {
return nullptr;
}
Object *o = (Object *)p_object;
return o->is_class_ptr(p_class_tag) ? (GDNativeObjectPtr)o : (GDNativeObjectPtr) nullptr;
}
static GDObjectInstanceID gdnative_object_get_instance_id(const GDNativeObjectPtr p_object) {
const Object *o = (const Object *)p_object;
return (GDObjectInstanceID)o->get_instance_id();
}
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);
if (mb->get_hash() != p_hash) {
ERR_PRINT_ONCE("Hash mismatch for method '" + String(p_classname) + "." + String(p_methodname) + "'.");
return nullptr;
}
// MethodBind *mb = ClassDB::get_method("Node", "get_name");
return (GDNativeMethodBindPtr)mb;
}
static GDNativeClassConstructor gdnative_classdb_get_constructor(const char *p_classname) {
ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(StringName(p_classname));
if (class_info) {
return (GDNativeClassConstructor)class_info->creation_func;
}
return nullptr;
}
static void *gdnative_classdb_get_class_tag(const char *p_classname) {
ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(p_classname);
return class_info ? class_info->class_ptr : nullptr;
}
void gdnative_setup_interface(GDNativeInterface *p_interface) {
GDNativeInterface &gdni = *p_interface;
gdni.version_major = VERSION_MAJOR;
gdni.version_minor = VERSION_MINOR;
#if VERSION_PATCH
gdni.version_patch = VERSION_PATCH;
#else
gdni.version_patch = 0;
#endif
gdni.version_string = VERSION_FULL_NAME;
/* GODOT CORE */
gdni.mem_alloc = gdnative_alloc;
gdni.mem_realloc = gdnative_realloc;
gdni.mem_free = gdnative_free;
gdni.print_error = gdnative_print_error;
gdni.print_warning = gdnative_print_warning;
gdni.print_script_error = gdnative_print_script_error;
/* GODOT VARIANT */
// variant general
gdni.variant_new_copy = gdnative_variant_new_copy;
gdni.variant_new_nil = gdnative_variant_new_nil;
gdni.variant_destroy = gdnative_variant_destroy;
gdni.variant_call = gdnative_variant_call;
gdni.variant_call_static = gdnative_variant_call_static;
gdni.variant_evaluate = gdnative_variant_evaluate;
gdni.variant_set = gdnative_variant_set;
gdni.variant_set_named = gdnative_variant_set_named;
gdni.variant_set_keyed = gdnative_variant_set_keyed;
gdni.variant_set_indexed = gdnative_variant_set_indexed;
gdni.variant_get = gdnative_variant_get;
gdni.variant_get_named = gdnative_variant_get_named;
gdni.variant_get_keyed = gdnative_variant_get_keyed;
gdni.variant_get_indexed = gdnative_variant_get_indexed;
gdni.variant_iter_init = gdnative_variant_iter_init;
gdni.variant_iter_next = gdnative_variant_iter_next;
gdni.variant_iter_get = gdnative_variant_iter_get;
gdni.variant_hash_compare = gdnative_variant_hash_compare;
gdni.variant_booleanize = gdnative_variant_booleanize;
gdni.variant_blend = gdnative_variant_blend;
gdni.variant_interpolate = gdnative_variant_interpolate;
gdni.variant_duplicate = gdnative_variant_duplicate;
gdni.variant_stringify = gdnative_variant_stringify;
gdni.variant_get_type = gdnative_variant_get_type;
gdni.variant_has_method = gdnative_variant_has_method;
gdni.variant_has_member = gdnative_variant_has_member;
gdni.variant_has_key = gdnative_variant_has_key;
gdni.variant_get_type_name = gdnative_variant_get_type_name;
gdni.variant_can_convert = gdnative_variant_can_convert;
gdni.variant_can_convert_strict = gdnative_variant_can_convert_strict;
//ptrcalls
#if 0
GDNativeVariantFromTypeConstructorFunc (*get_variant_from_type_constructor)(GDNativeVariantType p_type);
GDNativeTypeFromVariantConstructorFunc (*get_variant_to_type_constructor)(GDNativeVariantType p_type);
#endif
gdni.variant_get_ptr_operator_evaluator = gdnative_variant_get_ptr_operator_evaluator;
gdni.variant_get_ptr_builtin_method = gdnative_variant_get_ptr_builtin_method;
gdni.variant_get_ptr_constructor = gdnative_variant_get_ptr_constructor;
gdni.variant_construct = gdnative_variant_construct;
gdni.variant_get_ptr_setter = gdnative_variant_get_ptr_setter;
gdni.variant_get_ptr_getter = gdnative_variant_get_ptr_getter;
gdni.variant_get_ptr_indexed_setter = gdnative_variant_get_ptr_indexed_setter;
gdni.variant_get_ptr_indexed_getter = gdnative_variant_get_ptr_indexed_getter;
gdni.variant_get_ptr_keyed_setter = gdnative_variant_get_ptr_keyed_setter;
gdni.variant_get_ptr_keyed_getter = gdnative_variant_get_ptr_keyed_getter;
gdni.variant_get_ptr_keyed_checker = gdnative_variant_get_ptr_keyed_checker;
gdni.variant_get_constant_value = gdnative_variant_get_constant_value;
gdni.variant_get_ptr_utility_function = gdnative_variant_get_ptr_utility_function;
// extra utilities
gdni.string_new_with_latin1_chars = gdnative_string_new_with_latin1_chars;
gdni.string_new_with_utf8_chars = gdnative_string_new_with_utf8_chars;
gdni.string_new_with_utf16_chars = gdnative_string_new_with_utf16_chars;
gdni.string_new_with_utf32_chars = gdnative_string_new_with_utf32_chars;
gdni.string_new_with_wide_chars = gdnative_string_new_with_wide_chars;
gdni.string_new_with_latin1_chars_and_len = gdnative_string_new_with_latin1_chars_and_len;
gdni.string_new_with_utf8_chars_and_len = gdnative_string_new_with_utf8_chars_and_len;
gdni.string_new_with_utf16_chars_and_len = gdnative_string_new_with_utf16_chars_and_len;
gdni.string_new_with_utf32_chars_and_len = gdnative_string_new_with_utf32_chars_and_len;
gdni.string_new_with_wide_chars_and_len = gdnative_string_new_with_wide_chars_and_len;
gdni.string_to_latin1_chars = gdnative_string_to_latin1_chars;
gdni.string_to_utf8_chars = gdnative_string_to_utf8_chars;
gdni.string_to_utf16_chars = gdnative_string_to_utf16_chars;
gdni.string_to_utf32_chars = gdnative_string_to_utf32_chars;
gdni.string_to_wide_chars = gdnative_string_to_wide_chars;
gdni.string_operator_index = gdnative_string_operator_index;
gdni.string_operator_index_const = gdnative_string_operator_index_const;
/* OBJECT */
gdni.object_method_bind_ptrcall = gdnative_object_method_bind_ptrcall;
gdni.object_destroy = gdnative_object_destroy;
gdni.global_get_singleton = gdnative_global_get_singleton;
gdni.object_cast_to = gdnative_object_cast_to;
gdni.object_get_instance_from_id = gdnative_object_get_instance_from_id;
gdni.object_get_instance_id = gdnative_object_get_instance_id;
/* CLASSDB */
gdni.classdb_get_constructor = gdnative_classdb_get_constructor;
gdni.classdb_get_method_bind = gdnative_classdb_get_method_bind;
gdni.classdb_get_class_tag = gdnative_classdb_get_class_tag;
/* CLASSDB EXTENSION */
//these are filled by implementation, since it will want to keep track of registered classes
gdni.classdb_register_extension_class = nullptr;
gdni.classdb_register_extension_class_method = nullptr;
gdni.classdb_register_extension_class_integer_constant = nullptr;
gdni.classdb_register_extension_class_property = nullptr;
gdni.classdb_register_extension_class_signal = nullptr;
gdni.classdb_unregister_extension_class = nullptr;
}

View File

@ -0,0 +1,427 @@
/*************************************************************************/
/* gdnative_interface.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef GDNATIVE_INTERFACE_H
#define GDNATIVE_INTERFACE_H
/* This is a C class header, you can copy it and use it directly in your own binders.
* Together with the JSON file, you should be able to generate any binder.
*/
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
/* VARIANT TYPES */
typedef enum {
GDNATIVE_VARIANT_TYPE_NIL,
/* atomic types */
GDNATIVE_VARIANT_TYPE_BOOL,
GDNATIVE_VARIANT_TYPE_INT,
GDNATIVE_VARIANT_TYPE_FLOAT,
GDNATIVE_VARIANT_TYPE_STRING,
/* math types */
GDNATIVE_VARIANT_TYPE_VECTOR2,
GDNATIVE_VARIANT_TYPE_VECTOR2I,
GDNATIVE_VARIANT_TYPE_RECT2,
GDNATIVE_VARIANT_TYPE_RECT2I,
GDNATIVE_VARIANT_TYPE_VECTOR3,
GDNATIVE_VARIANT_TYPE_VECTOR3I,
GDNATIVE_VARIANT_TYPE_TRANSFORM2D,
GDNATIVE_VARIANT_TYPE_PLANE,
GDNATIVE_VARIANT_TYPE_QUATERNION,
GDNATIVE_VARIANT_TYPE_AABB,
GDNATIVE_VARIANT_TYPE_BASIS,
GDNATIVE_VARIANT_TYPE_TRANSFORM3D,
/* misc types */
GDNATIVE_VARIANT_TYPE_COLOR,
GDNATIVE_VARIANT_TYPE_STRING_NAME,
GDNATIVE_VARIANT_TYPE_NODE_PATH,
GDNATIVE_VARIANT_TYPE_RID,
GDNATIVE_VARIANT_TYPE_OBJECT,
GDNATIVE_VARIANT_TYPE_CALLABLE,
GDNATIVE_VARIANT_TYPE_SIGNAL,
GDNATIVE_VARIANT_TYPE_DICTIONARY,
GDNATIVE_VARIANT_TYPE_ARRAY,
/* typed arrays */
GDNATIVE_VARIANT_TYPE_PACKED_BYTE_ARRAY,
GDNATIVE_VARIANT_TYPE_PACKED_INT32_ARRAY,
GDNATIVE_VARIANT_TYPE_PACKED_INT64_ARRAY,
GDNATIVE_VARIANT_TYPE_PACKED_FLOAT32_ARRAY,
GDNATIVE_VARIANT_TYPE_PACKED_FLOAT64_ARRAY,
GDNATIVE_VARIANT_TYPE_PACKED_STRING_ARRAY,
GDNATIVE_VARIANT_TYPE_PACKED_VECTOR2_ARRAY,
GDNATIVE_VARIANT_TYPE_PACKED_VECTOR3_ARRAY,
GDNATIVE_VARIANT_TYPE_PACKED_COLOR_ARRAY,
GDNATIVE_VARIANT_TYPE_VARIANT_MAX
} GDNativeVariantType;
typedef enum {
/* comparison */
GDNATIVE_VARIANT_OP_EQUAL,
GDNATIVE_VARIANT_OP_NOT_EQUAL,
GDNATIVE_VARIANT_OP_LESS,
GDNATIVE_VARIANT_OP_LESS_EQUAL,
GDNATIVE_VARIANT_OP_GREATER,
GDNATIVE_VARIANT_OP_GREATER_EQUAL,
/* mathematic */
GDNATIVE_VARIANT_OP_ADD,
GDNATIVE_VARIANT_OP_SUBTRACT,
GDNATIVE_VARIANT_OP_MULTIPLY,
GDNATIVE_VARIANT_OP_DIVIDE,
GDNATIVE_VARIANT_OP_NEGATE,
GDNATIVE_VARIANT_OP_POSITIVE,
GDNATIVE_VARIANT_OP_MODULE,
/* bitwise */
GDNATIVE_VARIANT_OP_SHIFT_LEFT,
GDNATIVE_VARIANT_OP_SHIFT_RIGHT,
GDNATIVE_VARIANT_OP_BIT_AND,
GDNATIVE_VARIANT_OP_BIT_OR,
GDNATIVE_VARIANT_OP_BIT_XOR,
GDNATIVE_VARIANT_OP_BIT_NEGATE,
/* logic */
GDNATIVE_VARIANT_OP_AND,
GDNATIVE_VARIANT_OP_OR,
GDNATIVE_VARIANT_OP_XOR,
GDNATIVE_VARIANT_OP_NOT,
/* containment */
GDNATIVE_VARIANT_OP_IN,
GDNATIVE_VARIANT_OP_MAX
} GDNativeVariantOperator;
typedef void *GDNativeVariantPtr;
typedef void *GDNativeStringNamePtr;
typedef void *GDNativeStringPtr;
typedef void *GDNativeObjectPtr;
typedef void *GDNativeTypePtr;
typedef void *GDNativeMethodBindPtr;
typedef int64_t GDNativeInt;
typedef uint32_t GDNativeBool;
typedef uint64_t GDObjectInstanceID;
/* VARIANT DATA I/O */
typedef enum {
NATIVE_CALL_OK,
NATIVE_CALL_ERROR_INVALID_METHOD,
NATIVE_CALL_ERROR_INVALID_ARGUMENT, /* expected is variant type */
NATIVE_CALL_ERROR_TOO_MANY_ARGUMENTS, /* expected is number of arguments */
NATIVE_CALL_ERROR_TOO_FEW_ARGUMENTS, /* expected is number of arguments */
NATIVE_CALL_ERROR_INSTANCE_IS_NULL,
} GDNativeCallErrorType;
typedef struct {
GDNativeCallErrorType error;
int32_t argument;
int32_t expected;
} GDNativeCallError;
typedef void (*GDNativeVariantFromTypeConstructorFunc)(GDNativeVariantPtr, GDNativeTypePtr);
typedef void (*GDNativeTypeFromVariantConstructorFunc)(GDNativeTypePtr, GDNativeVariantPtr);
typedef void (*GDNativePtrOperatorEvaluator)(const GDNativeTypePtr p_left, const GDNativeTypePtr p_right, GDNativeTypePtr r_result);
typedef void (*GDNativePtrBuiltInMethod)(GDNativeTypePtr p_base, const GDNativeTypePtr *p_args, GDNativeTypePtr r_return, int p_argument_count);
typedef void (*GDNativePtrConstructor)(GDNativeTypePtr p_base, const GDNativeTypePtr *p_args);
typedef void (*GDNativePtrSetter)(GDNativeTypePtr p_base, const GDNativeTypePtr p_value);
typedef void (*GDNativePtrGetter)(const GDNativeTypePtr p_base, GDNativeTypePtr r_value);
typedef void (*GDNativePtrIndexedSetter)(GDNativeTypePtr p_base, GDNativeInt p_index, const GDNativeTypePtr p_value);
typedef void (*GDNativePtrIndexedGetter)(const GDNativeTypePtr p_base, GDNativeInt p_index, GDNativeTypePtr r_value);
typedef void (*GDNativePtrKeyedSetter)(GDNativeTypePtr p_base, const GDNativeTypePtr p_key, const GDNativeTypePtr p_value);
typedef void (*GDNativePtrKeyedGetter)(const GDNativeTypePtr p_base, const GDNativeTypePtr p_key, GDNativeTypePtr r_value);
typedef uint32_t (*GDNativePtrKeyedChecker)(const GDNativeVariantPtr p_base, const GDNativeVariantPtr p_key);
typedef void (*GDNativePtrUtilityFunction)(GDNativeTypePtr r_return, const GDNativeTypePtr *p_arguments, int p_argument_count);
typedef GDNativeObjectPtr (*GDNativeClassConstructor)();
/* EXTENSION CLASSES */
typedef void *GDExtensionClassInstancePtr;
typedef GDNativeBool (*GDNativeExtensionClassSet)(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, const GDNativeVariantPtr p_value);
typedef GDNativeBool (*GDNativeExtensionClassGet)(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret);
typedef struct {
uint32_t type;
const char *name;
const char *class_name;
uint32_t hint;
const char *hint_string;
uint32_t usage;
} GDNativePropertyInfo;
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);
typedef const char *(*GDNativeExtensionClassToString)(GDExtensionClassInstancePtr p_instance);
typedef void (*GDNativeExtensionClassReference)(GDExtensionClassInstancePtr p_instance);
typedef void (*GDNativeExtensionClassUnreference)(GDExtensionClassInstancePtr p_instance);
typedef void (*GDNativeExtensionClassCallVirtual)(GDExtensionClassInstancePtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret);
typedef GDExtensionClassInstancePtr (*GDNativeExtensionClassCreateInstance)(void *p_userdata);
typedef void (*GDNativeExtensionClassFreeInstance)(void *p_userdata, GDExtensionClassInstancePtr p_instance);
typedef GDNativeExtensionClassCallVirtual (*GDNativeExtensionClassGetVirtual)(void *p_userdata, const char *p_name);
typedef struct {
GDNativeExtensionClassSet set_func;
GDNativeExtensionClassGet get_func;
GDNativeExtensionClassGetPropertyList get_property_list_func;
GDNativeExtensionClassFreePropertyList free_property_list_func;
GDNativeExtensionClassNotification notification_func;
GDNativeExtensionClassToString to_string_func;
GDNativeExtensionClassReference reference_func;
GDNativeExtensionClassUnreference unreference_func;
GDNativeExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
GDNativeExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
GDNativeExtensionClassGetVirtual get_firtual_func;
void *class_userdata;
} GDNativeExtensionClassCreationInfo;
typedef void *GDNativeExtensionClassLibraryPtr;
typedef const GDNativePropertyInfo *(*GDNativeExtensionClassGetPropertyList)(GDExtensionClassInstancePtr p_instance, uint32_t *r_count);
/* Method */
typedef enum {
GDNATIVE_EXTENSION_METHOD_FLAG_NORMAL = 1,
GDNATIVE_EXTENSION_METHOD_FLAG_EDITOR = 2,
GDNATIVE_EXTENSION_METHOD_FLAG_NOSCRIPT = 4,
GDNATIVE_EXTENSION_METHOD_FLAG_CONST = 8,
GDNATIVE_EXTENSION_METHOD_FLAG_REVERSE = 16, /* used for events */
GDNATIVE_EXTENSION_METHOD_FLAG_VIRTUAL = 32,
GDNATIVE_EXTENSION_METHOD_FLAG_FROM_SCRIPT = 64,
GDNATIVE_EXTENSION_METHOD_FLAG_VARARG = 128,
GDNATIVE_EXTENSION_METHOD_FLAG_STATIC = 256,
GDNATIVE_EXTENSION_METHOD_FLAGS_DEFAULT = GDNATIVE_EXTENSION_METHOD_FLAG_NORMAL,
} GDNativeExtensionClassMethodFlags;
typedef enum {
GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_NONE,
GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT8,
GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT16,
GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT32,
GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT64,
GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT8,
GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT16,
GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT32,
GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT64,
GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_FLOAT,
GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_DOUBLE
} GDNativeExtensionClassMethodArgumentMetadata;
typedef void (*GDNativeExtensionClassMethodCall)(GDExtensionClassInstancePtr p_instance, const GDNativeVariantPtr *p_args, const GDNativeInt p_argument_count, GDNativeVariantPtr r_return, GDNativeCallError *r_error);
typedef void (*GDNativeExtensionClassMethodPtrCall)(GDExtensionClassInstancePtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret);
/* passing -1 as argument in the following functions refers to the return type */
typedef GDNativeVariantType (*GDNativeExtensionClassMethodGetArgumentType)(void *p_method_userdata, int32_t p_argument);
typedef void (*GDNativeExtensionClassMethodGetArgumentInfo)(void *p_method_userdata, int32_t p_argument, GDNativePropertyInfo *r_info);
typedef GDNativeExtensionClassMethodArgumentMetadata (*GDNativeExtensionClassMethodGetArgumentMetadata)(void *p_method_userdata, int32_t p_argument);
typedef struct {
const char *name;
void *method_userdata;
GDNativeExtensionClassMethodCall call_func;
GDNativeExtensionClassMethodPtrCall ptrcall_func;
uint32_t method_flags; /* GDNativeExtensionClassMethodFlags */
uint32_t argument_count;
GDNativeBool has_return_value;
GDNativeExtensionClassMethodGetArgumentType get_argument_type_func;
GDNativeExtensionClassMethodGetArgumentInfo get_argument_info_func; /* name and hint information for the argument can be omitted in release builds. Class name should always be present if it applies. */
GDNativeExtensionClassMethodGetArgumentMetadata get_argument_metadata_func;
uint32_t default_argument_count;
GDNativeVariantPtr *default_arguments;
} GDNativeExtensionClassMethodInfo;
/* INTERFACE */
typedef struct {
uint32_t version_major;
uint32_t version_minor;
uint32_t version_patch;
const char *version_string;
/* GODOT CORE */
void *(*mem_alloc)(size_t p_bytes);
void *(*mem_realloc)(void *p_ptr, size_t p_bytes);
void (*mem_free)(void *p_ptr);
void (*print_error)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line);
void (*print_warning)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line);
void (*print_script_error)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line);
/* GODOT VARIANT */
/* variant general */
void (*variant_new_copy)(GDNativeVariantPtr r_dest, const GDNativeVariantPtr p_src);
void (*variant_new_nil)(GDNativeVariantPtr r_dest);
void (*variant_destroy)(GDNativeVariantPtr p_self);
/* variant type */
void (*variant_call)(GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_method, const GDNativeVariantPtr *p_args, const GDNativeInt p_argument_count, GDNativeVariantPtr r_return, GDNativeCallError *r_error);
void (*variant_call_static)(GDNativeVariantType p_type, const GDNativeStringNamePtr p_method, const GDNativeVariantPtr *p_args, const GDNativeInt p_argument_count, GDNativeVariantPtr r_return, GDNativeCallError *r_error);
void (*variant_evaluate)(GDNativeVariantOperator p_op, const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, GDNativeVariantPtr r_return, GDNativeBool *r_valid);
void (*variant_set)(GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, const GDNativeVariantPtr p_value, GDNativeBool *r_valid);
void (*variant_set_named)(GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_key, const GDNativeVariantPtr p_value, GDNativeBool *r_valid);
void (*variant_set_keyed)(GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, const GDNativeVariantPtr p_value, GDNativeBool *r_valid);
void (*variant_set_indexed)(GDNativeVariantPtr p_self, GDNativeInt p_index, const GDNativeVariantPtr p_value, GDNativeBool *r_valid, GDNativeBool *r_oob);
void (*variant_get)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, GDNativeVariantPtr r_ret, GDNativeBool *r_valid);
void (*variant_get_named)(const GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_key, GDNativeVariantPtr r_ret, GDNativeBool *r_valid);
void (*variant_get_keyed)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, GDNativeVariantPtr r_ret, GDNativeBool *r_valid);
void (*variant_get_indexed)(const GDNativeVariantPtr p_self, GDNativeInt p_index, GDNativeVariantPtr r_ret, GDNativeBool *r_valid, GDNativeBool *r_oob);
GDNativeBool (*variant_iter_init)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeBool *r_valid);
GDNativeBool (*variant_iter_next)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeBool *r_valid);
void (*variant_iter_get)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeVariantPtr r_ret, GDNativeBool *r_valid);
GDNativeBool (*variant_hash_compare)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_other);
GDNativeBool (*variant_booleanize)(const GDNativeVariantPtr p_self);
void (*variant_blend)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst);
void (*variant_interpolate)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst);
void (*variant_duplicate)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_ret, GDNativeBool p_deep);
void (*variant_stringify)(const GDNativeVariantPtr p_self, GDNativeStringPtr r_ret);
GDNativeVariantType (*variant_get_type)(const GDNativeVariantPtr p_self);
GDNativeBool (*variant_has_method)(const GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_method);
GDNativeBool (*variant_has_member)(GDNativeVariantType p_type, const GDNativeStringNamePtr p_member);
GDNativeBool (*variant_has_key)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, GDNativeBool *r_valid);
void (*variant_get_type_name)(GDNativeVariantType p_type, GDNativeStringPtr r_name);
GDNativeBool (*variant_can_convert)(GDNativeVariantType p_from, GDNativeVariantType p_to);
GDNativeBool (*variant_can_convert_strict)(GDNativeVariantType p_from, GDNativeVariantType p_to);
/* ptrcalls */
GDNativeVariantFromTypeConstructorFunc (*get_variant_from_type_constructor)(GDNativeVariantType p_type);
GDNativeTypeFromVariantConstructorFunc (*get_variant_to_type_constructor)(GDNativeVariantType p_type);
GDNativePtrOperatorEvaluator (*variant_get_ptr_operator_evaluator)(GDNativeVariantOperator p_operator, GDNativeVariantType p_type_a, GDNativeVariantType p_type_b);
GDNativePtrBuiltInMethod (*variant_get_ptr_builtin_method)(GDNativeVariantType p_type, const char *p_method, GDNativeInt p_hash);
GDNativePtrConstructor (*variant_get_ptr_constructor)(GDNativeVariantType p_type, int32_t p_constructor);
void (*variant_construct)(GDNativeVariantType p_type, GDNativeVariantPtr p_base, const GDNativeVariantPtr *p_args, int32_t p_argument_count, GDNativeCallError *r_error);
GDNativePtrSetter (*variant_get_ptr_setter)(GDNativeVariantType p_type, const char *p_member);
GDNativePtrGetter (*variant_get_ptr_getter)(GDNativeVariantType p_type, const char *p_member);
GDNativePtrIndexedSetter (*variant_get_ptr_indexed_setter)(GDNativeVariantType p_type);
GDNativePtrIndexedGetter (*variant_get_ptr_indexed_getter)(GDNativeVariantType p_type);
GDNativePtrKeyedSetter (*variant_get_ptr_keyed_setter)(GDNativeVariantType p_type);
GDNativePtrKeyedGetter (*variant_get_ptr_keyed_getter)(GDNativeVariantType p_type);
GDNativePtrKeyedChecker (*variant_get_ptr_keyed_checker)(GDNativeVariantType p_type);
void (*variant_get_constant_value)(GDNativeVariantType p_type, const char *p_constant, GDNativeVariantPtr r_ret);
GDNativePtrUtilityFunction (*variant_get_ptr_utility_function)(const char *p_function, GDNativeInt p_hash);
/* extra utilities */
void (*string_new_with_latin1_chars)(GDNativeStringPtr r_dest, const char *p_contents);
void (*string_new_with_utf8_chars)(GDNativeStringPtr r_dest, const char *p_contents);
void (*string_new_with_utf16_chars)(GDNativeStringPtr r_dest, const char16_t *p_contents);
void (*string_new_with_utf32_chars)(GDNativeStringPtr r_dest, const char32_t *p_contents);
void (*string_new_with_wide_chars)(GDNativeStringPtr r_dest, const wchar_t *p_contents);
void (*string_new_with_latin1_chars_and_len)(GDNativeStringPtr r_dest, const char *p_contents, const GDNativeInt p_size);
void (*string_new_with_utf8_chars_and_len)(GDNativeStringPtr r_dest, const char *p_contents, const GDNativeInt p_size);
void (*string_new_with_utf16_chars_and_len)(GDNativeStringPtr r_dest, const char16_t *p_contents, const GDNativeInt p_size);
void (*string_new_with_utf32_chars_and_len)(GDNativeStringPtr r_dest, const char32_t *p_contents, const GDNativeInt p_size);
void (*string_new_with_wide_chars_and_len)(GDNativeStringPtr r_dest, const wchar_t *p_contents, const GDNativeInt p_size);
/* Information about the following functions:
* - The return value is the resulting encoded string length.
* - The length returned is in characters, not in bytes. It also does not include a trailing zero.
* - These functions also do not write trailing zero, If you need it, write it yourself at the position indicated by the length (and make sure to allocate it).
* - Passing NULL in r_text means only the length is computed (again, without including trailing zero).
* - p_max_write_length argument is in characters, not bytes. It will be ignored if r_text is NULL.
* - p_max_write_length argument does not affect the return value, it's only to cap write length.
*/
GDNativeInt (*string_to_latin1_chars)(const GDNativeStringPtr p_self, char *r_text, GDNativeInt p_max_write_length);
GDNativeInt (*string_to_utf8_chars)(const GDNativeStringPtr p_self, char *r_text, GDNativeInt p_max_write_length);
GDNativeInt (*string_to_utf16_chars)(const GDNativeStringPtr p_self, char16_t *r_text, GDNativeInt p_max_write_length);
GDNativeInt (*string_to_utf32_chars)(const GDNativeStringPtr p_self, char32_t *r_text, GDNativeInt p_max_write_length);
GDNativeInt (*string_to_wide_chars)(const GDNativeStringPtr p_self, wchar_t *r_text, GDNativeInt p_max_write_length);
char32_t *(*string_operator_index)(GDNativeStringPtr p_self, GDNativeInt p_index);
const char32_t *(*string_operator_index_const)(const GDNativeStringPtr p_self, GDNativeInt p_index);
/* OBJECT */
void (*object_method_bind_ptrcall)(GDNativeMethodBindPtr p_method_bind, GDNativeObjectPtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret);
void (*object_destroy)(GDNativeObjectPtr p_o);
GDNativeObjectPtr (*global_get_singleton)(const char *p_name);
GDNativeObjectPtr (*object_cast_to)(const GDNativeObjectPtr p_object, void *p_class_tag);
GDNativeObjectPtr (*object_get_instance_from_id)(GDObjectInstanceID p_instance_id);
GDObjectInstanceID (*object_get_instance_id)(const GDNativeObjectPtr p_object);
/* CLASSDB */
GDNativeClassConstructor (*classdb_get_constructor)(const char *p_classname);
GDNativeMethodBindPtr (*classdb_get_method_bind)(const char *p_classname, const char *p_methodname, GDNativeInt p_hash);
void *(*classdb_get_class_tag)(const char *p_classname);
/* CLASSDB EXTENSION */
void (*classdb_register_extension_class)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs);
void (*classdb_register_extension_class_method)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info);
void (*classdb_register_extension_class_integer_constant)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_enum_name, const char *p_class_name, const char *p_constant_name, uint32_t p_constant_value);
void (*classdb_register_extension_class_property)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativePropertyInfo *p_info, const char *p_setter, const char *p_getter);
void (*classdb_register_extension_class_signal)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count);
void (*classdb_unregister_extension_class)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name); /* Unregistering a parent class before a class that inherits it will result in failure. Inheritors must be unregistered first. */
} GDNativeInterface;
/* INITIALIZATION */
typedef enum {
GDNATIVE_INITIALIZATION_CORE,
GDNATIVE_INITIALIZATION_SERVERS,
GDNATIVE_INITIALIZATION_SCENE,
GDNATIVE_INITIALIZATION_EDITOR,
} GDNativeInitializationLevel;
typedef struct {
/* Minimum initialization level required.
* If Core or Servers, the extension needs editor or game restart to take effect */
GDNativeInitializationLevel minimum_initialization_level;
/* Up to the user to supply when initializing */
void *userdata;
/* This function will be called multiple times for each initialization level. */
void (*initialize)(void *userdata, GDNativeInitializationLevel p_level);
void (*deinitialize)(void *userdata, GDNativeInitializationLevel p_level);
} GDNativeInitialization;
/* Define a C function prototype that implements the function below and expose it to dlopen() (or similar).
* It will be called on initialization. The name must be an unique one specified in the .gdextension config file.
*/
typedef GDNativeBool (*GDNativeInitializationFunction)(const GDNativeInterface *p_interface, const GDNativeExtensionClassLibraryPtr p_library, GDNativeInitialization *r_initialization);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,411 @@
/*************************************************************************/
/* native_extension.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "native_extension.h"
#include "core/io/config_file.h"
#include "core/object/class_db.h"
#include "core/object/method_bind.h"
#include "core/os/os.h"
class NativeExtensionMethodBind : public MethodBind {
GDNativeExtensionClassMethodCall call_func;
GDNativeExtensionClassMethodPtrCall ptrcall_func;
GDNativeExtensionClassMethodGetArgumentType get_argument_type_func;
GDNativeExtensionClassMethodGetArgumentInfo get_argument_info_func;
GDNativeExtensionClassMethodGetArgumentMetadata get_argument_metadata_func;
void *method_userdata;
bool vararg;
protected:
virtual Variant::Type _gen_argument_type(int p_arg) const {
return Variant::Type(get_argument_type_func(method_userdata, p_arg));
}
virtual PropertyInfo _gen_argument_type_info(int p_arg) const {
GDNativePropertyInfo pinfo;
get_argument_info_func(method_userdata, p_arg, &pinfo);
PropertyInfo ret;
ret.type = Variant::Type(pinfo.type);
ret.name = pinfo.name;
ret.class_name = pinfo.class_name;
ret.hint = PropertyHint(pinfo.hint);
ret.usage = pinfo.usage;
ret.class_name = pinfo.class_name;
return ret;
}
public:
virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
return GodotTypeInfo::Metadata(get_argument_metadata_func(method_userdata, p_arg));
}
virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
Variant ret;
GDExtensionClassInstancePtr extension_instance = p_object->_get_extension_instance();
GDNativeCallError ce;
call_func(extension_instance, (const GDNativeVariantPtr *)p_args, p_arg_count, (GDNativeVariantPtr)&ret, &ce);
r_error.error = Callable::CallError::Error(ce.error);
r_error.argument = ce.argument;
r_error.expected = ce.expected;
return ret;
}
virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) {
ERR_FAIL_COND_MSG(vararg, "Vararg methods don't have ptrcall support. This is most likely an engine bug.");
GDExtensionClassInstancePtr extension_instance = p_object->_get_extension_instance();
ptrcall_func(extension_instance, (const GDNativeTypePtr *)p_args, (GDNativeTypePtr)r_ret);
}
virtual bool is_vararg() const {
return false;
}
NativeExtensionMethodBind(const GDNativeExtensionClassMethodInfo *p_method_info) {
method_userdata = p_method_info->method_userdata;
call_func = p_method_info->call_func;
ptrcall_func = p_method_info->ptrcall_func;
get_argument_type_func = p_method_info->get_argument_type_func;
get_argument_info_func = p_method_info->get_argument_info_func;
get_argument_metadata_func = p_method_info->get_argument_metadata_func;
vararg = p_method_info->method_flags & GDNATIVE_EXTENSION_METHOD_FLAG_VARARG;
_set_returns(p_method_info->has_return_value);
_set_const(p_method_info->method_flags & GDNATIVE_EXTENSION_METHOD_FLAG_CONST);
#ifdef DEBUG_METHODS_ENABLED
_generate_argument_types(p_method_info->argument_count);
#endif
set_argument_count(p_method_info->argument_count);
}
};
static GDNativeInterface gdnative_interface;
void NativeExtension::_register_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs) {
NativeExtension *self = (NativeExtension *)p_library;
StringName class_name = p_class_name;
ERR_FAIL_COND_MSG(String(class_name).is_valid_identifier(), "Attempt to register extension clas '" + class_name + "', which is not a valid class identifier.");
ERR_FAIL_COND_MSG(ClassDB::class_exists(class_name), "Attempt to register extension class '" + class_name + "', which appears to be already registered.");
Extension *parent_extension = nullptr;
StringName parent_class_name = p_parent_class_name;
if (self->extension_classes.has(parent_class_name)) {
parent_extension = &self->extension_classes[parent_class_name];
} else if (ClassDB::class_exists(parent_class_name)) {
if (ClassDB::get_api_type(parent_class_name) == ClassDB::API_EXTENSION || ClassDB::get_api_type(parent_class_name) == ClassDB::API_EDITOR_EXTENSION) {
ERR_PRINT("Unimplemented yet");
//inheriting from another extension
} else {
//inheriting from engine class
}
} else {
ERR_FAIL_MSG("Attempt to register an extension class '" + String(class_name) + "' using non-existing parent class '" + String(parent_class_name) + "'");
}
self->extension_classes[class_name] = Extension();
Extension *extension = &self->extension_classes[class_name];
if (parent_extension) {
extension->native_extension.parent = &parent_extension->native_extension;
parent_extension->native_extension.children.push_back(&extension->native_extension);
}
extension->native_extension.parent_class_name = parent_class_name;
extension->native_extension.class_name = class_name;
extension->native_extension.editor_class = self->level_initialized == INITIALIZATION_LEVEL_EDITOR;
extension->native_extension.set = p_extension_funcs->set_func;
extension->native_extension.get = p_extension_funcs->get_func;
extension->native_extension.get_property_list = p_extension_funcs->get_property_list_func;
extension->native_extension.free_property_list = p_extension_funcs->free_property_list_func;
extension->native_extension.notification = p_extension_funcs->notification_func;
extension->native_extension.to_string = p_extension_funcs->to_string_func;
extension->native_extension.reference = p_extension_funcs->reference_func;
extension->native_extension.unreference = p_extension_funcs->unreference_func;
extension->native_extension.class_userdata = p_extension_funcs->class_userdata;
extension->native_extension.create_instance = p_extension_funcs->create_instance_func;
extension->native_extension.free_instance = p_extension_funcs->free_instance_func;
ClassDB::register_extension_class(&extension->native_extension);
}
void NativeExtension::_register_extension_class_method(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info) {
NativeExtension *self = (NativeExtension *)p_library;
StringName class_name = p_class_name;
StringName method_name = p_method_info->name;
ERR_FAIL_COND_MSG(self->extension_classes.has(class_name), "Attempt to register extension method '" + String(method_name) + "' for unexisting class '" + class_name + "'.");
//Extension *extension = &self->extension_classes[class_name];
NativeExtensionMethodBind *method = memnew(NativeExtensionMethodBind(p_method_info));
ClassDB::bind_method_custom(class_name, method);
}
void NativeExtension::_register_extension_class_integer_constant(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_enum_name, const char *p_constant_name, uint32_t p_constant_value) {
NativeExtension *self = (NativeExtension *)p_library;
StringName class_name = p_class_name;
ERR_FAIL_COND_MSG(self->extension_classes.has(class_name), "Attempt to register extension constant '" + String(p_constant_name) + "' for unexisting class '" + class_name + "'.");
//Extension *extension = &self->extension_classes[class_name];
ClassDB::bind_integer_constant(class_name, p_enum_name, p_constant_name, p_constant_value);
}
void NativeExtension::_register_extension_class_property(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativePropertyInfo *p_info, const char *p_setter, const char *p_getter) {
NativeExtension *self = (NativeExtension *)p_library;
StringName class_name = p_class_name;
ERR_FAIL_COND_MSG(self->extension_classes.has(class_name), "Attempt to register extension class property '" + String(p_info->name) + "' for unexisting class '" + class_name + "'.");
//Extension *extension = &self->extension_classes[class_name];
PropertyInfo pinfo;
pinfo.type = Variant::Type(p_info->type);
pinfo.name = p_info->name;
pinfo.class_name = p_info->class_name;
pinfo.hint = PropertyHint(p_info->hint);
pinfo.hint_string = p_info->hint_string;
pinfo.usage = p_info->usage;
ClassDB::add_property(class_name, pinfo, p_setter, p_getter);
}
void NativeExtension::_register_extension_class_signal(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count) {
NativeExtension *self = (NativeExtension *)p_library;
StringName class_name = p_class_name;
ERR_FAIL_COND_MSG(self->extension_classes.has(class_name), "Attempt to register extension class signal '" + String(p_signal_name) + "' for unexisting class '" + class_name + "'.");
MethodInfo s;
s.name = p_signal_name;
for (int i = 0; i < p_argument_count; i++) {
PropertyInfo arg;
arg.type = Variant::Type(p_argument_info[i].type);
arg.name = p_argument_info[i].name;
arg.class_name = p_argument_info[i].class_name;
arg.hint = PropertyHint(p_argument_info[i].hint);
arg.hint_string = p_argument_info[i].hint_string;
arg.usage = p_argument_info[i].usage;
s.arguments.push_back(arg);
}
ClassDB::add_signal(class_name, s);
}
void NativeExtension::_unregister_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name) {
NativeExtension *self = (NativeExtension *)p_library;
StringName class_name = p_class_name;
ERR_FAIL_COND_MSG(self->extension_classes.has(class_name), "Attempt to unregister unexisting extension class '" + class_name + "'.");
Extension *ext = &self->extension_classes[class_name];
ERR_FAIL_COND_MSG(ext->native_extension.children.size(), "Attempt to unregister class '" + class_name + "' while other extension classes inherit from it.");
ClassDB::unregister_extension_class(class_name);
if (ext->native_extension.parent != nullptr) {
ext->native_extension.parent->children.erase(&ext->native_extension);
}
self->extension_classes.erase(class_name);
}
Error NativeExtension::open_library(const String &p_path, const String &p_entry_symbol) {
Error err = OS::get_singleton()->open_dynamic_library(p_path, library, true);
if (err != OK) {
return err;
}
void *entry_funcptr = nullptr;
err = OS::get_singleton()->get_dynamic_library_symbol_handle(library, p_entry_symbol, entry_funcptr, false);
if (err != OK) {
OS::get_singleton()->close_dynamic_library(library);
return err;
}
GDNativeInitializationFunction initialization_function = (GDNativeInitializationFunction)entry_funcptr;
initialization_function(&gdnative_interface, this, &initialization);
level_initialized = -1;
return OK;
}
void NativeExtension::close_library() {
ERR_FAIL_COND(library == nullptr);
OS::get_singleton()->close_dynamic_library(library);
library = nullptr;
}
bool NativeExtension::is_library_open() const {
return library != nullptr;
}
NativeExtension::InitializationLevel NativeExtension::get_minimum_library_initialization_level() const {
ERR_FAIL_COND_V(library == nullptr, INITIALIZATION_LEVEL_CORE);
return InitializationLevel(initialization.minimum_initialization_level);
}
void NativeExtension::initialize_library(InitializationLevel p_level) {
ERR_FAIL_COND(library == nullptr);
ERR_FAIL_COND(p_level <= int32_t(level_initialized));
level_initialized = int32_t(p_level);
ERR_FAIL_COND(initialization.initialize == nullptr);
initialization.initialize(initialization.userdata, GDNativeInitializationLevel(p_level));
}
void NativeExtension::deinitialize_library(InitializationLevel p_level) {
ERR_FAIL_COND(library == nullptr);
ERR_FAIL_COND(p_level > int32_t(level_initialized));
level_initialized = int32_t(p_level) - 1;
initialization.deinitialize(initialization.userdata, GDNativeInitializationLevel(p_level));
}
void NativeExtension::_bind_methods() {
ClassDB::bind_method(D_METHOD("open_library", "path", "entry_symbol"), &NativeExtension::open_library);
ClassDB::bind_method(D_METHOD("close_library"), &NativeExtension::close_library);
ClassDB::bind_method(D_METHOD("is_library_open"), &NativeExtension::is_library_open);
ClassDB::bind_method(D_METHOD("get_minimum_library_initialization_level"), &NativeExtension::get_minimum_library_initialization_level);
ClassDB::bind_method(D_METHOD("initialize_library", "level"), &NativeExtension::initialize_library);
BIND_ENUM_CONSTANT(INITIALIZATION_LEVEL_CORE);
BIND_ENUM_CONSTANT(INITIALIZATION_LEVEL_SERVERS);
BIND_ENUM_CONSTANT(INITIALIZATION_LEVEL_SCENE);
BIND_ENUM_CONSTANT(INITIALIZATION_LEVEL_EDITOR);
}
NativeExtension::NativeExtension() {
}
NativeExtension::~NativeExtension() {
if (library != nullptr) {
close_library();
}
}
extern void gdnative_setup_interface(GDNativeInterface *p_interface);
void NativeExtension::initialize_native_extensions() {
gdnative_setup_interface(&gdnative_interface);
gdnative_interface.classdb_register_extension_class = _register_extension_class;
gdnative_interface.classdb_register_extension_class_method = _register_extension_class_method;
gdnative_interface.classdb_register_extension_class_integer_constant = _register_extension_class_integer_constant;
gdnative_interface.classdb_register_extension_class_property = _register_extension_class_property;
gdnative_interface.classdb_register_extension_class_signal = _register_extension_class_signal;
gdnative_interface.classdb_unregister_extension_class = _unregister_extension_class;
}
RES NativeExtensionResourceLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
Ref<ConfigFile> config;
config.instantiate();
Error err = config->load(p_path);
if (r_error) {
*r_error = err;
}
if (err != OK) {
return RES();
}
if (!config->has_section_key("configuration", "entry_symbol")) {
if (r_error) {
*r_error = ERR_INVALID_DATA;
}
return RES();
}
String entry_symbol = config->get_value("configuration", "entry_symbol");
List<String> libraries;
config->get_section_keys("libraries", &libraries);
String library_path;
for (List<String>::Element *E = libraries.front(); E; E = E->next()) {
Vector<String> tags = E->get().split(".");
bool all_tags_met = true;
for (int i = 0; i < tags.size(); i++) {
String tag = tags[i].strip_edges();
if (!OS::get_singleton()->has_feature(tag)) {
all_tags_met = false;
break;
}
}
if (all_tags_met) {
library_path = config->get_value("libraries", E->get());
break;
}
}
if (library_path != String()) {
if (r_error) {
*r_error = ERR_FILE_NOT_FOUND;
}
return RES();
}
if (!library_path.is_resource_file()) {
library_path = p_path.get_base_dir().plus_file(library_path);
}
Ref<NativeExtension> lib;
lib.instantiate();
err = lib->open_library(library_path, entry_symbol);
if (r_error) {
*r_error = err;
}
if (err != OK) {
return RES();
}
return lib;
}
void NativeExtensionResourceLoader::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("gdextension");
}
bool NativeExtensionResourceLoader::handles_type(const String &p_type) const {
return p_type == "NativeExtension";
}
String NativeExtensionResourceLoader::get_resource_type(const String &p_path) const {
String el = p_path.get_extension().to_lower();
if (el == "gdextension") {
return "NativeExtension";
}
return "";
}

View File

@ -0,0 +1,94 @@
/*************************************************************************/
/* native_extension.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef NATIVE_EXTENSION_H
#define NATIVE_EXTENSION_H
#include "core/extension/gdnative_interface.h"
#include "core/io/resource_loader.h"
#include "core/object/ref_counted.h"
class NativeExtension : public RefCounted {
GDCLASS(NativeExtension, RefCounted)
void *library = nullptr; // pointer if valid,
struct Extension {
ObjectNativeExtension native_extension;
};
Map<StringName, Extension> extension_classes;
static void _register_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs);
static void _register_extension_class_method(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info);
static void _register_extension_class_integer_constant(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_enum_name, const char *p_constant_name, uint32_t p_constant_value);
static void _register_extension_class_property(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativePropertyInfo *p_info, const char *p_setter, const char *p_getter);
static void _register_extension_class_signal(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count);
static void _unregister_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name);
GDNativeInitialization initialization;
int32_t level_initialized = -1;
protected:
static void _bind_methods();
public:
Error open_library(const String &p_path, const String &p_entry_symbol);
void close_library();
enum InitializationLevel {
INITIALIZATION_LEVEL_CORE,
INITIALIZATION_LEVEL_SERVERS,
INITIALIZATION_LEVEL_SCENE,
INITIALIZATION_LEVEL_EDITOR,
};
bool is_library_open() const;
InitializationLevel get_minimum_library_initialization_level() const;
void initialize_library(InitializationLevel p_level);
void deinitialize_library(InitializationLevel p_level);
static void initialize_native_extensions();
NativeExtension();
~NativeExtension();
};
VARIANT_ENUM_CAST(NativeExtension::InitializationLevel)
class NativeExtensionResourceLoader : public ResourceFormatLoader {
public:
virtual RES load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
};
#endif // NATIVEEXTENSION_H

View File

@ -0,0 +1,130 @@
/*************************************************************************/
/* native_extension_manager.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "native_extension_manager.h"
NativeExtensionManager::LoadStatus NativeExtensionManager::load_extension(const String &p_path) {
if (native_extension_map.has(p_path)) {
return LOAD_STATUS_ALREADY_LOADED;
}
Ref<NativeExtension> extension = ResourceLoader::load(p_path);
if (extension.is_null()) {
return LOAD_STATUS_FAILED;
}
if (level >= 0) { //already initialized up to some level
int32_t minimum_level = extension->get_minimum_library_initialization_level();
if (minimum_level < MIN(level, NativeExtension::INITIALIZATION_LEVEL_SCENE)) {
return LOAD_STATUS_NEEDS_RESTART;
}
//initialize up to current level
for (int32_t i = minimum_level; i < level; i++) {
extension->initialize_library(NativeExtension::InitializationLevel(level));
}
}
native_extension_map[p_path] = extension;
return LOAD_STATUS_OK;
}
NativeExtensionManager::LoadStatus NativeExtensionManager::reload_extension(const String &p_path) {
return LOAD_STATUS_OK; //TODO
}
NativeExtensionManager::LoadStatus NativeExtensionManager::unload_extension(const String &p_path) {
if (!native_extension_map.has(p_path)) {
return LOAD_STATUS_NOT_LOADED;
}
Ref<NativeExtension> extension = native_extension_map[p_path];
if (level >= 0) { //already initialized up to some level
int32_t minimum_level = extension->get_minimum_library_initialization_level();
if (minimum_level < MIN(level, NativeExtension::INITIALIZATION_LEVEL_SCENE)) {
return LOAD_STATUS_NEEDS_RESTART;
}
//initialize up to current level
for (int32_t i = level; i >= minimum_level; i--) {
extension->deinitialize_library(NativeExtension::InitializationLevel(level));
}
}
native_extension_map.erase(p_path);
return LOAD_STATUS_OK;
}
Vector<String> NativeExtensionManager::get_loaded_extensions() const {
Vector<String> ret;
for (const Map<String, Ref<NativeExtension>>::Element *E = native_extension_map.front(); E; E = E->next()) {
ret.push_back(E->key());
}
return ret;
}
Ref<NativeExtension> NativeExtensionManager::get_extension(const String &p_path) {
Map<String, Ref<NativeExtension>>::Element *E = native_extension_map.find(p_path);
ERR_FAIL_COND_V(!E, Ref<NativeExtension>());
return E->get();
}
void NativeExtensionManager::initialize_extensions(NativeExtension::InitializationLevel p_level) {
ERR_FAIL_COND(int32_t(p_level) - 1 != level);
for (Map<String, Ref<NativeExtension>>::Element *E = native_extension_map.front(); E; E = E->next()) {
E->get()->initialize_library(p_level);
}
level = p_level;
}
void NativeExtensionManager::deinitialize_extensions(NativeExtension::InitializationLevel p_level) {
ERR_FAIL_COND(int32_t(p_level) != level);
for (Map<String, Ref<NativeExtension>>::Element *E = native_extension_map.front(); E; E = E->next()) {
E->get()->deinitialize_library(p_level);
}
level = int32_t(p_level) - 1;
}
NativeExtensionManager *NativeExtensionManager::get_singleton() {
return singleton;
}
void NativeExtensionManager::_bind_methods() {
ClassDB::bind_method(D_METHOD("load_extension", "path"), &NativeExtensionManager::load_extension);
ClassDB::bind_method(D_METHOD("reload_extension", "path"), &NativeExtensionManager::reload_extension);
ClassDB::bind_method(D_METHOD("unload_extension", "path"), &NativeExtensionManager::unload_extension);
ClassDB::bind_method(D_METHOD("get_loaded_extensions"), &NativeExtensionManager::get_loaded_extensions);
ClassDB::bind_method(D_METHOD("get_extension", "path"), &NativeExtensionManager::get_extension);
BIND_ENUM_CONSTANT(LOAD_STATUS_OK);
BIND_ENUM_CONSTANT(LOAD_STATUS_FAILED);
BIND_ENUM_CONSTANT(LOAD_STATUS_ALREADY_LOADED);
BIND_ENUM_CONSTANT(LOAD_STATUS_NOT_LOADED);
BIND_ENUM_CONSTANT(LOAD_STATUS_NEEDS_RESTART);
}
NativeExtensionManager *NativeExtensionManager::singleton = nullptr;
NativeExtensionManager::NativeExtensionManager() {
ERR_FAIL_COND(singleton != nullptr);
singleton = this;
}

View File

@ -0,0 +1,71 @@
/*************************************************************************/
/* native_extension_manager.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef NATIVE_EXTENSION_MANAGER_H
#define NATIVE_EXTENSION_MANAGER_H
#include "core/extension/native_extension.h"
class NativeExtensionManager : public Object {
GDCLASS(NativeExtensionManager, Object);
int32_t level = -1;
Map<String, Ref<NativeExtension>> native_extension_map;
static void _bind_methods();
static NativeExtensionManager *singleton;
public:
enum LoadStatus {
LOAD_STATUS_OK,
LOAD_STATUS_FAILED,
LOAD_STATUS_ALREADY_LOADED,
LOAD_STATUS_NOT_LOADED,
LOAD_STATUS_NEEDS_RESTART,
};
LoadStatus load_extension(const String &p_path);
LoadStatus reload_extension(const String &p_path);
LoadStatus unload_extension(const String &p_path);
Vector<String> get_loaded_extensions() const;
Ref<NativeExtension> get_extension(const String &p_path);
void initialize_extensions(NativeExtension::InitializationLevel p_level);
void deinitialize_extensions(NativeExtension::InitializationLevel p_level);
static NativeExtensionManager *get_singleton();
NativeExtensionManager();
};
VARIANT_ENUM_CAST(NativeExtensionManager::LoadStatus)
#endif // NATIVEEXTENSIONMANAGER_H

View File

@ -2,6 +2,11 @@
Import("env")
import make_virtuals
from platform_methods import run_in_subprocess
env.CommandNoCache(["gdvirtual.gen.inc"], "make_virtuals.py", run_in_subprocess(make_virtuals.run))
env_object = env.Clone()
env_object.add_source_files(env.core_sources, "*.cpp")

View File

@ -503,9 +503,9 @@ void ClassDB::add_compatibility_class(const StringName &p_class, const StringNam
thread_local bool initializing_with_extension = false;
thread_local ObjectNativeExtension *initializing_extension = nullptr;
thread_local void *initializing_extension_instance = nullptr;
thread_local GDExtensionClassInstancePtr initializing_extension_instance = nullptr;
void ClassDB::instance_get_native_extension_data(ObjectNativeExtension **r_extension, void **r_extension_instance) {
void ClassDB::instance_get_native_extension_data(ObjectNativeExtension **r_extension, GDExtensionClassInstancePtr *r_extension_instance) {
if (initializing_with_extension) {
*r_extension = initializing_extension;
*r_extension_instance = initializing_extension_instance;
@ -539,7 +539,7 @@ Object *ClassDB::instantiate(const StringName &p_class) {
if (ti->native_extension) {
initializing_with_extension = true;
initializing_extension = ti->native_extension;
initializing_extension_instance = ti->native_extension->create_instance(ti->native_extension->create_instance_userdata);
initializing_extension_instance = ti->native_extension->create_instance(ti->native_extension->class_userdata);
}
return ti->creation_func();
}
@ -1603,6 +1603,11 @@ void ClassDB::register_extension_class(ObjectNativeExtension *p_extension) {
classes[p_extension->class_name] = c;
}
void ClassDB::unregister_extension_class(const StringName &p_class) {
ERR_FAIL_COND(!classes.has(p_class));
classes.erase(p_class);
}
RWLock ClassDB::lock;
void ClassDB::cleanup_defaults() {

View File

@ -204,6 +204,7 @@ public:
}
static void register_extension_class(ObjectNativeExtension *p_extension);
static void unregister_extension_class(const StringName &p_class);
template <class T>
static Object *_create_ptr_func() {
@ -232,7 +233,8 @@ public:
static bool is_parent_class(const StringName &p_class, const StringName &p_inherits);
static bool can_instantiate(const StringName &p_class);
static Object *instantiate(const StringName &p_class);
static void instance_get_native_extension_data(ObjectNativeExtension **r_extension, void **r_extension_instance);
static void instance_get_native_extension_data(ObjectNativeExtension **r_extension, GDExtensionClassInstancePtr *r_extension_instance);
static APIType get_api_type(const StringName &p_class);
static uint64_t get_api_hash(APIType p_api);

View File

@ -0,0 +1,152 @@
proto = """
#define GDVIRTUAL$VER($RET m_name $ARG) \\
GDNativeExtensionClassCallVirtual _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, #m_name) : (GDNativeExtensionClassCallVirtual) nullptr;\\
StringName _gdvirtual_##m_name##_sn = #m_name;\\
bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\
ScriptInstance *script_instance = ((Object*)(this))->get_script_instance();\\
if (script_instance) {\\
Callable::CallError ce; \\
$CALLSIARGS\\
$CALLSIBEGINscript_instance->call(_gdvirtual_##m_name##_sn, $CALLSIARGPASS, ce);\\
if (ce.error == Callable::CallError::CALL_OK) {\\
$CALLSIRET\\
return true;\\
} \\
}\\
if (_gdvirtual_##m_name) {\\
$CALLPTRARGS\\
$CALLPTRRETDEF\\
_gdvirtual_##m_name(_get_extension_instance(),$CALLPTRARGPASS,$CALLPTRRETPASS);\\
$CALLPTRRET\\
return true;\\
}\\
\\
return false;\\
}\\
\\
_FORCE_INLINE_ static MethodInfo _gdvirtual_##m_name##_get_method_info() { \\
MethodInfo method_info;\\
method_info.name = #m_name;\\
method_info.flags = METHOD_FLAG_VIRTUAL;\\
$FILL_METHOD_INFO\\
return method_info;\\
}
"""
def generate_version(argcount, const=False, returns=False):
s = proto
sproto = str(argcount)
method_info = ""
if returns:
sproto += "R"
s = s.replace("$RET", "m_ret, ")
s = s.replace("$CALLPTRRETDEF", "PtrToArg<m_ret>::EncodeT ret;")
method_info += "\tmethod_info.return_val = GetTypeInfo<m_ret>::get_class_info();\\\n"
else:
s = s.replace("$RET", "")
s = s.replace("$CALLPTRRETDEF", "")
if const:
sproto += "C"
s = s.replace("$CONST", "const")
method_info += "\tmethod_info.flags|=METHOD_FLAG_CONST;\\\n"
else:
s = s.replace("$CONST", "")
s = s.replace("$VER", sproto)
argtext = ""
callargtext = ""
callsiargs = ""
callsiargptrs = ""
callptrargsptr = ""
if argcount > 0:
argtext += ", "
callsiargs = "Variant vargs[" + str(argcount) + "]={"
callsiargptrs = "\t\tconst Variant *vargptrs[" + str(argcount) + "]={"
callptrargsptr = "\t\tconst GDNativeTypePtr argptrs[" + str(argcount) + "]={"
callptrargs = ""
for i in range(argcount):
if i > 0:
argtext += ", "
callargtext += ", "
callsiargs += ", "
callsiargptrs += ", "
callptrargs += "\t\t"
callptrargsptr += ", "
argtext += "m_type" + str(i + 1)
callargtext += "const m_type" + str(i + 1) + "& arg" + str(i + 1)
callsiargs += "Variant(arg" + str(i + 1) + ")"
callsiargptrs += "&vargs[" + str(i) + "]"
callptrargs += (
"PtrToArg<m_type" + str(i + 1) + ">::EncodeT argval" + str(i + 1) + " = arg" + str(i + 1) + ";\\\n"
)
callptrargsptr += "&argval" + str(i + 1)
method_info += "\tmethod_info.arguments.push_back(GetTypeInfo<m_type" + str(i + 1) + ">::get_class_info());\\\n"
if argcount:
callsiargs += "};\\\n"
callsiargptrs += "};\\\n"
s = s.replace("$CALLSIARGS", callsiargs + callsiargptrs)
s = s.replace("$CALLSIARGPASS", "(const Variant **)vargptrs," + str(argcount))
callptrargsptr += "};\\\n"
s = s.replace("$CALLPTRARGS", callptrargs + callptrargsptr)
s = s.replace("$CALLPTRARGPASS", "(const GDNativeTypePtr*)argptrs")
else:
s = s.replace("$CALLSIARGS", "")
s = s.replace("$CALLSIARGPASS", "nullptr, 0")
s = s.replace("$CALLPTRARGS", "")
s = s.replace("$CALLPTRARGPASS", "nullptr")
if returns:
if argcount > 0:
callargtext += ","
callargtext += " m_ret& r_ret"
s = s.replace("$CALLSIBEGIN", "Variant ret = ")
s = s.replace("$CALLSIRET", "r_ret = ret;")
s = s.replace("$CALLPTRRETPASS", "&ret")
s = s.replace("$CALLPTRRET", "r_ret = ret;")
else:
s = s.replace("$CALLSIBEGIN", "")
s = s.replace("$CALLSIRET", "")
s = s.replace("$CALLPTRRETPASS", "nullptr")
s = s.replace("$CALLPTRRET", "")
s = s.replace("$ARG", argtext)
s = s.replace("$CALLARGS", callargtext)
s = s.replace("$FILL_METHOD_INFO", method_info)
return s
def run(target, source, env):
max_versions = 12
txt = """
#ifndef GDVIRTUAL_GEN_H
#define GDVIRTUAL_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())

View File

@ -34,6 +34,35 @@
#include "method_bind.h"
uint32_t MethodBind::get_hash() const {
uint32_t hash = hash_djb2_one_32(has_return() ? 1 : 0);
hash = hash_djb2_one_32(get_argument_count(), hash);
#ifndef _MSC_VER
#warning This needs proper class name and argument type for hashing
#endif
#if 0
for (int i = (has_return() ? -1 : 0); i < get_argument_count(); i++) {
PropertyInfo pi = i == -1 ? get_return_info() : get_argument_info(i);
hash = hash_djb2_one_32(get_argument_type(i), hash);
if (pi.class_name != StringName()) {
hash = hash_djb2_one_32(pi.class_name.operator String().hash(), hash);
}
}
#endif
hash = hash_djb2_one_32(get_default_argument_count(), hash);
for (int i = 0; i < get_default_argument_count(); i++) {
Variant v = get_default_argument(i);
hash = hash_djb2_one_32(v.hash(), hash);
}
hash = hash_djb2_one_32(is_const(), hash);
hash = hash_djb2_one_32(is_vararg(), hash);
return hash;
}
#ifdef DEBUG_METHODS_ENABLED
PropertyInfo MethodBind::get_argument_info(int p_argument) const {
ERR_FAIL_INDEX_V(p_argument, get_argument_count(), PropertyInfo());

View File

@ -135,6 +135,8 @@ public:
void set_default_arguments(const Vector<Variant> &p_defargs);
uint32_t get_hash() const;
MethodBind();
virtual ~MethodBind();
};

View File

@ -386,12 +386,20 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid
}
if (_extension && _extension->set) {
if (_extension->set(_extension_instance, &p_name, &p_value)) {
// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it.
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
#endif
if (_extension->set(_extension_instance, (const GDNativeStringNamePtr)&p_name, (const GDNativeVariantPtr)&p_value)) {
if (r_valid) {
*r_valid = true;
}
return;
}
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
}
//try built-in setgetter
@ -459,14 +467,22 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const {
return ret;
}
}
if (_extension && _extension->get) {
if (_extension->get(_extension_instance, &p_name, &ret)) {
// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it.
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
#endif
if (_extension->get(_extension_instance, (const GDNativeStringNamePtr)&p_name, (GDNativeVariantPtr)&ret)) {
if (r_valid) {
*r_valid = true;
}
return ret;
}
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
}
//try built-in setgetter
@ -616,7 +632,7 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
if (_extension && _extension->get_property_list) {
uint32_t pcount;
const ObjectNativeExtension::PInfo *pinfo = _extension->get_property_list(_extension_instance, &pcount);
const GDNativePropertyInfo *pinfo = _extension->get_property_list(_extension_instance, &pcount);
for (uint32_t i = 0; i < pcount; i++) {
p_list->push_back(PropertyInfo(Variant::Type(pinfo[i].type), pinfo[i].class_name, PropertyHint(pinfo[i].hint), pinfo[i].hint_string, pinfo[i].usage, pinfo[i].class_name));
}
@ -1812,7 +1828,7 @@ Object::~Object() {
script_instance = nullptr;
if (_extension && _extension->free_instance) {
_extension->free_instance(_extension->create_instance_userdata, _extension_instance);
_extension->free_instance(_extension->class_userdata, _extension_instance);
_extension = nullptr;
_extension_instance = nullptr;
}

View File

@ -31,6 +31,7 @@
#ifndef OBJECT_H
#define OBJECT_H
#include "core/extension/gdnative_interface.h"
#include "core/object/object_id.h"
#include "core/os/rw_lock.h"
#include "core/os/spin_lock.h"
@ -244,29 +245,18 @@ class MethodBind;
struct ObjectNativeExtension {
ObjectNativeExtension *parent = nullptr;
List<ObjectNativeExtension *> children;
StringName parent_class_name;
StringName class_name;
bool editor_class = false;
bool (*set)(void *instance, const void *name, const void *value) = nullptr;
bool (*get)(void *instance, const void *name, void *ret_variant) = nullptr;
struct PInfo {
uint32_t type;
const char *name;
const char *class_name;
uint32_t hint;
const char *hint_string;
uint32_t usage;
};
const PInfo *(*get_property_list)(void *instance, uint32_t *count) = nullptr;
void (*free_property_list)(void *instance, const PInfo *) = nullptr;
//call is not used, as all methods registered in ClassDB
void (*notification)(void *instance, int32_t what) = nullptr;
const char *(*to_string)(void *instance) = nullptr;
void (*reference)(void *instance) = nullptr;
void (*unreference)(void *instance) = nullptr;
GDNativeExtensionClassSet set;
GDNativeExtensionClassGet get;
GDNativeExtensionClassGetPropertyList get_property_list;
GDNativeExtensionClassFreePropertyList free_property_list;
GDNativeExtensionClassNotification notification;
GDNativeExtensionClassToString to_string;
GDNativeExtensionClassReference reference;
GDNativeExtensionClassReference unreference;
_FORCE_INLINE_ bool is_class(const String &p_class) const {
const ObjectNativeExtension *e = this;
@ -278,11 +268,16 @@ struct ObjectNativeExtension {
}
return false;
}
void *create_instance_userdata = nullptr;
void *(*create_instance)(void *create_instance_userdata) = nullptr;
void (*free_instance)(void *create_instance_userdata, void *instance) = nullptr;
void *class_userdata = nullptr;
GDNativeExtensionClassCreateInstance create_instance;
GDNativeExtensionClassFreeInstance free_instance;
GDNativeExtensionClassGetVirtual get_virtual;
};
#define GDVIRTUAL_CALL(m_name, ...) _gdvirtual_##m_name##_call(__VA_ARGS__)
#define GDVIRTUAL_BIND(m_name) ClassDB::add_virtual_method(get_class_static(), _gdvirtual_##m_name##_get_method_info());
/*
the following is an incomprehensible blob of hacks and workarounds to compensate for many of the fallencies in C++. As a plus, this macro pretty much alone defines the object model.
*/
@ -497,7 +492,7 @@ private:
friend void postinitialize_handler(Object *);
ObjectNativeExtension *_extension = nullptr;
void *_extension_instance = nullptr;
GDExtensionClassInstancePtr _extension_instance = nullptr;
struct SignalData {
struct Slot {
@ -554,8 +549,9 @@ private:
Object(bool p_reference);
protected:
friend class NativeExtensionMethodBind;
_ALWAYS_INLINE_ const ObjectNativeExtension *_get_extension() const { return _extension; }
_ALWAYS_INLINE_ void *_get_extension_instance() const { return _extension_instance; }
_ALWAYS_INLINE_ GDExtensionClassInstancePtr _get_extension_instance() const { return _extension_instance; }
virtual void _initialize_classv() { initialize_class(); }
virtual bool _setv(const StringName &p_name, const Variant &p_property) { return false; };
virtual bool _getv(const StringName &p_name, Variant &r_property) const { return false; };

View File

@ -258,6 +258,8 @@ struct PtrToArg<Ref<T>> {
return Ref<T>(const_cast<T *>(reinterpret_cast<const T *>(p_ptr)));
}
typedef Ref<T> EncodeT;
_FORCE_INLINE_ static void encode(Ref<T> p_val, const void *p_ptr) {
*(Ref<RefCounted> *)p_ptr = p_val;
}
@ -265,6 +267,8 @@ struct PtrToArg<Ref<T>> {
template <class T>
struct PtrToArg<const Ref<T> &> {
typedef Ref<T> EncodeT;
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
return Ref<T>((T *)p_ptr);
}

View File

@ -37,6 +37,8 @@
#include "core/crypto/aes_context.h"
#include "core/crypto/crypto.h"
#include "core/crypto/hashing_context.h"
#include "core/extension/native_extension.h"
#include "core/extension/native_extension_manager.h"
#include "core/input/input.h"
#include "core/input/input_map.h"
#include "core/io/config_file.h"
@ -95,6 +97,8 @@ static _Geometry3D *_geometry_3d = nullptr;
extern Mutex _global_mutex;
static NativeExtensionManager *native_extension_manager = nullptr;
extern void register_global_constants();
extern void unregister_global_constants();
@ -217,6 +221,12 @@ void register_core_types() {
ClassDB::register_virtual_class<ResourceImporter>();
ClassDB::register_class<NativeExtension>();
ClassDB::register_virtual_class<NativeExtensionManager>();
native_extension_manager = memnew(NativeExtensionManager);
ip = IP::create();
_geometry_2d = memnew(_Geometry2D);
@ -261,7 +271,7 @@ void register_core_singletons() {
ClassDB::register_class<Time>();
Engine::get_singleton()->add_singleton(Engine::Singleton("ProjectSettings", ProjectSettings::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("IP", IP::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("IP", IP::get_singleton(), "IP"));
Engine::get_singleton()->add_singleton(Engine::Singleton("Geometry2D", _Geometry2D::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("Geometry3D", _Geometry3D::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("ResourceLoader", _ResourceLoader::get_singleton()));
@ -275,9 +285,25 @@ void register_core_singletons() {
Engine::get_singleton()->add_singleton(Engine::Singleton("InputMap", InputMap::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("EngineDebugger", _EngineDebugger::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("Time", Time::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("NativeExtensionManager", NativeExtensionManager::get_singleton()));
}
void register_core_extensions() {
//harcoded for now
if (ProjectSettings::get_singleton()->has_setting("native_extensions/paths")) {
Vector<String> paths = ProjectSettings::get_singleton()->get("native_extensions/paths");
for (int i = 0; i < paths.size(); i++) {
NativeExtensionManager::LoadStatus status = native_extension_manager->load_extension(paths[i]);
ERR_CONTINUE_MSG(status != NativeExtensionManager::LOAD_STATUS_OK, "Error loading extension: " + paths[i]);
}
}
native_extension_manager->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_CORE);
}
void unregister_core_types() {
native_extension_manager->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_CORE);
memdelete(native_extension_manager);
memdelete(_resource_loader);
memdelete(_resource_saver);
memdelete(_os);

View File

@ -33,6 +33,7 @@
void register_core_types();
void register_core_settings();
void register_core_extensions();
void register_core_singletons();
void unregister_core_types();

View File

@ -77,6 +77,7 @@ struct VariantCaster<const T &> {
_FORCE_INLINE_ static m_enum convert(const void *p_ptr) { \
return m_enum(*reinterpret_cast<const int *>(p_ptr)); \
} \
typedef int64_t EncodeT; \
_FORCE_INLINE_ static void encode(m_enum p_val, const void *p_ptr) { \
*(int *)p_ptr = p_val; \
} \
@ -117,6 +118,7 @@ struct PtrToArg<char32_t> {
_FORCE_INLINE_ static char32_t convert(const void *p_ptr) {
return char32_t(*reinterpret_cast<const int *>(p_ptr));
}
typedef int64_t EncodeT;
_FORCE_INLINE_ static void encode(char32_t p_val, const void *p_ptr) {
*(int *)p_ptr = p_val;
}

View File

@ -45,6 +45,7 @@ struct PtrToArg {};
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
return *reinterpret_cast<const m_type *>(p_ptr); \
} \
typedef m_type EncodeT; \
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
*((m_type *)p_ptr) = p_val; \
} \
@ -54,6 +55,7 @@ struct PtrToArg {};
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
return *reinterpret_cast<const m_type *>(p_ptr); \
} \
typedef m_type EncodeT; \
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
*((m_type *)p_ptr) = p_val; \
} \
@ -65,6 +67,7 @@ struct PtrToArg {};
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \
} \
typedef m_conv EncodeT; \
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
*((m_conv *)p_ptr) = static_cast<m_conv>(p_val); \
} \
@ -74,6 +77,7 @@ struct PtrToArg {};
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \
} \
typedef m_conv EncodeT; \
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
*((m_conv *)p_ptr) = static_cast<m_conv>(p_val); \
} \
@ -85,6 +89,7 @@ struct PtrToArg {};
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
return *reinterpret_cast<const m_type *>(p_ptr); \
} \
typedef m_type EncodeT; \
_FORCE_INLINE_ static void encode(const m_type &p_val, void *p_ptr) { \
*((m_type *)p_ptr) = p_val; \
} \
@ -94,12 +99,13 @@ struct PtrToArg {};
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
return *reinterpret_cast<const m_type *>(p_ptr); \
} \
typedef m_type EncodeT; \
_FORCE_INLINE_ static void encode(const m_type &p_val, void *p_ptr) { \
*((m_type *)p_ptr) = p_val; \
} \
}
MAKE_PTRARG(bool);
MAKE_PTRARGCONV(bool, uint32_t);
// Integer types.
MAKE_PTRARGCONV(uint8_t, int64_t);
MAKE_PTRARGCONV(int8_t, int64_t);
@ -153,7 +159,7 @@ struct PtrToArg<T *> {
_FORCE_INLINE_ static T *convert(const void *p_ptr) {
return const_cast<T *>(reinterpret_cast<const T *>(p_ptr));
}
typedef Object *EncodeT;
_FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) {
*((T **)p_ptr) = p_var;
}
@ -164,7 +170,7 @@ struct PtrToArg<const T *> {
_FORCE_INLINE_ static const T *convert(const void *p_ptr) {
return reinterpret_cast<const T *>(p_ptr);
}
typedef const Object *EncodeT;
_FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) {
*((T **)p_ptr) = p_var;
}
@ -177,7 +183,7 @@ struct PtrToArg<ObjectID> {
_FORCE_INLINE_ static const ObjectID convert(const void *p_ptr) {
return ObjectID(*reinterpret_cast<const uint64_t *>(p_ptr));
}
typedef uint64_t EncodeT;
_FORCE_INLINE_ static void encode(const ObjectID &p_val, void *p_ptr) {
*((uint64_t *)p_ptr) = p_val;
}

View File

@ -499,6 +499,7 @@ public:
static bool is_builtin_method_vararg(Variant::Type p_type, const StringName &p_method);
static void get_builtin_method_list(Variant::Type p_type, List<StringName> *p_list);
static int get_builtin_method_count(Variant::Type p_type);
static uint32_t get_builtin_method_hash(Variant::Type p_type, const StringName &p_method);
void call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error);
Variant call(const StringName &p_method, const Variant &p_arg1 = Variant(), const Variant &p_arg2 = Variant(), const Variant &p_arg3 = Variant(), const Variant &p_arg4 = Variant(), const Variant &p_arg5 = Variant());
@ -586,7 +587,7 @@ public:
typedef void (*PTRKeyedSetter)(void *base, const void *key, const void *value);
typedef void (*PTRKeyedGetter)(const void *base, const void *key, void *value);
typedef bool (*PTRKeyedChecker)(const void *base, const void *key);
typedef uint32_t (*PTRKeyedChecker)(const void *base, const void *key);
static PTRKeyedSetter get_member_ptr_keyed_setter(Variant::Type p_type);
static PTRKeyedGetter get_member_ptr_keyed_getter(Variant::Type p_type);
@ -631,6 +632,7 @@ public:
static bool has_utility_function_return_value(const StringName &p_name);
static Variant::Type get_utility_function_return_type(const StringName &p_name);
static bool is_utility_function_vararg(const StringName &p_name);
static uint32_t get_utility_function_hash(const StringName &p_name);
static void get_utility_function_list(List<StringName> *r_functions);
static int get_utility_function_count();

View File

@ -1126,6 +1126,25 @@ bool Variant::is_builtin_method_vararg(Variant::Type p_type, const StringName &p
return method->is_vararg;
}
uint32_t Variant::get_builtin_method_hash(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, 0);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
ERR_FAIL_COND_V(!method, 0);
uint32_t hash = hash_djb2_one_32(method->is_const);
hash = hash_djb2_one_32(method->is_static, hash);
hash = hash_djb2_one_32(method->is_vararg, hash);
hash = hash_djb2_one_32(method->has_return_type, hash);
if (method->has_return_type) {
hash = hash_djb2_one_32(method->return_type, hash);
}
hash = hash_djb2_one_32(method->argument_count, hash);
for (int i = 0; i < method->argument_count; i++) {
hash = method->get_argument_type(i);
}
return hash;
}
void Variant::get_method_list(List<MethodInfo> *p_list) const {
if (type == OBJECT) {
Object *obj = get_validated_object();

View File

@ -661,8 +661,8 @@ static const char *_op_names[Variant::OP_MAX] = {
"-",
"*",
"/",
"-",
"+",
"unary-",
"unary+",
"%",
"<<",
">>",

View File

@ -871,7 +871,7 @@ struct VariantKeyedSetGetDictionary {
*r_valid = true;
return VariantGetInternalPtr<Dictionary>::get_ptr(base)->has(*key);
}
static bool ptr_has(const void *base, const void *key) {
static uint32_t ptr_has(const void *base, const void *key) {
/* avoid ptrconvert for performance*/
const Dictionary &v = *reinterpret_cast<const Dictionary *>(base);
return v.has(PtrToArg<Variant>::convert(key));
@ -921,7 +921,7 @@ struct VariantKeyedSetGetObject {
obj->getvar(*key, &exists);
return exists;
}
static bool ptr_has(const void *base, const void *key) {
static uint32_t ptr_has(const void *base, const void *key) {
const Object *obj = PtrToArg<Object *>::convert(base);
ERR_FAIL_COND_V(!obj, false);
bool valid;

View File

@ -1348,8 +1348,8 @@ String Variant::get_utility_function_argument_name(const StringName &p_name, int
if (!bfi) {
return String();
}
ERR_FAIL_COND_V(bfi->is_vararg, String());
ERR_FAIL_INDEX_V(p_arg, bfi->argnames.size(), String());
ERR_FAIL_COND_V(bfi->is_vararg, String());
return bfi->argnames[p_arg];
}
@ -1379,6 +1379,23 @@ bool Variant::is_utility_function_vararg(const StringName &p_name) {
return bfi->is_vararg;
}
uint32_t Variant::get_utility_function_hash(const StringName &p_name) {
const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name);
ERR_FAIL_COND_V(!bfi, 0);
uint32_t hash = hash_djb2_one_32(bfi->is_vararg);
hash = hash_djb2_one_32(bfi->returns_value, hash);
if (bfi->returns_value) {
hash = hash_djb2_one_32(bfi->return_type, hash);
}
hash = hash_djb2_one_32(bfi->argcount, hash);
for (int i = 0; i < bfi->argcount; i++) {
hash = hash_djb2_one_32(bfi->get_arg_type(i), hash);
}
return hash;
}
void Variant::get_utility_function_list(List<StringName> *r_functions) {
for (List<StringName>::Element *E = utility_function_name_table.front(); E; E = E->next()) {
r_functions->push_back(E->get());

View File

@ -1224,6 +1224,8 @@
<member name="Marshalls" type="Marshalls" setter="" getter="">
The [Marshalls] singleton.
</member>
<member name="NativeExtensionManager" type="NativeExtensionManager" setter="" getter="">
</member>
<member name="NavigationMeshGenerator" type="NavigationMeshGenerator" setter="" getter="">
The [NavigationMeshGenerator] singleton.
</member>

View File

@ -80,14 +80,16 @@
</argument>
<argument index="2" name="b" type="float">
</argument>
<argument index="3" name="a" type="float">
</argument>
<description>
Constructs a [Color] from RGB values, typically between 0 and 1. Alpha will be 1.
Constructs a [Color] from RGBA values, typically between 0 and 1.
[codeblocks]
[gdscript]
var color = Color(0.2, 1.0, 0.7) # Similar to `Color8(51, 255, 178, 255)`
var color = Color(0.2, 1.0, 0.7, 0.8) # Similar to `Color8(51, 255, 178, 204)`
[/gdscript]
[csharp]
var color = new Color(0.2f, 1.0f, 0.7f); // Similar to `Color.Color8(51, 255, 178, 255)`
var color = new Color(0.2f, 1.0f, 0.7f, 0.8f); // Similar to `Color.Color8(51, 255, 178, 255, 204)`
[/csharp]
[/codeblocks]
</description>
@ -101,16 +103,14 @@
</argument>
<argument index="2" name="b" type="float">
</argument>
<argument index="3" name="a" type="float">
</argument>
<description>
Constructs a [Color] from RGBA values, typically between 0 and 1.
Constructs a [Color] from RGB values, typically between 0 and 1. Alpha will be 1.
[codeblocks]
[gdscript]
var color = Color(0.2, 1.0, 0.7, 0.8) # Similar to `Color8(51, 255, 178, 204)`
var color = Color(0.2, 1.0, 0.7) # Similar to `Color8(51, 255, 178, 255)`
[/gdscript]
[csharp]
var color = new Color(0.2f, 1.0f, 0.7f, 0.8f); // Similar to `Color.Color8(51, 255, 178, 255, 204)`
var color = new Color(0.2f, 1.0f, 0.7f); // Similar to `Color.Color8(51, 255, 178, 255)`
[/csharp]
[/codeblocks]
</description>
@ -346,12 +346,6 @@
<description>
</description>
</method>
<method name="operator +" qualifiers="operator">
<return type="Color">
</return>
<description>
</description>
</method>
<method name="operator +" qualifiers="operator">
<return type="Color">
</return>
@ -360,12 +354,6 @@
<description>
</description>
</method>
<method name="operator -" qualifiers="operator">
<return type="Color">
</return>
<description>
</description>
</method>
<method name="operator -" qualifiers="operator">
<return type="Color">
</return>
@ -414,6 +402,18 @@
<description>
</description>
</method>
<method name="operator unary+" qualifiers="operator">
<return type="Color">
</return>
<description>
</description>
</method>
<method name="operator unary-" qualifiers="operator">
<return type="Color">
</return>
<description>
</description>
</method>
<method name="to_abgr32" qualifiers="const">
<return type="int">
</return>

View File

@ -150,10 +150,10 @@
* it happens outside parent's rectangle and the parent has either [member rect_clip_content] enabled.
</description>
</method>
<method name="_has_point" qualifiers="virtual">
<method name="_has_point" qualifiers="virtual const">
<return type="bool">
</return>
<argument index="0" name="point" type="Vector2">
<argument index="0" name="" type="Vector2">
</argument>
<description>
Virtual method to be implemented by the user. Returns whether the given [code]point[/code] is inside this control.

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="NativeExtension" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
<methods>
<method name="close_library">
<return type="void">
</return>
<description>
</description>
</method>
<method name="get_minimum_library_initialization_level" qualifiers="const">
<return type="int" enum="NativeExtension.InitializationLevel">
</return>
<description>
</description>
</method>
<method name="initialize_library">
<return type="void">
</return>
<argument index="0" name="level" type="int" enum="NativeExtension.InitializationLevel">
</argument>
<description>
</description>
</method>
<method name="is_library_open" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
<method name="open_library">
<return type="int" enum="Error">
</return>
<argument index="0" name="path" type="String">
</argument>
<argument index="1" name="entry_symbol" type="String">
</argument>
<description>
</description>
</method>
</methods>
<constants>
<constant name="INITIALIZATION_LEVEL_CORE" value="0" enum="InitializationLevel">
</constant>
<constant name="INITIALIZATION_LEVEL_SERVERS" value="1" enum="InitializationLevel">
</constant>
<constant name="INITIALIZATION_LEVEL_SCENE" value="2" enum="InitializationLevel">
</constant>
<constant name="INITIALIZATION_LEVEL_EDITOR" value="3" enum="InitializationLevel">
</constant>
</constants>
</class>

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="NativeExtensionManager" inherits="Object" version="4.0">
<brief_description>
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_extension">
<return type="NativeExtension">
</return>
<argument index="0" name="path" type="String">
</argument>
<description>
</description>
</method>
<method name="get_loaded_extensions" qualifiers="const">
<return type="PackedStringArray">
</return>
<description>
</description>
</method>
<method name="load_extension">
<return type="int" enum="NativeExtensionManager.LoadStatus">
</return>
<argument index="0" name="path" type="String">
</argument>
<description>
</description>
</method>
<method name="reload_extension">
<return type="int" enum="NativeExtensionManager.LoadStatus">
</return>
<argument index="0" name="path" type="String">
</argument>
<description>
</description>
</method>
<method name="unload_extension">
<return type="int" enum="NativeExtensionManager.LoadStatus">
</return>
<argument index="0" name="path" type="String">
</argument>
<description>
</description>
</method>
</methods>
<constants>
<constant name="LOAD_STATUS_OK" value="0" enum="LoadStatus">
</constant>
<constant name="LOAD_STATUS_FAILED" value="1" enum="LoadStatus">
</constant>
<constant name="LOAD_STATUS_ALREADY_LOADED" value="2" enum="LoadStatus">
</constant>
<constant name="LOAD_STATUS_NOT_LOADED" value="3" enum="LoadStatus">
</constant>
<constant name="LOAD_STATUS_NEEDS_RESTART" value="4" enum="LoadStatus">
</constant>
</constants>
</class>

View File

@ -169,18 +169,6 @@
<description>
</description>
</method>
<method name="operator +" qualifiers="operator">
<return type="Plane">
</return>
<description>
</description>
</method>
<method name="operator -" qualifiers="operator">
<return type="Plane">
</return>
<description>
</description>
</method>
<method name="operator ==" qualifiers="operator">
<return type="bool">
</return>
@ -189,6 +177,18 @@
<description>
</description>
</method>
<method name="operator unary+" qualifiers="operator">
<return type="Plane">
</return>
<description>
</description>
</method>
<method name="operator unary-" qualifiers="operator">
<return type="Plane">
</return>
<description>
</description>
</method>
<method name="project" qualifiers="const">
<return type="Vector3">
</return>

View File

@ -177,17 +177,17 @@
</description>
</method>
<method name="operator *" qualifiers="operator">
<return type="Quaternion">
<return type="Vector3">
</return>
<argument index="0" name="right" type="Quaternion">
<argument index="0" name="right" type="Vector3">
</argument>
<description>
</description>
</method>
<method name="operator *" qualifiers="operator">
<return type="Vector3">
<return type="Quaternion">
</return>
<argument index="0" name="right" type="Vector3">
<argument index="0" name="right" type="Quaternion">
</argument>
<description>
</description>
@ -208,12 +208,6 @@
<description>
</description>
</method>
<method name="operator +" qualifiers="operator">
<return type="Quaternion">
</return>
<description>
</description>
</method>
<method name="operator +" qualifiers="operator">
<return type="Quaternion">
</return>
@ -222,12 +216,6 @@
<description>
</description>
</method>
<method name="operator -" qualifiers="operator">
<return type="Quaternion">
</return>
<description>
</description>
</method>
<method name="operator -" qualifiers="operator">
<return type="Quaternion">
</return>
@ -268,6 +256,18 @@
<description>
</description>
</method>
<method name="operator unary+" qualifiers="operator">
<return type="Quaternion">
</return>
<description>
</description>
</method>
<method name="operator unary-" qualifiers="operator">
<return type="Quaternion">
</return>
<description>
</description>
</method>
<method name="slerp" qualifiers="const">
<return type="Quaternion">
</return>

View File

@ -301,12 +301,6 @@
<description>
</description>
</method>
<method name="operator +" qualifiers="operator">
<return type="Vector2">
</return>
<description>
</description>
</method>
<method name="operator +" qualifiers="operator">
<return type="Vector2">
</return>
@ -315,12 +309,6 @@
<description>
</description>
</method>
<method name="operator -" qualifiers="operator">
<return type="Vector2">
</return>
<description>
</description>
</method>
<method name="operator -" qualifiers="operator">
<return type="Vector2">
</return>
@ -401,6 +389,18 @@
<description>
</description>
</method>
<method name="operator unary+" qualifiers="operator">
<return type="Vector2">
</return>
<description>
</description>
</method>
<method name="operator unary-" qualifiers="operator">
<return type="Vector2">
</return>
<description>
</description>
</method>
<method name="orthogonal" qualifiers="const">
<return type="Vector2">
</return>

View File

@ -123,12 +123,6 @@
<description>
</description>
</method>
<method name="operator +" qualifiers="operator">
<return type="Vector2i">
</return>
<description>
</description>
</method>
<method name="operator +" qualifiers="operator">
<return type="Vector2i">
</return>
@ -137,12 +131,6 @@
<description>
</description>
</method>
<method name="operator -" qualifiers="operator">
<return type="Vector2i">
</return>
<description>
</description>
</method>
<method name="operator -" qualifiers="operator">
<return type="Vector2i">
</return>
@ -223,6 +211,18 @@
<description>
</description>
</method>
<method name="operator unary+" qualifiers="operator">
<return type="Vector2i">
</return>
<description>
</description>
</method>
<method name="operator unary-" qualifiers="operator">
<return type="Vector2i">
</return>
<description>
</description>
</method>
<method name="sign" qualifiers="const">
<return type="Vector2i">
</return>

View File

@ -315,12 +315,6 @@
<description>
</description>
</method>
<method name="operator +" qualifiers="operator">
<return type="Vector3">
</return>
<description>
</description>
</method>
<method name="operator +" qualifiers="operator">
<return type="Vector3">
</return>
@ -329,12 +323,6 @@
<description>
</description>
</method>
<method name="operator -" qualifiers="operator">
<return type="Vector3">
</return>
<description>
</description>
</method>
<method name="operator -" qualifiers="operator">
<return type="Vector3">
</return>
@ -415,6 +403,18 @@
<description>
</description>
</method>
<method name="operator unary+" qualifiers="operator">
<return type="Vector3">
</return>
<description>
</description>
</method>
<method name="operator unary-" qualifiers="operator">
<return type="Vector3">
</return>
<description>
</description>
</method>
<method name="outer" qualifiers="const">
<return type="Basis">
</return>

View File

@ -131,12 +131,6 @@
<description>
</description>
</method>
<method name="operator +" qualifiers="operator">
<return type="Vector3i">
</return>
<description>
</description>
</method>
<method name="operator +" qualifiers="operator">
<return type="Vector3i">
</return>
@ -145,12 +139,6 @@
<description>
</description>
</method>
<method name="operator -" qualifiers="operator">
<return type="Vector3i">
</return>
<description>
</description>
</method>
<method name="operator -" qualifiers="operator">
<return type="Vector3i">
</return>
@ -231,6 +219,18 @@
<description>
</description>
</method>
<method name="operator unary+" qualifiers="operator">
<return type="Vector3i">
</return>
<description>
</description>
</method>
<method name="operator unary-" qualifiers="operator">
<return type="Vector3i">
</return>
<description>
</description>
</method>
<method name="sign" qualifiers="const">
<return type="Vector3i">
</return>

View File

@ -142,16 +142,6 @@
Multiplies a [float] and an [int]. The result is a [float].
</description>
</method>
<method name="operator +" qualifiers="operator">
<return type="float">
</return>
<description>
Unary plus operator. Doesn't have any effect.
[codeblock]
var a = +2.5 # a is 2.5.
[/codeblock]
</description>
</method>
<method name="operator +" qualifiers="operator">
<return type="float">
</return>
@ -170,17 +160,6 @@
Adds a [float] and an [int]. The result is a [float].
</description>
</method>
<method name="operator -" qualifiers="operator">
<return type="float">
</return>
<description>
Unary minus operator. Negates the number.
[codeblock]
var a = -2.5 # a is -2.5.
print(-a) # 2.5
[/codeblock]
</description>
</method>
<method name="operator -" qualifiers="operator">
<return type="float">
</return>
@ -308,6 +287,18 @@
Returns [code]true[/code] if this [float] is greater than or equal to the given [int].
</description>
</method>
<method name="operator unary+" qualifiers="operator">
<return type="float">
</return>
<description>
</description>
</method>
<method name="operator unary-" qualifiers="operator">
<return type="float">
</return>
<description>
</description>
</method>
</methods>
<constants>
</constants>

View File

@ -125,15 +125,6 @@
[/codeblock]
</description>
</method>
<method name="operator *" qualifiers="operator">
<return type="float">
</return>
<argument index="0" name="right" type="float">
</argument>
<description>
Multiplies an [int] and a [float]. The result is a [float].
</description>
</method>
<method name="operator *" qualifiers="operator">
<return type="int">
</return>
@ -143,6 +134,15 @@
Multiplies two [int]s.
</description>
</method>
<method name="operator *" qualifiers="operator">
<return type="float">
</return>
<argument index="0" name="right" type="float">
</argument>
<description>
Multiplies an [int] and a [float]. The result is a [float].
</description>
</method>
<method name="operator *" qualifiers="operator">
<return type="Vector2">
</return>
@ -203,16 +203,6 @@
[/codeblock]
</description>
</method>
<method name="operator +" qualifiers="operator">
<return type="int">
</return>
<description>
Unary plus operator. Doesn't have any effect.
[codeblock]
var a = +1 # a is 1.
[/codeblock]
</description>
</method>
<method name="operator +" qualifiers="operator">
<return type="float">
</return>
@ -231,17 +221,6 @@
Adds two integers.
</description>
</method>
<method name="operator -" qualifiers="operator">
<return type="int">
</return>
<description>
Unary minus operator. Negates the number.
[codeblock]
var a = -1 # a is -1.
print(-a) # 1
[/codeblock]
</description>
</method>
<method name="operator -" qualifiers="operator">
<return type="float">
</return>
@ -414,6 +393,18 @@
[/codeblock]
</description>
</method>
<method name="operator unary+" qualifiers="operator">
<return type="int">
</return>
<description>
</description>
</method>
<method name="operator unary-" qualifiers="operator">
<return type="int">
</return>
<description>
</description>
</method>
<method name="operator |" qualifiers="operator">
<return type="int">
</return>

View File

@ -32,6 +32,7 @@
#include "core/config/project_settings.h"
#include "core/core_bind.h"
#include "core/extension/native_extension_manager.h"
#include "core/input/input.h"
#include "core/io/config_file.h"
#include "core/io/file_access.h"
@ -3771,9 +3772,12 @@ void EditorNode::register_editor_types() {
ClassDB::register_class<EditorScenePostImport>();
//ClassDB::register_type<EditorImportExport>();
ClassDB::register_class<EditorDebuggerPlugin>();
NativeExtensionManager::get_singleton()->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_EDITOR);
}
void EditorNode::unregister_editor_types() {
NativeExtensionManager::get_singleton()->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_EDITOR);
_init_callbacks.clear();
if (EditorPaths::get_singleton()) {
EditorPaths::free();

View File

@ -34,6 +34,7 @@
#include "core/core_string_names.h"
#include "core/crypto/crypto.h"
#include "core/debugger/engine_debugger.h"
#include "core/extension/extension_api_dump.h"
#include "core/input/input.h"
#include "core/input/input_map.h"
#include "core/io/dir_access.h"
@ -174,7 +175,9 @@ static int frame_delay = 0;
static bool disable_render_loop = false;
static int fixed_fps = -1;
static bool print_fps = false;
#ifdef TOOLS_ENABLED
static bool dump_extension_api = false;
#endif
bool profile_gpu = false;
/* Helper methods */
@ -406,6 +409,8 @@ Error Main::test_setup() {
translation_server = memnew(TranslationServer);
register_core_extensions();
// From `Main::setup2()`.
preregister_module_types();
preregister_server_types();
@ -887,7 +892,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
auto_build_solutions = true;
editor = true;
cmdline_tool = true;
#ifdef DEBUG_METHODS_ENABLED
} else if (I->get() == "--gdnative-generate-json-api" || I->get() == "--gdnative-generate-json-builtin-api") {
// Register as an editor instance to use low-end fallback if relevant.
editor = true;
@ -895,7 +900,13 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
// We still pass it to the main arguments since the argument handling itself is not done in this function
main_args.push_back(I->get());
#endif
} else if (I->get() == "--dump-extension-api") {
// Register as an editor instance to use low-end fallback if relevant.
editor = true;
cmdline_tool = true;
dump_extension_api = true;
print_line("dump extension?");
main_args.push_back(I->get());
} else if (I->get() == "--export" || I->get() == "--export-debug" ||
I->get() == "--export-pack") { // Export project
// Actually handling is done in start().
@ -1198,6 +1209,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->set_cmdline(execpath, main_args);
register_core_extensions(); //before display
GLOBAL_DEF("rendering/driver/driver_name", "Vulkan");
ProjectSettings::get_singleton()->set_custom_property_info("rendering/driver/driver_name",
PropertyInfo(Variant::STRING,
@ -2004,6 +2017,11 @@ bool Main::start() {
return false;
}
if (dump_extension_api) {
NativeExtensionAPIDump::generate_extension_json_file("extension_api.json");
return false;
}
#endif
if (script == "" && game_path == "" && String(GLOBAL_GET("application/run/main_scene")) != "") {

View File

@ -164,7 +164,7 @@ typedef void (*godot_validated_keyed_getter)(const godot_variant *p_base, const
typedef bool (*godot_validated_keyed_checker)(const godot_variant *p_base, const godot_variant *p_key, bool *r_valid);
typedef void (*godot_ptr_keyed_setter)(void *p_base, const void *p_key, const void *p_value);
typedef void (*godot_ptr_keyed_getter)(const void *p_base, const void *p_key, void *r_value);
typedef bool (*godot_ptr_keyed_checker)(const godot_variant *p_base, const godot_variant *p_key);
typedef uint32_t (*godot_ptr_keyed_checker)(const godot_variant *p_base, const godot_variant *p_key);
typedef void (*godot_validated_utility_function)(godot_variant *r_return, const godot_variant **p_arguments, int p_argument_count);
typedef void (*godot_ptr_utility_function)(void *r_return, const void **p_arguments, int p_argument_count);

View File

@ -651,19 +651,10 @@ void Control::_notification(int p_notification) {
}
bool Control::has_point(const Point2 &p_point) const {
if (get_script_instance()) {
Variant v = p_point;
const Variant *p = &v;
Callable::CallError ce;
Variant ret = get_script_instance()->call(SceneStringNames::get_singleton()->_has_point, &p, 1, ce);
if (ce.error == Callable::CallError::CALL_OK) {
return ret;
}
bool ret;
if (GDVIRTUAL_CALL(_has_point, p_point, ret)) {
return ret;
}
/*if (has_stylebox("mask")) {
Ref<StyleBox> mask = get_stylebox("mask");
return mask->test_mask(p_point,Rect2(Point2(),get_size()));
}*/
return Rect2(Point2(), get_size()).has_point(p_point);
}
@ -2932,5 +2923,5 @@ void Control::_bind_methods() {
ADD_SIGNAL(MethodInfo("minimum_size_changed"));
ADD_SIGNAL(MethodInfo("theme_changed"));
BIND_VMETHOD(MethodInfo(Variant::BOOL, "_has_point", PropertyInfo(Variant::VECTOR2, "point")));
GDVIRTUAL_BIND(_has_point);
}

View File

@ -32,6 +32,7 @@
#define CONTROL_H
#include "core/math/transform_2d.h"
#include "core/object/gdvirtual.gen.inc"
#include "core/templates/rid.h"
#include "scene/gui/shortcut.h"
#include "scene/main/canvas_item.h"
@ -264,6 +265,7 @@ private:
static bool has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types);
_FORCE_INLINE_ void _get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const;
GDVIRTUAL1RC(bool, _has_point, Vector2)
protected:
virtual void add_child_notify(Node *p_child) override;
virtual void remove_child_notify(Node *p_child) override;

View File

@ -31,6 +31,7 @@
#include "register_scene_types.h"
#include "core/config/project_settings.h"
#include "core/extension/native_extension_manager.h"
#include "core/object/class_db.h"
#include "core/os/os.h"
#include "scene/2d/animated_sprite_2d.h"
@ -1040,9 +1041,13 @@ void register_scene_types() {
}
}
SceneDebugger::initialize();
NativeExtensionManager::get_singleton()->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SCENE);
}
void unregister_scene_types() {
NativeExtensionManager::get_singleton()->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SCENE);
SceneDebugger::deinitialize();
clear_default_theme();

View File

@ -55,6 +55,7 @@
#include "audio_server.h"
#include "camera/camera_feed.h"
#include "camera_server.h"
#include "core/extension/native_extension_manager.h"
#include "display_server.h"
#include "navigation_server_2d.h"
#include "navigation_server_3d.h"
@ -233,22 +234,26 @@ void register_server_types() {
PhysicsServer3DManager::register_server("GodotPhysics3D", &_createGodotPhysics3DCallback);
PhysicsServer3DManager::set_default_server("GodotPhysics3D");
NativeExtensionManager::get_singleton()->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS);
}
void unregister_server_types() {
NativeExtensionManager::get_singleton()->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS);
memdelete(shader_types);
TextServer::finish_hex_code_box_fonts();
}
void register_server_singletons() {
Engine::get_singleton()->add_singleton(Engine::Singleton("DisplayServer", DisplayServer::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("RenderingServer", RenderingServer::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("AudioServer", AudioServer::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer2D", PhysicsServer2D::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer3D", PhysicsServer3D::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer2D", NavigationServer2D::get_singleton_mut()));
Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer3D", NavigationServer3D::get_singleton_mut()));
Engine::get_singleton()->add_singleton(Engine::Singleton("TextServerManager", TextServerManager::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("XRServer", XRServer::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("CameraServer", CameraServer::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("DisplayServer", DisplayServer::get_singleton(), "DisplayServer"));
Engine::get_singleton()->add_singleton(Engine::Singleton("RenderingServer", RenderingServer::get_singleton(), "RenderingServer"));
Engine::get_singleton()->add_singleton(Engine::Singleton("AudioServer", AudioServer::get_singleton(), "AudioServer"));
Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer2D", PhysicsServer2D::get_singleton(), "PhysicsServer2D"));
Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer3D", PhysicsServer3D::get_singleton(), "PhysicsServer3D"));
Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer2D", NavigationServer2D::get_singleton_mut(), "NavigationServer2D"));
Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer3D", NavigationServer3D::get_singleton_mut(), "NavigationServer3D"));
Engine::get_singleton()->add_singleton(Engine::Singleton("TextServerManager", TextServerManager::get_singleton(), "TextServerManager"));
Engine::get_singleton()->add_singleton(Engine::Singleton("XRServer", XRServer::get_singleton(), "XRServer"));
Engine::get_singleton()->add_singleton(Engine::Singleton("CameraServer", CameraServer::get_singleton(), "CameraServer"));
}