class_name SyncController extends Node var module: copyMultiplayer var model_controller: ModelController var peer_id: int var nickname: String # FIXME: Not assigned or used. var model_name: String var model: Node var skeleton: Skeleton3D # Allows us to use the "apply_animations" function to apply blendshapes to a model. static var _functions_blendshapes: Script = load("res://Mods/MediaPipe/MediaPipeController_BlendShapes.gd") func _ready() -> void: module = get_parent().get_parent() model_controller = get_parent() peer_id = model_controller.name.to_int() ## Attempts to change the model of this player. func change_model(filename: String) -> void: if not filename.is_valid_filename(): module.print_log("ERROR: '%s' is not a valid file name!" % filename) return var full_path := module.cache.path_join(filename) if not FileAccess.file_exists(full_path): module.print_log("Player %d wanted to switch to '%s', but it doesn't exist, skipping" % [ peer_id, filename ]) return if not model_controller.load_vrm(full_path): module.print_log("ERROR: Model '%s' could not be loaded!" % filename) return module.print_log("Player %d switched to '%s'" % [ peer_id, filename ]) model_name = filename model = model_controller.get_node_or_null("Model") skeleton = model_controller._get_model_skeleton() func sync_model_animation( model_transform: Transform3D, shape_dict: Dictionary, # Dictionary[String, float] bone_poses: Dictionary, # Dictionary[String, Transform3D] ) -> void: if (not model) or (not skeleton): return model.transform = model_transform _functions_blendshapes.apply_animations(model, shape_dict) for bone_name in bone_poses: var pose: Transform3D = bone_poses[bone_name] var idx := skeleton.find_bone(bone_name) if idx != -1: skeleton.set_bone_pose(idx, pose) @warning_ignore("shadowed_variable") static func send_model_animation(module: copyMultiplayer) -> void: # Check if there's other players we're connected to. if module.multiplayer.get_peers().size() == 0: return var model := module.get_model() var skeleton := module.get_skeleton() var media_pipe = module.get_node("../MediaPipeController") if (not model) or (not skeleton) or (not media_pipe): return var shape_dict = media_pipe.blend_shape_last_values 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 # FIXME: This sends way more information than necessary, but works as a proof-of-concept! module.sync_model_animation.rpc(model.transform, shape_dict, bone_poses)