1 /*************************************************************************/
2 /*  gdnative.cpp                                                         */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
10 /*                                                                       */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the       */
13 /* "Software"), to deal in the Software without restriction, including   */
14 /* without limitation the rights to use, copy, modify, merge, publish,   */
15 /* distribute, sublicense, and/or sell copies of the Software, and to    */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions:                                             */
18 /*                                                                       */
19 /* The above copyright notice and this permission notice shall be        */
20 /* included in all copies or substantial portions of the Software.       */
21 /*                                                                       */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
29 /*************************************************************************/
30 
31 #include "gdnative/gdnative.h"
32 
33 #include "core/class_db.h"
34 #include "core/engine.h"
35 #include "core/error_macros.h"
36 #include "core/global_constants.h"
37 #include "core/os/os.h"
38 #include "core/variant.h"
39 
40 #include "modules/gdnative/gdnative.h"
41 
42 #ifdef __cplusplus
43 extern "C" {
44 #endif
45 
godot_object_destroy(godot_object * p_o)46 void GDAPI godot_object_destroy(godot_object *p_o) {
47 	memdelete((Object *)p_o);
48 }
49 
50 // Singleton API
51 
godot_global_get_singleton(char * p_name)52 godot_object GDAPI *godot_global_get_singleton(char *p_name) {
53 	return (godot_object *)Engine::get_singleton()->get_singleton_object(String(p_name));
54 } // result shouldn't be freed
55 
56 // MethodBind API
57 
godot_method_bind_get_method(const char * p_classname,const char * p_methodname)58 godot_method_bind GDAPI *godot_method_bind_get_method(const char *p_classname, const char *p_methodname) {
59 
60 	MethodBind *mb = ClassDB::get_method(StringName(p_classname), StringName(p_methodname));
61 	// MethodBind *mb = ClassDB::get_method("Node", "get_name");
62 	return (godot_method_bind *)mb;
63 }
64 
godot_method_bind_ptrcall(godot_method_bind * p_method_bind,godot_object * p_instance,const void ** p_args,void * p_ret)65 void GDAPI godot_method_bind_ptrcall(godot_method_bind *p_method_bind, godot_object *p_instance, const void **p_args, void *p_ret) {
66 
67 	MethodBind *mb = (MethodBind *)p_method_bind;
68 	Object *o = (Object *)p_instance;
69 	mb->ptrcall(o, p_args, p_ret);
70 }
71 
godot_method_bind_call(godot_method_bind * p_method_bind,godot_object * p_instance,const godot_variant ** p_args,const int p_arg_count,godot_variant_call_error * p_call_error)72 godot_variant GDAPI godot_method_bind_call(godot_method_bind *p_method_bind, godot_object *p_instance, const godot_variant **p_args, const int p_arg_count, godot_variant_call_error *p_call_error) {
73 	MethodBind *mb = (MethodBind *)p_method_bind;
74 	Object *o = (Object *)p_instance;
75 	const Variant **args = (const Variant **)p_args;
76 
77 	godot_variant ret;
78 	godot_variant_new_nil(&ret);
79 
80 	Variant *ret_val = (Variant *)&ret;
81 
82 	Variant::CallError r_error;
83 	*ret_val = mb->call(o, args, p_arg_count, r_error);
84 
85 	if (p_call_error) {
86 		p_call_error->error = (godot_variant_call_error_error)r_error.error;
87 		p_call_error->argument = r_error.argument;
88 		p_call_error->expected = (godot_variant_type)r_error.expected;
89 	}
90 
91 	return ret;
92 }
93 
godot_get_class_constructor(const char * p_classname)94 godot_class_constructor GDAPI godot_get_class_constructor(const char *p_classname) {
95 	ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(StringName(p_classname));
96 	if (class_info)
97 		return (godot_class_constructor)class_info->creation_func;
98 	return NULL;
99 }
100 
godot_get_global_constants()101 godot_dictionary GDAPI godot_get_global_constants() {
102 	godot_dictionary constants;
103 	godot_dictionary_new(&constants);
104 	Dictionary *p_constants = (Dictionary *)&constants;
105 	const int constants_count = GlobalConstants::get_global_constant_count();
106 	for (int i = 0; i < constants_count; ++i) {
107 		const char *name = GlobalConstants::get_global_constant_name(i);
108 		int value = GlobalConstants::get_global_constant_value(i);
109 		(*p_constants)[name] = value;
110 	}
111 	return constants;
112 }
113 
114 // System functions
godot_register_native_call_type(const char * p_call_type,native_call_cb p_callback)115 void GDAPI godot_register_native_call_type(const char *p_call_type, native_call_cb p_callback) {
116 	GDNativeCallRegistry::get_singleton()->register_native_call_type(StringName(p_call_type), p_callback);
117 }
118 
godot_alloc(int p_bytes)119 void GDAPI *godot_alloc(int p_bytes) {
120 	return memalloc(p_bytes);
121 }
122 
godot_realloc(void * p_ptr,int p_bytes)123 void GDAPI *godot_realloc(void *p_ptr, int p_bytes) {
124 	return memrealloc(p_ptr, p_bytes);
125 }
126 
godot_free(void * p_ptr)127 void GDAPI godot_free(void *p_ptr) {
128 	memfree(p_ptr);
129 }
130 
godot_print_error(const char * p_description,const char * p_function,const char * p_file,int p_line)131 void GDAPI godot_print_error(const char *p_description, const char *p_function, const char *p_file, int p_line) {
132 	_err_print_error(p_function, p_file, p_line, p_description, ERR_HANDLER_ERROR);
133 }
134 
godot_print_warning(const char * p_description,const char * p_function,const char * p_file,int p_line)135 void GDAPI godot_print_warning(const char *p_description, const char *p_function, const char *p_file, int p_line) {
136 	_err_print_error(p_function, p_file, p_line, p_description, ERR_HANDLER_WARNING);
137 }
138 
godot_print(const godot_string * p_message)139 void GDAPI godot_print(const godot_string *p_message) {
140 	print_line(*(String *)p_message);
141 }
142 
_gdnative_report_version_mismatch(const godot_object * p_library,const char * p_ext,godot_gdnative_api_version p_want,godot_gdnative_api_version p_have)143 void _gdnative_report_version_mismatch(const godot_object *p_library, const char *p_ext, godot_gdnative_api_version p_want, godot_gdnative_api_version p_have) {
144 	String message = "Error loading GDNative file ";
145 	GDNativeLibrary *library = (GDNativeLibrary *)p_library;
146 
147 	message += library->get_current_library_path() + ": Extension \"" + p_ext + "\" can't be loaded.\n";
148 
149 	Dictionary versions;
150 	versions["have_major"] = p_have.major;
151 	versions["have_minor"] = p_have.minor;
152 	versions["want_major"] = p_want.major;
153 	versions["want_minor"] = p_want.minor;
154 
155 	message += String("Got version {have_major}.{have_minor} but needs {want_major}.{want_minor}!").format(versions);
156 
157 	_err_print_error("gdnative_init", library->get_current_library_path().utf8().ptr(), 0, message.utf8().ptr());
158 }
159 
_gdnative_report_loading_error(const godot_object * p_library,const char * p_what)160 void _gdnative_report_loading_error(const godot_object *p_library, const char *p_what) {
161 	String message = "Error loading GDNative file ";
162 	GDNativeLibrary *library = (GDNativeLibrary *)p_library;
163 
164 	message += library->get_current_library_path() + ": " + p_what;
165 
166 	_err_print_error("gdnative_init", library->get_current_library_path().utf8().ptr(), 0, message.utf8().ptr());
167 }
168 
godot_is_instance_valid(const godot_object * p_object)169 bool GDAPI godot_is_instance_valid(const godot_object *p_object) {
170 	return ObjectDB::instance_validate((Object *)p_object);
171 }
172 
godot_instance_from_id(godot_int p_instance_id)173 godot_object GDAPI *godot_instance_from_id(godot_int p_instance_id) {
174 	return (godot_object *)ObjectDB::get_instance((ObjectID)p_instance_id);
175 }
176 
godot_get_class_tag(const godot_string_name * p_class)177 void *godot_get_class_tag(const godot_string_name *p_class) {
178 	StringName class_name = *(StringName *)p_class;
179 	ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(class_name);
180 	return class_info ? class_info->class_ptr : NULL;
181 }
182 
godot_object_cast_to(const godot_object * p_object,void * p_class_tag)183 godot_object *godot_object_cast_to(const godot_object *p_object, void *p_class_tag) {
184 	if (!p_object) return NULL;
185 	Object *o = (Object *)p_object;
186 
187 	return o->is_class_ptr(p_class_tag) ? (godot_object *)o : NULL;
188 }
189 
190 #ifdef __cplusplus
191 }
192 #endif
193