[AvatarScaleMod] Mod Network attempt 2.

I lost the first attempt when switching branches.
Lot of this still needs to be redone, as it is just quickly slapped together atm.
This commit is contained in:
NotAKidoS 2023-09-20 05:24:07 -05:00
parent 69cb3b7804
commit d599f57973
13 changed files with 850 additions and 544 deletions

View file

@ -0,0 +1,112 @@
using ABI_RC.Core.Player;
using NAK.AvatarScaleMod.Networking;
using UnityEngine;
namespace NAK.AvatarScaleMod.AvatarScaling;
public class AvatarScaleManager : MonoBehaviour
{
public static AvatarScaleManager Instance;
private Dictionary<string, UniversalAvatarScaler> _networkedScalers;
private UniversalAvatarScaler _localAvatarScaler;
#region Unity Methods
private void Awake()
{
if (Instance != null)
{
DestroyImmediate(this);
return;
}
Instance = this;
_networkedScalers = new Dictionary<string, UniversalAvatarScaler>();
}
#endregion
#region Local Methods
public void OnAvatarInstantiated(PlayerSetup playerSetup)
{
if (playerSetup._avatar == null)
return;
if (_localAvatarScaler != null)
Destroy(_localAvatarScaler);
_localAvatarScaler = playerSetup._avatar.AddComponent<UniversalAvatarScaler>();
_localAvatarScaler.Initialize(playerSetup._initialAvatarHeight, playerSetup.initialScale);
}
public void OnAvatarDestroyed()
{
if (_localAvatarScaler != null)
Destroy(_localAvatarScaler);
}
public void SetHeight(float targetHeight)
{
if (_localAvatarScaler == null)
return;
_localAvatarScaler.SetHeight(targetHeight);
ModNetwork.SendNetworkHeight(targetHeight);
// immediately update play space scale
PlayerSetup.Instance.CheckUpdateAvatarScaleToPlaySpaceRelation();
}
public void ResetHeight()
{
if (_localAvatarScaler != null)
_localAvatarScaler.ResetHeight();
}
public float GetHeight()
{
return (_localAvatarScaler != null) ? _localAvatarScaler.GetHeight() : -1f;
}
#endregion
#region Network Methods
public void OnNetworkAvatarInstantiated(PuppetMaster puppetMaster)
{
if (puppetMaster.avatarObject == null)
return;
string playerId = puppetMaster._playerDescriptor.ownerId;
if (_networkedScalers.ContainsKey(playerId))
_networkedScalers.Remove(playerId);
UniversalAvatarScaler scaler = puppetMaster.avatarObject.AddComponent<UniversalAvatarScaler>();
scaler.Initialize(puppetMaster._initialAvatarHeight, puppetMaster.initialAvatarScale);
_networkedScalers[playerId] = scaler;
}
public void OnNetworkAvatarDestroyed(string playerId)
{
if (_networkedScalers.ContainsKey(playerId))
_networkedScalers.Remove(playerId);
}
public void OnNetworkHeightUpdateReceived(string playerId, float targetHeight)
{
if (_networkedScalers.TryGetValue(playerId, out UniversalAvatarScaler scaler))
scaler.SetHeight(targetHeight);
}
public float GetNetworkHeight(string playerId)
{
if (_networkedScalers.TryGetValue(playerId, out UniversalAvatarScaler scaler))
return scaler.GetHeight();
return -1f;
}
#endregion
}

View file

