| 
						
						
							
								
							
						
						
					 | 
				
				 | 
				 | 
				
					@ -7,6 +7,8 @@ extends Mod_Base | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					@export var port     := 52410 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					var main_controller: ModelController | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					var main_stats : PlayerStats | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					var ping_update_timer: Timer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					## Hardcoded list of bone names that will get syncronized. | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					var tracked_bones: Array[String] | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				 | 
				
					@ -27,6 +29,7 @@ var can_move_players := false | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					func _ready() -> void: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						# FIXME: Hardcoded way to get the main model controller. | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						main_controller = $"/root/SnekStudio_Main/ModelController" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						main_stats      = new_player_stats() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						# FIXME: This is just thrown together. Dunno if this is an accurate list. | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						# TODO: Allow specifying additional bones, with the help of a hierachical list of existing bones in the model. | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				 | 
				
					@ -57,7 +60,7 @@ func _ready() -> void: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						# Filter whitespace characters from nickname before saving it to "nickname" field. | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						var nickname_widget := get_settings_window().settings_nickname | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						nickname_widget.text_changed.connect(func(new_text): modify_setting("nickname", new_text.strip_edges())) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						nickname_widget.text_submitted.connect(func(_new_text): nickname_widget.text = nickname) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						nickname_widget.text_submitted.connect(func(_new_text): nickname_widget.text = nickname; main_stats.set_nickname(nickname)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						nickname_widget.focus_exited.connect(func(): nickname_widget.text = nickname) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						multiplayer.peer_connected     .connect(on_peer_connected) | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				 | 
				
					@ -99,6 +102,10 @@ func setup_button_connections() -> void: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						settings.connect_host.pressed.connect(on_host_pressed) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						settings.connect_disconnect.pressed.connect(on_disconnect_pressed) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					func load_after(_old : Dictionary, _new : Dictionary) -> void: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						main_stats.set_nickname(nickname) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					var player_settings_scene: PackedScene = load("res://Mods/copyMultiplayer/Scenes/player_settings.tscn") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					func new_player_settings() -> PlayerSettings: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						var container = get_settings_window().get_node("Players/VBoxContainer") | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				 | 
				
					@ -106,6 +113,13 @@ func new_player_settings() -> PlayerSettings: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						container.add_child(result) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						return result | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					var player_stats_scene: PackedScene = load("res://Mods/copyMultiplayer/Scenes/player_stats.tscn") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					func new_player_stats() -> PlayerStats: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						var container = get_settings_window().get_node("Stats/VBoxContainer") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						var result := player_stats_scene.instantiate() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						container.add_child(result) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						return result | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					func on_join_pressed() -> void: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						var address_widget: LineEdit = get_settings_window().get_node("Connect/VBoxContainer/Join/Address") | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				 | 
				
					@ -128,6 +142,10 @@ func on_host_pressed() -> void: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							update_status() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							print_log("Opened server") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							update_enabled_state(true) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							ping_update_timer = Timer.new() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							ping_update_timer.timeout.connect(do_update_pings) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							add_child(ping_update_timer) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							ping_update_timer.start(1) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						else: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							print_log("Unable to open server!") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				 | 
				
					@ -138,6 +156,8 @@ func on_disconnect_pressed() -> void: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							print_log("Closed server") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							update_enabled_state(false) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							clear_player_models() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							ping_update_timer.queue_free() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							ping_update_timer = null | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						multiplayer.multiplayer_peer.close() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				 | 
				
					@ -189,6 +209,7 @@ func update_enabled_state(is_online: bool) -> void: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						settings.connect_join      .disabled =  is_online | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						settings.connect_host      .disabled =  is_online | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						settings.connect_disconnect.disabled = !is_online | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						if not is_online: main_stats.set_ping(0) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					func update_status() -> void: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						var num_players := 1 + multiplayer.get_peers().size() | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				 | 
				
					@ -207,9 +228,11 @@ func clear_player_models() -> void: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					func _process(_delta: float) -> void: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						SyncController.send_model_animation(self) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						var settings: copyMultiplayerSettings = get_settings_window() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						# TODO: Add a setting to allow moving players even if "Players" tab is not active. | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						can_move_players = settings.is_visible_in_tree() && settings.is_tab_selected("Players") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						# FIXME: Temporary fix until my pull request is accepted or at least the above TODO is implemented. | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						can_move_players = true | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						# var settings: copyMultiplayerSettings = get_settings_window() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						# can_move_players = settings.is_visible_in_tree() && settings.is_tab_selected("Players") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					# Called when module is initialized or load_vrm is called. | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					func scene_init() -> void: | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				 | 
				
					@ -243,10 +266,40 @@ func scene_init() -> void: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							change_model.rpc(version, bone_lookup, blendshape_lookup, filename) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					## Gets the SyncController for the player with the specified peer id. | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					func get_sync_controller(peer_id: int) -> SyncController: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						return get_node_or_null(str(peer_id)) as SyncController | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					func get_all_sync_controllers() -> Array[SyncController]: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						var result: Array[SyncController] = [] | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						for controller in get_children(): | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							if controller is SyncController: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								result.append(controller) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						return result | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					func get_player_stats(peer_id: int) -> PlayerStats: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						if peer_id == multiplayer.get_unique_id(): return main_stats | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						var controller := get_sync_controller(peer_id) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						if controller: return controller.stats | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						return null | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					@rpc("authority", "unreliable_ordered", "call_local") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					func update_pings(pairs: Array[int]) -> void: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						for i in range(0, pairs.size(), 2): | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							var peer_id := pairs[i] | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							var ping    := pairs[i + 1] | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							var stats   := get_player_stats(peer_id) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							if stats: stats.set_ping(ping) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					func do_update_pings() -> void: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						var pairs: Array[int] = [] | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						var server: ENetMultiplayerPeer = multiplayer.multiplayer_peer | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						for peer_id in multiplayer.get_peers(): | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							var peer := server.get_peer(peer_id) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							var ping := peer.get_statistic(ENetPacketPeer.PEER_ROUND_TRIP_TIME) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							pairs.append_array([ peer_id, int(ping) ]) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						update_pings.rpc(pairs) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					@rpc("any_peer", "reliable") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					func change_nickname(new_nickname: String) -> void: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						var peer_id := multiplayer.get_remote_sender_id() | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
				 | 
				 | 
				
					
  |