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
+7
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")
+805
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
+45
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
+688
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;
}
+427
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
+411
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 "";
}
+94
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
+130
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;
}
+71
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