1 | /**************************************************************************/ |
2 | /* multiplayer_api.cpp */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
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 "multiplayer_api.h" |
32 | |
33 | #include "core/debugger/engine_debugger.h" |
34 | #include "core/io/marshalls.h" |
35 | |
36 | #include <stdint.h> |
37 | |
38 | #ifdef DEBUG_ENABLED |
39 | #include "core/os/os.h" |
40 | #endif |
41 | |
42 | StringName MultiplayerAPI::default_interface; |
43 | |
44 | void MultiplayerAPI::set_default_interface(const StringName &p_interface) { |
45 | ERR_FAIL_COND_MSG(!ClassDB::is_parent_class(p_interface, MultiplayerAPI::get_class_static()), vformat("Can't make %s the default multiplayer interface since it does not extend MultiplayerAPI." , p_interface)); |
46 | default_interface = StringName(p_interface, true); |
47 | } |
48 | |
49 | StringName MultiplayerAPI::get_default_interface() { |
50 | return default_interface; |
51 | } |
52 | |
53 | Ref<MultiplayerAPI> MultiplayerAPI::create_default_interface() { |
54 | if (default_interface != StringName()) { |
55 | return Ref<MultiplayerAPI>(Object::cast_to<MultiplayerAPI>(ClassDB::instantiate(default_interface))); |
56 | } |
57 | return Ref<MultiplayerAPI>(memnew(MultiplayerAPIExtension)); |
58 | } |
59 | |
60 | // The variant is compressed and encoded; The first byte contains all the meta |
61 | // information and the format is: |
62 | // - The first LSB 6 bits are used for the variant type. |
63 | // - The next two bits are used to store the encoding mode. |
64 | // - Boolean values uses the encoding mode to store the value. |
65 | #define VARIANT_META_TYPE_MASK 0x3F |
66 | #define VARIANT_META_EMODE_MASK 0xC0 |
67 | #define VARIANT_META_BOOL_MASK 0x80 |
68 | #define ENCODE_8 0 << 6 |
69 | #define ENCODE_16 1 << 6 |
70 | #define ENCODE_32 2 << 6 |
71 | #define ENCODE_64 3 << 6 |
72 | Error MultiplayerAPI::encode_and_compress_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_allow_object_decoding) { |
73 | // Unreachable because `VARIANT_MAX` == 38 and `ENCODE_VARIANT_MASK` == 77 |
74 | CRASH_COND(p_variant.get_type() > VARIANT_META_TYPE_MASK); |
75 | |
76 | uint8_t *buf = r_buffer; |
77 | r_len = 0; |
78 | uint8_t encode_mode = 0; |
79 | |
80 | switch (p_variant.get_type()) { |
81 | case Variant::BOOL: { |
82 | if (buf) { |
83 | // We don't use encode_mode for booleans, so we can use it to store the value. |
84 | buf[0] = (p_variant.operator bool()) ? (1 << 7) : 0; |
85 | buf[0] |= p_variant.get_type(); |
86 | } |
87 | r_len += 1; |
88 | } break; |
89 | case Variant::INT: { |
90 | if (buf) { |
91 | // Reserve the first byte for the meta. |
92 | buf += 1; |
93 | } |
94 | r_len += 1; |
95 | int64_t val = p_variant; |
96 | if (val <= (int64_t)INT8_MAX && val >= (int64_t)INT8_MIN) { |
97 | // Use 8 bit |
98 | encode_mode = ENCODE_8; |
99 | if (buf) { |
100 | buf[0] = val; |
101 | } |
102 | r_len += 1; |
103 | } else if (val <= (int64_t)INT16_MAX && val >= (int64_t)INT16_MIN) { |
104 | // Use 16 bit |
105 | encode_mode = ENCODE_16; |
106 | if (buf) { |
107 | encode_uint16(val, buf); |
108 | } |
109 | r_len += 2; |
110 | } else if (val <= (int64_t)INT32_MAX && val >= (int64_t)INT32_MIN) { |
111 | // Use 32 bit |
112 | encode_mode = ENCODE_32; |
113 | if (buf) { |
114 | encode_uint32(val, buf); |
115 | } |
116 | r_len += 4; |
117 | } else { |
118 | // Use 64 bit |
119 | encode_mode = ENCODE_64; |
120 | if (buf) { |
121 | encode_uint64(val, buf); |
122 | } |
123 | r_len += 8; |
124 | } |
125 | // Store the meta |
126 | if (buf) { |
127 | buf -= 1; |
128 | buf[0] = encode_mode | p_variant.get_type(); |
129 | } |
130 | } break; |
131 | default: |
132 | // Any other case is not yet compressed. |
133 | Error err = encode_variant(p_variant, r_buffer, r_len, p_allow_object_decoding); |
134 | if (err != OK) { |
135 | return err; |
136 | } |
137 | if (r_buffer) { |
138 | // The first byte is not used by the marshaling, so store the type |
139 | // so we know how to decompress and decode this variant. |
140 | r_buffer[0] = p_variant.get_type(); |
141 | } |
142 | } |
143 | |
144 | return OK; |
145 | } |
146 | |
147 | Error MultiplayerAPI::decode_and_decompress_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len, bool p_allow_object_decoding) { |
148 | const uint8_t *buf = p_buffer; |
149 | int len = p_len; |
150 | |
151 | ERR_FAIL_COND_V(len < 1, ERR_INVALID_DATA); |
152 | uint8_t type = buf[0] & VARIANT_META_TYPE_MASK; |
153 | uint8_t encode_mode = buf[0] & VARIANT_META_EMODE_MASK; |
154 | |
155 | ERR_FAIL_COND_V(type >= Variant::VARIANT_MAX, ERR_INVALID_DATA); |
156 | |
157 | switch (type) { |
158 | case Variant::BOOL: { |
159 | bool val = (buf[0] & VARIANT_META_BOOL_MASK) > 0; |
160 | r_variant = val; |
161 | if (r_len) { |
162 | *r_len = 1; |
163 | } |
164 | } break; |
165 | case Variant::INT: { |
166 | buf += 1; |
167 | len -= 1; |
168 | if (r_len) { |
169 | *r_len = 1; |
170 | } |
171 | if (encode_mode == ENCODE_8) { |
172 | // 8 bits. |
173 | ERR_FAIL_COND_V(len < 1, ERR_INVALID_DATA); |
174 | int8_t val = buf[0]; |
175 | r_variant = val; |
176 | if (r_len) { |
177 | (*r_len) += 1; |
178 | } |
179 | } else if (encode_mode == ENCODE_16) { |
180 | // 16 bits. |
181 | ERR_FAIL_COND_V(len < 2, ERR_INVALID_DATA); |
182 | int16_t val = decode_uint16(buf); |
183 | r_variant = val; |
184 | if (r_len) { |
185 | (*r_len) += 2; |
186 | } |
187 | } else if (encode_mode == ENCODE_32) { |
188 | // 32 bits. |
189 | ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA); |
190 | int32_t val = decode_uint32(buf); |
191 | r_variant = val; |
192 | if (r_len) { |
193 | (*r_len) += 4; |
194 | } |
195 | } else { |
196 | // 64 bits. |
197 | ERR_FAIL_COND_V(len < 8, ERR_INVALID_DATA); |
198 | int64_t val = decode_uint64(buf); |
199 | r_variant = val; |
200 | if (r_len) { |
201 | (*r_len) += 8; |
202 | } |
203 | } |
204 | } break; |
205 | default: |
206 | Error err = decode_variant(r_variant, p_buffer, p_len, r_len, p_allow_object_decoding); |
207 | if (err != OK) { |
208 | return err; |
209 | } |
210 | } |
211 | |
212 | return OK; |
213 | } |
214 | |
215 | Error MultiplayerAPI::encode_and_compress_variants(const Variant **p_variants, int p_count, uint8_t *p_buffer, int &r_len, bool *r_raw, bool p_allow_object_decoding) { |
216 | r_len = 0; |
217 | int size = 0; |
218 | |
219 | if (p_count == 0) { |
220 | if (r_raw) { |
221 | *r_raw = true; |
222 | } |
223 | return OK; |
224 | } |
225 | |
226 | // Try raw encoding optimization. |
227 | if (r_raw && p_count == 1) { |
228 | *r_raw = false; |
229 | const Variant &v = *(p_variants[0]); |
230 | if (v.get_type() == Variant::PACKED_BYTE_ARRAY) { |
231 | *r_raw = true; |
232 | const PackedByteArray pba = v; |
233 | if (p_buffer) { |
234 | memcpy(p_buffer, pba.ptr(), pba.size()); |
235 | } |
236 | r_len += pba.size(); |
237 | } else { |
238 | encode_and_compress_variant(v, p_buffer, size, p_allow_object_decoding); |
239 | r_len += size; |
240 | } |
241 | return OK; |
242 | } |
243 | |
244 | // Regular encoding. |
245 | for (int i = 0; i < p_count; i++) { |
246 | const Variant &v = *(p_variants[i]); |
247 | encode_and_compress_variant(v, p_buffer ? p_buffer + r_len : nullptr, size, p_allow_object_decoding); |
248 | r_len += size; |
249 | } |
250 | return OK; |
251 | } |
252 | |
253 | Error MultiplayerAPI::decode_and_decompress_variants(Vector<Variant> &r_variants, const uint8_t *p_buffer, int p_len, int &r_len, bool p_raw, bool p_allow_object_decoding) { |
254 | r_len = 0; |
255 | int argc = r_variants.size(); |
256 | if (argc == 0 && p_raw) { |
257 | return OK; |
258 | } |
259 | ERR_FAIL_COND_V(p_raw && argc != 1, ERR_INVALID_DATA); |
260 | if (p_raw) { |
261 | r_len = p_len; |
262 | PackedByteArray pba; |
263 | pba.resize(p_len); |
264 | memcpy(pba.ptrw(), p_buffer, p_len); |
265 | r_variants.write[0] = pba; |
266 | return OK; |
267 | } |
268 | |
269 | Vector<Variant> args; |
270 | Vector<const Variant *> argp; |
271 | args.resize(argc); |
272 | |
273 | for (int i = 0; i < argc; i++) { |
274 | ERR_FAIL_COND_V_MSG(r_len >= p_len, ERR_INVALID_DATA, "Invalid packet received. Size too small." ); |
275 | |
276 | int vlen; |
277 | Error err = MultiplayerAPI::decode_and_decompress_variant(r_variants.write[i], &p_buffer[r_len], p_len - r_len, &vlen, p_allow_object_decoding); |
278 | ERR_FAIL_COND_V_MSG(err != OK, err, "Invalid packet received. Unable to decode state variable." ); |
279 | r_len += vlen; |
280 | } |
281 | return OK; |
282 | } |
283 | |
284 | Error MultiplayerAPI::_rpc_bind(int p_peer, Object *p_object, const StringName &p_method, Array p_args) { |
285 | Vector<Variant> args; |
286 | Vector<const Variant *> argsp; |
287 | args.resize(p_args.size()); |
288 | argsp.resize(p_args.size()); |
289 | Variant *ptr = args.ptrw(); |
290 | const Variant **pptr = argsp.ptrw(); |
291 | for (int i = 0; i < p_args.size(); i++) { |
292 | ptr[i] = p_args[i]; |
293 | pptr[i] = &ptr[i]; |
294 | } |
295 | return rpcp(p_object, p_peer, p_method, argsp.size() ? argsp.ptrw() : nullptr, argsp.size()); |
296 | } |
297 | |
298 | void MultiplayerAPI::_bind_methods() { |
299 | ClassDB::bind_method(D_METHOD("has_multiplayer_peer" ), &MultiplayerAPI::has_multiplayer_peer); |
300 | ClassDB::bind_method(D_METHOD("get_multiplayer_peer" ), &MultiplayerAPI::get_multiplayer_peer); |
301 | ClassDB::bind_method(D_METHOD("set_multiplayer_peer" , "peer" ), &MultiplayerAPI::set_multiplayer_peer); |
302 | ClassDB::bind_method(D_METHOD("get_unique_id" ), &MultiplayerAPI::get_unique_id); |
303 | ClassDB::bind_method(D_METHOD("is_server" ), &MultiplayerAPI::is_server); |
304 | ClassDB::bind_method(D_METHOD("get_remote_sender_id" ), &MultiplayerAPI::get_remote_sender_id); |
305 | ClassDB::bind_method(D_METHOD("poll" ), &MultiplayerAPI::poll); |
306 | ClassDB::bind_method(D_METHOD("rpc" , "peer" , "object" , "method" , "arguments" ), &MultiplayerAPI::_rpc_bind, DEFVAL(Array())); |
307 | ClassDB::bind_method(D_METHOD("object_configuration_add" , "object" , "configuration" ), &MultiplayerAPI::object_configuration_add); |
308 | ClassDB::bind_method(D_METHOD("object_configuration_remove" , "object" , "configuration" ), &MultiplayerAPI::object_configuration_remove); |
309 | |
310 | ClassDB::bind_method(D_METHOD("get_peers" ), &MultiplayerAPI::get_peer_ids); |
311 | |
312 | ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multiplayer_peer" , PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerPeer" , PROPERTY_USAGE_NONE), "set_multiplayer_peer" , "get_multiplayer_peer" ); |
313 | |
314 | ClassDB::bind_static_method("MultiplayerAPI" , D_METHOD("set_default_interface" , "interface_name" ), &MultiplayerAPI::set_default_interface); |
315 | ClassDB::bind_static_method("MultiplayerAPI" , D_METHOD("get_default_interface" ), &MultiplayerAPI::get_default_interface); |
316 | ClassDB::bind_static_method("MultiplayerAPI" , D_METHOD("create_default_interface" ), &MultiplayerAPI::create_default_interface); |
317 | |
318 | ADD_SIGNAL(MethodInfo("peer_connected" , PropertyInfo(Variant::INT, "id" ))); |
319 | ADD_SIGNAL(MethodInfo("peer_disconnected" , PropertyInfo(Variant::INT, "id" ))); |
320 | ADD_SIGNAL(MethodInfo("connected_to_server" )); |
321 | ADD_SIGNAL(MethodInfo("connection_failed" )); |
322 | ADD_SIGNAL(MethodInfo("server_disconnected" )); |
323 | |
324 | BIND_ENUM_CONSTANT(RPC_MODE_DISABLED); |
325 | BIND_ENUM_CONSTANT(RPC_MODE_ANY_PEER); |
326 | BIND_ENUM_CONSTANT(RPC_MODE_AUTHORITY); |
327 | } |
328 | |
329 | /// MultiplayerAPIExtension |
330 | |
331 | Error MultiplayerAPIExtension::poll() { |
332 | Error err = OK; |
333 | GDVIRTUAL_CALL(_poll, err); |
334 | return err; |
335 | } |
336 | |
337 | void MultiplayerAPIExtension::set_multiplayer_peer(const Ref<MultiplayerPeer> &p_peer) { |
338 | GDVIRTUAL_CALL(_set_multiplayer_peer, p_peer); |
339 | } |
340 | |
341 | Ref<MultiplayerPeer> MultiplayerAPIExtension::get_multiplayer_peer() { |
342 | Ref<MultiplayerPeer> peer; |
343 | GDVIRTUAL_CALL(_get_multiplayer_peer, peer); |
344 | return peer; |
345 | } |
346 | |
347 | int MultiplayerAPIExtension::get_unique_id() { |
348 | int id = 1; |
349 | GDVIRTUAL_CALL(_get_unique_id, id); |
350 | return id; |
351 | } |
352 | |
353 | Vector<int> MultiplayerAPIExtension::get_peer_ids() { |
354 | Vector<int> ids; |
355 | GDVIRTUAL_CALL(_get_peer_ids, ids); |
356 | return ids; |
357 | } |
358 | |
359 | Error MultiplayerAPIExtension::rpcp(Object *p_obj, int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount) { |
360 | if (!GDVIRTUAL_IS_OVERRIDDEN(_rpc)) { |
361 | return ERR_UNAVAILABLE; |
362 | } |
363 | Array args; |
364 | for (int i = 0; i < p_argcount; i++) { |
365 | args.push_back(*p_arg[i]); |
366 | } |
367 | Error ret = FAILED; |
368 | GDVIRTUAL_CALL(_rpc, p_peer_id, p_obj, p_method, args, ret); |
369 | return ret; |
370 | } |
371 | |
372 | int MultiplayerAPIExtension::get_remote_sender_id() { |
373 | int id = 0; |
374 | GDVIRTUAL_CALL(_get_remote_sender_id, id); |
375 | return id; |
376 | } |
377 | |
378 | Error MultiplayerAPIExtension::object_configuration_add(Object *p_object, Variant p_config) { |
379 | Error err = ERR_UNAVAILABLE; |
380 | GDVIRTUAL_CALL(_object_configuration_add, p_object, p_config, err); |
381 | return err; |
382 | } |
383 | |
384 | Error MultiplayerAPIExtension::object_configuration_remove(Object *p_object, Variant p_config) { |
385 | Error err = ERR_UNAVAILABLE; |
386 | GDVIRTUAL_CALL(_object_configuration_remove, p_object, p_config, err); |
387 | return err; |
388 | } |
389 | |
390 | void MultiplayerAPIExtension::_bind_methods() { |
391 | GDVIRTUAL_BIND(_poll); |
392 | GDVIRTUAL_BIND(_set_multiplayer_peer, "multiplayer_peer" ); |
393 | GDVIRTUAL_BIND(_get_multiplayer_peer); |
394 | GDVIRTUAL_BIND(_get_unique_id); |
395 | GDVIRTUAL_BIND(_get_peer_ids); |
396 | GDVIRTUAL_BIND(_rpc, "peer" , "object" , "method" , "args" ); |
397 | GDVIRTUAL_BIND(_get_remote_sender_id); |
398 | GDVIRTUAL_BIND(_object_configuration_add, "object" , "configuration" ); |
399 | GDVIRTUAL_BIND(_object_configuration_remove, "object" , "configuration" ); |
400 | } |
401 | |