267 lines
9.5 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|