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