1 /*************************************************************************/
2 /*  gd_glue.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 "gd_glue.h"
32 
33 #ifdef MONO_GLUE_ENABLED
34 
35 #include "core/array.h"
36 #include "core/io/marshalls.h"
37 #include "core/os/os.h"
38 #include "core/ustring.h"
39 #include "core/variant.h"
40 #include "core/variant_parser.h"
41 
42 #include "../mono_gd/gd_mono_cache.h"
43 #include "../mono_gd/gd_mono_utils.h"
44 
godot_icall_GD_bytes2var(MonoArray * p_bytes,MonoBoolean p_allow_objects)45 MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes, MonoBoolean p_allow_objects) {
46 	Variant ret;
47 	PoolByteArray varr = GDMonoMarshal::mono_array_to_PoolByteArray(p_bytes);
48 	PoolByteArray::Read r = varr.read();
49 	Error err = decode_variant(ret, r.ptr(), varr.size(), NULL, p_allow_objects);
50 	if (err != OK) {
51 		ret = RTR("Not enough bytes for decoding bytes, or invalid format.");
52 	}
53 	return GDMonoMarshal::variant_to_mono_object(ret);
54 }
55 
godot_icall_GD_convert(MonoObject * p_what,int32_t p_type)56 MonoObject *godot_icall_GD_convert(MonoObject *p_what, int32_t p_type) {
57 	Variant what = GDMonoMarshal::mono_object_to_variant(p_what);
58 	const Variant *args[1] = { &what };
59 	Variant::CallError ce;
60 	Variant ret = Variant::construct(Variant::Type(p_type), args, 1, ce);
61 	ERR_FAIL_COND_V(ce.error != Variant::CallError::CALL_OK, NULL);
62 	return GDMonoMarshal::variant_to_mono_object(ret);
63 }
64 
godot_icall_GD_hash(MonoObject * p_var)65 int godot_icall_GD_hash(MonoObject *p_var) {
66 	return GDMonoMarshal::mono_object_to_variant(p_var).hash();
67 }
68 
godot_icall_GD_instance_from_id(uint64_t p_instance_id)69 MonoObject *godot_icall_GD_instance_from_id(uint64_t p_instance_id) {
70 	return GDMonoUtils::unmanaged_get_managed(ObjectDB::get_instance(p_instance_id));
71 }
72 
godot_icall_GD_print(MonoArray * p_what)73 void godot_icall_GD_print(MonoArray *p_what) {
74 	String str;
75 	int length = mono_array_length(p_what);
76 
77 	for (int i = 0; i < length; i++) {
78 		MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
79 
80 		MonoException *exc = NULL;
81 		String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
82 
83 		if (exc) {
84 			GDMonoUtils::set_pending_exception(exc);
85 			return;
86 		}
87 
88 		str += elem_str;
89 	}
90 
91 	print_line(str);
92 }
93 
godot_icall_GD_printerr(MonoArray * p_what)94 void godot_icall_GD_printerr(MonoArray *p_what) {
95 
96 	String str;
97 	int length = mono_array_length(p_what);
98 
99 	for (int i = 0; i < length; i++) {
100 		MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
101 
102 		MonoException *exc = NULL;
103 		String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
104 
105 		if (exc) {
106 			GDMonoUtils::set_pending_exception(exc);
107 			return;
108 		}
109 
110 		str += elem_str;
111 	}
112 
113 	print_error(str);
114 }
115 
godot_icall_GD_printraw(MonoArray * p_what)116 void godot_icall_GD_printraw(MonoArray *p_what) {
117 	String str;
118 	int length = mono_array_length(p_what);
119 
120 	for (int i = 0; i < length; i++) {
121 		MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
122 
123 		MonoException *exc = NULL;
124 		String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
125 
126 		if (exc) {
127 			GDMonoUtils::set_pending_exception(exc);
128 			return;
129 		}
130 
131 		str += elem_str;
132 	}
133 
134 	OS::get_singleton()->print("%s", str.utf8().get_data());
135 }
136 
godot_icall_GD_prints(MonoArray * p_what)137 void godot_icall_GD_prints(MonoArray *p_what) {
138 	String str;
139 	int length = mono_array_length(p_what);
140 
141 	for (int i = 0; i < length; i++) {
142 		MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
143 
144 		MonoException *exc = NULL;
145 		String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
146 
147 		if (exc) {
148 			GDMonoUtils::set_pending_exception(exc);
149 			return;
150 		}
151 
152 		if (i)
153 			str += " ";
154 
155 		str += elem_str;
156 	}
157 
158 	print_line(str);
159 }
160 
godot_icall_GD_printt(MonoArray * p_what)161 void godot_icall_GD_printt(MonoArray *p_what) {
162 	String str;
163 	int length = mono_array_length(p_what);
164 
165 	for (int i = 0; i < length; i++) {
166 		MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
167 
168 		MonoException *exc = NULL;
169 		String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
170 
171 		if (exc) {
172 			GDMonoUtils::set_pending_exception(exc);
173 			return;
174 		}
175 
176 		if (i)
177 			str += "\t";
178 
179 		str += elem_str;
180 	}
181 
182 	print_line(str);
183 }
184 
godot_icall_GD_randf()185 float godot_icall_GD_randf() {
186 	return Math::randf();
187 }
188 
godot_icall_GD_randi()189 uint32_t godot_icall_GD_randi() {
190 	return Math::rand();
191 }
192 
godot_icall_GD_randomize()193 void godot_icall_GD_randomize() {
194 	Math::randomize();
195 }
196 
godot_icall_GD_rand_range(double from,double to)197 double godot_icall_GD_rand_range(double from, double to) {
198 	return Math::random(from, to);
199 }
200 
godot_icall_GD_rand_seed(uint64_t seed,uint64_t * newSeed)201 uint32_t godot_icall_GD_rand_seed(uint64_t seed, uint64_t *newSeed) {
202 	int ret = Math::rand_from_seed(&seed);
203 	*newSeed = seed;
204 	return ret;
205 }
206 
godot_icall_GD_seed(uint64_t p_seed)207 void godot_icall_GD_seed(uint64_t p_seed) {
208 	Math::seed(p_seed);
209 }
210 
godot_icall_GD_str(MonoArray * p_what)211 MonoString *godot_icall_GD_str(MonoArray *p_what) {
212 	String str;
213 	Array what = GDMonoMarshal::mono_array_to_Array(p_what);
214 
215 	for (int i = 0; i < what.size(); i++) {
216 		String os = what[i].operator String();
217 
218 		if (i == 0)
219 			str = os;
220 		else
221 			str += os;
222 	}
223 
224 	return GDMonoMarshal::mono_string_from_godot(str);
225 }
226 
godot_icall_GD_str2var(MonoString * p_str)227 MonoObject *godot_icall_GD_str2var(MonoString *p_str) {
228 	Variant ret;
229 
230 	VariantParser::StreamString ss;
231 	ss.s = GDMonoMarshal::mono_string_to_godot(p_str);
232 
233 	String errs;
234 	int line;
235 	Error err = VariantParser::parse(&ss, ret, errs, line);
236 	if (err != OK) {
237 		String err_str = "Parse error at line " + itos(line) + ": " + errs + ".";
238 		ERR_PRINTS(err_str);
239 		ret = err_str;
240 	}
241 
242 	return GDMonoMarshal::variant_to_mono_object(ret);
243 }
244 
godot_icall_GD_type_exists(MonoString * p_type)245 MonoBoolean godot_icall_GD_type_exists(MonoString *p_type) {
246 	return ClassDB::class_exists(GDMonoMarshal::mono_string_to_godot(p_type));
247 }
248 
godot_icall_GD_pusherror(MonoString * p_str)249 void godot_icall_GD_pusherror(MonoString *p_str) {
250 	ERR_PRINTS(GDMonoMarshal::mono_string_to_godot(p_str));
251 }
252 
godot_icall_GD_pushwarning(MonoString * p_str)253 void godot_icall_GD_pushwarning(MonoString *p_str) {
254 	WARN_PRINTS(GDMonoMarshal::mono_string_to_godot(p_str));
255 }
256 
godot_icall_GD_var2bytes(MonoObject * p_var,MonoBoolean p_full_objects)257 MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var, MonoBoolean p_full_objects) {
258 	Variant var = GDMonoMarshal::mono_object_to_variant(p_var);
259 
260 	PoolByteArray barr;
261 	int len;
262 	Error err = encode_variant(var, NULL, len, p_full_objects);
263 	ERR_FAIL_COND_V_MSG(err != OK, NULL, "Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).");
264 
265 	barr.resize(len);
266 	{
267 		PoolByteArray::Write w = barr.write();
268 		encode_variant(var, w.ptr(), len, p_full_objects);
269 	}
270 
271 	return GDMonoMarshal::PoolByteArray_to_mono_array(barr);
272 }
273 
godot_icall_GD_var2str(MonoObject * p_var)274 MonoString *godot_icall_GD_var2str(MonoObject *p_var) {
275 	String vars;
276 	VariantWriter::write_to_string(GDMonoMarshal::mono_object_to_variant(p_var), vars);
277 	return GDMonoMarshal::mono_string_from_godot(vars);
278 }
279 
godot_icall_DefaultGodotTaskScheduler()280 MonoObject *godot_icall_DefaultGodotTaskScheduler() {
281 	return GDMonoCache::cached_data.task_scheduler_handle->get_target();
282 }
283 
godot_register_gd_icalls()284 void godot_register_gd_icalls() {
285 	mono_add_internal_call("Godot.GD::godot_icall_GD_bytes2var", (void *)godot_icall_GD_bytes2var);
286 	mono_add_internal_call("Godot.GD::godot_icall_GD_convert", (void *)godot_icall_GD_convert);
287 	mono_add_internal_call("Godot.GD::godot_icall_GD_hash", (void *)godot_icall_GD_hash);
288 	mono_add_internal_call("Godot.GD::godot_icall_GD_instance_from_id", (void *)godot_icall_GD_instance_from_id);
289 	mono_add_internal_call("Godot.GD::godot_icall_GD_pusherror", (void *)godot_icall_GD_pusherror);
290 	mono_add_internal_call("Godot.GD::godot_icall_GD_pushwarning", (void *)godot_icall_GD_pushwarning);
291 	mono_add_internal_call("Godot.GD::godot_icall_GD_print", (void *)godot_icall_GD_print);
292 	mono_add_internal_call("Godot.GD::godot_icall_GD_printerr", (void *)godot_icall_GD_printerr);
293 	mono_add_internal_call("Godot.GD::godot_icall_GD_printraw", (void *)godot_icall_GD_printraw);
294 	mono_add_internal_call("Godot.GD::godot_icall_GD_prints", (void *)godot_icall_GD_prints);
295 	mono_add_internal_call("Godot.GD::godot_icall_GD_printt", (void *)godot_icall_GD_printt);
296 	mono_add_internal_call("Godot.GD::godot_icall_GD_randf", (void *)godot_icall_GD_randf);
297 	mono_add_internal_call("Godot.GD::godot_icall_GD_randi", (void *)godot_icall_GD_randi);
298 	mono_add_internal_call("Godot.GD::godot_icall_GD_randomize", (void *)godot_icall_GD_randomize);
299 	mono_add_internal_call("Godot.GD::godot_icall_GD_rand_range", (void *)godot_icall_GD_rand_range);
300 	mono_add_internal_call("Godot.GD::godot_icall_GD_rand_seed", (void *)godot_icall_GD_rand_seed);
301 	mono_add_internal_call("Godot.GD::godot_icall_GD_seed", (void *)godot_icall_GD_seed);
302 	mono_add_internal_call("Godot.GD::godot_icall_GD_str", (void *)godot_icall_GD_str);
303 	mono_add_internal_call("Godot.GD::godot_icall_GD_str2var", (void *)godot_icall_GD_str2var);
304 	mono_add_internal_call("Godot.GD::godot_icall_GD_type_exists", (void *)godot_icall_GD_type_exists);
305 	mono_add_internal_call("Godot.GD::godot_icall_GD_var2bytes", (void *)godot_icall_GD_var2bytes);
306 	mono_add_internal_call("Godot.GD::godot_icall_GD_var2str", (void *)godot_icall_GD_var2str);
307 
308 	// Dispatcher
309 	mono_add_internal_call("Godot.Dispatcher::godot_icall_DefaultGodotTaskScheduler", (void *)godot_icall_DefaultGodotTaskScheduler);
310 }
311 
312 #endif // MONO_GLUE_ENABLED
313