mirror of
https://github.com/NotAKidoS/NAK_CVR_Mods.git
synced 2025-09-02 06:19:22 +00:00
ASTExtension: Removed need for Avatar Scale Tool
This commit is contained in:
parent
458d4b3987
commit
5c7f7ab265
7 changed files with 257 additions and 137 deletions
|
@ -3,4 +3,12 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<RootNamespace>ASTExtension</RootNamespace>
|
<RootNamespace>ASTExtension</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="BTKUILib">
|
||||||
|
<HintPath>..\.ManagedLibs\BTKUILib.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Resources\ASM_Icon_AvatarHeightCopy.png" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -8,6 +8,12 @@ public static class PlayerSetupExtensions
|
||||||
// immediate measurement of the player's avatar height
|
// immediate measurement of the player's avatar height
|
||||||
public static float GetCurrentAvatarHeight(this PlayerSetup playerSetup)
|
public static float GetCurrentAvatarHeight(this PlayerSetup playerSetup)
|
||||||
{
|
{
|
||||||
|
if (playerSetup._avatar == null)
|
||||||
|
{
|
||||||
|
ASTExtensionMod.Logger.Error("GetCurrentAvatarHeight: Avatar is null");
|
||||||
|
return 0f;
|
||||||
|
}
|
||||||
|
|
||||||
Vector3 localScale = playerSetup._avatar.transform.localScale;
|
Vector3 localScale = playerSetup._avatar.transform.localScale;
|
||||||
Vector3 initialScale = playerSetup.initialScale;
|
Vector3 initialScale = playerSetup.initialScale;
|
||||||
float initialHeight = playerSetup._initialAvatarHeight;
|
float initialHeight = playerSetup._initialAvatarHeight;
|
||||||
|
|
56
ASTExtension/Integrations/BTKUI/BtkUiAddon.cs
Normal file
56
ASTExtension/Integrations/BTKUI/BtkUiAddon.cs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
using ABI_RC.Core.Player;
|
||||||
|
using BTKUILib;
|
||||||
|
using BTKUILib.UIObjects;
|
||||||
|
using BTKUILib.UIObjects.Components;
|
||||||
|
|
||||||
|
namespace NAK.ASTExtension.Integrations
|
||||||
|
{
|
||||||
|
public static partial class BtkUiAddon
|
||||||
|
{
|
||||||
|
public static void Initialize()
|
||||||
|
{
|
||||||
|
Prepare_Icons();
|
||||||
|
Setup_PlayerSelectPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Prepare_Icons()
|
||||||
|
{
|
||||||
|
QuickMenuAPI.PrepareIcon(ASTExtensionMod.ModName, "ASM_Icon_AvatarHeightCopy",
|
||||||
|
GetIconStream("ASM_Icon_AvatarHeightCopy.png"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Player Select Page
|
||||||
|
|
||||||
|
private static string _selectedPlayer;
|
||||||
|
|
||||||
|
private static void Setup_PlayerSelectPage()
|
||||||
|
{
|
||||||
|
QuickMenuAPI.OnPlayerSelected += OnPlayerSelected;
|
||||||
|
Category category = QuickMenuAPI.PlayerSelectPage.AddCategory(ASTExtensionMod.ModName, ASTExtensionMod.ModName);
|
||||||
|
Button button = category.AddButton("Copy Height", "ASM_Icon_AvatarHeightCopy", "Copy selected players Eye Height.");
|
||||||
|
button.OnPress += OnCopyPlayerHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnPlayerSelected(string _, string id)
|
||||||
|
{
|
||||||
|
_selectedPlayer = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnCopyPlayerHeight()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_selectedPlayer))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!CVRPlayerManager.Instance.GetPlayerPuppetMaster(_selectedPlayer, out PuppetMaster player))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (player._avatar == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float height = player.netIkController.GetRemoteHeight();
|
||||||
|
ASTExtensionMod.Instance.SetAvatarHeight(height);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Player Select Page
|
||||||
|
}
|
||||||
|
}
|
18
ASTExtension/Integrations/BTKUI/BtkUiAddon_Utils.cs
Normal file
18
ASTExtension/Integrations/BTKUI/BtkUiAddon_Utils.cs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace NAK.ASTExtension.Integrations
|
||||||
|
{
|
||||||
|
public static partial class BtkUiAddon
|
||||||
|
{
|
||||||
|
#region Icon Utils
|
||||||
|
|
||||||
|
private static Stream GetIconStream(string iconName)
|
||||||
|
{
|
||||||
|
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||||
|
string assemblyName = assembly.GetName().Name;
|
||||||
|
return assembly.GetManifestResourceStream($"{assemblyName}.Resources.{iconName}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Icon Utils
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ using ABI_RC.Core.Util.AnimatorManager;
|
||||||
using ABI_RC.Systems.GameEventSystem;
|
using ABI_RC.Systems.GameEventSystem;
|
||||||
using ABI_RC.Systems.InputManagement;
|
using ABI_RC.Systems.InputManagement;
|
||||||
using ABI.CCK.Components;
|
using ABI.CCK.Components;
|
||||||
|
using ABI.CCK.Scripts;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using MelonLoader;
|
using MelonLoader;
|
||||||
using NAK.ASTExtension.Extensions;
|
using NAK.ASTExtension.Extensions;
|
||||||
|
@ -16,25 +17,20 @@ namespace NAK.ASTExtension;
|
||||||
|
|
||||||
public class ASTExtensionMod : MelonMod
|
public class ASTExtensionMod : MelonMod
|
||||||
{
|
{
|
||||||
private static MelonLogger.Instance Logger;
|
internal static ASTExtensionMod Instance; // lazy
|
||||||
|
internal static MelonLogger.Instance Logger;
|
||||||
|
|
||||||
#region Melon Preferences
|
#region Melon Preferences
|
||||||
|
|
||||||
|
internal const string ModName = nameof(ASTExtension);
|
||||||
|
|
||||||
private static readonly MelonPreferences_Category Category =
|
private static readonly MelonPreferences_Category Category =
|
||||||
MelonPreferences.CreateCategory(nameof(ASTExtension));
|
MelonPreferences.CreateCategory(ModName);
|
||||||
|
|
||||||
private static readonly MelonPreferences_Entry<bool> EntryUseScaleGesture =
|
private static readonly MelonPreferences_Entry<bool> EntryUseScaleGesture =
|
||||||
Category.CreateEntry("use_scale_gesture", true,
|
Category.CreateEntry("use_scale_gesture", true,
|
||||||
"Use Scale Gesture", "Use the scale gesture to adjust your avatar's height.");
|
"Use Scale Gesture", "Use the scale gesture to adjust your avatar's height.");
|
||||||
|
|
||||||
private static readonly MelonPreferences_Entry<bool> EntryUseCustomParameter =
|
|
||||||
Category.CreateEntry("use_custom_parameter", false,
|
|
||||||
"Use Custom Parameter", "Use a custom parameter to adjust your avatar's height.");
|
|
||||||
|
|
||||||
private static readonly MelonPreferences_Entry<string> EntryCustomParameterName =
|
|
||||||
Category.CreateEntry("custom_parameter_name", "AvatarScale",
|
|
||||||
"Custom Parameter Name", "The name of the custom parameter to use for height adjustment.");
|
|
||||||
|
|
||||||
private static readonly MelonPreferences_Entry<bool> EntryPersistentHeight =
|
private static readonly MelonPreferences_Entry<bool> EntryPersistentHeight =
|
||||||
Category.CreateEntry("persistent_height", false,
|
Category.CreateEntry("persistent_height", false,
|
||||||
"Persistent Height", "Should the avatar height persist between avatar switches?");
|
"Persistent Height", "Should the avatar height persist between avatar switches?");
|
||||||
|
@ -51,79 +47,58 @@ public class ASTExtensionMod : MelonMod
|
||||||
private static readonly MelonPreferences_Entry<float> EntryHiddenAvatarHeight =
|
private static readonly MelonPreferences_Entry<float> EntryHiddenAvatarHeight =
|
||||||
Category.CreateEntry("hidden_avatar_height", -2f, is_hidden: true);
|
Category.CreateEntry("hidden_avatar_height", -2f, is_hidden: true);
|
||||||
|
|
||||||
private void InitializeSettings()
|
|
||||||
{
|
|
||||||
EntryUseCustomParameter.OnEntryValueChangedUntyped.Subscribe(OnUseCustomParameterChanged);
|
|
||||||
EntryCustomParameterName.OnEntryValueChangedUntyped.Subscribe(OnCustomParameterNameChanged);
|
|
||||||
OnUseCustomParameterChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnUseCustomParameterChanged(object oldValue = null, object newValue = null)
|
|
||||||
{
|
|
||||||
SetupCustomParameter();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnCustomParameterNameChanged(object oldValue = null, object newValue = null)
|
|
||||||
{
|
|
||||||
SetupCustomParameter();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetupCustomParameter()
|
|
||||||
{
|
|
||||||
// use custom parameter
|
|
||||||
if (EntryUseCustomParameter.Value)
|
|
||||||
{
|
|
||||||
_parameterName = EntryCustomParameterName.Value;
|
|
||||||
CalibrateCustomParameter();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset to default
|
|
||||||
_parameterName = "AvatarScale";
|
|
||||||
_minHeight = GlobalMinHeight;
|
|
||||||
_maxHeight = GlobalMaxHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Melon Preferences
|
#endregion Melon Preferences
|
||||||
|
|
||||||
#region Melon Events
|
#region Melon Events
|
||||||
|
|
||||||
public override void OnInitializeMelon()
|
public override void OnInitializeMelon()
|
||||||
{
|
{
|
||||||
|
Instance = this;
|
||||||
Logger = LoggerInstance;
|
Logger = LoggerInstance;
|
||||||
|
|
||||||
InitializeSettings();
|
//InitializeSettings();
|
||||||
|
|
||||||
CVRGameEventSystem.Avatar.OnLocalAvatarLoad.AddListener(OnLocalAvatarLoad);
|
CVRGameEventSystem.Avatar.OnLocalAvatarLoad.AddListener(OnLocalAvatarLoad);
|
||||||
CVRGameEventSystem.Avatar.OnLocalAvatarClear.AddListener(OnLocalAvatarClear);
|
CVRGameEventSystem.Avatar.OnLocalAvatarClear.AddListener(OnLocalAvatarClear);
|
||||||
MelonCoroutines.Start(WaitForGestureRecogniser()); // todo: once stable, use initialization game event
|
MelonCoroutines.Start(WaitForGestureRecogniser()); // todo: once stable, use initialization game event
|
||||||
|
|
||||||
|
InitializeIntegration("BTKUILib", Integrations.BtkUiAddon.Initialize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void InitializeIntegration(string modName, Action integrationAction)
|
||||||
|
{
|
||||||
|
if (RegisteredMelons.All(it => it.Info.Name != modName))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Logger.Msg($"Initializing {modName} integration.");
|
||||||
|
integrationAction.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Melon Events
|
||||||
|
|
||||||
|
#region Game Events
|
||||||
|
|
||||||
private IEnumerator WaitForGestureRecogniser()
|
private IEnumerator WaitForGestureRecogniser()
|
||||||
{
|
{
|
||||||
yield return new WaitUntil(() => CVRGestureRecognizer.Instance);
|
yield return new WaitUntil(() => CVRGestureRecognizer.Instance);
|
||||||
InitializeScaleGesture();
|
InitializeScaleGesture();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Melon Events
|
|
||||||
|
|
||||||
#region Game Events
|
|
||||||
|
|
||||||
private void OnLocalAvatarLoad(CVRAvatar _)
|
private void OnLocalAvatarLoad(CVRAvatar _)
|
||||||
{
|
{
|
||||||
_currentAvatarSupported = IsAvatarSupported();
|
if (!FindSupportedParameter(out string parameterName))
|
||||||
if (!_currentAvatarSupported)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (EntryUseCustomParameter.Value
|
if (!AttemptCalibrateParameter(parameterName, out float minHeight, out float maxHeight, out float modifier))
|
||||||
&& !string.IsNullOrEmpty(_parameterName))
|
return;
|
||||||
CalibrateCustomParameter();
|
|
||||||
|
SetupParameter(parameterName, minHeight, maxHeight, modifier);
|
||||||
|
|
||||||
if (EntryPersistThroughRestart.Value
|
if (EntryPersistThroughRestart.Value
|
||||||
&& _lastHeight < 0) // has not been set
|
&& _lastHeight < 0) // has not been set
|
||||||
{
|
{
|
||||||
var lastHeight = EntryHiddenAvatarHeight.Value;
|
var lastHeight = EntryHiddenAvatarHeight.Value;
|
||||||
if (lastHeight > 0) SetAvatarHeight(lastHeight, true);
|
if (lastHeight > 0) SetAvatarHeight(lastHeight);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,107 +107,178 @@ public class ASTExtensionMod : MelonMod
|
||||||
SetAvatarHeight(_lastHeight);
|
SetAvatarHeight(_lastHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnLocalAvatarClear(CVRAvatar _)
|
private void OnLocalAvatarClear(CVRAvatar avatar)
|
||||||
{
|
{
|
||||||
_currentAvatarSupported = false;
|
|
||||||
|
|
||||||
if (!EntryPersistentHeight.Value)
|
if (!EntryPersistentHeight.Value)
|
||||||
|
{
|
||||||
|
ResetParameter();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!IsAvatarSupported()
|
if (!_currentAvatarSupported
|
||||||
&& !EntryPersistFromUnsupported.Value)
|
&& !EntryPersistFromUnsupported.Value)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// update the last height
|
// update the last height
|
||||||
var height = PlayerSetup.Instance.GetCurrentAvatarHeight();
|
if (avatar != null) StoreLastHeight(PlayerSetup.Instance.GetCurrentAvatarHeight());
|
||||||
_lastHeight = height;
|
|
||||||
EntryHiddenAvatarHeight.Value = height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Game Events
|
#endregion Game Events
|
||||||
|
|
||||||
#region Avatar Scale Tool
|
#region Avatar Scale Tool Extension
|
||||||
|
|
||||||
// todo: tool needs a dedicated parameter name
|
private static HashSet<string> SUPPORTED_PARAMETERS = new()
|
||||||
//private const string ASTParameterName = "ASTHeight";
|
{
|
||||||
//private const string ASTMotionParameterName = "#MotionScale";
|
"AvatarScale", // default
|
||||||
|
"Scale", // most common
|
||||||
|
"Scale/Scale", // kafe
|
||||||
|
"Scaler", // momo
|
||||||
|
"Height", // loliwurt
|
||||||
|
"LoliModifier" // avatar
|
||||||
|
};
|
||||||
|
|
||||||
//https://github.com/NotAKidoS/AvatarScaleTool/blob/eaa6d343f916b9bb834bb30989fc6987680492a2/AvatarScaleTool/Editor/Scripts/AvatarScaleTool.cs#L13-L14
|
//https://github.com/NotAKidoS/AvatarScaleTool/blob/eaa6d343f916b9bb834bb30989fc6987680492a2/AvatarScaleTool/Editor/Scripts/AvatarScaleTool.cs#L13-L14
|
||||||
private const float GlobalMinHeight = 0.25f;
|
private const float DEFAULT_MIN_HEIGHT = 0.25f;
|
||||||
private const float GlobalMaxHeight = 2.5f;
|
private const float DEFAULT_MAX_HEIGHT = 2.5f;
|
||||||
|
|
||||||
private string _parameterName = "AvatarScale";
|
|
||||||
|
|
||||||
private float _lastHeight = -1f;
|
|
||||||
private float _minHeight = GlobalMinHeight;
|
|
||||||
private float _maxHeight = GlobalMaxHeight;
|
|
||||||
private bool _currentAvatarSupported;
|
private bool _currentAvatarSupported;
|
||||||
|
private string _parameterName = SUPPORTED_PARAMETERS.First();
|
||||||
|
|
||||||
|
private float _minHeight = DEFAULT_MIN_HEIGHT;
|
||||||
|
private float _maxHeight = DEFAULT_MAX_HEIGHT;
|
||||||
|
private float _modifier = 1f;
|
||||||
|
private float _lastHeight = -1f;
|
||||||
|
|
||||||
|
private void SetupParameter(string parameterName, float minHeight, float maxHeight, float modifier)
|
||||||
|
{
|
||||||
|
_parameterName = parameterName;
|
||||||
|
_minHeight = minHeight;
|
||||||
|
_maxHeight = maxHeight;
|
||||||
|
_modifier = modifier;
|
||||||
|
_currentAvatarSupported = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResetParameter()
|
||||||
|
{
|
||||||
|
_parameterName = SUPPORTED_PARAMETERS.First();
|
||||||
|
_minHeight = DEFAULT_MIN_HEIGHT;
|
||||||
|
_maxHeight = DEFAULT_MAX_HEIGHT;
|
||||||
|
_modifier = 1f;
|
||||||
|
_currentAvatarSupported = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StoreLastHeight(float height)
|
||||||
|
{
|
||||||
|
_lastHeight = height;
|
||||||
|
EntryHiddenAvatarHeight.Value = height;
|
||||||
|
}
|
||||||
|
|
||||||
private float GetValueFromHeight(float height)
|
private float GetValueFromHeight(float height)
|
||||||
{
|
{
|
||||||
return Mathf.Clamp01((height - _minHeight) / (_maxHeight - _minHeight));
|
return Mathf.Sign(_modifier) > 0 // negative means min & max heights were swapped (because i said so)
|
||||||
|
? Mathf.Clamp01((height - _minHeight) / (_maxHeight - _minHeight)) * Mathf.Abs(_modifier)
|
||||||
|
: 1 - Mathf.Clamp01((height - _minHeight) / (_maxHeight - _minHeight)) * Mathf.Abs(_modifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
private float GetHeightFromValue(float value)
|
// private float GetHeightFromValue(float value)
|
||||||
|
// => Mathf.Lerp(_minHeight, _maxHeight, value * Mathf.Abs(_modifier));
|
||||||
|
|
||||||
|
private static bool FindSupportedParameter(out string parameterName)
|
||||||
{
|
{
|
||||||
return Mathf.Lerp(_minHeight, _maxHeight, value);
|
parameterName = null;
|
||||||
}
|
|
||||||
|
|
||||||
private void SetAvatarHeight(float height, bool immediate = false)
|
|
||||||
{
|
|
||||||
if (!IsAvatarSupported())
|
|
||||||
return;
|
|
||||||
|
|
||||||
AvatarAnimatorManager animatorManager = PlayerSetup.Instance.animatorManager;
|
AvatarAnimatorManager animatorManager = PlayerSetup.Instance.animatorManager;
|
||||||
if (!animatorManager.IsInitialized)
|
if (!animatorManager.IsInitialized)
|
||||||
{
|
{
|
||||||
Logger.Error("AnimatorManager is not initialized!");
|
Logger.Error("AnimatorManager is not initialized!");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!animatorManager.HasParameter(_parameterName))
|
var parameterSet = new HashSet<string>(animatorManager.Parameters.Keys, StringComparer.OrdinalIgnoreCase);
|
||||||
|
foreach (var parameter in SUPPORTED_PARAMETERS)
|
||||||
{
|
{
|
||||||
Logger.Error($"Parameter '{_parameterName}' does not exist!");
|
if (!parameterSet.Contains(parameter)) continue;
|
||||||
return;
|
parameterName = parameterSet.First(p => p.Equals(parameter, StringComparison.OrdinalIgnoreCase));
|
||||||
|
Logger.Msg($"Found supported parameter '{parameterName}'");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Error("No supported parameter found!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool AttemptCalibrateParameter(string parameterName,
|
||||||
|
out float minHeight, out float maxHeight, out float modifier)
|
||||||
|
{
|
||||||
|
minHeight = 0f;
|
||||||
|
maxHeight = 0f;
|
||||||
|
modifier = 1f;
|
||||||
|
|
||||||
|
AvatarAnimatorManager animatorManager = PlayerSetup.Instance.animatorManager;
|
||||||
|
if (!animatorManager.IsInitialized)
|
||||||
|
{
|
||||||
|
Logger.Error("AnimatorManager is not initialized!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(parameterName))
|
||||||
|
{
|
||||||
|
Logger.Error("Parameter name is empty!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!animatorManager.HasParameter(parameterName))
|
||||||
|
{
|
||||||
|
Logger.Error($"Parameter '{parameterName}' does not exist!");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Animator animator = animatorManager.Animator;
|
Animator animator = animatorManager.Animator;
|
||||||
var value = GetValueFromHeight(height);
|
animatorManager.GetParameter(parameterName, out float initialValue);
|
||||||
animator.SetFloat(_parameterName, value);
|
|
||||||
if (immediate) animator.Update(0f); // apply
|
// set min height to 0
|
||||||
|
animator.SetFloat(parameterName, 0f);
|
||||||
_lastHeight = height; // session
|
animator.Update(0f); // apply
|
||||||
EntryHiddenAvatarHeight.Value = height; // persistent
|
minHeight = PlayerSetup.Instance.GetCurrentAvatarHeight();
|
||||||
|
|
||||||
// update in menus
|
// set max height to 1++
|
||||||
CVR_MenuManager.Instance.SendAdvancedAvatarUpdate(_parameterName, value);
|
for (int i = 1; i <= 10; i++)
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsAvatarSupported()
|
|
||||||
{
|
|
||||||
// check if avatar has the parameter
|
|
||||||
AvatarAnimatorManager animatorManager = PlayerSetup.Instance.animatorManager;
|
|
||||||
if (!animatorManager.IsInitialized)
|
|
||||||
{
|
{
|
||||||
Logger.Error("AnimatorManager is not initialized!");
|
animator.SetFloat(parameterName, i);
|
||||||
|
animator.Update(0f); // apply
|
||||||
|
var height = PlayerSetup.Instance.GetCurrentAvatarHeight();
|
||||||
|
if (height <= maxHeight) break; // stop if height is not increasing
|
||||||
|
modifier = i;
|
||||||
|
maxHeight = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset the parameter to its initial value
|
||||||
|
animator.SetFloat(parameterName, initialValue);
|
||||||
|
animator.Update(0f); // apply
|
||||||
|
|
||||||
|
// check if there was no change
|
||||||
|
if (Math.Abs(minHeight - maxHeight) < float.Epsilon)
|
||||||
|
{
|
||||||
|
Logger.Error("Calibration failed: min height is equal to max height!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!animatorManager.HasParameter(_parameterName))
|
// swap if needed
|
||||||
|
if (minHeight > maxHeight)
|
||||||
{
|
{
|
||||||
Logger.Error($"Parameter '{_parameterName}' does not exist!");
|
(minHeight, maxHeight) = (maxHeight, minHeight);
|
||||||
return false;
|
modifier = -modifier; // invert
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Msg($"Calibrated custom parameter '{parameterName}' with min height {minHeight} and max height {maxHeight} using modifier {modifier}");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Avatar Scale Tool
|
internal void SetAvatarHeight(float height)
|
||||||
|
|
||||||
#region Custom Parameter Calibration
|
|
||||||
|
|
||||||
private void CalibrateCustomParameter()
|
|
||||||
{
|
{
|
||||||
|
if (!_currentAvatarSupported)
|
||||||
|
return;
|
||||||
|
|
||||||
AvatarAnimatorManager animatorManager = PlayerSetup.Instance.animatorManager;
|
AvatarAnimatorManager animatorManager = PlayerSetup.Instance.animatorManager;
|
||||||
if (!animatorManager.IsInitialized)
|
if (!animatorManager.IsInitialized)
|
||||||
{
|
{
|
||||||
|
@ -246,28 +292,15 @@ public class ASTExtensionMod : MelonMod
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Animator animator = animatorManager.Animator; // we get from animator manager to ensure we have *profile* param
|
StoreLastHeight(height);
|
||||||
animatorManager.GetParameter(_parameterName, out float initialValue);
|
|
||||||
|
var value = GetValueFromHeight(height);
|
||||||
// set min height to 0
|
animatorManager.SetParameter(_parameterName, value);
|
||||||
animator.SetFloat(_parameterName, 0f);
|
animatorManager.Animator.Update(0f); // apply
|
||||||
animator.Update(0f); // apply
|
CVR_MenuManager.Instance.SendAdvancedAvatarUpdate(_parameterName, value); // update AAS menus
|
||||||
var minHeight = PlayerSetup.Instance.GetCurrentAvatarHeight();
|
|
||||||
|
|
||||||
// set max height to 1
|
|
||||||
animator.SetFloat(_parameterName, 1f);
|
|
||||||
animator.Update(0f); // apply
|
|
||||||
var maxHeight = PlayerSetup.Instance.GetCurrentAvatarHeight();
|
|
||||||
|
|
||||||
// reset the parameter to its initial value
|
|
||||||
animator.SetFloat(_parameterName, initialValue);
|
|
||||||
animator.Update(0f); // apply
|
|
||||||
|
|
||||||
Logger.Msg(
|
|
||||||
$"Calibrated custom parameter '{_parameterName}' with min height {minHeight} and max height {maxHeight}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Custom Parameter Calibration
|
#endregion Avatar Scale Tool Extension
|
||||||
|
|
||||||
#region Scale Reconizer
|
#region Scale Reconizer
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
Extension mod for [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool):
|
Extension mod for [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool):
|
||||||
- VR Gesture to scale
|
- VR Gesture to scale
|
||||||
- Match IRL height
|
|
||||||
- Persistent height
|
- Persistent height
|
||||||
- Copy height from others
|
- Copy height from others
|
||||||
|
|
||||||
|
|
BIN
ASTExtension/Resources/ASM_Icon_AvatarHeightCopy.png
Normal file
BIN
ASTExtension/Resources/ASM_Icon_AvatarHeightCopy.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
Loading…
Add table
Add a link
Reference in a new issue