[RelativeSync] Fixed buncha stuff, cleanup

This commit is contained in:
NotAKidoS 2024-05-29 13:41:11 -05:00
parent b97265ef37
commit b786ecd51c
11 changed files with 429 additions and 231 deletions

View file

@ -6,16 +6,13 @@ namespace NAK.RelativeSync.Components;
[DefaultExecutionOrder(int.MaxValue)] // make sure this runs after NetIKController
public class RelativeSyncController : MonoBehaviour
{
private static float MaxMagnitude = 750000000000f;
private const float MaxMagnitude = 750000000000f;
private float _updateInterval = 0.05f;
private float _lastUpdate;
private string _userId;
private PuppetMaster puppetMaster { get; set; }
private NetIKController netIkController { get; set; }
// private bool _syncMarkerChangedSinceLastSync;
private RelativeSyncMarker _relativeSyncMarker;
private RelativeSyncData _relativeSyncData;
@ -26,7 +23,6 @@ public class RelativeSyncController : MonoBehaviour
private void Start()
{
puppetMaster = GetComponent<PuppetMaster>();
netIkController = GetComponent<NetIKController>();
_userId = puppetMaster._playerDescriptor.ownerId;
RelativeSyncManager.RelativeSyncControllers.Add(_userId, this);
@ -50,60 +46,33 @@ public class RelativeSyncController : MonoBehaviour
return;
Transform avatarTransform = animator.transform;
Vector3 worldRootPos = avatarTransform.position;
Quaternion worldRootRot = avatarTransform.rotation;
Transform hipTrans = (animator.avatar != null && animator.isHuman)
? animator.GetBoneTransform(HumanBodyBones.Hips) : null;
Vector3 relativeHipPos = default;
Quaternion relativeHipRot = default;
Transform hipTrans = animator.GetBoneTransform(HumanBodyBones.Hips);
if (hipTrans != null)
{
Vector3 worldRootPos = avatarTransform.position;
Quaternion worldRootRot = avatarTransform.rotation;
Vector3 hipPos = hipTrans.position;
Quaternion hipRot = hipTrans.rotation;
relativeHipPos = Quaternion.Inverse(worldRootRot) * (hipPos - worldRootPos);
relativeHipRot = Quaternion.Inverse(worldRootRot) * hipRot;
}
// TODO: handle the case where hip is not synced but is found on remote client
float lerp = Mathf.Min((Time.time - _lastUpdate) / _updateInterval, 1f);
Vector3 targetLocalPosition = _relativeSyncData.LocalRootPosition;
Quaternion targetLocalRotation = Quaternion.Euler(_relativeSyncData.LocalRootRotation);
Transform targetTransform = _relativeSyncMarker.transform;
if (_relativeSyncMarker.ApplyRelativeRotation && _relativeSyncData.LocalRootRotation.sqrMagnitude < MaxMagnitude)
{
Quaternion rotation = targetTransform.rotation;
Quaternion worldRotation = rotation * targetLocalRotation;
Quaternion lastRotation = rotation * Quaternion.Euler(_lastSyncData.LocalRootRotation);
if (_relativeSyncMarker.OnlyApplyRelativeHeading)
{
Vector3 currentForward = lastRotation * Vector3.forward;
Vector3 targetForward = worldRotation * Vector3.forward;
Vector3 currentWorldUp = avatarTransform.up; // up direction of player before we touch it
// project forward vectors to the ground plane
currentForward = Vector3.ProjectOnPlane(currentForward, currentWorldUp).normalized;
targetForward = Vector3.ProjectOnPlane(targetForward, currentWorldUp).normalized;
lastRotation = Quaternion.LookRotation(currentForward, currentWorldUp);
worldRotation = Quaternion.LookRotation(targetForward, currentWorldUp);
}
transform.rotation = Quaternion.Slerp(lastRotation, worldRotation, lerp);
}
if (_relativeSyncMarker.ApplyRelativePosition && _relativeSyncData.LocalRootPosition.sqrMagnitude < MaxMagnitude)
{
Vector3 worldPosition = targetTransform.TransformPoint(targetLocalPosition);
transform.position = Vector3.Lerp(targetTransform.TransformPoint(_lastSyncData.LocalRootPosition), worldPosition, lerp);
}
// negate avatar transform movement
ApplyRelativeRotation(avatarTransform, hipTrans, lerp);
ApplyRelativePosition(hipTrans, lerp);
// idk if needed (both player root & avatar root are set to same world position) -_-_-_-
avatarTransform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity);
// fix hip syncing because it is not relative to root, it is synced in world space -_-
if (hipTrans != null)
{
@ -112,6 +81,53 @@ public class RelativeSyncController : MonoBehaviour
}
}
private void ApplyRelativeRotation(Transform avatarTransform, Transform hipTransform, float lerp)
{
if (!_relativeSyncMarker.ApplyRelativeRotation ||
!(_relativeSyncData.LocalRootRotation.sqrMagnitude < MaxMagnitude))
return; // not applying relative rotation or data is invalid
Quaternion markerRotation = _relativeSyncMarker.transform.rotation;
Quaternion lastWorldRotation = markerRotation * Quaternion.Euler(_lastSyncData.LocalRootRotation);
Quaternion worldRotation = markerRotation * Quaternion.Euler(_relativeSyncData.LocalRootRotation);
if (_relativeSyncMarker.OnlyApplyRelativeHeading)
{
Vector3 currentWorldUp = avatarTransform.up;
Vector3 currentForward = lastWorldRotation * Vector3.forward;
Vector3 targetForward = worldRotation * Vector3.forward;
currentForward = Vector3.ProjectOnPlane(currentForward, currentWorldUp).normalized;
targetForward = Vector3.ProjectOnPlane(targetForward, currentWorldUp).normalized;
lastWorldRotation = Quaternion.LookRotation(currentForward, currentWorldUp);
worldRotation = Quaternion.LookRotation(targetForward, currentWorldUp);
}
transform.rotation = Quaternion.Slerp(lastWorldRotation, worldRotation, lerp);
}
private void ApplyRelativePosition(Transform hipTransform, float lerp)
{
if (!_relativeSyncMarker.ApplyRelativePosition ||
!(_relativeSyncData.LocalRootPosition.sqrMagnitude < MaxMagnitude))
return; // not applying relative position or data is invalid
Transform targetTransform = _relativeSyncMarker.transform;
Vector3 lastWorldPosition = targetTransform.TransformPoint(_lastSyncData.LocalRootPosition);
Vector3 worldPosition = targetTransform.TransformPoint(_relativeSyncData.LocalRootPosition);
transform.position = Vector3.Lerp(lastWorldPosition, worldPosition, lerp);
// if (hipTransform == null)
// return;
//
// Vector3 lastWorldHipPosition = targetTransform.TransformPoint(_lastSyncData.LocalHipPosition);
// Vector3 worldHipPosition = targetTransform.TransformPoint(_relativeSyncData.LocalHipPosition);
// hipTransform.position = Vector3.Lerp(lastWorldHipPosition, worldHipPosition, lerp);
}
#endregion Unity Events
#region Public Methods
@ -124,21 +140,24 @@ public class RelativeSyncController : MonoBehaviour
_relativeSyncMarker = target;
// calculate relative position and rotation so lerp can smooth it out (hack)
if (_relativeSyncMarker != null)
{
Transform avatarTransform = puppetMaster._animator.transform;
Transform markerTransform = _relativeSyncMarker.transform;
Vector3 localPosition = markerTransform.InverseTransformPoint(avatarTransform.position);
Quaternion localRotation = Quaternion.Inverse(markerTransform.rotation) * avatarTransform.rotation;
if (_relativeSyncMarker == null)
return;
Animator avatarAnimator = puppetMaster._animator;
if (avatarAnimator == null)
return; // i dont care to bother
RelativeSyncManager.GetRelativeAvatarPositionsFromMarker(
avatarAnimator, _relativeSyncMarker.transform,
out Vector3 relativePosition, out Vector3 relativeRotation);
// set last sync data to current position and rotation so we don't lerp from the last marker
_lastSyncData.LocalRootPosition = localPosition;
_lastSyncData.LocalRootRotation = localRotation.eulerAngles;
//Debug.Log($"SetRelativeSyncMarker: {_relativeSyncMarker.name}");
}
// set last sync data to current position and rotation so we don't lerp from the last marker
_lastSyncData.LocalRootPosition = relativePosition;
_lastSyncData.LocalRootRotation = relativeRotation;
}
public void SetRelativePositions(Vector3 position, Vector3 rotation)
public void SetRelativePositions(
Vector3 position, Vector3 rotation)
{
// calculate update interval
float prevUpdate = _lastUpdate;
@ -146,8 +165,7 @@ public class RelativeSyncController : MonoBehaviour
_updateInterval = _lastUpdate - prevUpdate;
// cycle last sync data
_lastSyncData.LocalRootPosition = _relativeSyncData.LocalRootPosition;
_lastSyncData.LocalRootRotation = _relativeSyncData.LocalRootRotation;
_lastSyncData = _relativeSyncData;
// set new sync data
_relativeSyncData.LocalRootPosition = position;
@ -156,7 +174,7 @@ public class RelativeSyncController : MonoBehaviour
#endregion Public Methods
public struct RelativeSyncData
private struct RelativeSyncData
{
public Vector3 LocalRootPosition;
public Vector3 LocalRootRotation;

View file

@ -1,4 +1,6 @@
using ABI.CCK.Components;
using ABI_RC.Core.Player;
using ABI_RC.Core.Savior;
using ABI.CCK.Components;
using UnityEngine;
namespace NAK.RelativeSync.Components;
@ -14,8 +16,21 @@ public class RelativeSyncMarker : MonoBehaviour
private void Start()
{
string path = GetGameObjectPath(transform);
pathHash = path.GetHashCode();
RelativeSyncManager.RelativeSyncTransforms.Add(pathHash, this);
int hash = path.GetHashCode();
// check if it already exists (this **should** only matter in worlds)
if (RelativeSyncManager.RelativeSyncTransforms.ContainsKey(hash))
{
RelativeSyncMod.Logger.Warning($"Duplicate RelativeSyncMarker found at path {path}");
if (!FindAvailableHash(ref hash)) // super lazy fix idfc
{
RelativeSyncMod.Logger.Error($"Failed to find available hash for RelativeSyncMarker after 16 tries! {path}");
return;
}
}
pathHash = hash;
RelativeSyncManager.RelativeSyncTransforms.Add(hash, this);
ConfigureForPotentialMovementParent();
}
@ -39,12 +54,37 @@ public class RelativeSyncMarker : MonoBehaviour
private static string GetGameObjectPath(Transform transform)
{
// props already have a unique instance identifier at root
// worlds uhhhh, dont duplicate the same thing over and over thx
// avatars on remote/local client have diff path, we need to account for it -_-
string path = transform.name;
while (transform.parent != null)
{
transform = transform.parent;
// only true at root of local player object
if (transform.CompareTag("Player"))
{
path = MetaPort.Instance.ownerId + "/" + path;
break;
} // remote player object root is already player guid
path = transform.name + "/" + path;
}
return path;
}
private bool FindAvailableHash(ref int hash)
{
for (int i = 0; i < 16; i++)
{
hash += 1;
if (!RelativeSyncManager.RelativeSyncTransforms.ContainsKey(hash)) return true;
}
// failed to find a hash in 16 tries, dont care
return false;
}
}

View file

@ -37,8 +37,18 @@ public class RelativeSyncMonitor : MonoBehaviour
}
_lastRelativeSyncMarker = _relativeSyncMarker;
SendCurrentPositionAndRotation();
Animator avatarAnimator = PlayerSetup.Instance._animator;
if (avatarAnimator == null)
return; // i dont care to bother
RelativeSyncManager.GetRelativeAvatarPositionsFromMarker(
avatarAnimator, _relativeSyncMarker.transform,
out Vector3 relativePosition, out Vector3 relativeRotation);
ModNetwork.SetLatestRelativeSync(
_relativeSyncMarker.pathHash,
relativePosition, relativeRotation);
}
private void CheckForRelativeSyncMarker()
@ -60,23 +70,10 @@ public class RelativeSyncMonitor : MonoBehaviour
// none found
_relativeSyncMarker = null;
}
private void SendCurrentPositionAndRotation()
{
// because our syncing is retarded, we need to sync relative from the avatar root...
Transform avatarRoot = PlayerSetup.Instance._avatar.transform;
Vector3 avatarRootPosition = avatarRoot.position; // PlayerSetup.Instance.GetPlayerPosition()
Quaternion avatarRootRotation = avatarRoot.rotation; // PlayerSetup.Instance.GetPlayerRotation()
Transform markerTransform = _relativeSyncMarker.transform;
Vector3 localPosition = markerTransform.InverseTransformPoint(avatarRootPosition);
Quaternion localRotation = Quaternion.Inverse(markerTransform.rotation) * avatarRootRotation;
ModNetwork.SendNetworkPosition(_relativeSyncMarker.pathHash, localPosition, localRotation.eulerAngles);
}
private void SendEmptyPositionAndRotation()
{
ModNetwork.SendNetworkPosition(RelativeSyncManager.NoTarget, Vector3.zero, Vector3.zero);
ModNetwork.SetLatestRelativeSync(RelativeSyncManager.NoTarget,
Vector3.zero, Vector3.zero);
}
}

