Files
BoneSync/BoneSync/Player/PlayerRig.cs
2025-03-09 22:32:47 +02:00

267 lines
9.5 KiB
C#

using MelonLoader;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using StressLevelZero;
using StressLevelZero.Rig;
using StressLevelZero.Player;
using StressLevelZero.VRMK;
using BoneSync.Networking;
using BoneSync.Networking.Messages;
using System.Reflection;
using System.IO;
using BoneSync.Data;
using StressLevelZero.Interaction;
using UnhollowerBaseLib;
using BoneSync.Patching;
using BoneSync.Sync.Components;
using Oculus.Platform.Models;
namespace BoneSync.Player
{
internal class PlayerRig
{
private const float RIG_SYNC_FPS = Syncable.SYNC_FPS;
public static AssetBundle rigBundle;
private static float _lastLocalSyncTime = 0;
private static Dictionary<ulong, PlayerRig> _playerRigs = new Dictionary<ulong, PlayerRig>();
private ulong _ownerId;
private GameObject playerRig;
private SLZ_Body body;
private CharacterAnimationManager characterAnimationManager;
private Animator animator;
private Transform headTransform;
private Transform leftHandTransform;
private Transform rightHandTransform;
public static void LoadBundle()
{
rigBundle = EmebeddedAssetBundle.LoadFromAssembly("BoneSync.playerrep.eres");
if (rigBundle == null)
throw new NullReferenceException("playerRepBundle is null! Did you forget to compile the player bundle into the dll?");
MelonLogger.Msg("Loaded playerRepBundle success");
}
public static void Tick()
{
foreach (PlayerRig playerRig in _playerRigs.Values)
{
playerRig.UpdateIK();
}
}
public static void LocalSyncTick()
{
if (Time.realtimeSinceStartup - _lastLocalSyncTime > 1 / RIG_SYNC_FPS)
{
SendLocalPlayerSync();
_lastLocalSyncTime = Time.realtimeSinceStartup;
}
}
private void SetFingerCurl(Handedness handedness, SimpleFingerCurl fingerCurl)
{
characterAnimationManager.ApplyFingerCurl(handedness, 1f - fingerCurl.thumb, 1f - fingerCurl.index, 1f - fingerCurl.middle, 1f - fingerCurl.ring, 1f - fingerCurl.pinky);
}
public void UpdatePlayerSync(PlayerSyncInfo playerSyncInfo)
{
EnsurePlayerRig();
//MelonLogger.Msg("Updating player sync for " + _ownerId);
playerRig.transform.position = playerSyncInfo.rootPos;
headTransform.ApplySimpleTransform(playerSyncInfo.headPos);
leftHandTransform.ApplySimpleTransform(playerSyncInfo.leftHandPos);
rightHandTransform.ApplySimpleTransform(playerSyncInfo.rightHandPos);
SetFingerCurl(Handedness.LEFT, playerSyncInfo.leftHandFingerCurl);
SetFingerCurl(Handedness.RIGHT, playerSyncInfo.rightHandFingerCurl);
UpdatePose(Handedness.LEFT, playerSyncInfo.poseIndexLeft);
UpdatePose(Handedness.RIGHT, playerSyncInfo.poseIndexRight);
UpdatePoseRadius(Handedness.LEFT, playerSyncInfo.poseRadiusLeft);
UpdatePoseRadius(Handedness.RIGHT, playerSyncInfo.poseRadiusRight);
}
public void UpdatePose(Handedness hand, int index)
{
Il2CppStringArray handPoses = PlayerScripts.playerHandPoses;
if (handPoses.Count < index + 1)
return;
UpdatePose(hand, handPoses[index]);
}
public void UpdatePose(Handedness hand, string pose) => characterAnimationManager?.SetHandPose(hand, pose);
public void UpdatePoseRadius(Handedness hand, float radius) => characterAnimationManager?.SetCylinderRadius(hand, radius);
private static GameObject localPlayerRig;
private static Transform localRigRoot;
private static Transform localRigHeadTransform;
private static Transform localRigLeftHandTransform;
private static Transform localRigRightHandTransform;
public static void SetLocalRigReferences()
{
if (localPlayerRig != null) return;
localPlayerRig = GameObject.Find("[RigManager (Default Brett)]/[SkeletonRig (GameWorld Brett)]");
localRigRoot = localPlayerRig.transform;
localRigHeadTransform = localRigRoot.Find("Head");
localRigLeftHandTransform = localRigRoot.Find("Hand (left)");
localRigRightHandTransform = localRigRoot.Find("Hand (right)");
}
public static PlayerSyncInfo? GetLocalSyncInfo()
{
SetLocalRigReferences();
if (localPlayerRig == null)
{
MelonLogger.Msg("Local player rig not found");
return null;
}
if (localRigHeadTransform == null || localRigLeftHandTransform == null || localRigRightHandTransform == null)
{
MelonLogger.Msg("Local player rig components not found");
return null;
}
PlayerSyncInfo playerSyncInfo = new PlayerSyncInfo()
{
rootPos = localRigRoot.position,
headPos = new SimpleSyncTransform(localRigHeadTransform),
leftHandPos = new SimpleSyncTransform(localRigLeftHandTransform),
rightHandPos = new SimpleSyncTransform(localRigRightHandTransform),
//leftHandFingerCurl = new SimpleFingerCurl(PlayerScripts.playerLeftHand.fingerCurl),
//rightHandFingerCurl = new SimpleFingerCurl(PlayerScripts.playerRightHand.fingerCurl)
poseIndexLeft = SkeletonHandPatches.poseIndexLeft,
poseIndexRight = SkeletonHandPatches.poseIndexRight,
poseRadiusLeft = SkeletonHandPatches.radiusLeft,
poseRadiusRight = SkeletonHandPatches.radiusRight
};
if (PlayerScripts.playerLeftHand)
playerSyncInfo.leftHandFingerCurl = new SimpleFingerCurl(PlayerScripts.playerLeftHand.fingerCurl);
if (PlayerScripts.playerRightHand)
playerSyncInfo.rightHandFingerCurl = new SimpleFingerCurl(PlayerScripts.playerRightHand.fingerCurl);
return playerSyncInfo;
}
private static void SendLocalPlayerSync()
{
if (!BoneSync.IsConnected) return;
//MelonLogger.Msg("Sending local player sync");
PlayerSyncInfo? playerSyncInfo = GetLocalSyncInfo();
if (!playerSyncInfo.HasValue) return;
PlayerSyncMessage playerSyncMessage = new PlayerSyncMessage(playerSyncInfo.Value);
playerSyncMessage.Broadcast();
}
public static PlayerRig GetPlayerRig(ulong ownerId)
{
if (_playerRigs.ContainsKey(ownerId))
{
//MelonLogger.Msg("PlayerRig already exists for " + ownerId);
return _playerRigs[ownerId];
}
if (rigBundle == null)
{
MelonLogger.Msg("playerRepBundle is null! Did you forget to load the bundle?");
return null;
}
//PlayerScripts.GetPlayerScripts();
PlayerRig rig = new PlayerRig(ownerId);
return rig;
}
public static void DestroyRig(ulong ownerId)
{
if (_playerRigs.ContainsKey(ownerId))
{
_playerRigs[ownerId].Destroy();
}
}
private void EnsurePlayerRig() {
if (playerRig != null) return;
playerRig = GameObject.Instantiate(rigBundle.LoadAsset<GameObject>("PlayerRep"));
playerRig.name = "PlayerRep";
body = playerRig.GetComponentInChildren<SLZ_Body>();
characterAnimationManager = playerRig.GetComponentInChildren<CharacterAnimationManager>();
animator = playerRig.GetComponentInChildren<Animator>();
headTransform = playerRig.transform.Find("Head");
leftHandTransform = playerRig.transform.Find("Hand (left)");
rightHandTransform = playerRig.transform.Find("Hand (right)");
body.OnStart();
}
public void UpdateIK()
{
// Catch errors so other players arent broken
try
{
if (body == null || characterAnimationManager == null || animator == null || playerRig == null) return;
animator.Update(Time.fixedDeltaTime);
characterAnimationManager.OnLateUpdate();
Vector3 repInputVel = Vector3.zero;
body.FullBodyUpdate(repInputVel, Vector3.zero);
body.ArtToBlender.UpdateBlender();
}
catch (Exception e)
{
MelonLogger.Warning("Failed to update player rig " + _ownerId);
MelonLogger.Warning(e.ToString());
}
}
private PlayerRig(ulong id)
{
_playerRigs.Add(id, this);
_ownerId = id;
}
public static void OnPlayerSync(PlayerSyncMessage playerSyncMessage)
{
//MelonLogger.Msg("Player Sync Received " + playerSyncMessage.senderId);
PlayerRig playerRig = PlayerRig.GetPlayerRig(playerSyncMessage.senderId);
if (playerRig == null) return;
playerRig.UpdatePlayerSync(playerSyncMessage.playerSyncInfo);
}
public void Destroy()
{
_playerRigs.Remove(_ownerId);
GameObject.Destroy(playerRig);
}
}
}