@ -5,6 +5,9 @@ extends Mod_Base
@ export var address : = " "
@ export var port : = 52410
## Hardcoded list of bone names that will get syncronized.
var tracked_bones : Array [ String ]
var main_controller : ModelController
# Temporary positioning system.
@ -18,6 +21,23 @@ var accumulative_offset := Vector3( 0.35, 0.0, 0.0)
var functions_blendshapes : Script = load ( " res://Mods/MediaPipe/MediaPipeController_BlendShapes.gd " )
func _ready ( ) - > void :
# 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.
tracked_bones = [ " Hips " , " Chest " , " UpperChest " , " Neck " , " Head " ]
for side in [ " Left " , " Right " ] :
# Legs
for bone in [ " UpperLeg " , " LowerLeg " , " Foot " ] :
tracked_bones . append ( " %s %s " % [ side , bone ] )
# Arms
for bone in [ " Shoulder " , " UpperArm " , " LowerArm " , " Hand " ] :
tracked_bones . append ( " %s %s " % [ side , bone ] )
# Fingers
for phalange in [ " Metacarpal " , " Proximal " , " Distal " ] :
tracked_bones . append ( " %s Thumb %s " % [ side , phalange ] )
for finger in [ " Index " , " Middle " , " Ring " , " Little " ] :
for phalange in [ " Proximal " , " Intermediate " , " Distal " ] :
tracked_bones . append ( " %s %s %s " % [ side , finger , phalange ] )
# FIXME: Hardcoded way to get the main model controller.
main_controller = $ " /root/SnekStudio_Main/ModelController "
main_controller . child_entered_tree . connect ( model_changed )
@ -89,6 +109,7 @@ func disconnect_pressed() -> void:
set_status ( " " )
print_log ( " Closed server " )
update_enabled_state ( false )
clear_player_models ( )
multiplayer . multiplayer_peer . close ( )
@ -100,7 +121,7 @@ func peer_connected(id: int) -> void:
new_controller . name = str ( id )
add_child ( new_controller )
player_order . push_back ( id )
player_order . append ( id )
update_model_transforms ( )
var filename = main_controller . _last_loaded_vrm . get_file ( )
@ -129,13 +150,7 @@ func server_disconnected() -> void:
set_status ( " " )
print_log ( " Disconnected from server " )
update_enabled_state ( false )
for controller in get_children ( ) :
if controller is ModelController :
remove_child ( controller )
controller . queue_free ( )
player_order . clear ( )
clear_player_models ( )
func update_enabled_state ( is_online : bool ) - > void :
@ -169,6 +184,13 @@ func update_status() -> void:
var s : = " s " if num_players != 1 else " "
set_status ( [ side , " : " , num_players , " player " , s ] )
func clear_player_models ( ) - > void :
for controller in get_children ( ) :
if controller is ModelController :
remove_child ( controller )
controller . queue_free ( )
player_order . clear ( )
@ rpc ( " any_peer " , " reliable " )
func change_model ( filename : String ) - > void :
@ -201,7 +223,7 @@ func model_changed(child: Node) -> void:
# FIXME: This sends way more information than necessary, but works as a proof-of-concept!
@ rpc ( " any_peer " , " unreliable_ordered " )
func update (
func sync_model_animation (
model_transform : Transform3D ,
shape_dict : Dictionary , # Dictionary[String, float]
bone_poses : Dictionary , # Dictionary[String, Transform3D]
@ -232,8 +254,9 @@ func _process(_delta: float) -> void:
var shape_dict = media_pipe_ctrl . blend_shape_last_values
var bone_poses = { }
for idx in skeleton . get_bone_count ( ) :
var bone_name = skeleton . get_bone_name ( idx )
var bone_pose = skeleton . get_bone_pose ( idx )
for bone_name in 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
update . rpc ( model . transform , shape_dict , bone_poses )
sync_model_animation . rpc ( model . transform , shape_dict , bone_poses )