@ -6,6 +6,11 @@ var model_controller: ModelController 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					var  peer_id :  int  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					var  nickname :  String  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					var  version :  int  =  - 1  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					var  bone_lookup :  Array [ String ]  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					var  blendshape_lookup :  Array [ String ]  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					var  model_name :  String  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					var  model :  Node  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					var  skeleton :  Skeleton3D  
				
			 
			
		
	
	
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
				
				 
				 
				
					@ -32,7 +37,18 @@ func change_nickname(new_nickname: String) -> void: 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						nickname  =  new_nickname   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					## Attempts to change the model of this player.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					func  change_model ( filename :  String )  - >  void :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					func  change_model (  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						new_version :  int ,   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						new_bone_lookup :  Array [ String ] ,   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						new_blendshape_lookup :  Array [ String ] ,   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						filename :  String ,   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					)  - >  void :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						# These should be safe to update even if the model doesn't load.   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						# We just need to stay in sync with the lookup tables.   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						version            =  new_version   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						bone_lookup        =  new_bone_lookup   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						blendshape_lookup  =  new_blendshape_lookup   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						if  not  filename . is_valid_filename ( ) :   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							module . print_log ( " ERROR:  ' %s '  is not a valid file name! "  %  filename )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							return   
				
			 
			
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
				 
				 
				
					@ -43,34 +59,51 @@ func change_model(filename: String) -> void: 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						if  not  model_controller . load_vrm ( full_path ) :   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							module . print_log ( " ERROR: Model  ' %s '  could not be loaded! "  %  filename )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							return   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						module . print_log ( " %s  switched to  ' %s ' "  %  [  get_display_name ( ) ,  filename  ] )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						model_name  =  filename   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						model       =  model_controller . get_node_or_null ( " Model " )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						skeleton    =  model_controller . _get_model_skeleton ( )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					func  sync_model_animation ( uncompressed_length :  int ,  buffer :  PackedByteArray )  - >  void :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						module . print_log ( " %s  switched to  ' %s ' "  %  [  get_display_name ( ) ,  filename  ] )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					func  sync_model_animation (  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						current_version :  int ,   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						uncompressed_length :  int ,   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						buffer :  PackedByteArray ,   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					)  - >  void :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						if  version  !=  current_version :  return   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						if  ( not  model )  or  ( not  skeleton ) :  return   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						var  uncompressed_buffer  : =  buffer . decompress ( uncompressed_length ,  FileAccess . COMPRESSION_ZSTD ) ;   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						var  stream  : =  StreamBuffer . from_buffer ( uncompressed_buffer )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						model . transform  =  stream . read_transform32 ( )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						# We skipped some bones, so reset the skipped ones to the rest pose.   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						var  all_bones  : =  { }   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						for  bone_name  in  module . bone_to_lookup :   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							var  bone_idx   : =  skeleton . find_bone ( bone_name )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							var  bone_rest  : =  skeleton . get_bone_rest ( bone_idx )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							all_bones [ bone_name ]  =  {  idx  =  bone_idx ,  pose  =  bone_rest  }   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						# Override rest poses with ones from the packet.   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						var  num_bones  : =  stream . read_uint8 ( )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						for  i  in  num_bones :   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							var  bone_name  : =  bone_lookup [ stream . read_uint8 ( ) ]   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							all_bones [ bone_name ] . pose  =  stream . read_bone_pose ( )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						# Apply bone poses to skeleton.   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						for  bone_name  in  all_bones :   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							var  bone :  Dictionary  =  all_bones [ bone_name ]   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							skeleton . set_bone_pose ( bone . idx ,  bone . pose )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						var  shape_dict  : =  { }   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						# 256 blendshapes (and bones) should be enough, right?   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						var  num_shapes  : =  stream . read_uint8 ( )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						var  num_shapes  : =  stream . read_uint8 ( )  # 256 blendshapes (and bones) should be enough, right?   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						for  i  in  num_shapes :   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							var  shape_name   : =  stream . read_string ( )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							var  shape_alpha  : =  stream . read_float16 ( )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							var  shape_name     : =  blendshape_lookup [ stream . read_uint8 ( ) ]    
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							var  shape_alpha    : =  stream . read_float16 ( )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							shape_dict [ shape_name ]  =  shape_alpha   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						BlendShapes . apply_animations ( model ,  shape_dict )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						var  num_bones  : =  stream . read_uint8 ( )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						for  i  in  num_bones :   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							var  bone_name  : =  stream . read_string ( )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							var  bone_pose  : =  stream . read_bone_pose ( )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							var  bone_idx   : =  skeleton . find_bone ( bone_name )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							if  bone_idx  !=  - 1 :  skeleton . set_bone_pose ( bone_idx ,  bone_pose )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					@ warning_ignore ( " shadowed_variable " )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					static  func  send_model_animation ( module :  copyMultiplayer )  - >  void :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						# Check if there's other players we're connected to.   
				
			 
			
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
				 
				 
				
					@ -83,32 +116,32 @@ static func send_model_animation(module: copyMultiplayer) -> void: 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						write_stream . write_transform32 ( model . transform )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						# TODO: Do not write full strings. Use a lookup table!   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						# TODO: Only write non-default blendshapes. Anything missing = default.   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						# Pre-filter any bones that are in rest pose.   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						var  restless_bones  : =  { }   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						for  bone_name  in  module . bone_to_lookup :   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							var  bone_idx   : =  skeleton . find_bone ( bone_name )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							var  bone_pose  : =  skeleton . get_bone_pose ( bone_idx )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							var  bone_rest  : =  skeleton . get_bone_rest ( bone_idx )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							if  not  bone_pose . is_equal_approx ( bone_rest ) :   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
								restless_bones [ bone_name ]  =  bone_pose   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						write_stream . write_uint8 ( restless_bones . size ( ) )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						for  bone_name  in  restless_bones :   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							var  bone_pose :  Transform3D  =  restless_bones [ bone_name ]   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							write_stream . write_uint8 ( module . bone_to_lookup [ bone_name ] )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							write_stream . write_bone_pose ( bone_pose )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						# TODO: Only write non-default blendshapes. Anything missing = default.   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						var  shape_dict :  Dictionary  =  media_pipe . blend_shape_last_values   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						write_stream . write_uint8 ( shape_dict . size ( ) )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						for  shape_name  in  shape_dict :   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						write_stream . write_uint8 ( module . blend shape_to_lookup . size ( ) )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						for  shape_name  in  module . blend shape_to_lookup :   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							var  shape_alpha :  float  =  shape_dict [ shape_name ]   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							write_stream . write_string ( shape_name )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							write_stream . write_uint8 ( module . blendshape_to_lookup [ shape_name ]  )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							write_stream . write_float16 ( shape_alpha )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						var  bone_poses  =  { }   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						for  bone_name  in  module . tracked_bones :   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							var  bone_idx  =  skeleton . find_bone ( bone_name )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							if  bone_idx  ==  - 1 :  continue   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							var  bone_pose  =  skeleton . get_bone_pose ( bone_idx )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							bone_poses [ bone_name ]  =  bone_pose   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						write_stream . write_uint8 ( bone_poses . size ( ) )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						for  bone_name  in  bone_poses :   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							var  bone_pose :  Transform3D  =  bone_poses [ bone_name ]   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							write_stream . write_string ( bone_name )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
							write_stream . write_bone_pose ( bone_pose )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						# TODO: Ideally, compression won't be needed once we remove strings.   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						# The compression still helps, so we'll keep it for now.   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						var  compressed_buffer  : =  write_stream . slice ( ) . compress ( FileAccess . COMPRESSION_ZSTD ) ;   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						# DEBUG: Uncomment this to see packet size (ideally < 1024).    
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						# module.set_status("Packet size: %d (%d uncompressed)" % [compressed_buffer.size(), write_stream.size])   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						module . sync_model_animation . rpc ( write_stream . size ,  compressed_buffer )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						# Uncomment this to see packet size. Can we hit < 256 bytes?   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						# module.set_status("Packet size: %d bytes (%d uncompressed)" % [ compressed_buffer.size(), write_stream.size ])   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						module . sync_model_animation . rpc ( module . version ,  write_stream . size ,  compressed_buffer )   
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
						write_stream . clear ( )