View file

@ -31,4 +31,33 @@ public static class RelativeSyncManager
controller.SetRelativePositions(position, rotation);
controller.SetRelativeSyncMarker(syncMarker);
}
public static void GetRelativeAvatarPositionsFromMarker(
Animator avatarAnimator, Transform markerTransform,
out Vector3 relativePosition, out Vector3 relativeRotation)
// out Vector3 relativeHipPosition, out Vector3 relativeHipRotation)
{
Transform avatarTransform = avatarAnimator.transform;
// because our syncing is retarded, we need to sync relative from the avatar root...
Vector3 avatarRootPosition = avatarTransform.position; // PlayerSetup.Instance.GetPlayerPosition()
Quaternion avatarRootRotation = avatarTransform.rotation; // PlayerSetup.Instance.GetPlayerRotation()
relativePosition = markerTransform.InverseTransformPoint(avatarRootPosition);
relativeRotation = (Quaternion.Inverse(markerTransform.rotation) * avatarRootRotation).eulerAngles;
// Transform hipTrans = (avatarAnimator.avatar != null && avatarAnimator.isHuman)
// ? avatarAnimator.GetBoneTransform(HumanBodyBones.Hips) : null;
//
// if (hipTrans == null)
// {
// relativeHipPosition = Vector3.zero;
// relativeHipRotation = Vector3.zero;
// }
// else
// {
// relativeHipPosition = markerTransform.InverseTransformPoint(hipTrans.position);
// relativeHipRotation = (Quaternion.Inverse(markerTransform.rotation) * hipTrans.rotation).eulerAngles;
// }
}
}