@ -0,0 +1,133 @@
using UnityEngine;
using UnityEngine.Animations;
namespace NAK.AvatarScaleMod.ScaledComponents;
public class ScaledAudioSource
{
private readonly AudioSource Component;
private readonly float InitialMinDistance;
private readonly float InitialMaxDistance;
public ScaledAudioSource(AudioSource component)
{
Component = component;
InitialMinDistance = component.minDistance;
InitialMaxDistance = component.maxDistance;
}
public void Scale(float scaleFactor)
{
Component.minDistance = InitialMinDistance * scaleFactor;
Component.maxDistance = InitialMaxDistance * scaleFactor;
}
public void Reset()
{
Component.minDistance = InitialMinDistance;
Component.maxDistance = InitialMaxDistance;
}
}
public class ScaledLight
{
private readonly Light Component;
private readonly float InitialRange;
public ScaledLight(Light component)
{
Component = component;
InitialRange = component.range;
}
public void Scale(float scaleFactor)
{
Component.range = InitialRange * scaleFactor;
}
public void Reset()
{
Component.range = InitialRange;
}
}
public class ScaledPositionConstraint
{
private readonly PositionConstraint Component;
private readonly Vector3 InitialTranslationAtRest;
private readonly Vector3 InitialTranslationOffset;
public ScaledPositionConstraint(PositionConstraint component)
{
Component = component;
InitialTranslationAtRest = component.translationAtRest;
InitialTranslationOffset = component.translationOffset;
}
public void Scale(float scaleFactor)
{
Component.translationAtRest = InitialTranslationAtRest * scaleFactor;
Component.translationOffset = InitialTranslationOffset * scaleFactor;
}
public void Reset()
{
Component.translationAtRest = InitialTranslationAtRest;
Component.translationOffset = InitialTranslationOffset;
}
}
public class ScaledParentConstraint
{
private readonly ParentConstraint Component;
private readonly Vector3 InitialTranslationAtRest;
private readonly List<Vector3> InitialTranslationOffsets;
public ScaledParentConstraint(ParentConstraint component)
{
Component = component;
InitialTranslationAtRest = component.translationAtRest;
InitialTranslationOffsets = component.translationOffsets.ToList();
}
public void Scale(float scaleFactor)
{
Component.translationAtRest = InitialTranslationAtRest * scaleFactor;
for (int i = 0; i < InitialTranslationOffsets.Count; i++)
Component.translationOffsets[i] = InitialTranslationOffsets[i] * scaleFactor;
}
public void Reset()
{
Component.translationAtRest = InitialTranslationAtRest;
for (int i = 0; i < InitialTranslationOffsets.Count; i++)
Component.translationOffsets[i] = InitialTranslationOffsets[i];
}
}
public class ScaledScaleConstraint
{
private readonly ScaleConstraint Component;
private readonly Vector3 InitialScaleAtRest;
private readonly Vector3 InitialScaleOffset;
public ScaledScaleConstraint(ScaleConstraint component)
{
Component = component;
InitialScaleAtRest = component.scaleAtRest;
InitialScaleOffset = component.scaleOffset;
}
public void Scale(float scaleFactor)
{
Component.scaleAtRest = InitialScaleAtRest * scaleFactor;
Component.scaleOffset = InitialScaleOffset * scaleFactor;
}
public void Reset()
{
Component.scaleAtRest = InitialScaleAtRest;
Component.scaleOffset = InitialScaleOffset;
}
}

View file

@ -0,0 +1,231 @@
using ABI_RC.Core;
using ABI_RC.Core.Player;
using NAK.AvatarScaleMod.ScaledComponents;
using UnityEngine;
using UnityEngine.Animations;
namespace NAK.AvatarScaleMod.AvatarScaling;
[DefaultExecutionOrder(-99999)] // before playersetup/puppetmaster but after animator
public class UniversalAvatarScaler : MonoBehaviour
{
#region Constants
// Universal Scaling Limits
private const float MinHeight = 0.1f;
private const float MaxHeight = 10f;
private const string ScaleFactorParameterName = "ScaleFactor";
private const string ScaleFactorParameterNameLocal = "#ScaleFactor";
#endregion
#region Variables
private CVRAnimatorManager _animatorManager;
private float _initialHeight;
private Vector3 _initialScale;
private float _targetHeight;
private float _scaleFactor = 1f;
private bool _isLocalAvatar;
private bool _heightWasUpdated;
#endregion
#region Unity Methods
private async void Start()
{
await FindComponentsOfTypeAsync(scalableComponentTypes);
}
private void LateUpdate()
{
ScaleAvatarRoot(); // override animation-based scaling
}
#endregion
#region Public Methods
public void Initialize(float initialHeight, Vector3 initialScale)
{
_initialHeight = _targetHeight = initialHeight;
_initialScale = initialScale;
_scaleFactor = 1f;
_isLocalAvatar = gameObject.layer == 8;
_animatorManager = _isLocalAvatar
? GetComponentInParent<PlayerSetup>().animatorManager
: GetComponentInParent<PuppetMaster>()._animatorManager;
_heightWasUpdated = false;
}
public void SetHeight(float height)
{
_targetHeight = Mathf.Clamp(height, MinHeight, MaxHeight);
_scaleFactor = _targetHeight / _initialHeight;
_heightWasUpdated = true;
ApplyScaling();
}
public void ResetHeight()
{
_targetHeight = _initialHeight;
_scaleFactor = 1f;
_heightWasUpdated = true;
ApplyScaling();
}
public float GetHeight()
{
return _targetHeight;
}
#endregion
#region Private Methods
private void ScaleAvatarRoot()
{
transform.localScale = _initialScale * _scaleFactor;
}
private void UpdateAnimatorParameter()
{
if (_animatorManager == null)
return;
// synced parameter
if (_isLocalAvatar) _animatorManager.SetAnimatorParameter(ScaleFactorParameterName, _scaleFactor);
// local parameter
_animatorManager.SetAnimatorParameter(ScaleFactorParameterNameLocal, _scaleFactor);
}
private void ApplyScaling()
{
if (!_heightWasUpdated)
return;
_heightWasUpdated = false;
ScaleAvatarRoot();
UpdateAnimatorParameter();
ApplyComponentScaling();
}
#endregion
#region Component Scaling
private static readonly Type[] scalableComponentTypes =
{
typeof(Light),
typeof(AudioSource),
typeof(ParticleSystem),
typeof(ParentConstraint),
typeof(PositionConstraint),
typeof(ScaleConstraint)
};
private readonly List<ScaledLight> _scaledLights = new List<ScaledLight>();
private readonly List<ScaledAudioSource> _scaledAudioSources = new List<ScaledAudioSource>();
private readonly List<ScaledParentConstraint> _scaledParentConstraints = new List<ScaledParentConstraint>();
private readonly List<ScaledPositionConstraint> _scaledPositionConstraints = new List<ScaledPositionConstraint>();
private readonly List<ScaledScaleConstraint> _scaledScaleConstraints = new List<ScaledScaleConstraint>();
private async Task FindComponentsOfTypeAsync(Type[] types)
{
var tasks = new List<Task>();
var components = GetComponentsInChildren<Component>(true);
foreach (Component component in components)
{
if (this == null) break;
if (component == null) continue;
tasks.Add(Task.Run(() =>
{
Type componentType = component.GetType();
if (types.Contains(componentType))
{
AddScaledComponent(componentType, component);
}
}));
}
await Task.WhenAll(tasks);
}
private void AddScaledComponent(Type type, Component component)
{
switch (type)
{
case not null when type == typeof(AudioSource):
_scaledAudioSources.Add(new ScaledAudioSource((AudioSource)component));
break;
case not null when type == typeof(Light):
_scaledLights.Add(new ScaledLight((Light)component));
break;
case not null when type == typeof(ParentConstraint):
_scaledParentConstraints.Add(new ScaledParentConstraint((ParentConstraint)component));
break;
case not null when type == typeof(PositionConstraint):
_scaledPositionConstraints.Add(new ScaledPositionConstraint((PositionConstraint)component));
break;
case not null when type == typeof(ScaleConstraint):
_scaledScaleConstraints.Add(new ScaledScaleConstraint((ScaleConstraint)component));
break;
}
}
private void ApplyComponentScaling()
{
// UpdateLightScales(); // might break dps
UpdateAudioSourceScales();
UpdateParentConstraintScales();
UpdatePositionConstraintScales();
UpdateScaleConstraintScales();
}
private void UpdateLightScales()
{
// Update range of each light component
foreach (ScaledLight light in _scaledLights)
light.Scale(_scaleFactor);
}
private void UpdateAudioSourceScales()
{
// Update min and max distance of each audio source component
foreach (ScaledAudioSource audioSource in _scaledAudioSources)
audioSource.Scale(_scaleFactor);
}
private void UpdateParentConstraintScales()
{
// Update translationAtRest and translationOffsets of each parent constraint component
foreach (ScaledParentConstraint parentConstraint in _scaledParentConstraints)
parentConstraint.Scale(_scaleFactor);
}
private void UpdatePositionConstraintScales()
{
// Update translationAtRest and translationOffset of each position constraint component
foreach (ScaledPositionConstraint positionConstraint in _scaledPositionConstraints)
positionConstraint.Scale(_scaleFactor);
}
private void UpdateScaleConstraintScales()
{
// Update scaleAtRest and scaleOffset of each scale constraint component
foreach (ScaledScaleConstraint scaleConstraint in _scaledScaleConstraints)
scaleConstraint.Scale(_scaleFactor);
}
#endregion
}