| 
									
										
										
										
											2022-10-05 17:50:19 +02:00
										 |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /*  multiplayer_debugger.cpp                                              */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /*                         This file is part of:                          */ | 
					
						
							|  |  |  | /*                             GODOT ENGINE                               */ | 
					
						
							|  |  |  | /*                        https://godotengine.org                         */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ | 
					
						
							|  |  |  | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */ | 
					
						
							|  |  |  | /*                                                                        */ | 
					
						
							|  |  |  | /* 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 "multiplayer_debugger.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-17 03:31:23 +01:00
										 |  |  | #include "multiplayer_synchronizer.h"
 | 
					
						
							|  |  |  | #include "scene_replication_config.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-05 17:50:19 +02:00
										 |  |  | #include "core/debugger/engine_debugger.h"
 | 
					
						
							|  |  |  | #include "scene/main/node.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | List<Ref<EngineProfiler>> multiplayer_profilers; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MultiplayerDebugger::initialize() { | 
					
						
							|  |  |  | 	Ref<BandwidthProfiler> bandwidth; | 
					
						
							|  |  |  | 	bandwidth.instantiate(); | 
					
						
							| 
									
										
										
										
											2022-11-17 03:31:23 +01:00
										 |  |  | 	bandwidth->bind("multiplayer:bandwidth"); | 
					
						
							| 
									
										
										
										
											2022-10-05 17:50:19 +02:00
										 |  |  | 	multiplayer_profilers.push_back(bandwidth); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Ref<RPCProfiler> rpc_profiler; | 
					
						
							|  |  |  | 	rpc_profiler.instantiate(); | 
					
						
							| 
									
										
										
										
											2022-11-17 03:31:23 +01:00
										 |  |  | 	rpc_profiler->bind("multiplayer:rpc"); | 
					
						
							| 
									
										
										
										
											2022-10-05 17:50:19 +02:00
										 |  |  | 	multiplayer_profilers.push_back(rpc_profiler); | 
					
						
							| 
									
										
										
										
											2022-11-17 03:31:23 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	Ref<ReplicationProfiler> replication_profiler; | 
					
						
							|  |  |  | 	replication_profiler.instantiate(); | 
					
						
							|  |  |  | 	replication_profiler->bind("multiplayer:replication"); | 
					
						
							|  |  |  | 	multiplayer_profilers.push_back(replication_profiler); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	EngineDebugger::register_message_capture("multiplayer", EngineDebugger::Capture(nullptr, &_capture)); | 
					
						
							| 
									
										
										
										
											2022-10-05 17:50:19 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MultiplayerDebugger::deinitialize() { | 
					
						
							|  |  |  | 	multiplayer_profilers.clear(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-17 03:31:23 +01:00
										 |  |  | Error MultiplayerDebugger::_capture(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured) { | 
					
						
							|  |  |  | 	if (p_msg == "cache") { | 
					
						
							|  |  |  | 		Array out; | 
					
						
							|  |  |  | 		for (int i = 0; i < p_args.size(); i++) { | 
					
						
							|  |  |  | 			ObjectID id = p_args[i].operator ObjectID(); | 
					
						
							|  |  |  | 			Object *obj = ObjectDB::get_instance(id); | 
					
						
							|  |  |  | 			ERR_CONTINUE(!obj); | 
					
						
							|  |  |  | 			if (Object::cast_to<SceneReplicationConfig>(obj)) { | 
					
						
							|  |  |  | 				out.push_back(id); | 
					
						
							|  |  |  | 				out.push_back(obj->get_class()); | 
					
						
							|  |  |  | 				out.push_back(((SceneReplicationConfig *)obj)->get_path()); | 
					
						
							|  |  |  | 			} else if (Object::cast_to<Node>(obj)) { | 
					
						
							|  |  |  | 				out.push_back(id); | 
					
						
							|  |  |  | 				out.push_back(obj->get_class()); | 
					
						
							|  |  |  | 				out.push_back(String(((Node *)obj)->get_path())); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				ERR_FAIL_V(FAILED); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		EngineDebugger::get_singleton()->send_message("multiplayer:cache", out); | 
					
						
							|  |  |  | 		return OK; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ERR_FAIL_V(FAILED); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-05 17:50:19 +02:00
										 |  |  | // BandwidthProfiler
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int MultiplayerDebugger::BandwidthProfiler::bandwidth_usage(const Vector<BandwidthFrame> &p_buffer, int p_pointer) { | 
					
						
							| 
									
										
										
										
											2024-01-19 13:21:39 +01:00
										 |  |  | 	ERR_FAIL_COND_V(p_buffer.is_empty(), 0); | 
					
						
							| 
									
										
										
										
											2022-10-05 17:50:19 +02:00
										 |  |  | 	int total_bandwidth = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	uint64_t timestamp = OS::get_singleton()->get_ticks_msec(); | 
					
						
							|  |  |  | 	uint64_t final_timestamp = timestamp - 1000; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int i = (p_pointer + p_buffer.size() - 1) % p_buffer.size(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (i != p_pointer && p_buffer[i].packet_size > 0) { | 
					
						
							|  |  |  | 		if (p_buffer[i].timestamp < final_timestamp) { | 
					
						
							|  |  |  | 			return total_bandwidth; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		total_bandwidth += p_buffer[i].packet_size; | 
					
						
							|  |  |  | 		i = (i + p_buffer.size() - 1) % p_buffer.size(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ERR_FAIL_COND_V_MSG(i == p_pointer, total_bandwidth, "Reached the end of the bandwidth profiler buffer, values might be inaccurate."); | 
					
						
							|  |  |  | 	return total_bandwidth; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MultiplayerDebugger::BandwidthProfiler::toggle(bool p_enable, const Array &p_opts) { | 
					
						
							|  |  |  | 	if (!p_enable) { | 
					
						
							|  |  |  | 		bandwidth_in.clear(); | 
					
						
							|  |  |  | 		bandwidth_out.clear(); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		bandwidth_in_ptr = 0; | 
					
						
							|  |  |  | 		bandwidth_in.resize(16384); // ~128kB
 | 
					
						
							|  |  |  | 		for (int i = 0; i < bandwidth_in.size(); ++i) { | 
					
						
							|  |  |  | 			bandwidth_in.write[i].packet_size = -1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		bandwidth_out_ptr = 0; | 
					
						
							|  |  |  | 		bandwidth_out.resize(16384); // ~128kB
 | 
					
						
							|  |  |  | 		for (int i = 0; i < bandwidth_out.size(); ++i) { | 
					
						
							|  |  |  | 			bandwidth_out.write[i].packet_size = -1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MultiplayerDebugger::BandwidthProfiler::add(const Array &p_data) { | 
					
						
							|  |  |  | 	ERR_FAIL_COND(p_data.size() < 3); | 
					
						
							|  |  |  | 	const String inout = p_data[0]; | 
					
						
							|  |  |  | 	int time = p_data[1]; | 
					
						
							|  |  |  | 	int size = p_data[2]; | 
					
						
							|  |  |  | 	if (inout == "in") { | 
					
						
							|  |  |  | 		bandwidth_in.write[bandwidth_in_ptr].timestamp = time; | 
					
						
							|  |  |  | 		bandwidth_in.write[bandwidth_in_ptr].packet_size = size; | 
					
						
							|  |  |  | 		bandwidth_in_ptr = (bandwidth_in_ptr + 1) % bandwidth_in.size(); | 
					
						
							|  |  |  | 	} else if (inout == "out") { | 
					
						
							|  |  |  | 		bandwidth_out.write[bandwidth_out_ptr].timestamp = time; | 
					
						
							|  |  |  | 		bandwidth_out.write[bandwidth_out_ptr].packet_size = size; | 
					
						
							|  |  |  | 		bandwidth_out_ptr = (bandwidth_out_ptr + 1) % bandwidth_out.size(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MultiplayerDebugger::BandwidthProfiler::tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) { | 
					
						
							|  |  |  | 	uint64_t pt = OS::get_singleton()->get_ticks_msec(); | 
					
						
							|  |  |  | 	if (pt - last_bandwidth_time > 200) { | 
					
						
							|  |  |  | 		last_bandwidth_time = pt; | 
					
						
							|  |  |  | 		int incoming_bandwidth = bandwidth_usage(bandwidth_in, bandwidth_in_ptr); | 
					
						
							|  |  |  | 		int outgoing_bandwidth = bandwidth_usage(bandwidth_out, bandwidth_out_ptr); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-22 22:53:26 +01:00
										 |  |  | 		Array arr = { incoming_bandwidth, outgoing_bandwidth }; | 
					
						
							| 
									
										
										
										
											2022-10-05 17:50:19 +02:00
										 |  |  | 		EngineDebugger::get_singleton()->send_message("multiplayer:bandwidth", arr); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RPCProfiler
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Array MultiplayerDebugger::RPCFrame::serialize() { | 
					
						
							| 
									
										
										
										
											2024-03-22 22:53:26 +01:00
										 |  |  | 	Array arr = { infos.size() * 6 }; | 
					
						
							| 
									
										
										
										
											2022-10-05 17:50:19 +02:00
										 |  |  | 	for (int i = 0; i < infos.size(); ++i) { | 
					
						
							|  |  |  | 		arr.push_back(uint64_t(infos[i].node)); | 
					
						
							|  |  |  | 		arr.push_back(infos[i].node_path); | 
					
						
							|  |  |  | 		arr.push_back(infos[i].incoming_rpc); | 
					
						
							| 
									
										
										
										
											2022-11-16 22:48:12 +01:00
										 |  |  | 		arr.push_back(infos[i].incoming_size); | 
					
						
							| 
									
										
										
										
											2022-10-05 17:50:19 +02:00
										 |  |  | 		arr.push_back(infos[i].outgoing_rpc); | 
					
						
							| 
									
										
										
										
											2022-11-16 22:48:12 +01:00
										 |  |  | 		arr.push_back(infos[i].outgoing_size); | 
					
						
							| 
									
										
										
										
											2022-10-05 17:50:19 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return arr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool MultiplayerDebugger::RPCFrame::deserialize(const Array &p_arr) { | 
					
						
							| 
									
										
										
										
											2024-01-19 13:21:39 +01:00
										 |  |  | 	ERR_FAIL_COND_V(p_arr.is_empty(), false); | 
					
						
							| 
									
										
										
										
											2022-10-05 17:50:19 +02:00
										 |  |  | 	uint32_t size = p_arr[0]; | 
					
						
							| 
									
										
										
										
											2022-11-16 22:48:12 +01:00
										 |  |  | 	ERR_FAIL_COND_V(size % 6, false); | 
					
						
							| 
									
										
										
										
											2022-10-05 17:50:19 +02:00
										 |  |  | 	ERR_FAIL_COND_V((uint32_t)p_arr.size() != size + 1, false); | 
					
						
							| 
									
										
										
										
											2022-11-16 22:48:12 +01:00
										 |  |  | 	infos.resize(size / 6); | 
					
						
							| 
									
										
										
										
											2022-10-05 17:50:19 +02:00
										 |  |  | 	int idx = 1; | 
					
						
							| 
									
										
										
										
											2022-11-16 22:48:12 +01:00
										 |  |  | 	for (uint32_t i = 0; i < size / 6; i++) { | 
					
						
							| 
									
										
										
										
											2022-10-05 17:50:19 +02:00
										 |  |  | 		infos.write[i].node = uint64_t(p_arr[idx]); | 
					
						
							|  |  |  | 		infos.write[i].node_path = p_arr[idx + 1]; | 
					
						
							|  |  |  | 		infos.write[i].incoming_rpc = p_arr[idx + 2]; | 
					
						
							| 
									
										
										
										
											2022-11-16 22:48:12 +01:00
										 |  |  | 		infos.write[i].incoming_size = p_arr[idx + 3]; | 
					
						
							|  |  |  | 		infos.write[i].outgoing_rpc = p_arr[idx + 4]; | 
					
						
							|  |  |  | 		infos.write[i].outgoing_size = p_arr[idx + 5]; | 
					
						
							|  |  |  | 		idx += 6; | 
					
						
							| 
									
										
										
										
											2022-10-05 17:50:19 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MultiplayerDebugger::RPCProfiler::init_node(const ObjectID p_node) { | 
					
						
							|  |  |  | 	if (rpc_node_data.has(p_node)) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	rpc_node_data.insert(p_node, RPCNodeInfo()); | 
					
						
							|  |  |  | 	rpc_node_data[p_node].node = p_node; | 
					
						
							| 
									
										
										
										
											2025-06-11 16:19:23 +02:00
										 |  |  | 	rpc_node_data[p_node].node_path = String(ObjectDB::get_instance<Node>(p_node)->get_path()); | 
					
						
							| 
									
										
										
										
											2022-10-05 17:50:19 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MultiplayerDebugger::RPCProfiler::toggle(bool p_enable, const Array &p_opts) { | 
					
						
							|  |  |  | 	rpc_node_data.clear(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MultiplayerDebugger::RPCProfiler::add(const Array &p_data) { | 
					
						
							| 
									
										
										
										
											2022-11-16 22:48:12 +01:00
										 |  |  | 	ERR_FAIL_COND(p_data.size() != 3); | 
					
						
							|  |  |  | 	const String what = p_data[0]; | 
					
						
							|  |  |  | 	const ObjectID id = p_data[1]; | 
					
						
							|  |  |  | 	const int size = p_data[2]; | 
					
						
							| 
									
										
										
										
											2022-10-05 17:50:19 +02:00
										 |  |  | 	init_node(id); | 
					
						
							|  |  |  | 	RPCNodeInfo &info = rpc_node_data[id]; | 
					
						
							|  |  |  | 	if (what == "rpc_in") { | 
					
						
							|  |  |  | 		info.incoming_rpc++; | 
					
						
							| 
									
										
										
										
											2022-11-16 22:48:12 +01:00
										 |  |  | 		info.incoming_size += size; | 
					
						
							| 
									
										
										
										
											2022-10-05 17:50:19 +02:00
										 |  |  | 	} else if (what == "rpc_out") { | 
					
						
							|  |  |  | 		info.outgoing_rpc++; | 
					
						
							| 
									
										
										
										
											2022-11-16 22:48:12 +01:00
										 |  |  | 		info.outgoing_size += size; | 
					
						
							| 
									
										
										
										
											2022-10-05 17:50:19 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MultiplayerDebugger::RPCProfiler::tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) { | 
					
						
							|  |  |  | 	uint64_t pt = OS::get_singleton()->get_ticks_msec(); | 
					
						
							|  |  |  | 	if (pt - last_profile_time > 100) { | 
					
						
							|  |  |  | 		last_profile_time = pt; | 
					
						
							|  |  |  | 		RPCFrame frame; | 
					
						
							|  |  |  | 		for (const KeyValue<ObjectID, RPCNodeInfo> &E : rpc_node_data) { | 
					
						
							|  |  |  | 			frame.infos.push_back(E.value); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		rpc_node_data.clear(); | 
					
						
							|  |  |  | 		EngineDebugger::get_singleton()->send_message("multiplayer:rpc", frame.serialize()); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-11-17 03:31:23 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // ReplicationProfiler
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MultiplayerDebugger::SyncInfo::SyncInfo(MultiplayerSynchronizer *p_sync) { | 
					
						
							| 
									
										
										
										
											2023-09-09 17:40:07 +02:00
										 |  |  | 	ERR_FAIL_NULL(p_sync); | 
					
						
							| 
									
										
										
										
											2022-11-17 03:31:23 +01:00
										 |  |  | 	synchronizer = p_sync->get_instance_id(); | 
					
						
							| 
									
										
										
										
											2023-10-02 10:56:21 +02:00
										 |  |  | 	if (p_sync->get_replication_config_ptr()) { | 
					
						
							|  |  |  | 		config = p_sync->get_replication_config_ptr()->get_instance_id(); | 
					
						
							| 
									
										
										
										
											2022-11-17 03:31:23 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if (p_sync->get_root_node()) { | 
					
						
							|  |  |  | 		root_node = p_sync->get_root_node()->get_instance_id(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MultiplayerDebugger::SyncInfo::write_to_array(Array &r_arr) const { | 
					
						
							|  |  |  | 	r_arr.push_back(synchronizer); | 
					
						
							|  |  |  | 	r_arr.push_back(config); | 
					
						
							|  |  |  | 	r_arr.push_back(root_node); | 
					
						
							|  |  |  | 	r_arr.push_back(incoming_syncs); | 
					
						
							|  |  |  | 	r_arr.push_back(incoming_size); | 
					
						
							|  |  |  | 	r_arr.push_back(outgoing_syncs); | 
					
						
							|  |  |  | 	r_arr.push_back(outgoing_size); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool MultiplayerDebugger::SyncInfo::read_from_array(const Array &p_arr, int p_offset) { | 
					
						
							|  |  |  | 	ERR_FAIL_COND_V(p_arr.size() - p_offset < 7, false); | 
					
						
							|  |  |  | 	synchronizer = int64_t(p_arr[p_offset]); | 
					
						
							|  |  |  | 	config = int64_t(p_arr[p_offset + 1]); | 
					
						
							|  |  |  | 	root_node = int64_t(p_arr[p_offset + 2]); | 
					
						
							|  |  |  | 	incoming_syncs = p_arr[p_offset + 3]; | 
					
						
							|  |  |  | 	incoming_size = p_arr[p_offset + 4]; | 
					
						
							|  |  |  | 	outgoing_syncs = p_arr[p_offset + 5]; | 
					
						
							|  |  |  | 	outgoing_size = p_arr[p_offset + 6]; | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Array MultiplayerDebugger::ReplicationFrame::serialize() { | 
					
						
							| 
									
										
										
										
											2024-03-22 22:53:26 +01:00
										 |  |  | 	Array arr = { infos.size() * 7 }; | 
					
						
							| 
									
										
										
										
											2022-11-17 03:31:23 +01:00
										 |  |  | 	for (const KeyValue<ObjectID, SyncInfo> &E : infos) { | 
					
						
							|  |  |  | 		E.value.write_to_array(arr); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return arr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool MultiplayerDebugger::ReplicationFrame::deserialize(const Array &p_arr) { | 
					
						
							| 
									
										
										
										
											2024-01-19 13:21:39 +01:00
										 |  |  | 	ERR_FAIL_COND_V(p_arr.is_empty(), false); | 
					
						
							| 
									
										
										
										
											2022-11-17 03:31:23 +01:00
										 |  |  | 	uint32_t size = p_arr[0]; | 
					
						
							|  |  |  | 	ERR_FAIL_COND_V(size % 7, false); | 
					
						
							|  |  |  | 	ERR_FAIL_COND_V((uint32_t)p_arr.size() != size + 1, false); | 
					
						
							|  |  |  | 	int idx = 1; | 
					
						
							|  |  |  | 	for (uint32_t i = 0; i < size / 7; i++) { | 
					
						
							|  |  |  | 		SyncInfo info; | 
					
						
							|  |  |  | 		if (!info.read_from_array(p_arr, idx)) { | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		infos[info.synchronizer] = info; | 
					
						
							|  |  |  | 		idx += 7; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MultiplayerDebugger::ReplicationProfiler::toggle(bool p_enable, const Array &p_opts) { | 
					
						
							|  |  |  | 	sync_data.clear(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MultiplayerDebugger::ReplicationProfiler::add(const Array &p_data) { | 
					
						
							|  |  |  | 	ERR_FAIL_COND(p_data.size() != 3); | 
					
						
							|  |  |  | 	const String what = p_data[0]; | 
					
						
							|  |  |  | 	const ObjectID id = p_data[1]; | 
					
						
							|  |  |  | 	const uint64_t size = p_data[2]; | 
					
						
							| 
									
										
										
										
											2025-03-27 14:42:42 +01:00
										 |  |  | 	MultiplayerSynchronizer *sync = ObjectDB::get_instance<MultiplayerSynchronizer>(id); | 
					
						
							| 
									
										
										
										
											2023-09-09 17:40:07 +02:00
										 |  |  | 	ERR_FAIL_NULL(sync); | 
					
						
							| 
									
										
										
										
											2022-11-17 03:31:23 +01:00
										 |  |  | 	if (!sync_data.has(id)) { | 
					
						
							|  |  |  | 		sync_data[id] = SyncInfo(sync); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	SyncInfo &info = sync_data[id]; | 
					
						
							|  |  |  | 	if (what == "sync_in") { | 
					
						
							|  |  |  | 		info.incoming_syncs++; | 
					
						
							|  |  |  | 		info.incoming_size += size; | 
					
						
							|  |  |  | 	} else if (what == "sync_out") { | 
					
						
							|  |  |  | 		info.outgoing_syncs++; | 
					
						
							|  |  |  | 		info.outgoing_size += size; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MultiplayerDebugger::ReplicationProfiler::tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) { | 
					
						
							|  |  |  | 	uint64_t pt = OS::get_singleton()->get_ticks_msec(); | 
					
						
							|  |  |  | 	if (pt - last_profile_time > 100) { | 
					
						
							|  |  |  | 		last_profile_time = pt; | 
					
						
							|  |  |  | 		ReplicationFrame frame; | 
					
						
							|  |  |  | 		for (const KeyValue<ObjectID, SyncInfo> &E : sync_data) { | 
					
						
							|  |  |  | 			frame.infos[E.key] = E.value; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		sync_data.clear(); | 
					
						
							|  |  |  | 		EngineDebugger::get_singleton()->send_message("multiplayer:syncs", frame.serialize()); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |