From 25ccf7c61c5d354356629b28cdbf293371b4ffe3 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Sun, 24 Sep 2023 06:14:26 -0500 Subject: [PATCH] [PortableCameraAdditions] Remove F11 fullscreen bind. --- .../AvatarScaling/Components/BaseScaler.cs | 278 ++++++++++++++++++ .../AvatarScaling/Components/LocalScaler.cs | 84 ++++++ .../AvatarScaling/Components/NetworkScaler.cs | 52 ++++ PortableCameraAdditions/HarmonyPatches.cs | 22 -- .../Properties/AssemblyInfo.cs | 2 +- PortableCameraAdditions/format.json | 10 +- 6 files changed, 420 insertions(+), 28 deletions(-) create mode 100644 AvatarScale/AvatarScaling/Components/BaseScaler.cs create mode 100644 AvatarScale/AvatarScaling/Components/LocalScaler.cs create mode 100644 AvatarScale/AvatarScaling/Components/NetworkScaler.cs diff --git a/AvatarScale/AvatarScaling/Components/BaseScaler.cs b/AvatarScale/AvatarScaling/Components/BaseScaler.cs new file mode 100644 index 0000000..01f04df --- /dev/null +++ b/AvatarScale/AvatarScaling/Components/BaseScaler.cs @@ -0,0 +1,278 @@ +using ABI_RC.Core; +using ABI_RC.Core.Player; +using NAK.AvatarScaleMod.AvatarScaling; +using NAK.AvatarScaleMod.ScaledComponents; +using UnityEngine; +using UnityEngine.Animations; + +namespace NAK.AvatarScaleMod.Components; + +[DefaultExecutionOrder(-99999)] // before playersetup/puppetmaster but after animator +public class BaseScaler : MonoBehaviour +{ + #region Constants + + public const string ScaleFactorParameterName = "ScaleFactor"; + public const string ScaleFactorParameterNameLocal = "#ScaleFactor"; + + #endregion + + #region Variables + + internal bool _isAvatarInstantiated; + internal bool _isHeightAdjustedFromInitial; + internal bool _heightNeedsUpdate; + + internal Transform _avatarTransform; + internal CVRAnimatorManager _animatorManager; + + internal float _initialHeight; + internal Vector3 _initialScale; + + internal float _targetHeight = -1; + internal Vector3 _targetScale = Vector3.one; + internal float _scaleFactor = 1f; + + // detection for animation clip-based scaling + internal Vector3 _legacyAnimationScale; + + #endregion + + #region Public Methods + + public virtual void OnAvatarInstantiated(GameObject avatarObject, float initialHeight, Vector3 initialScale) + { + if (_isAvatarInstantiated) return; + _isAvatarInstantiated = true; + + _initialHeight = Mathf.Clamp(initialHeight, 0.01f, 100f); + _initialScale = initialScale; + _avatarTransform = avatarObject.transform; + } + + public void OnAvatarDestroyed() + { + if (!_isAvatarInstantiated) return; + _isAvatarInstantiated = false; + + _avatarTransform = null; + _heightNeedsUpdate = false; + ClearComponentLists(); + } + + public void SetTargetHeight(float height) + { + if (Math.Abs(height - _targetHeight) < float.Epsilon) + return; + + if (height < float.Epsilon + || Math.Abs(height - _initialHeight) < float.Epsilon) + { + ResetHeight(); + return; + } + + if (!_isHeightAdjustedFromInitial) + _legacyAnimationScale = Vector3.zero; + + _isHeightAdjustedFromInitial = true; + + _targetHeight = Mathf.Clamp(height, AvatarScaleManager.MinHeight, AvatarScaleManager.MaxHeight); + _heightNeedsUpdate = true; + + UpdateScaleIfInstantiated(); + } + + public void ResetHeight() + { + if (!_isHeightAdjustedFromInitial) return; + _isHeightAdjustedFromInitial = false; + + if (Math.Abs(_initialHeight - _targetHeight) < float.Epsilon) + return; + + _legacyAnimationScale = Vector3.zero; + + _targetHeight = _initialHeight; + _heightNeedsUpdate = true; + + UpdateScaleIfInstantiated(); + } + + public float GetHeight() => _targetHeight; + public float GetInitialHeight() => _initialHeight; + public bool IsHeightAdjustedFromInitial() => _isHeightAdjustedFromInitial; + + #endregion + + #region Private Methods + + internal void ScaleAvatarRoot() + { + if (_avatarTransform == null) return; + _avatarTransform.localScale = _targetScale; + } + + internal virtual void UpdateAnimatorParameter() + { + // empty + } + + internal void UpdateScaleIfInstantiated() + { + if (!_isAvatarInstantiated || _initialHeight == 0) + return; + + if (_avatarTransform == null) + return; + + _scaleFactor = Mathf.Max(_targetHeight / _initialHeight, 0.01f); //safety + + _heightNeedsUpdate = false; + _targetScale = _initialScale * _scaleFactor; + + ScaleAvatarRoot(); + UpdateAnimatorParameter(); + ApplyComponentScaling(); + } + + #endregion + + #region Unity Methods + + public virtual void LateUpdate() + { + if (!_isHeightAdjustedFromInitial) + return; + + if (!_isAvatarInstantiated) + return; + + ScaleAvatarRoot(); // override animationclip-based scaling + } + + internal virtual void OnDestroy() + { + ClearComponentLists(); + } + + #endregion + + #region Component Scaling + + internal static readonly Type[] scalableComponentTypes = + { + typeof(Light), + typeof(AudioSource), + typeof(ParticleSystem), + typeof(ParentConstraint), + typeof(PositionConstraint), + typeof(ScaleConstraint) + }; + + private readonly List _scaledLights = new List(); + private readonly List _scaledAudioSources = new List(); + private readonly List _scaledParentConstraints = new List(); + private readonly List _scaledPositionConstraints = new List(); + private readonly List _scaledScaleConstraints = new List(); + + private void ClearComponentLists() + { + _scaledLights.Clear(); + _scaledAudioSources.Clear(); + _scaledParentConstraints.Clear(); + _scaledPositionConstraints.Clear(); + _scaledScaleConstraints.Clear(); + } + + internal async Task FindComponentsOfTypeAsync(Type[] types) + { + var tasks = new List(); + var components = _avatarTransform.gameObject.GetComponentsInChildren(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 +} \ No newline at end of file diff --git a/AvatarScale/AvatarScaling/Components/LocalScaler.cs b/AvatarScale/AvatarScaling/Components/LocalScaler.cs new file mode 100644 index 0000000..7ea7e23 --- /dev/null +++ b/AvatarScale/AvatarScaling/Components/LocalScaler.cs @@ -0,0 +1,84 @@ +using ABI_RC.Core.Player; +using NAK.AvatarScaleMod.AvatarScaling; +using UnityEngine; + +namespace NAK.AvatarScaleMod.Components; + +public class LocalScaler : BaseScaler +{ + #region Public Methods + + public void Initialize() + { + _animatorManager = GetComponentInParent().animatorManager; + + _heightNeedsUpdate = false; + _isAvatarInstantiated = false; + _isHeightAdjustedFromInitial = false; + } + + #endregion + + #region Overrides + + public override async void OnAvatarInstantiated(GameObject avatarObject, float initialHeight, Vector3 initialScale) + { + if (avatarObject == null) + return; + + base.OnAvatarInstantiated(avatarObject, initialHeight, initialScale); + await FindComponentsOfTypeAsync(scalableComponentTypes); + + _targetHeight = initialHeight; + _scaleFactor = 1f; + + _legacyAnimationScale = Vector3.zero; + } + + internal override void UpdateAnimatorParameter() + { + if (_animatorManager == null) + return; + + _animatorManager.SetAnimatorParameter(ScaleFactorParameterName, _scaleFactor); + _animatorManager.SetAnimatorParameter(ScaleFactorParameterNameLocal, _scaleFactor); + } + + public override void LateUpdate() + { + if (!_isHeightAdjustedFromInitial) + return; + + if (!_isAvatarInstantiated) + return; + + if (!CheckForAnimationScaleChange()) + ScaleAvatarRoot(); + } + + #endregion + + #region Private Methods + + private bool CheckForAnimationScaleChange() + { + if (_avatarTransform == null) return false; + if (_avatarTransform.localScale == _legacyAnimationScale) + return false; + + // scale was likely reset or not initiated + if (_legacyAnimationScale == Vector3.zero) + { + _legacyAnimationScale = _avatarTransform.localScale; + return false; + } + + _legacyAnimationScale = _avatarTransform.localScale; + + AvatarScaleMod.Logger.Msg("AnimationClip-based avatar scaling detected. Disabling Universal Scaling."); + AvatarScaleManager.Instance.ResetHeight(); // disable mod, user used a scale slider + return true; + } + + #endregion +} \ No newline at end of file diff --git a/AvatarScale/AvatarScaling/Components/NetworkScaler.cs b/AvatarScale/AvatarScaling/Components/NetworkScaler.cs new file mode 100644 index 0000000..842500b --- /dev/null +++ b/AvatarScale/AvatarScaling/Components/NetworkScaler.cs @@ -0,0 +1,52 @@ +using ABI_RC.Core.Player; +using NAK.AvatarScaleMod.AvatarScaling; +using UnityEngine; + +namespace NAK.AvatarScaleMod.Components; + +public class NetworkScaler : BaseScaler +{ + private string playerGuid; + + #region Public Methods + + public void Initialize(string playerId) + { + playerGuid = playerId; + + _animatorManager = GetComponentInParent().animatorManager; + + _heightNeedsUpdate = false; + _isAvatarInstantiated = false; + _isHeightAdjustedFromInitial = false; + } + + #endregion + + #region Overrides + + public override async void OnAvatarInstantiated(GameObject avatarObject, float initialHeight, Vector3 initialScale) + { + if (avatarObject == null) + return; + + base.OnAvatarInstantiated(avatarObject, initialHeight, initialScale); + await FindComponentsOfTypeAsync(scalableComponentTypes); + + if (_isHeightAdjustedFromInitial && _heightNeedsUpdate) + UpdateScaleIfInstantiated(); + } + + internal override void UpdateAnimatorParameter() + { + _animatorManager?.SetAnimatorParameter(ScaleFactorParameterNameLocal, _scaleFactor); + } + + internal override void OnDestroy() + { + AvatarScaleManager.Instance.RemoveNetworkHeightScaler(playerGuid); + base.OnDestroy(); + } + + #endregion +} \ No newline at end of file diff --git a/PortableCameraAdditions/HarmonyPatches.cs b/PortableCameraAdditions/HarmonyPatches.cs index d924f75..a8740c6 100644 --- a/PortableCameraAdditions/HarmonyPatches.cs +++ b/PortableCameraAdditions/HarmonyPatches.cs @@ -28,26 +28,4 @@ internal class PortableCameraPatches { VisualMods.CameraAdditions.Instance?.OnUpdateOptionsDisplay(____showExpertSettings); } - - [HarmonyPostfix] - [HarmonyPatch(typeof(PortableCamera), nameof(PortableCamera.Update))] - private static void Postfix_PortableCamera_Update(ref PortableCamera __instance) - { - if (Input.GetKeyDown(KeyCode.F11)) - { - bool flag = __instance.mode == MirroringMode.NoMirror; - __instance.mode = (flag) ? MirroringMode.Mirror : MirroringMode.NoMirror; - __instance.mirroringActive.SetActive(flag); - __instance.mirroringCanvas.gameObject.SetActive(flag); - } - } - - [HarmonyPostfix] - [HarmonyPatch(typeof(PortableCamera), nameof(PortableCamera.OnDisable))] - private static void Postfix_PortableCamera_OnDisable(ref PortableCamera __instance) - { - __instance.mode = MirroringMode.NoMirror; - __instance.mirroringActive.SetActive(false); - __instance.mirroringCanvas.gameObject.SetActive(false); - } } \ No newline at end of file diff --git a/PortableCameraAdditions/Properties/AssemblyInfo.cs b/PortableCameraAdditions/Properties/AssemblyInfo.cs index 9a5b629..1bcb633 100644 --- a/PortableCameraAdditions/Properties/AssemblyInfo.cs +++ b/PortableCameraAdditions/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.PortableCameraAdditions.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.3"; + public const string Version = "1.0.4"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/PortableCameraAdditions/format.json b/PortableCameraAdditions/format.json index 34a2247..dad83c5 100644 --- a/PortableCameraAdditions/format.json +++ b/PortableCameraAdditions/format.json @@ -1,12 +1,12 @@ { "_id": 123, "name": "PortableCameraAdditions", - "modversion": "1.0.3", - "gameversion": "2023r171", + "modversion": "1.0.4", + "gameversion": "2023r172", "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS", - "description": "Adds a few basic settings to the Portable Camera.\n\nExpert settings for Near Clip & Far Clip.\nExpert settings for Orthographic & Orthographic Size.\nBy default, Near Clip & Far Clip are copied on world load.\nF11 to fullscreen on Desktop.", + "description": "Adds a few basic settings to the Portable Camera.\n\nExpert settings for Near Clip & Far Clip.\nExpert settings for Orthographic & Orthographic Size.\nBy default, Near Clip & Far Clip are copied on world load.", "searchtags": [ "camera", "settings", @@ -18,8 +18,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/download/r16/PortableCameraAdditions.dll", + "downloadlink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/download/r21/PortableCameraAdditions.dll", "sourcelink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/PortableCameraAdditions/", - "changelog": "Fixes for 2023r171.", + "changelog": "- Removed F11 bind to fullscreen Portable Camera.\nIt is now a native bind with 2023r172.", "embedcolor": "#ffd96a" } \ No newline at end of file