From 407af391552cc931eba1ccf6885a2c1e4c3d62a3 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Sun, 25 Dec 2022 21:04:22 -0600 Subject: [PATCH 01/60] Initial commit --- .gitattributes | 2 + .gitignore | 398 +++++++++++++++++++++++++++++++++++++++++++++++++ LICENSE | 21 +++ README.md | 2 + 4 files changed, 423 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..426d76d --- /dev/null +++ b/.gitignore @@ -0,0 +1,398 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..262b1ec --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 NotAKidoS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..58f80e9 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# DesktopVRIK + Adds VRIK to Desktop ChilloutVR avatars. From 50c5016cc687b6ecbab8091db8e05a0d2c76be84 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Sun, 25 Dec 2022 21:05:13 -0600 Subject: [PATCH 02/60] last minute refactor --- DesktopVRIK/DesktopVRIK.cs | 108 +++++++++++ DesktopVRIK/DesktopVRIK.csproj | 52 ++++++ DesktopVRIK/DesktopVRIK.sln | 25 +++ DesktopVRIK/HarmonyPatches.cs | 35 ++++ DesktopVRIK/Main.cs | 240 +++++++++++++++++++++++++ DesktopVRIK/Properties/AssemblyInfo.cs | 30 ++++ DesktopVRIK/format.json | 23 +++ 7 files changed, 513 insertions(+) create mode 100644 DesktopVRIK/DesktopVRIK.cs create mode 100644 DesktopVRIK/DesktopVRIK.csproj create mode 100644 DesktopVRIK/DesktopVRIK.sln create mode 100644 DesktopVRIK/HarmonyPatches.cs create mode 100644 DesktopVRIK/Main.cs create mode 100644 DesktopVRIK/Properties/AssemblyInfo.cs create mode 100644 DesktopVRIK/format.json diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs new file mode 100644 index 0000000..ba4e1dd --- /dev/null +++ b/DesktopVRIK/DesktopVRIK.cs @@ -0,0 +1,108 @@ +using ABI.CCK.Components; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using ABI_RC.Systems.MovementSystem; +using ABI_RC.Systems.IK; +using ABI_RC.Systems.IK.SubSystems; +using MelonLoader; +using System.Text; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using RootMotion.FinalIK; + +namespace DesktopVRIK; + +public class NAKDesktopVRIK : MonoBehaviour +{ + public static NAKDesktopVRIK Instance; + public VRIK vrik; + + void Start() + { + Instance = this; + } + + void LateUpdate() + { + //pretty much zero out VRIK trying to locomote us using autofootstep + transform.localPosition = Vector3.zero; + transform.localRotation = Quaternion.identity; + } + + public void CalibrateAvatarVRIK(CVRAvatar avatar) + { + //check if VRIK already exists, as it is an allowed component + vrik = avatar.gameObject.GetComponent(); + if (vrik == null) + { + vrik = avatar.gameObject.AddComponent(); + } + + //Generic VRIK calibration shit + + vrik.fixTransforms = false; + vrik.solver.plantFeet = false; + vrik.solver.locomotion.weight = 1f; + vrik.solver.locomotion.angleThreshold = 30f; + vrik.solver.locomotion.maxLegStretch = 0.75f; + //nuke weights + vrik.solver.spine.headClampWeight = 0f; + vrik.solver.spine.minHeadHeight = 0f; + vrik.solver.leftArm.positionWeight = 0f; + vrik.solver.leftArm.rotationWeight = 0f; + vrik.solver.rightArm.positionWeight = 0f; + vrik.solver.rightArm.rotationWeight = 0f; + vrik.solver.leftLeg.positionWeight = 0f; + vrik.solver.leftLeg.rotationWeight = 0f; + vrik.solver.rightLeg.positionWeight = 0f; + vrik.solver.rightLeg.rotationWeight = 0f; + + //ChilloutVR specific stuff + + //centerEyeAnchor now is head bone + Transform headAnchor = FindIKTarget(IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.Head)); + IKSystem.Instance.headAnchorPositionOffset = Vector3.zero; + IKSystem.Instance.headAnchorRotationOffset = Vector3.zero; + IKSystem.Instance.ApplyAvatarScaleToIk(avatar.viewPosition.y); + BodySystem.TrackingLeftArmEnabled = false; + BodySystem.TrackingRightArmEnabled = false; + BodySystem.TrackingLeftLegEnabled = false; + BodySystem.TrackingRightLegEnabled = false; + vrik.solver.IKPositionWeight = 0f; + vrik.enabled = false; + //Calibrate HeadIKOffset + VRIKCalibrator.CalibrateHead(vrik, headAnchor, IKSystem.Instance.headAnchorPositionOffset, IKSystem.Instance.headAnchorRotationOffset); + vrik.enabled = true; + vrik.solver.IKPositionWeight = 1f; + vrik.solver.spine.maintainPelvisPosition = 0f; + } + + private static Transform FindIKTarget(Transform targetParent) + { + /** + I want creators to be able to specify their own custom IK Targets, so they can move them around with animations if they want. + We check for existing target objects, and if none are found we make our own. + Naming scheme is parentobject name + " IK Target". + **/ + Transform parentTransform = targetParent.transform; + string targetName = parentTransform.name + " IK Target"; + + //check for existing target + foreach (object obj in parentTransform) + { + Transform childTransform = (Transform)obj; + if (childTransform.name == targetName) + { + return childTransform; + } + } + + //create new target if none are found + GameObject newTarget = new GameObject(targetName); + newTarget.transform.parent = parentTransform; + newTarget.transform.localPosition = Vector3.zero; + newTarget.transform.localRotation = Quaternion.identity; + return newTarget.transform; + } +} \ No newline at end of file diff --git a/DesktopVRIK/DesktopVRIK.csproj b/DesktopVRIK/DesktopVRIK.csproj new file mode 100644 index 0000000..c947a92 --- /dev/null +++ b/DesktopVRIK/DesktopVRIK.csproj @@ -0,0 +1,52 @@ + + + + + net472 + enable + latest + false + + + + + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\MelonLoader\0Harmony.dll + + + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll + + + ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll + + + ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll + + + ..\..\Giamoz\Giamoz\bin\Debug\net472\Giamoz.dll + + + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\MelonLoader\MelonLoader.dll + + + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\SteamVR.dll + + + ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.InputLegacyModule.dll + + + ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.PhysicsModule.dll + + + + + + + + + diff --git a/DesktopVRIK/DesktopVRIK.sln b/DesktopVRIK/DesktopVRIK.sln new file mode 100644 index 0000000..6aba351 --- /dev/null +++ b/DesktopVRIK/DesktopVRIK.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32630.192 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DesktopVRIK", "DesktopVRIK.csproj", "{07F06485-C387-470A-A43D-F3779A059F30}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {07F06485-C387-470A-A43D-F3779A059F30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {07F06485-C387-470A-A43D-F3779A059F30}.Debug|Any CPU.Build.0 = Debug|Any CPU + {07F06485-C387-470A-A43D-F3779A059F30}.Release|Any CPU.ActiveCfg = Release|Any CPU + {07F06485-C387-470A-A43D-F3779A059F30}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {05F83429-FD88-4C7A-B7D5-40516382B6FD} + EndGlobalSection +EndGlobal diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs new file mode 100644 index 0000000..43cc8eb --- /dev/null +++ b/DesktopVRIK/HarmonyPatches.cs @@ -0,0 +1,35 @@ +using ABI_RC.Core.Player; +using ABI.CCK.Components; +using ABI_RC.Core.Savior; +using ABI_RC.Systems.IK; +using ABI_RC.Systems.IK.SubSystems; +using HarmonyLib; +using MelonLoader; +using RootMotion.FinalIK; + +namespace DesktopVRIK; + +[HarmonyPatch] +internal class HarmonyPatches +{ + [HarmonyPostfix] + [HarmonyPatch(typeof(PlayerSetup), "SetupAvatarGeneral")] + private static void InitializeDesktopIKSystem(ref CVRAvatar ____avatarDescriptor) + { + if (MetaPort.Instance.isUsingVr) return; + + //this will stop at the useless isVr return (the function is only ever called by vr anyways...) + IKSystem.Instance.InitializeAvatar(____avatarDescriptor); + } + + [HarmonyPostfix] + [HarmonyPatch(typeof(IKSystem), "InitializeAvatar")] + private static void InitializeDesktopAvatar(CVRAvatar avatar, ref VRIK ____vrik) + { + //need IKSystem to see VRIK component for setup + ____vrik = avatar.gameObject.AddComponent(); + //now i add my own VRIK stuff + NAKDesktopVRIK NAKVRIK = avatar.gameObject.AddComponent(); + NAKVRIK.CalibrateAvatarVRIK(avatar); + } +} \ No newline at end of file diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs new file mode 100644 index 0000000..21e25d9 --- /dev/null +++ b/DesktopVRIK/Main.cs @@ -0,0 +1,240 @@ +using ABI.CCK.Components; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using ABI_RC.Systems.MovementSystem; +using ABI_RC.Systems.IK; +using ABI_RC.Systems.IK.SubSystems; +using HarmonyLib; +using MelonLoader; +using RootMotion.FinalIK; +using UnityEngine; +using UnityEngine.Events; + +namespace DesktopVRIK; + +public class DesktopVRIK : MelonMod +{ + + private static MelonPreferences_Category m_categoryDesktopVRIK; + private static MelonPreferences_Entry m_entryEnabled; + private static MelonPreferences_Entry m_entryEmulateHipMovement; + private static MelonPreferences_Entry m_entryEmoteVRIK; + private static MelonPreferences_Entry m_entryEmoteLookAtIK; + + public override void OnApplicationStart() + { + m_categoryDesktopVRIK = MelonPreferences.CreateCategory(nameof(DesktopVRIK)); + m_entryEnabled = m_categoryDesktopVRIK.CreateEntry("Enabled", true, description: "Attempt to give Desktop VRIK."); + m_entryEmulateHipMovement = m_categoryDesktopVRIK.CreateEntry("Emulate Hip Movement", true, description: "Emulates VRChat-like hip movement when moving head up/down on desktop."); + m_entryEmoteVRIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote VRIK", true, description: "Disable VRIK while emoting."); + m_entryEmoteLookAtIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote LookAtIK", true, description: "Disable LookAtIK while emoting."); + } + + [HarmonyPatch] + private class HarmonyPatches + { + private static bool emotePlayed = false; + + [HarmonyPostfix] + [HarmonyPatch(typeof(PlayerSetup), "Update")] + private static void CorrectVRIK(ref bool ____emotePlaying, ref LookAtIK ___lookIK) + { + if (MetaPort.Instance.isUsingVr) return; + + if (IKSystem.vrik == null) return; + + //pretty much zero out VRIK trying to locomote us using autofootstep + IKSystem.Instance.avatar.transform.localPosition = Vector3.zero; + IKSystem.Instance.avatar.transform.localRotation = Quaternion.identity; + + //TODO: Smooth out offset when walking/running + if ( m_entryEmulateHipMovement.Value ) + { + float angle = PlayerSetup.Instance.desktopCamera.transform.localEulerAngles.x; + angle = (angle > 180) ? angle - 360 : angle; + float weight = (1 - MovementSystem.Instance.movementVector.magnitude); + Quaternion rotation = Quaternion.AngleAxis(angle * weight, IKSystem.Instance.avatar.transform.right); + IKSystem.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Head, rotation); + } + + + //Avatar Motion Tweaker has custom emote detection to disable VRIK via state tags + if (____emotePlaying && !emotePlayed) + { + emotePlayed = true; + if (m_entryEmoteVRIK.Value) + { + BodySystem.TrackingEnabled = false; + IKSystem.vrik.solver.Reset(); + } + if (m_entryEmoteLookAtIK.Value && ___lookIK != null) + { + ___lookIK.enabled = false; + } + } + else if (!____emotePlaying && emotePlayed) + { + emotePlayed = false; + BodySystem.TrackingEnabled = true; + IKSystem.vrik.solver.Reset(); + if (___lookIK != null) + { + ___lookIK.enabled = true; + } + } + } + + [HarmonyPostfix] + [HarmonyPatch(typeof(IKSystem), "InitializeAvatar")] + private static void InitializeDesktopAvatar(CVRAvatar avatar, ref VRIK ____vrik, ref HumanPoseHandler ____poseHandler, ref Vector3 ____referenceRootPosition, ref Quaternion ____referenceRootRotation, ref float[] ___HandCalibrationPoseMuscles) + { + if (!m_entryEnabled.Value) return; + + if (MetaPort.Instance.isUsingVr) return; + + //set avatar to + Quaternion initialRotation = avatar.transform.rotation; + avatar.transform.rotation = Quaternion.identity; + + ____vrik = avatar.gameObject.AddComponent(); + ____vrik.fixTransforms = false; + ____vrik.solver.locomotion.weight = 1f; + IKSystem.Instance.ApplyAvatarScaleToIk(avatar.viewPosition.y); + ____vrik.solver.locomotion.angleThreshold = 30f; + ____vrik.solver.locomotion.maxLegStretch = 0.75f; + ____vrik.solver.spine.headClampWeight = 0f; + ____vrik.solver.spine.minHeadHeight = 0f; + if (____vrik != null) + { + ____vrik.onPreSolverUpdate.AddListener(new UnityAction(IKSystem.Instance.OnPreSolverUpdate)); + } + + if (____poseHandler == null) + { + ____poseHandler = new HumanPoseHandler(IKSystem.Instance.animator.avatar, IKSystem.Instance.animator.transform); + } + ____poseHandler.GetHumanPose(ref IKSystem.Instance.humanPose); + ____referenceRootPosition = IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.Hips).position; + ____referenceRootRotation = IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.Hips).rotation; + for (int i = 0; i < ___HandCalibrationPoseMuscles.Length; i++) + { + IKSystem.Instance.ApplyMuscleValue((MuscleIndex)i, ___HandCalibrationPoseMuscles[i], ref IKSystem.Instance.humanPose.muscles); + } + ____poseHandler.SetHumanPose(ref IKSystem.Instance.humanPose); + if (IKSystem.Instance.applyOriginalHipPosition) + { + IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.Hips).position = ____referenceRootPosition; + } + if (IKSystem.Instance.applyOriginalHipRotation) + { + IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.Hips).rotation = ____referenceRootRotation; + } + + BodySystem.isCalibratedAsFullBody = false; + BodySystem.isCalibrating = false; + BodySystem.TrackingPositionWeight = 1f; + BodySystem.isCalibratedAsFullBody = false; + + //InitializeDesktopIK + + //centerEyeAnchor now is head bone + Transform headAnchor = FindIKTarget(IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.Head)); + IKSystem.Instance.headAnchorPositionOffset = Vector3.zero; + IKSystem.Instance.headAnchorRotationOffset = Vector3.zero; + + IKSystem.Instance.leftHandModel.SetActive(false); + IKSystem.Instance.rightHandModel.SetActive(false); + IKSystem.Instance.animator = IKSystem.Instance.avatar.GetComponent(); + IKSystem.Instance.animator.cullingMode = AnimatorCullingMode.AlwaysAnimate; + + //tell game to not track limbs + BodySystem.TrackingLeftArmEnabled = false; + BodySystem.TrackingRightArmEnabled = false; + BodySystem.TrackingLeftLegEnabled = false; + BodySystem.TrackingRightLegEnabled = false; + + //create ik targets for avatars to utilize + //____vrik.solver.leftLeg.target = FindIKTarget(IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.LeftFoot)); + //____vrik.solver.rightLeg.target = FindIKTarget(IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.RightFoot)); + + ____vrik.solver.IKPositionWeight = 0f; + ____vrik.enabled = false; + + VRIKCalibrator.CalibrateHead(____vrik, headAnchor, IKSystem.Instance.headAnchorPositionOffset, IKSystem.Instance.headAnchorRotationOffset); + //IKSystem.Instance.leftHandPose.transform.position = ____vrik.references.leftHand.position; + //IKSystem.Instance.rightHandPose.transform.position = ____vrik.references.rightHand.position; + //____vrik.solver.leftArm.target = IKSystem.Instance.leftHandAnchor; + //____vrik.solver.rightArm.target = IKSystem.Instance.rightHandAnchor; + + //Transform boneTransform = IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.LeftLowerArm); + //Transform boneTransform2 = IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.RightLowerArm); + //if (boneTransform.GetComponent() == null) + //{ + // TwistRelaxer twistRelaxer = boneTransform.gameObject.AddComponent(); + // twistRelaxer.ik = ____vrik; + // twistRelaxer.child = IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.LeftHand); + // twistRelaxer.weight = 0.5f; + // twistRelaxer.parentChildCrossfade = 0.9f; + // twistRelaxer.twistAngleOffset = 0f; + //} + //if (boneTransform2.GetComponent() == null) + //{ + // TwistRelaxer twistRelaxer2 = boneTransform2.gameObject.AddComponent(); + // twistRelaxer2.ik = ____vrik; + // twistRelaxer2.child = IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.RightHand); + // twistRelaxer2.weight = 0.5f; + // twistRelaxer2.parentChildCrossfade = 0.9f; + // twistRelaxer2.twistAngleOffset = 0f; + //} + //if (IKSystem.Instance.animator != null && IKSystem.Instance.animator.avatar != null && IKSystem.Instance.animator.avatar.isHuman) + //{ + // Transform boneTransform3 = IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.LeftThumbProximal); + // if (boneTransform3 != null) + // { + // ____vrik.solver.leftArm.palmToThumbAxis = VRIKCalibrator.GuessPalmToThumbAxis(____vrik.references.leftHand, ____vrik.references.leftForearm, boneTransform3); + // } + // Transform boneTransform4 = IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.RightThumbProximal); + // if (boneTransform4 != null) + // { + // ____vrik.solver.rightArm.palmToThumbAxis = VRIKCalibrator.GuessPalmToThumbAxis(____vrik.references.rightHand, ____vrik.references.rightForearm, boneTransform4); + // } + //} + + ____vrik.enabled = true; + ____vrik.solver.IKPositionWeight = 1f; + ____vrik.solver.spine.maintainPelvisPosition = 0f; + + //prevent the IK from walking away + ____vrik.solver.locomotion.maxVelocity = 0f; + avatar.transform.rotation = initialRotation; + } + + private static Transform FindIKTarget(Transform targetParent) + { + /** + I want creators to be able to specify their own custom IK Targets, so they can move them around with animations if they want. + We check for existing target objects, and if none are found we make our own. + Naming scheme is parentobject name + " IK Target". + **/ + Transform parentTransform = targetParent.transform; + string targetName = parentTransform.name + " IK Target"; + + //check for existing target + foreach (object obj in parentTransform) + { + Transform childTransform = (Transform)obj; + if (childTransform.name == targetName) + { + return childTransform; + } + } + + //create new target if none are found + GameObject newTarget = new GameObject(targetName); + newTarget.transform.parent = parentTransform; + newTarget.transform.localPosition = Vector3.zero; + newTarget.transform.localRotation = Quaternion.identity; + return newTarget.transform; + } + } +} \ No newline at end of file diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..e0f699c --- /dev/null +++ b/DesktopVRIK/Properties/AssemblyInfo.cs @@ -0,0 +1,30 @@ +using MelonLoader; +using System.Reflection; +using DesktopVRIK.Properties; + + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(DesktopVRIK))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(DesktopVRIK))] + +[assembly: MelonInfo( + typeof(DesktopVRIK.DesktopVRIK), + nameof(DesktopVRIK), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidOnSteam/DesktopVRIK" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] + +namespace DesktopVRIK.Properties; +internal static class AssemblyInfoParams +{ + public const string Version = "1.0.0"; + public const string Author = "NotAKidoS"; +} \ No newline at end of file diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json new file mode 100644 index 0000000..aee1a24 --- /dev/null +++ b/DesktopVRIK/format.json @@ -0,0 +1,23 @@ +{ + "_id": 95, + "name": "DesktopVRIK", + "modversion": "1.1.0", + "gameversion": "2022r168", + "loaderversion": "0.5.4", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Corrects MM and QM position when avatar is scaled.\nAdditional option to scale player collision.", + "searchtags": [ + "menu", + "scale", + "avatarscale", + "slider" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/r2/DesktopVRIK.dll", + "sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRIK/", + "changelog": "Added option to scale player collision. Fixed some VR specific issues.", + "embedcolor": "804221" +} \ No newline at end of file From 22391d1fcc597e3d8ddb7d29aa1cb6a749db95c0 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Sun, 25 Dec 2022 22:27:12 -0600 Subject: [PATCH 03/60] final touches completely migrated to new setup using a helper monobehavior, which makes code a lot cleaner --- DesktopVRIK/DesktopVRIK.cs | 92 +++++---- DesktopVRIK/HarmonyPatches.cs | 64 ++++-- DesktopVRIK/Main.cs | 262 ++++--------------------- DesktopVRIK/Properties/AssemblyInfo.cs | 2 +- DesktopVRIK/format.json | 24 +-- 5 files changed, 148 insertions(+), 296 deletions(-) diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index ba4e1dd..096940a 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -1,62 +1,65 @@ using ABI.CCK.Components; using ABI_RC.Core.Player; -using ABI_RC.Core.Savior; -using ABI_RC.Systems.MovementSystem; using ABI_RC.Systems.IK; using ABI_RC.Systems.IK.SubSystems; -using MelonLoader; -using System.Text; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; +using ABI_RC.Systems.MovementSystem; using RootMotion.FinalIK; +using UnityEngine; +using UnityEngine.Events; namespace DesktopVRIK; -public class NAKDesktopVRIK : MonoBehaviour +public class DesktopVRIK : MonoBehaviour { - public static NAKDesktopVRIK Instance; - public VRIK vrik; + public static DesktopVRIK Instance; + + public bool Setting_Enabled; + public bool Setting_EmulateVRChatHipMovement; + public bool Setting_EmoteVRIK; + public bool Setting_EmoteLookAtIK; void Start() { Instance = this; } - void LateUpdate() + public void OnPreSolverUpdate() { - //pretty much zero out VRIK trying to locomote us using autofootstep - transform.localPosition = Vector3.zero; - transform.localRotation = Quaternion.identity; + //Reset avatar offset (VRIK will literally make you walk away from root otherwise) + IKSystem.vrik.transform.localPosition = Vector3.zero; + IKSystem.vrik.transform.localRotation = Quaternion.identity; + + //VRChat hip movement emulation + if (Setting_EmulateVRChatHipMovement) + { + float angle = PlayerSetup.Instance.desktopCamera.transform.localEulerAngles.x; + angle = (angle > 180) ? angle - 360 : angle; + float weight = (1 - MovementSystem.Instance.movementVector.magnitude); + Quaternion rotation = Quaternion.AngleAxis(angle * weight, IKSystem.Instance.avatar.transform.right); + IKSystem.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Head, rotation); + } } public void CalibrateAvatarVRIK(CVRAvatar avatar) { - //check if VRIK already exists, as it is an allowed component - vrik = avatar.gameObject.GetComponent(); - if (vrik == null) - { - vrik = avatar.gameObject.AddComponent(); - } - //Generic VRIK calibration shit - vrik.fixTransforms = false; - vrik.solver.plantFeet = false; - vrik.solver.locomotion.weight = 1f; - vrik.solver.locomotion.angleThreshold = 30f; - vrik.solver.locomotion.maxLegStretch = 0.75f; + IKSystem.vrik.fixTransforms = false; + IKSystem.vrik.solver.plantFeet = false; + IKSystem.vrik.solver.locomotion.weight = 1f; + IKSystem.vrik.solver.locomotion.angleThreshold = 30f; + IKSystem.vrik.solver.locomotion.maxLegStretch = 0.75f; //nuke weights - vrik.solver.spine.headClampWeight = 0f; - vrik.solver.spine.minHeadHeight = 0f; - vrik.solver.leftArm.positionWeight = 0f; - vrik.solver.leftArm.rotationWeight = 0f; - vrik.solver.rightArm.positionWeight = 0f; - vrik.solver.rightArm.rotationWeight = 0f; - vrik.solver.leftLeg.positionWeight = 0f; - vrik.solver.leftLeg.rotationWeight = 0f; - vrik.solver.rightLeg.positionWeight = 0f; - vrik.solver.rightLeg.rotationWeight = 0f; + IKSystem.vrik.solver.spine.headClampWeight = 0f; + IKSystem.vrik.solver.spine.minHeadHeight = 0f; + IKSystem.vrik.solver.leftArm.positionWeight = 0f; + IKSystem.vrik.solver.leftArm.rotationWeight = 0f; + IKSystem.vrik.solver.rightArm.positionWeight = 0f; + IKSystem.vrik.solver.rightArm.rotationWeight = 0f; + IKSystem.vrik.solver.leftLeg.positionWeight = 0f; + IKSystem.vrik.solver.leftLeg.rotationWeight = 0f; + IKSystem.vrik.solver.rightLeg.positionWeight = 0f; + IKSystem.vrik.solver.rightLeg.rotationWeight = 0f; //ChilloutVR specific stuff @@ -69,15 +72,20 @@ public class NAKDesktopVRIK : MonoBehaviour BodySystem.TrackingRightArmEnabled = false; BodySystem.TrackingLeftLegEnabled = false; BodySystem.TrackingRightLegEnabled = false; - vrik.solver.IKPositionWeight = 0f; - vrik.enabled = false; + IKSystem.vrik.solver.IKPositionWeight = 0f; + IKSystem.vrik.enabled = false; //Calibrate HeadIKOffset - VRIKCalibrator.CalibrateHead(vrik, headAnchor, IKSystem.Instance.headAnchorPositionOffset, IKSystem.Instance.headAnchorRotationOffset); - vrik.enabled = true; - vrik.solver.IKPositionWeight = 1f; - vrik.solver.spine.maintainPelvisPosition = 0f; + VRIKCalibrator.CalibrateHead(IKSystem.vrik, headAnchor, IKSystem.Instance.headAnchorPositionOffset, IKSystem.Instance.headAnchorRotationOffset); + IKSystem.vrik.enabled = true; + IKSystem.vrik.solver.IKPositionWeight = 1f; + IKSystem.vrik.solver.spine.maintainPelvisPosition = 0f; + if (IKSystem.vrik != null) + { + IKSystem.vrik.onPreSolverUpdate.AddListener(new UnityAction(this.OnPreSolverUpdate)); + } } + //This is built because original build placed IK Targets on all joints. private static Transform FindIKTarget(Transform targetParent) { /** diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index 43cc8eb..38cf1ba 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -1,10 +1,9 @@ -using ABI_RC.Core.Player; -using ABI.CCK.Components; +using ABI.CCK.Components; +using ABI_RC.Core.Player; using ABI_RC.Core.Savior; using ABI_RC.Systems.IK; using ABI_RC.Systems.IK.SubSystems; using HarmonyLib; -using MelonLoader; using RootMotion.FinalIK; namespace DesktopVRIK; @@ -14,22 +13,59 @@ internal class HarmonyPatches { [HarmonyPostfix] [HarmonyPatch(typeof(PlayerSetup), "SetupAvatarGeneral")] - private static void InitializeDesktopIKSystem(ref CVRAvatar ____avatarDescriptor) + private static void SetupDesktopIKSystem(ref CVRAvatar ____avatarDescriptor) { - if (MetaPort.Instance.isUsingVr) return; - - //this will stop at the useless isVr return (the function is only ever called by vr anyways...) - IKSystem.Instance.InitializeAvatar(____avatarDescriptor); + if (!MetaPort.Instance.isUsingVr && DesktopVRIK.Instance.Setting_Enabled) + { + //this will stop at the useless isVr return (the function is only ever called by vr anyways...) + IKSystem.Instance.InitializeAvatar(____avatarDescriptor); + } } [HarmonyPostfix] [HarmonyPatch(typeof(IKSystem), "InitializeAvatar")] - private static void InitializeDesktopAvatar(CVRAvatar avatar, ref VRIK ____vrik) + private static void InitializeDesktopAvatarVRIK(CVRAvatar avatar, ref VRIK ____vrik) { - //need IKSystem to see VRIK component for setup - ____vrik = avatar.gameObject.AddComponent(); - //now i add my own VRIK stuff - NAKDesktopVRIK NAKVRIK = avatar.gameObject.AddComponent(); - NAKVRIK.CalibrateAvatarVRIK(avatar); + if (!MetaPort.Instance.isUsingVr && DesktopVRIK.Instance.Setting_Enabled) + { + //need IKSystem to see VRIK component for setup + ____vrik = avatar.gameObject.AddComponent(); + //now I calibrate DesktopVRIK + DesktopVRIK.Instance.CalibrateAvatarVRIK(avatar); + } + } + + private static bool emotePlayed = false; + + [HarmonyPostfix] + [HarmonyPatch(typeof(PlayerSetup), "Update")] + private static void CorrectVRIK(ref bool ____emotePlaying, ref LookAtIK ___lookIK) + { + if (MetaPort.Instance.isUsingVr || DesktopVRIK.Instance == null) return; + + //might need to rework this in the future + if (____emotePlaying && !emotePlayed) + { + emotePlayed = true; + if (DesktopVRIK.Instance.Setting_EmoteVRIK) + { + BodySystem.TrackingEnabled = false; + //IKSystem.vrik.solver.Reset(); + } + if (DesktopVRIK.Instance.Setting_EmoteLookAtIK && ___lookIK != null) + { + ___lookIK.enabled = false; + } + } + else if (!____emotePlaying && emotePlayed) + { + emotePlayed = false; + IKSystem.vrik.solver.Reset(); + BodySystem.TrackingEnabled = true; + if (___lookIK != null) + { + ___lookIK.enabled = true; + } + } } } \ No newline at end of file diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index 21e25d9..a04b2fc 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -1,240 +1,48 @@ -using ABI.CCK.Components; -using ABI_RC.Core.Player; -using ABI_RC.Core.Savior; -using ABI_RC.Systems.MovementSystem; -using ABI_RC.Systems.IK; -using ABI_RC.Systems.IK.SubSystems; -using HarmonyLib; +using ABI_RC.Core.Player; using MelonLoader; -using RootMotion.FinalIK; -using UnityEngine; -using UnityEngine.Events; namespace DesktopVRIK; -public class DesktopVRIK : MelonMod +public class DesktopVRIKMod : MelonMod { - + internal const string SettingsCategory = "DesktopVRIK"; private static MelonPreferences_Category m_categoryDesktopVRIK; - private static MelonPreferences_Entry m_entryEnabled; - private static MelonPreferences_Entry m_entryEmulateHipMovement; - private static MelonPreferences_Entry m_entryEmoteVRIK; - private static MelonPreferences_Entry m_entryEmoteLookAtIK; - - public override void OnApplicationStart() + private static MelonPreferences_Entry m_entryEnabled, m_entryEmulateHipMovement, m_entryEmoteVRIK, m_entryEmoteLookAtIK; + public override void OnInitializeMelon() { - m_categoryDesktopVRIK = MelonPreferences.CreateCategory(nameof(DesktopVRIK)); - m_entryEnabled = m_categoryDesktopVRIK.CreateEntry("Enabled", true, description: "Attempt to give Desktop VRIK."); + m_categoryDesktopVRIK = MelonPreferences.CreateCategory(SettingsCategory); + m_entryEnabled = m_categoryDesktopVRIK.CreateEntry("Enabled", true, description: "Attempt to give Desktop VRIK on avatar load."); m_entryEmulateHipMovement = m_categoryDesktopVRIK.CreateEntry("Emulate Hip Movement", true, description: "Emulates VRChat-like hip movement when moving head up/down on desktop."); - m_entryEmoteVRIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote VRIK", true, description: "Disable VRIK while emoting."); - m_entryEmoteLookAtIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote LookAtIK", true, description: "Disable LookAtIK while emoting."); + m_entryEmoteVRIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote VRIK", true, description: "Disable VRIK while emoting. Only disable if you are ok with looking dumb."); + m_entryEmoteLookAtIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote LookAtIK", true, description: "Disable LookAtIK while emoting. This setting doesn't really matter, as LookAtIK isn't networked while doing an emote."); + m_categoryDesktopVRIK.SaveToFile(false); + + foreach (var setting in m_categoryDesktopVRIK.Entries) + { + setting.OnEntryValueChangedUntyped.Subscribe(OnUpdateSettings); + } + + MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); } - [HarmonyPatch] - private class HarmonyPatches + System.Collections.IEnumerator WaitForLocalPlayer() { - private static bool emotePlayed = false; - - [HarmonyPostfix] - [HarmonyPatch(typeof(PlayerSetup), "Update")] - private static void CorrectVRIK(ref bool ____emotePlaying, ref LookAtIK ___lookIK) - { - if (MetaPort.Instance.isUsingVr) return; - - if (IKSystem.vrik == null) return; - - //pretty much zero out VRIK trying to locomote us using autofootstep - IKSystem.Instance.avatar.transform.localPosition = Vector3.zero; - IKSystem.Instance.avatar.transform.localRotation = Quaternion.identity; - - //TODO: Smooth out offset when walking/running - if ( m_entryEmulateHipMovement.Value ) - { - float angle = PlayerSetup.Instance.desktopCamera.transform.localEulerAngles.x; - angle = (angle > 180) ? angle - 360 : angle; - float weight = (1 - MovementSystem.Instance.movementVector.magnitude); - Quaternion rotation = Quaternion.AngleAxis(angle * weight, IKSystem.Instance.avatar.transform.right); - IKSystem.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Head, rotation); - } - - - //Avatar Motion Tweaker has custom emote detection to disable VRIK via state tags - if (____emotePlaying && !emotePlayed) - { - emotePlayed = true; - if (m_entryEmoteVRIK.Value) - { - BodySystem.TrackingEnabled = false; - IKSystem.vrik.solver.Reset(); - } - if (m_entryEmoteLookAtIK.Value && ___lookIK != null) - { - ___lookIK.enabled = false; - } - } - else if (!____emotePlaying && emotePlayed) - { - emotePlayed = false; - BodySystem.TrackingEnabled = true; - IKSystem.vrik.solver.Reset(); - if (___lookIK != null) - { - ___lookIK.enabled = true; - } - } - } - - [HarmonyPostfix] - [HarmonyPatch(typeof(IKSystem), "InitializeAvatar")] - private static void InitializeDesktopAvatar(CVRAvatar avatar, ref VRIK ____vrik, ref HumanPoseHandler ____poseHandler, ref Vector3 ____referenceRootPosition, ref Quaternion ____referenceRootRotation, ref float[] ___HandCalibrationPoseMuscles) - { - if (!m_entryEnabled.Value) return; - - if (MetaPort.Instance.isUsingVr) return; - - //set avatar to - Quaternion initialRotation = avatar.transform.rotation; - avatar.transform.rotation = Quaternion.identity; - - ____vrik = avatar.gameObject.AddComponent(); - ____vrik.fixTransforms = false; - ____vrik.solver.locomotion.weight = 1f; - IKSystem.Instance.ApplyAvatarScaleToIk(avatar.viewPosition.y); - ____vrik.solver.locomotion.angleThreshold = 30f; - ____vrik.solver.locomotion.maxLegStretch = 0.75f; - ____vrik.solver.spine.headClampWeight = 0f; - ____vrik.solver.spine.minHeadHeight = 0f; - if (____vrik != null) - { - ____vrik.onPreSolverUpdate.AddListener(new UnityAction(IKSystem.Instance.OnPreSolverUpdate)); - } - - if (____poseHandler == null) - { - ____poseHandler = new HumanPoseHandler(IKSystem.Instance.animator.avatar, IKSystem.Instance.animator.transform); - } - ____poseHandler.GetHumanPose(ref IKSystem.Instance.humanPose); - ____referenceRootPosition = IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.Hips).position; - ____referenceRootRotation = IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.Hips).rotation; - for (int i = 0; i < ___HandCalibrationPoseMuscles.Length; i++) - { - IKSystem.Instance.ApplyMuscleValue((MuscleIndex)i, ___HandCalibrationPoseMuscles[i], ref IKSystem.Instance.humanPose.muscles); - } - ____poseHandler.SetHumanPose(ref IKSystem.Instance.humanPose); - if (IKSystem.Instance.applyOriginalHipPosition) - { - IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.Hips).position = ____referenceRootPosition; - } - if (IKSystem.Instance.applyOriginalHipRotation) - { - IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.Hips).rotation = ____referenceRootRotation; - } - - BodySystem.isCalibratedAsFullBody = false; - BodySystem.isCalibrating = false; - BodySystem.TrackingPositionWeight = 1f; - BodySystem.isCalibratedAsFullBody = false; - - //InitializeDesktopIK - - //centerEyeAnchor now is head bone - Transform headAnchor = FindIKTarget(IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.Head)); - IKSystem.Instance.headAnchorPositionOffset = Vector3.zero; - IKSystem.Instance.headAnchorRotationOffset = Vector3.zero; - - IKSystem.Instance.leftHandModel.SetActive(false); - IKSystem.Instance.rightHandModel.SetActive(false); - IKSystem.Instance.animator = IKSystem.Instance.avatar.GetComponent(); - IKSystem.Instance.animator.cullingMode = AnimatorCullingMode.AlwaysAnimate; - - //tell game to not track limbs - BodySystem.TrackingLeftArmEnabled = false; - BodySystem.TrackingRightArmEnabled = false; - BodySystem.TrackingLeftLegEnabled = false; - BodySystem.TrackingRightLegEnabled = false; - - //create ik targets for avatars to utilize - //____vrik.solver.leftLeg.target = FindIKTarget(IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.LeftFoot)); - //____vrik.solver.rightLeg.target = FindIKTarget(IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.RightFoot)); - - ____vrik.solver.IKPositionWeight = 0f; - ____vrik.enabled = false; - - VRIKCalibrator.CalibrateHead(____vrik, headAnchor, IKSystem.Instance.headAnchorPositionOffset, IKSystem.Instance.headAnchorRotationOffset); - //IKSystem.Instance.leftHandPose.transform.position = ____vrik.references.leftHand.position; - //IKSystem.Instance.rightHandPose.transform.position = ____vrik.references.rightHand.position; - //____vrik.solver.leftArm.target = IKSystem.Instance.leftHandAnchor; - //____vrik.solver.rightArm.target = IKSystem.Instance.rightHandAnchor; - - //Transform boneTransform = IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.LeftLowerArm); - //Transform boneTransform2 = IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.RightLowerArm); - //if (boneTransform.GetComponent() == null) - //{ - // TwistRelaxer twistRelaxer = boneTransform.gameObject.AddComponent(); - // twistRelaxer.ik = ____vrik; - // twistRelaxer.child = IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.LeftHand); - // twistRelaxer.weight = 0.5f; - // twistRelaxer.parentChildCrossfade = 0.9f; - // twistRelaxer.twistAngleOffset = 0f; - //} - //if (boneTransform2.GetComponent() == null) - //{ - // TwistRelaxer twistRelaxer2 = boneTransform2.gameObject.AddComponent(); - // twistRelaxer2.ik = ____vrik; - // twistRelaxer2.child = IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.RightHand); - // twistRelaxer2.weight = 0.5f; - // twistRelaxer2.parentChildCrossfade = 0.9f; - // twistRelaxer2.twistAngleOffset = 0f; - //} - //if (IKSystem.Instance.animator != null && IKSystem.Instance.animator.avatar != null && IKSystem.Instance.animator.avatar.isHuman) - //{ - // Transform boneTransform3 = IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.LeftThumbProximal); - // if (boneTransform3 != null) - // { - // ____vrik.solver.leftArm.palmToThumbAxis = VRIKCalibrator.GuessPalmToThumbAxis(____vrik.references.leftHand, ____vrik.references.leftForearm, boneTransform3); - // } - // Transform boneTransform4 = IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.RightThumbProximal); - // if (boneTransform4 != null) - // { - // ____vrik.solver.rightArm.palmToThumbAxis = VRIKCalibrator.GuessPalmToThumbAxis(____vrik.references.rightHand, ____vrik.references.rightForearm, boneTransform4); - // } - //} - - ____vrik.enabled = true; - ____vrik.solver.IKPositionWeight = 1f; - ____vrik.solver.spine.maintainPelvisPosition = 0f; - - //prevent the IK from walking away - ____vrik.solver.locomotion.maxVelocity = 0f; - avatar.transform.rotation = initialRotation; - } - - private static Transform FindIKTarget(Transform targetParent) - { - /** - I want creators to be able to specify their own custom IK Targets, so they can move them around with animations if they want. - We check for existing target objects, and if none are found we make our own. - Naming scheme is parentobject name + " IK Target". - **/ - Transform parentTransform = targetParent.transform; - string targetName = parentTransform.name + " IK Target"; - - //check for existing target - foreach (object obj in parentTransform) - { - Transform childTransform = (Transform)obj; - if (childTransform.name == targetName) - { - return childTransform; - } - } - - //create new target if none are found - GameObject newTarget = new GameObject(targetName); - newTarget.transform.parent = parentTransform; - newTarget.transform.localPosition = Vector3.zero; - newTarget.transform.localRotation = Quaternion.identity; - return newTarget.transform; - } + while (PlayerSetup.Instance == null) + yield return null; + PlayerSetup.Instance.gameObject.AddComponent(); + while (DesktopVRIK.Instance == null) + yield return null; + UpdateAllSettings(); } + + private void UpdateAllSettings() + { + if (!DesktopVRIK.Instance) return; + DesktopVRIK.Instance.Setting_Enabled = m_entryEnabled.Value; + DesktopVRIK.Instance.Setting_EmulateVRChatHipMovement = m_entryEmulateHipMovement.Value; + DesktopVRIK.Instance.Setting_EmoteVRIK = m_entryEmoteVRIK.Value; + DesktopVRIK.Instance.Setting_EmoteLookAtIK = m_entryEmoteLookAtIK.Value; + } + + private void OnUpdateSettings(object arg1, object arg2) => UpdateAllSettings(); } \ No newline at end of file diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs index e0f699c..fc089f3 100644 --- a/DesktopVRIK/Properties/AssemblyInfo.cs +++ b/DesktopVRIK/Properties/AssemblyInfo.cs @@ -11,7 +11,7 @@ using DesktopVRIK.Properties; [assembly: AssemblyProduct(nameof(DesktopVRIK))] [assembly: MelonInfo( - typeof(DesktopVRIK.DesktopVRIK), + typeof(DesktopVRIK.DesktopVRIKMod), nameof(DesktopVRIK), AssemblyInfoParams.Version, AssemblyInfoParams.Author, diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json index aee1a24..6eef4bf 100644 --- a/DesktopVRIK/format.json +++ b/DesktopVRIK/format.json @@ -1,23 +1,23 @@ { - "_id": 95, + "_id": -1, "name": "DesktopVRIK", - "modversion": "1.1.0", - "gameversion": "2022r168", - "loaderversion": "0.5.4", + "modversion": "1.0.0", + "gameversion": "2022r170", + "loaderversion": "0.5.7", "modtype": "Mod", "author": "NotAKidoS", - "description": "Corrects MM and QM position when avatar is scaled.\nAdditional option to scale player collision.", + "description": "Adds VRIK to Desktop avatars. No longer will you be a liveless sliding statue~!\nAdds the small feet stepping when looking around on Desktop.\n\nAdditional option to emulate VRChat-like hip movement if you like becoming a fish.", "searchtags": [ - "menu", - "scale", - "avatarscale", - "slider" + "desktop", + "vrik", + "ik", + "feet" ], "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/r2/DesktopVRIK.dll", + "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/r1/DesktopVRIK.dll", "sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRIK/", - "changelog": "Added option to scale player collision. Fixed some VR specific issues.", - "embedcolor": "804221" + "changelog": "Simplified VRIK calibration to avoid low heel issue.", + "embedcolor": "9b59b6" } \ No newline at end of file From adafbe8e7a4c7f81f5639476e7b1672e2d750d6f Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Sun, 25 Dec 2022 22:41:54 -0600 Subject: [PATCH 04/60] Update format.json --- DesktopVRIK/format.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json index 6eef4bf..888a4d8 100644 --- a/DesktopVRIK/format.json +++ b/DesktopVRIK/format.json @@ -16,7 +16,7 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/r1/DesktopVRIK.dll", + "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v1.0.0/DesktopVRIK.dll", "sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRIK/", "changelog": "Simplified VRIK calibration to avoid low heel issue.", "embedcolor": "9b59b6" From 857d53a3d7bdbf056bd7dce6e85cf5137c49a5ae Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Sun, 25 Dec 2022 22:44:08 -0600 Subject: [PATCH 05/60] Update README.md --- README.md | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 58f80e9..42618ec 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,32 @@ # DesktopVRIK - Adds VRIK to Desktop ChilloutVR avatars. +Adds VRIK to Desktop ChilloutVR avatars. No longer will you be a liveless sliding statue~! + +(adds the small feet stepping when looking around on Desktop) + +Additional option to emulate VRChat-like hip movement if you like becoming a fish. +Control over disabling VRIK & LookAtIK during Emotes. (this can cause funky behavior) + +--- + +Here is the block of text where I tell you this mod is not affiliated or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> I am not affiliated with ABI in any official capacity, these mods are not endorsed or outright permitted by ABI and are subject to scrutiny. + +> Neither I nor these mods are in any way affiliated with Alpha Blend Interactive and/or ChilloutVR. Using these modifications might cause issues with the performance, security or stability of the game. Use at your own risk. + +> Any modifications that are not approved can get your ABI account terminated and such this modification is following the "modding guidelines" at the best it could be. +> They reserve the right to punish users using my mod. +> If you are scared of using modifications in your game do not install mods. + +> I do not affiliate ABI and the mod is not supported by ABI. + +> Me and this modification are in no affiliation with ABI and not supported by ABI. + +> This mod is not affiliated with Alpha Blend Interactive. The mod comes with no warranty. Use at your own risk, as I am not responsible for any misuse. + +> I'm not affiliated with Alpha Blend Interactive and this mod is not officially supported by the game. + +> When releasing mods to the public, it is required to state, that the mod authors and modification are in no affiliation with ABI and not supported by ABI. :trollface: + +> i ran out of places to steal disclaimers from From f25c8762afa38b697be71f108dfe6305fb431aca Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Sun, 25 Dec 2022 22:44:28 -0600 Subject: [PATCH 06/60] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 42618ec..e48d9ba 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ Adds VRIK to Desktop ChilloutVR avatars. No longer will you be a liveless slidin (adds the small feet stepping when looking around on Desktop) Additional option to emulate VRChat-like hip movement if you like becoming a fish. + Control over disabling VRIK & LookAtIK during Emotes. (this can cause funky behavior) --- From e653d2b8043fcaf7439202e046c0ab51dddf84ec Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Sun, 25 Dec 2022 22:52:14 -0600 Subject: [PATCH 07/60] rename method --- DesktopVRIK/DesktopVRIK.cs | 2 +- DesktopVRIK/HarmonyPatches.cs | 2 +- DesktopVRIK/format.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index 096940a..7e28795 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -40,7 +40,7 @@ public class DesktopVRIK : MonoBehaviour } } - public void CalibrateAvatarVRIK(CVRAvatar avatar) + public void CalibrateDesktopVRIK(CVRAvatar avatar) { //Generic VRIK calibration shit diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index 38cf1ba..eef2266 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -31,7 +31,7 @@ internal class HarmonyPatches //need IKSystem to see VRIK component for setup ____vrik = avatar.gameObject.AddComponent(); //now I calibrate DesktopVRIK - DesktopVRIK.Instance.CalibrateAvatarVRIK(avatar); + DesktopVRIK.Instance.CalibrateDesktopVRIK(avatar); } } diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json index 888a4d8..8f81334 100644 --- a/DesktopVRIK/format.json +++ b/DesktopVRIK/format.json @@ -6,7 +6,7 @@ "loaderversion": "0.5.7", "modtype": "Mod", "author": "NotAKidoS", - "description": "Adds VRIK to Desktop avatars. No longer will you be a liveless sliding statue~!\nAdds the small feet stepping when looking around on Desktop.\n\nAdditional option to emulate VRChat-like hip movement if you like becoming a fish.", + "description": "Adds VRIK to Desktop avatars. No longer will you be a liveless sliding statue~!\nAdds the small feet stepping when looking around on Desktop.\n\nAdditional option to emulate VRChat-like hip movement if you like being fish.\nThis mod pairs well with Avatar Motion Tweaker by SDraw.", "searchtags": [ "desktop", "vrik", From c71036f74fb595b1e7042b836cb181ab09049485 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Mon, 26 Dec 2022 00:26:13 -0600 Subject: [PATCH 08/60] added compatibility mode add compatibility mode that somehow fixes avatars with scuffed armatures and initial poses gonna look into using a tpose animation --- DesktopVRIK/DesktopVRIK.cs | 2 ++ DesktopVRIK/HarmonyPatches.cs | 36 +++++++++++++++++++++++++++++++++-- DesktopVRIK/Main.cs | 4 +++- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index 7e28795..783e8db 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -17,6 +17,8 @@ public class DesktopVRIK : MonoBehaviour public bool Setting_EmulateVRChatHipMovement; public bool Setting_EmoteVRIK; public bool Setting_EmoteLookAtIK; + //fuck + public bool Setting_CompatibilityMode; void Start() { diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index eef2266..49940eb 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -5,12 +5,14 @@ using ABI_RC.Systems.IK; using ABI_RC.Systems.IK.SubSystems; using HarmonyLib; using RootMotion.FinalIK; +using UnityEngine; namespace DesktopVRIK; [HarmonyPatch] internal class HarmonyPatches { + [HarmonyPostfix] [HarmonyPatch(typeof(PlayerSetup), "SetupAvatarGeneral")] private static void SetupDesktopIKSystem(ref CVRAvatar ____avatarDescriptor) @@ -24,12 +26,42 @@ internal class HarmonyPatches [HarmonyPostfix] [HarmonyPatch(typeof(IKSystem), "InitializeAvatar")] - private static void InitializeDesktopAvatarVRIK(CVRAvatar avatar, ref VRIK ____vrik) + private static void InitializeDesktopAvatarVRIK(CVRAvatar avatar, ref VRIK ____vrik, ref HumanPoseHandler ____poseHandler, ref float[] ___HandCalibrationPoseMuscles, ref Vector3 ____referenceRootPosition, ref Quaternion ____referenceRootRotation, ref HumanPose ___humanPose) { if (!MetaPort.Instance.isUsingVr && DesktopVRIK.Instance.Setting_Enabled) { //need IKSystem to see VRIK component for setup - ____vrik = avatar.gameObject.AddComponent(); + if (____vrik == null) + { + ____vrik = avatar.gameObject.AddComponent(); + } + + //ChilloutVR stuffs that makes sure garbage armatures are supported + //this places heels in the ground... can i just use my own tpose animation + if (DesktopVRIK.Instance.Setting_CompatibilityMode) + { + if (____poseHandler == null) + { + ____poseHandler = new HumanPoseHandler(IKSystem.Instance.animator.avatar, IKSystem.Instance.animator.transform); + } + ____poseHandler.GetHumanPose(ref ___humanPose); + ____referenceRootPosition = IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.Hips).position; + ____referenceRootRotation = IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.Hips).rotation; + for (int i = 0; i < ___HandCalibrationPoseMuscles.Length; i++) + { + IKSystem.Instance.ApplyMuscleValue((MuscleIndex)i, ___HandCalibrationPoseMuscles[i], ref ___humanPose.muscles); + } + ____poseHandler.SetHumanPose(ref ___humanPose); + if (IKSystem.Instance.applyOriginalHipPosition) + { + IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.Hips).position = ____referenceRootPosition; + } + if (IKSystem.Instance.applyOriginalHipRotation) + { + IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.Hips).rotation = ____referenceRootRotation; + } + } + //now I calibrate DesktopVRIK DesktopVRIK.Instance.CalibrateDesktopVRIK(avatar); } diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index a04b2fc..14119ad 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -7,7 +7,7 @@ public class DesktopVRIKMod : MelonMod { internal const string SettingsCategory = "DesktopVRIK"; private static MelonPreferences_Category m_categoryDesktopVRIK; - private static MelonPreferences_Entry m_entryEnabled, m_entryEmulateHipMovement, m_entryEmoteVRIK, m_entryEmoteLookAtIK; + private static MelonPreferences_Entry m_entryEnabled, m_entryEmulateHipMovement, m_entryEmoteVRIK, m_entryEmoteLookAtIK, m_entryCompatibilityMode; public override void OnInitializeMelon() { m_categoryDesktopVRIK = MelonPreferences.CreateCategory(SettingsCategory); @@ -15,6 +15,7 @@ public class DesktopVRIKMod : MelonMod m_entryEmulateHipMovement = m_categoryDesktopVRIK.CreateEntry("Emulate Hip Movement", true, description: "Emulates VRChat-like hip movement when moving head up/down on desktop."); m_entryEmoteVRIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote VRIK", true, description: "Disable VRIK while emoting. Only disable if you are ok with looking dumb."); m_entryEmoteLookAtIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote LookAtIK", true, description: "Disable LookAtIK while emoting. This setting doesn't really matter, as LookAtIK isn't networked while doing an emote."); + m_entryCompatibilityMode = m_categoryDesktopVRIK.CreateEntry("Compatibility Mode", false, description: "Runs finger muscle calibration- which somehow makes bad armatures work better but also pushes heels into the ground."); ; m_categoryDesktopVRIK.SaveToFile(false); foreach (var setting in m_categoryDesktopVRIK.Entries) @@ -42,6 +43,7 @@ public class DesktopVRIKMod : MelonMod DesktopVRIK.Instance.Setting_EmulateVRChatHipMovement = m_entryEmulateHipMovement.Value; DesktopVRIK.Instance.Setting_EmoteVRIK = m_entryEmoteVRIK.Value; DesktopVRIK.Instance.Setting_EmoteLookAtIK = m_entryEmoteLookAtIK.Value; + DesktopVRIK.Instance.Setting_CompatibilityMode = m_entryCompatibilityMode.Value; } private void OnUpdateSettings(object arg1, object arg2) => UpdateAllSettings(); From df61830c8357de2282d112dddcf75a7a46098ce9 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Mon, 26 Dec 2022 00:52:50 -0600 Subject: [PATCH 09/60] Removed compatibility mode & added integrity checks. Why the fuck did deleting code make the issue better... --- DesktopVRIK/DesktopVRIK.cs | 2 -- DesktopVRIK/HarmonyPatches.cs | 44 ++++++++++---------------- DesktopVRIK/Main.cs | 2 -- DesktopVRIK/Properties/AssemblyInfo.cs | 2 +- DesktopVRIK/format.json | 8 ++--- 5 files changed, 21 insertions(+), 37 deletions(-) diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index 783e8db..7e28795 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -17,8 +17,6 @@ public class DesktopVRIK : MonoBehaviour public bool Setting_EmulateVRChatHipMovement; public bool Setting_EmoteVRIK; public bool Setting_EmoteLookAtIK; - //fuck - public bool Setting_CompatibilityMode; void Start() { diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index 49940eb..49844f8 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -15,12 +15,15 @@ internal class HarmonyPatches [HarmonyPostfix] [HarmonyPatch(typeof(PlayerSetup), "SetupAvatarGeneral")] - private static void SetupDesktopIKSystem(ref CVRAvatar ____avatarDescriptor) + private static void SetupDesktopIKSystem(ref CVRAvatar ____avatarDescriptor, ref Animator ____animator) { if (!MetaPort.Instance.isUsingVr && DesktopVRIK.Instance.Setting_Enabled) { - //this will stop at the useless isVr return (the function is only ever called by vr anyways...) - IKSystem.Instance.InitializeAvatar(____avatarDescriptor); + if (____avatarDescriptor != null && ____animator != null && ____animator.isHuman) + { + //this will stop at the useless isVr return (the function is only ever called by vr anyways...) + IKSystem.Instance.InitializeAvatar(____avatarDescriptor); + } } } @@ -30,40 +33,25 @@ internal class HarmonyPatches { if (!MetaPort.Instance.isUsingVr && DesktopVRIK.Instance.Setting_Enabled) { - //need IKSystem to see VRIK component for setup - if (____vrik == null) + if (IKSystem.Instance.animator != null && IKSystem.Instance.animator.avatar != null && IKSystem.Instance.animator.avatar.isHuman) { - ____vrik = avatar.gameObject.AddComponent(); - } + //need IKSystem to see VRIK component for setup + if (____vrik == null) + { + ____vrik = avatar.gameObject.AddComponent(); + } - //ChilloutVR stuffs that makes sure garbage armatures are supported - //this places heels in the ground... can i just use my own tpose animation - if (DesktopVRIK.Instance.Setting_CompatibilityMode) - { + //why the fuck does this fix bad armatures and heels in ground ??? if (____poseHandler == null) { ____poseHandler = new HumanPoseHandler(IKSystem.Instance.animator.avatar, IKSystem.Instance.animator.transform); } ____poseHandler.GetHumanPose(ref ___humanPose); - ____referenceRootPosition = IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.Hips).position; - ____referenceRootRotation = IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.Hips).rotation; - for (int i = 0; i < ___HandCalibrationPoseMuscles.Length; i++) - { - IKSystem.Instance.ApplyMuscleValue((MuscleIndex)i, ___HandCalibrationPoseMuscles[i], ref ___humanPose.muscles); - } ____poseHandler.SetHumanPose(ref ___humanPose); - if (IKSystem.Instance.applyOriginalHipPosition) - { - IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.Hips).position = ____referenceRootPosition; - } - if (IKSystem.Instance.applyOriginalHipRotation) - { - IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.Hips).rotation = ____referenceRootRotation; - } - } - //now I calibrate DesktopVRIK - DesktopVRIK.Instance.CalibrateDesktopVRIK(avatar); + //now I calibrate DesktopVRIK + DesktopVRIK.Instance.CalibrateDesktopVRIK(avatar); + } } } diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index 14119ad..7bcff02 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -15,7 +15,6 @@ public class DesktopVRIKMod : MelonMod m_entryEmulateHipMovement = m_categoryDesktopVRIK.CreateEntry("Emulate Hip Movement", true, description: "Emulates VRChat-like hip movement when moving head up/down on desktop."); m_entryEmoteVRIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote VRIK", true, description: "Disable VRIK while emoting. Only disable if you are ok with looking dumb."); m_entryEmoteLookAtIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote LookAtIK", true, description: "Disable LookAtIK while emoting. This setting doesn't really matter, as LookAtIK isn't networked while doing an emote."); - m_entryCompatibilityMode = m_categoryDesktopVRIK.CreateEntry("Compatibility Mode", false, description: "Runs finger muscle calibration- which somehow makes bad armatures work better but also pushes heels into the ground."); ; m_categoryDesktopVRIK.SaveToFile(false); foreach (var setting in m_categoryDesktopVRIK.Entries) @@ -43,7 +42,6 @@ public class DesktopVRIKMod : MelonMod DesktopVRIK.Instance.Setting_EmulateVRChatHipMovement = m_entryEmulateHipMovement.Value; DesktopVRIK.Instance.Setting_EmoteVRIK = m_entryEmoteVRIK.Value; DesktopVRIK.Instance.Setting_EmoteLookAtIK = m_entryEmoteLookAtIK.Value; - DesktopVRIK.Instance.Setting_CompatibilityMode = m_entryCompatibilityMode.Value; } private void OnUpdateSettings(object arg1, object arg2) => UpdateAllSettings(); diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs index fc089f3..8590777 100644 --- a/DesktopVRIK/Properties/AssemblyInfo.cs +++ b/DesktopVRIK/Properties/AssemblyInfo.cs @@ -25,6 +25,6 @@ using DesktopVRIK.Properties; namespace DesktopVRIK.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.0"; + public const string Version = "1.0.2"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json index 8f81334..0caa9b1 100644 --- a/DesktopVRIK/format.json +++ b/DesktopVRIK/format.json @@ -1,7 +1,7 @@ { - "_id": -1, + "_id": 117, "name": "DesktopVRIK", - "modversion": "1.0.0", + "modversion": "1.0.2", "gameversion": "2022r170", "loaderversion": "0.5.7", "modtype": "Mod", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v1.0.0/DesktopVRIK.dll", + "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v1.0.2/DesktopVRIK.dll", "sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRIK/", - "changelog": "Simplified VRIK calibration to avoid low heel issue.", + "changelog": "Simplified VRIK calibration to avoid low heel issue.\nRemoved rushed compatibility mode & implemented integrity checks for valid Humanoid rigs.", "embedcolor": "9b59b6" } \ No newline at end of file From 55a3009f96d1cd5a72ed8864542816679d411620 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:34:59 -0600 Subject: [PATCH 10/60] cleanup & remove safefile() got yelled at by sdraw for m_categoryDesktopVRIK.SaveToFile(false); oopsies --- DesktopVRIK/HarmonyPatches.cs | 2 +- DesktopVRIK/Main.cs | 3 +-- DesktopVRIK/Properties/AssemblyInfo.cs | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index 49844f8..e2b05fc 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -29,7 +29,7 @@ internal class HarmonyPatches [HarmonyPostfix] [HarmonyPatch(typeof(IKSystem), "InitializeAvatar")] - private static void InitializeDesktopAvatarVRIK(CVRAvatar avatar, ref VRIK ____vrik, ref HumanPoseHandler ____poseHandler, ref float[] ___HandCalibrationPoseMuscles, ref Vector3 ____referenceRootPosition, ref Quaternion ____referenceRootRotation, ref HumanPose ___humanPose) + private static void InitializeDesktopAvatarVRIK(CVRAvatar avatar, ref VRIK ____vrik, ref HumanPoseHandler ____poseHandler, ref HumanPose ___humanPose) { if (!MetaPort.Instance.isUsingVr && DesktopVRIK.Instance.Setting_Enabled) { diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index 7bcff02..539c7b8 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -7,7 +7,7 @@ public class DesktopVRIKMod : MelonMod { internal const string SettingsCategory = "DesktopVRIK"; private static MelonPreferences_Category m_categoryDesktopVRIK; - private static MelonPreferences_Entry m_entryEnabled, m_entryEmulateHipMovement, m_entryEmoteVRIK, m_entryEmoteLookAtIK, m_entryCompatibilityMode; + private static MelonPreferences_Entry m_entryEnabled, m_entryEmulateHipMovement, m_entryEmoteVRIK, m_entryEmoteLookAtIK; public override void OnInitializeMelon() { m_categoryDesktopVRIK = MelonPreferences.CreateCategory(SettingsCategory); @@ -15,7 +15,6 @@ public class DesktopVRIKMod : MelonMod m_entryEmulateHipMovement = m_categoryDesktopVRIK.CreateEntry("Emulate Hip Movement", true, description: "Emulates VRChat-like hip movement when moving head up/down on desktop."); m_entryEmoteVRIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote VRIK", true, description: "Disable VRIK while emoting. Only disable if you are ok with looking dumb."); m_entryEmoteLookAtIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote LookAtIK", true, description: "Disable LookAtIK while emoting. This setting doesn't really matter, as LookAtIK isn't networked while doing an emote."); - m_categoryDesktopVRIK.SaveToFile(false); foreach (var setting in m_categoryDesktopVRIK.Entries) { diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs index 8590777..135711e 100644 --- a/DesktopVRIK/Properties/AssemblyInfo.cs +++ b/DesktopVRIK/Properties/AssemblyInfo.cs @@ -1,6 +1,6 @@ -using MelonLoader; +using DesktopVRIK.Properties; +using MelonLoader; using System.Reflection; -using DesktopVRIK.Properties; [assembly: AssemblyVersion(AssemblyInfoParams.Version)] From 65896d5f1438c3f7d9500a7808d39e4137f6ecdc Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Wed, 28 Dec 2022 00:11:14 -0600 Subject: [PATCH 11/60] Added PlantFeet & EnforceViewPosition Settings. --- DesktopVRIK/DesktopVRIK.cs | 26 ++++++++++++++++++++++++-- DesktopVRIK/HarmonyPatches.cs | 19 +++++++++++++++++++ DesktopVRIK/Main.cs | 6 +++++- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index 7e28795..06f66cc 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -15,20 +15,35 @@ public class DesktopVRIK : MonoBehaviour public bool Setting_Enabled; public bool Setting_EmulateVRChatHipMovement; + public bool Setting_EnforceViewPosition; public bool Setting_EmoteVRIK; public bool Setting_EmoteLookAtIK; + public bool Setting_PlantFeet; + + public Transform viewpoint; + public Vector3 initialCamPos; void Start() { Instance = this; } + public void ChangeViewpointHandling(bool enabled) + { + Setting_EnforceViewPosition = enabled; + if (enabled) + { + PlayerSetup.Instance.desktopCamera.transform.localPosition = Vector3.zero; + return; + } + PlayerSetup.Instance.desktopCamera.transform.localPosition = initialCamPos; + } + public void OnPreSolverUpdate() { //Reset avatar offset (VRIK will literally make you walk away from root otherwise) IKSystem.vrik.transform.localPosition = Vector3.zero; IKSystem.vrik.transform.localRotation = Quaternion.identity; - //VRChat hip movement emulation if (Setting_EmulateVRChatHipMovement) { @@ -38,6 +53,7 @@ public class DesktopVRIK : MonoBehaviour Quaternion rotation = Quaternion.AngleAxis(angle * weight, IKSystem.Instance.avatar.transform.right); IKSystem.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Head, rotation); } + IKSystem.vrik.solver.plantFeet = Setting_PlantFeet; } public void CalibrateDesktopVRIK(CVRAvatar avatar) @@ -63,8 +79,14 @@ public class DesktopVRIK : MonoBehaviour //ChilloutVR specific stuff + //Find eyeoffset + initialCamPos = PlayerSetup.Instance.desktopCamera.transform.localPosition; + Transform headTransform = IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.Head); + viewpoint = headTransform.Find("LocalHeadPoint"); + ChangeViewpointHandling(Setting_EnforceViewPosition); + //centerEyeAnchor now is head bone - Transform headAnchor = FindIKTarget(IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.Head)); + Transform headAnchor = FindIKTarget(headTransform); IKSystem.Instance.headAnchorPositionOffset = Vector3.zero; IKSystem.Instance.headAnchorRotationOffset = Vector3.zero; IKSystem.Instance.ApplyAvatarScaleToIk(avatar.viewPosition.y); diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index e2b05fc..fb2d796 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -3,6 +3,8 @@ using ABI_RC.Core.Player; using ABI_RC.Core.Savior; using ABI_RC.Systems.IK; using ABI_RC.Systems.IK.SubSystems; +using ABI_RC.Systems.MovementSystem; +using ABI_RC.Core.Player.AvatarTracking.Local; using HarmonyLib; using RootMotion.FinalIK; using UnityEngine; @@ -88,4 +90,21 @@ internal class HarmonyPatches } } } + + [HarmonyPostfix] + [HarmonyPatch(typeof(PlayerSetup), "HandleDesktopCameraPosition")] + private static void Postfix_PlayerSetup_HandleDesktopCameraPosition(bool ignore, ref PlayerSetup __instance, ref MovementSystem ____movementSystem, ref int ___headBobbingLevel) + { + if (DesktopVRIK.Instance.Setting_EnforceViewPosition) + { + if (!____movementSystem.disableCameraControl || ignore) + { + if (___headBobbingLevel == 2 && DesktopVRIK.Instance.viewpoint != null) + { + __instance.desktopCamera.transform.localPosition = Vector3.zero; + __instance.desktopCameraRig.transform.position = DesktopVRIK.Instance.viewpoint.position; + } + } + } + } } \ No newline at end of file diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index 539c7b8..ffed9c8 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -7,14 +7,16 @@ public class DesktopVRIKMod : MelonMod { internal const string SettingsCategory = "DesktopVRIK"; private static MelonPreferences_Category m_categoryDesktopVRIK; - private static MelonPreferences_Entry m_entryEnabled, m_entryEmulateHipMovement, m_entryEmoteVRIK, m_entryEmoteLookAtIK; + private static MelonPreferences_Entry m_entryEnabled, m_entryEmulateHipMovement, m_entryEnforceViewPosition, m_entryEmoteVRIK, m_entryEmoteLookAtIK, m_entryPlantFeet; public override void OnInitializeMelon() { m_categoryDesktopVRIK = MelonPreferences.CreateCategory(SettingsCategory); m_entryEnabled = m_categoryDesktopVRIK.CreateEntry("Enabled", true, description: "Attempt to give Desktop VRIK on avatar load."); m_entryEmulateHipMovement = m_categoryDesktopVRIK.CreateEntry("Emulate Hip Movement", true, description: "Emulates VRChat-like hip movement when moving head up/down on desktop."); + m_entryEnforceViewPosition = m_categoryDesktopVRIK.CreateEntry("Enforce View Position", false, description: "Corrects view position to use VRIK offsets."); m_entryEmoteVRIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote VRIK", true, description: "Disable VRIK while emoting. Only disable if you are ok with looking dumb."); m_entryEmoteLookAtIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote LookAtIK", true, description: "Disable LookAtIK while emoting. This setting doesn't really matter, as LookAtIK isn't networked while doing an emote."); + m_entryPlantFeet = m_categoryDesktopVRIK.CreateEntry("Plant Feet", true, description: "Enables Plant Feet for VRIK while in Desktop. Keeps avatar on ground when entering Idle instead of hovering."); foreach (var setting in m_categoryDesktopVRIK.Entries) { @@ -41,6 +43,8 @@ public class DesktopVRIKMod : MelonMod DesktopVRIK.Instance.Setting_EmulateVRChatHipMovement = m_entryEmulateHipMovement.Value; DesktopVRIK.Instance.Setting_EmoteVRIK = m_entryEmoteVRIK.Value; DesktopVRIK.Instance.Setting_EmoteLookAtIK = m_entryEmoteLookAtIK.Value; + DesktopVRIK.Instance.Setting_PlantFeet = m_entryPlantFeet.Value; + DesktopVRIK.Instance.ChangeViewpointHandling(m_entryEnforceViewPosition.Value); } private void OnUpdateSettings(object arg1, object arg2) => UpdateAllSettings(); From a4dba09c2129dfc2344b7692e1c62c394b5c1a12 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Wed, 28 Dec 2022 12:46:00 -0600 Subject: [PATCH 12/60] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index e48d9ba..804a49a 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,11 @@ Additional option to emulate VRChat-like hip movement if you like becoming a fis Control over disabling VRIK & LookAtIK during Emotes. (this can cause funky behavior) +## Relevant Feedback Posts: +https://feedback.abinteractive.net/p/desktop-feet-ik-for-avatars + +https://feedback.abinteractive.net/p/pivot-desktop-camera-with-head + --- Here is the block of text where I tell you this mod is not affiliated or endorsed by ABI. From c89497fe352dcff5464722c8f49a28b54b16f168 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Tue, 3 Jan 2023 01:18:30 -0600 Subject: [PATCH 13/60] a --- DesktopVRIK/Properties/AssemblyInfo.cs | 2 +- DesktopVRIK/format.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs index 135711e..a048daf 100644 --- a/DesktopVRIK/Properties/AssemblyInfo.cs +++ b/DesktopVRIK/Properties/AssemblyInfo.cs @@ -25,6 +25,6 @@ using System.Reflection; namespace DesktopVRIK.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.2"; + public const string Version = "1.0.3"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json index 0caa9b1..5fc0a93 100644 --- a/DesktopVRIK/format.json +++ b/DesktopVRIK/format.json @@ -1,12 +1,12 @@ { "_id": 117, "name": "DesktopVRIK", - "modversion": "1.0.2", + "modversion": "1.0.3", "gameversion": "2022r170", "loaderversion": "0.5.7", "modtype": "Mod", "author": "NotAKidoS", - "description": "Adds VRIK to Desktop avatars. No longer will you be a liveless sliding statue~!\nAdds the small feet stepping when looking around on Desktop.\n\nAdditional option to emulate VRChat-like hip movement if you like being fish.\nThis mod pairs well with Avatar Motion Tweaker by SDraw.", + "description": "Adds VRIK to Desktop avatars. No longer will you be a liveless sliding statue~!\nAdds the small feet stepping when looking around on Desktop.\n\nAdditional option to emulate VRChat-like hip movement if you like being fish.", "searchtags": [ "desktop", "vrik", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v1.0.2/DesktopVRIK.dll", + "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v1.0.3/DesktopVRIK.dll", "sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRIK/", - "changelog": "Simplified VRIK calibration to avoid low heel issue.\nRemoved rushed compatibility mode & implemented integrity checks for valid Humanoid rigs.", + "changelog": "- Simplified VRIK calibration to avoid low heel issue.\n- Removed rushed compatibility mode.\n- Added checks for valid Humanoid rigs.\n- Added PlantFeet & EnforceViewPosition Settings.", "embedcolor": "9b59b6" } \ No newline at end of file From 04de34d5d3a5ad7de959e51901cabc2abd85abaa Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Tue, 10 Jan 2023 20:20:50 -0600 Subject: [PATCH 14/60] Added HipMovement Weight & Fixed Emote avatar position --- DesktopVRIK/DesktopVRIK.cs | 15 ++++++++------- DesktopVRIK/HarmonyPatches.cs | 4 ++++ DesktopVRIK/Main.cs | 11 ++++++++++- DesktopVRIK/Properties/AssemblyInfo.cs | 2 +- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index 06f66cc..9377ce1 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -13,12 +13,13 @@ public class DesktopVRIK : MonoBehaviour { public static DesktopVRIK Instance; - public bool Setting_Enabled; - public bool Setting_EmulateVRChatHipMovement; - public bool Setting_EnforceViewPosition; - public bool Setting_EmoteVRIK; - public bool Setting_EmoteLookAtIK; - public bool Setting_PlantFeet; + public bool Setting_Enabled, + Setting_EmulateVRChatHipMovement, + Setting_EnforceViewPosition, + Setting_EmoteVRIK, + Setting_EmoteLookAtIK, + Setting_PlantFeet; + public float Setting_EmulateVRChatHipMovementWeight; public Transform viewpoint; public Vector3 initialCamPos; @@ -49,7 +50,7 @@ public class DesktopVRIK : MonoBehaviour { float angle = PlayerSetup.Instance.desktopCamera.transform.localEulerAngles.x; angle = (angle > 180) ? angle - 360 : angle; - float weight = (1 - MovementSystem.Instance.movementVector.magnitude); + float weight = (Setting_EmulateVRChatHipMovementWeight - MovementSystem.Instance.movementVector.magnitude); Quaternion rotation = Quaternion.AngleAxis(angle * weight, IKSystem.Instance.avatar.transform.right); IKSystem.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Head, rotation); } diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index fb2d796..192163b 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -78,6 +78,8 @@ internal class HarmonyPatches { ___lookIK.enabled = false; } + IKSystem.vrik.transform.localPosition = Vector3.zero; + IKSystem.vrik.transform.localRotation = Quaternion.identity; } else if (!____emotePlaying && emotePlayed) { @@ -88,6 +90,8 @@ internal class HarmonyPatches { ___lookIK.enabled = true; } + IKSystem.vrik.transform.localPosition = Vector3.zero; + IKSystem.vrik.transform.localRotation = Quaternion.identity; } } diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index ffed9c8..bd6d50e 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -1,5 +1,6 @@ using ABI_RC.Core.Player; using MelonLoader; +using UnityEngine; namespace DesktopVRIK; @@ -7,12 +8,19 @@ public class DesktopVRIKMod : MelonMod { internal const string SettingsCategory = "DesktopVRIK"; private static MelonPreferences_Category m_categoryDesktopVRIK; - private static MelonPreferences_Entry m_entryEnabled, m_entryEmulateHipMovement, m_entryEnforceViewPosition, m_entryEmoteVRIK, m_entryEmoteLookAtIK, m_entryPlantFeet; + private static MelonPreferences_Entry m_entryEnabled, + m_entryEmulateHipMovement, + m_entryEnforceViewPosition, + m_entryEmoteVRIK, + m_entryEmoteLookAtIK, + m_entryPlantFeet; + private static MelonPreferences_Entry m_entryEmulateVRChatHipMovementWeight; public override void OnInitializeMelon() { m_categoryDesktopVRIK = MelonPreferences.CreateCategory(SettingsCategory); m_entryEnabled = m_categoryDesktopVRIK.CreateEntry("Enabled", true, description: "Attempt to give Desktop VRIK on avatar load."); m_entryEmulateHipMovement = m_categoryDesktopVRIK.CreateEntry("Emulate Hip Movement", true, description: "Emulates VRChat-like hip movement when moving head up/down on desktop."); + m_entryEmulateVRChatHipMovementWeight = m_categoryDesktopVRIK.CreateEntry("Hip Movement Weight", 1f, description: "The weight modifier for the hip movement."); m_entryEnforceViewPosition = m_categoryDesktopVRIK.CreateEntry("Enforce View Position", false, description: "Corrects view position to use VRIK offsets."); m_entryEmoteVRIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote VRIK", true, description: "Disable VRIK while emoting. Only disable if you are ok with looking dumb."); m_entryEmoteLookAtIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote LookAtIK", true, description: "Disable LookAtIK while emoting. This setting doesn't really matter, as LookAtIK isn't networked while doing an emote."); @@ -41,6 +49,7 @@ public class DesktopVRIKMod : MelonMod if (!DesktopVRIK.Instance) return; DesktopVRIK.Instance.Setting_Enabled = m_entryEnabled.Value; DesktopVRIK.Instance.Setting_EmulateVRChatHipMovement = m_entryEmulateHipMovement.Value; + DesktopVRIK.Instance.Setting_EmulateVRChatHipMovementWeight = Mathf.Clamp01(m_entryEmulateVRChatHipMovementWeight.Value); DesktopVRIK.Instance.Setting_EmoteVRIK = m_entryEmoteVRIK.Value; DesktopVRIK.Instance.Setting_EmoteLookAtIK = m_entryEmoteLookAtIK.Value; DesktopVRIK.Instance.Setting_PlantFeet = m_entryPlantFeet.Value; diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs index a048daf..47ffe51 100644 --- a/DesktopVRIK/Properties/AssemblyInfo.cs +++ b/DesktopVRIK/Properties/AssemblyInfo.cs @@ -25,6 +25,6 @@ using System.Reflection; namespace DesktopVRIK.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 From fb5c3c00b5e3a26ac8fe4a6779653f05a097a254 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Thu, 12 Jan 2023 07:48:18 -0600 Subject: [PATCH 15/60] attempt to fix compatibility with more avatars (Fuck you Default Robot Kyle)(Fuck you Default Robot Kyle)(Fuck you Default Robot Kyle)(Fuck you Default Robot Kyle)(Fuck you Default Robot Kyle)(Fuck you Default Robot Kyle)(Fuck you Default Robot Kyle) --- DesktopVRIK/DesktopVRIK.cs | 16 +++- DesktopVRIK/HarmonyPatches.cs | 142 ++++++++++++++++++++++++++++++++-- DesktopVRIK/Main.cs | 2 +- DesktopVRIK/format.json | 4 +- 4 files changed, 152 insertions(+), 12 deletions(-) diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index 9377ce1..83b8408 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -59,6 +59,12 @@ public class DesktopVRIK : MonoBehaviour public void CalibrateDesktopVRIK(CVRAvatar avatar) { + //Stuff to make bad armatures work (Fuck you Default Robot Kyle) + IKSystem.Instance.animator.cullingMode = AnimatorCullingMode.AlwaysAnimate; + avatar.transform.localPosition = Vector3.zero; + Quaternion originalRotation = avatar.transform.rotation; + avatar.transform.rotation = Quaternion.identity; + //Generic VRIK calibration shit IKSystem.vrik.fixTransforms = false; @@ -89,7 +95,7 @@ public class DesktopVRIK : MonoBehaviour //centerEyeAnchor now is head bone Transform headAnchor = FindIKTarget(headTransform); IKSystem.Instance.headAnchorPositionOffset = Vector3.zero; - IKSystem.Instance.headAnchorRotationOffset = Vector3.zero; + IKSystem.Instance.headAnchorRotationOffset = headAnchor.rotation.eulerAngles; //set to head bone world rotation (Fuck you Default Robot Kyle) IKSystem.Instance.ApplyAvatarScaleToIk(avatar.viewPosition.y); BodySystem.TrackingLeftArmEnabled = false; BodySystem.TrackingRightArmEnabled = false; @@ -97,8 +103,10 @@ public class DesktopVRIK : MonoBehaviour BodySystem.TrackingRightLegEnabled = false; IKSystem.vrik.solver.IKPositionWeight = 0f; IKSystem.vrik.enabled = false; - //Calibrate HeadIKOffset + + //Calibrate HeadIKOffset *(this is fucked on some avatars, (Fuck you Default Robot Kyle) but setting headAnchorRotationOffset to head rotation fixes (Fuck you Default Robot Kyle))* VRIKCalibrator.CalibrateHead(IKSystem.vrik, headAnchor, IKSystem.Instance.headAnchorPositionOffset, IKSystem.Instance.headAnchorRotationOffset); + IKSystem.vrik.enabled = true; IKSystem.vrik.solver.IKPositionWeight = 1f; IKSystem.vrik.solver.spine.maintainPelvisPosition = 0f; @@ -106,6 +114,10 @@ public class DesktopVRIK : MonoBehaviour { IKSystem.vrik.onPreSolverUpdate.AddListener(new UnityAction(this.OnPreSolverUpdate)); } + + //(Fuck you Default Robot Kyle).. oh wait nvm, not related + avatar.transform.rotation = originalRotation; + IKSystem.Instance.ResetIK(); } //This is built because original build placed IK Targets on all joints. diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index 192163b..07629d0 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -9,6 +9,30 @@ using HarmonyLib; using RootMotion.FinalIK; using UnityEngine; +/** + + The process of calibrating VRIK is fucking painful. + + Immediatly doing GetHumanPose() and then SetHumanPose() fixed heels in ground for all avatars. + + Setting the avatars rotation to identity, head rotation offset to head bone world rotation, and then calibrating head IK target (kinda) fixed only robot kyle. + + Enforcing a TPose only fixed my ferret avatars right shoulder. + + Mix and matching these, and changing order, fucks with random specific avatars with fucky armatures. + MOST AVATARS DONT EVEN CHANGE, ITS JUST THESE FEW SPECIFIC ONES + I NEED to look into an IKPose controller... + + Avatars of Note: + TurtleNeck Ferret- broken/inverted right shoulder + Space Robot Kyle- head ik target is rotated -90 90 0, so body/neck is fucked (Fuck you Default Robot Kyle) + Exteratta- the knees bend backwards like a fucking chicken... what the fuck im enforcing a tpose nowww + + Most other avatars play just fine. Never changes even when adding Tpose, rotating the avatar, headikrotationoffset, ect... + WHY (Fuck you Default Robot Kyle) + +**/ + namespace DesktopVRIK; [HarmonyPatch] @@ -37,20 +61,24 @@ internal class HarmonyPatches { if (IKSystem.Instance.animator != null && IKSystem.Instance.animator.avatar != null && IKSystem.Instance.animator.avatar.isHuman) { - //need IKSystem to see VRIK component for setup - if (____vrik == null) - { - ____vrik = avatar.gameObject.AddComponent(); - } - - //why the fuck does this fix bad armatures and heels in ground ??? + //why the fuck does this fix bad armatures and heels in ground ??? (this one is suprisingly not because of Default Robot Kyle) ... (Fuck you Default Robot Kyle) if (____poseHandler == null) { ____poseHandler = new HumanPoseHandler(IKSystem.Instance.animator.avatar, IKSystem.Instance.animator.transform); } ____poseHandler.GetHumanPose(ref ___humanPose); + for (int i = 0; i < TPoseMuscles.Length; i++) + { + IKSystem.Instance.ApplyMuscleValue((MuscleIndex)i, TPoseMuscles[i], ref ___humanPose.muscles); + } ____poseHandler.SetHumanPose(ref ___humanPose); + //need IKSystem to see VRIK component for setup + if (____vrik == null) + { + ____vrik = avatar.gameObject.AddComponent(); + } + //now I calibrate DesktopVRIK DesktopVRIK.Instance.CalibrateDesktopVRIK(avatar); } @@ -111,4 +139,104 @@ internal class HarmonyPatches } } } + + private static readonly float[] TPoseMuscles = new float[] + { + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0.6001086f, + 8.6213E-05f, + -0.0003308152f, + 0.9999163f, + -9.559652E-06f, + 3.41413E-08f, + -3.415095E-06f, + -1.024528E-07f, + 0.6001086f, + 8.602679E-05f, + -0.0003311098f, + 0.9999163f, + -9.510122E-06f, + 1.707468E-07f, + -2.732077E-06f, + 2.035554E-15f, + -2.748694E-07f, + 2.619475E-07f, + 0.401967f, + 0.3005583f, + 0.04102772f, + 0.9998822f, + -0.04634236f, + 0.002522987f, + 0.0003842837f, + -2.369134E-07f, + -2.232262E-07f, + 0.4019674f, + 0.3005582f, + 0.04103433f, + 0.9998825f, + -0.04634996f, + 0.00252335f, + 0.000383302f, + -1.52127f, + 0.2634507f, + 0.4322457f, + 0.6443988f, + 0.6669409f, + -0.4663372f, + 0.8116828f, + 0.8116829f, + 0.6678119f, + -0.6186608f, + 0.8116842f, + 0.8116842f, + 0.6677991f, + -0.619225f, + 0.8116842f, + 0.811684f, + 0.6670032f, + -0.465875f, + 0.811684f, + 0.8116836f, + -1.520098f, + 0.2613016f, + 0.432256f, + 0.6444503f, + 0.6668426f, + -0.4670413f, + 0.8116828f, + 0.8116828f, + 0.6677986f, + -0.6192409f, + 0.8116841f, + 0.811684f, + 0.6677839f, + -0.6198869f, + 0.8116839f, + 0.8116838f, + 0.6668782f, + -0.4667901f, + 0.8116842f, + 0.811684f + }; + } \ No newline at end of file diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index bd6d50e..6a25069 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -20,7 +20,7 @@ public class DesktopVRIKMod : MelonMod m_categoryDesktopVRIK = MelonPreferences.CreateCategory(SettingsCategory); m_entryEnabled = m_categoryDesktopVRIK.CreateEntry("Enabled", true, description: "Attempt to give Desktop VRIK on avatar load."); m_entryEmulateHipMovement = m_categoryDesktopVRIK.CreateEntry("Emulate Hip Movement", true, description: "Emulates VRChat-like hip movement when moving head up/down on desktop."); - m_entryEmulateVRChatHipMovementWeight = m_categoryDesktopVRIK.CreateEntry("Hip Movement Weight", 1f, description: "The weight modifier for the hip movement."); + m_entryEmulateVRChatHipMovementWeight = m_categoryDesktopVRIK.CreateEntry("Hip Movement Weight", 0.5f, description: "The weight modifier for the hip movement."); m_entryEnforceViewPosition = m_categoryDesktopVRIK.CreateEntry("Enforce View Position", false, description: "Corrects view position to use VRIK offsets."); m_entryEmoteVRIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote VRIK", true, description: "Disable VRIK while emoting. Only disable if you are ok with looking dumb."); m_entryEmoteLookAtIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote LookAtIK", true, description: "Disable LookAtIK while emoting. This setting doesn't really matter, as LookAtIK isn't networked while doing an emote."); diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json index 5fc0a93..0b534f6 100644 --- a/DesktopVRIK/format.json +++ b/DesktopVRIK/format.json @@ -1,7 +1,7 @@ { "_id": 117, "name": "DesktopVRIK", - "modversion": "1.0.3", + "modversion": "1.0.4", "gameversion": "2022r170", "loaderversion": "0.5.7", "modtype": "Mod", @@ -18,6 +18,6 @@ ], "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v1.0.3/DesktopVRIK.dll", "sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRIK/", - "changelog": "- Simplified VRIK calibration to avoid low heel issue.\n- Removed rushed compatibility mode.\n- Added checks for valid Humanoid rigs.\n- Added PlantFeet & EnforceViewPosition Settings.", + "changelog": "- Simplified VRIK calibration to avoid low heel issue.\n- Removed rushed compatibility mode.\n- Added checks for valid Humanoid rigs.\n- Added PlantFeet & EnforceViewPosition Settings.\n- Added Weight option for the VRChat-like hip movement.", "embedcolor": "9b59b6" } \ No newline at end of file From da42d3da5731114e4b8572b18511990d56fe42b7 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Fri, 13 Jan 2023 18:30:22 -0600 Subject: [PATCH 16/60] simplified mod, added proper BTKUILib support --- .../BTKUI_Integration/BTKUI_Integration.cs | 30 ++ DesktopVRIK/DesktopVRIK.cs | 57 +++- DesktopVRIK/DesktopVRIK.csproj | 12 +- DesktopVRIK/HarmonyPatches.cs | 319 +++++++++--------- DesktopVRIK/Main.cs | 56 +-- DesktopVRIK/Properties/AssemblyInfo.cs | 11 +- 6 files changed, 273 insertions(+), 212 deletions(-) create mode 100644 DesktopVRIK/BTKUI_Integration/BTKUI_Integration.cs diff --git a/DesktopVRIK/BTKUI_Integration/BTKUI_Integration.cs b/DesktopVRIK/BTKUI_Integration/BTKUI_Integration.cs new file mode 100644 index 0000000..c0b9b1c --- /dev/null +++ b/DesktopVRIK/BTKUI_Integration/BTKUI_Integration.cs @@ -0,0 +1,30 @@ +using System.Runtime.CompilerServices; +using BTKUILib; +using BTKUILib.UIObjects; + +namespace NAK.Melons.DesktopVRIK.BTKUI_Integration; + +public static class BTKUI_Integration +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static void Init() + { + Page miscPage = QuickMenuAPI.MiscTabPage; + Category CategoryUI = miscPage.AddCategory("DesktopVRIK"); + + var setting_Enabled = CategoryUI.AddToggle(DesktopVRIKMod.m_entryEnabled.DisplayName, DesktopVRIKMod.m_entryEnabled.Description, DesktopVRIKMod.m_entryEnabled.Value); + setting_Enabled.OnValueUpdated += b => DesktopVRIKMod.m_entryEnabled.Value = b; + + var setting_EnforceViewPosition = CategoryUI.AddToggle(DesktopVRIKMod.m_entryEnforceViewPosition.DisplayName, DesktopVRIKMod.m_entryEnforceViewPosition.Description, DesktopVRIKMod.m_entryEnforceViewPosition.Value); + setting_EnforceViewPosition.OnValueUpdated += b => DesktopVRIKMod.m_entryEnforceViewPosition.Value = b; + + var setting_DisableEmoteVRIK = CategoryUI.AddToggle(DesktopVRIKMod.m_entryEmoteVRIK.DisplayName, DesktopVRIKMod.m_entryEmoteVRIK.Description, DesktopVRIKMod.m_entryEmoteVRIK.Value); + setting_DisableEmoteVRIK.OnValueUpdated += b => DesktopVRIKMod.m_entryEmoteVRIK.Value = b; + + var setting_DisableEmoteLookAtIK = CategoryUI.AddToggle(DesktopVRIKMod.m_entryEmoteLookAtIK.DisplayName, DesktopVRIKMod.m_entryEmoteLookAtIK.Description, DesktopVRIKMod.m_entryEmoteLookAtIK.Value); + setting_DisableEmoteLookAtIK.OnValueUpdated += b => DesktopVRIKMod.m_entryEmoteLookAtIK.Value = b; + + var setting_EmulateHipMovementWeight = miscPage.AddSlider(DesktopVRIKMod.m_entryEmulateVRChatHipMovementWeight.DisplayName, DesktopVRIKMod.m_entryEmulateVRChatHipMovementWeight.Description, DesktopVRIKMod.m_entryEmulateVRChatHipMovementWeight.Value, 0f, 1f); + setting_EmulateHipMovementWeight.OnValueUpdated += f => DesktopVRIKMod.m_entryEmulateVRChatHipMovementWeight.Value = f; + } +} \ No newline at end of file diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index 83b8408..99c2dee 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -7,19 +7,17 @@ using RootMotion.FinalIK; using UnityEngine; using UnityEngine.Events; -namespace DesktopVRIK; +namespace NAK.Melons.DesktopVRIK; public class DesktopVRIK : MonoBehaviour { public static DesktopVRIK Instance; - public bool Setting_Enabled, - Setting_EmulateVRChatHipMovement, - Setting_EnforceViewPosition, - Setting_EmoteVRIK, - Setting_EmoteLookAtIK, - Setting_PlantFeet; - public float Setting_EmulateVRChatHipMovementWeight; + public static bool Setting_Enabled, + Setting_EnforceViewPosition, + Setting_EmoteVRIK, + Setting_EmoteLookAtIK; + public static float Setting_EmulateVRChatHipMovementWeight; public Transform viewpoint; public Vector3 initialCamPos; @@ -31,6 +29,7 @@ public class DesktopVRIK : MonoBehaviour public void ChangeViewpointHandling(bool enabled) { + if (Setting_EnforceViewPosition == enabled) return; Setting_EnforceViewPosition = enabled; if (enabled) { @@ -39,28 +38,43 @@ public class DesktopVRIK : MonoBehaviour } PlayerSetup.Instance.desktopCamera.transform.localPosition = initialCamPos; } - + public void OnPreSolverUpdate() { + //this order matters, rotation offset will be choppy if avatar is not cenetered first //Reset avatar offset (VRIK will literally make you walk away from root otherwise) IKSystem.vrik.transform.localPosition = Vector3.zero; IKSystem.vrik.transform.localRotation = Quaternion.identity; //VRChat hip movement emulation - if (Setting_EmulateVRChatHipMovement) + if (Setting_EmulateVRChatHipMovementWeight != 0) { float angle = PlayerSetup.Instance.desktopCamera.transform.localEulerAngles.x; - angle = (angle > 180) ? angle - 360 : angle; - float weight = (Setting_EmulateVRChatHipMovementWeight - MovementSystem.Instance.movementVector.magnitude); - Quaternion rotation = Quaternion.AngleAxis(angle * weight, IKSystem.Instance.avatar.transform.right); + if (angle > 180) angle -= 360; + float leanAmount = angle * (1 - MovementSystem.Instance.movementVector.magnitude) * Setting_EmulateVRChatHipMovementWeight; + Quaternion rotation = Quaternion.AngleAxis(leanAmount, IKSystem.Instance.avatar.transform.right); IKSystem.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Head, rotation); } - IKSystem.vrik.solver.plantFeet = Setting_PlantFeet; + IKSystem.vrik.solver.plantFeet = true; } public void CalibrateDesktopVRIK(CVRAvatar avatar) { + //ikpose layer (specified by avatar author) + int? ikposeLayerIndex = PlayerSetup.Instance.animatorManager.GetAnimatorLayerIndex("IKPose"); + int? locoLayerIndex = PlayerSetup.Instance.animatorManager.GetAnimatorLayerIndex("Locomotion/Emotes"); + + if (ikposeLayerIndex != -1) + { + PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("IKPose", 1f); + if (locoLayerIndex != -1) + { + PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("Locomotion/Emotes", 0f); + } + IKSystem.Instance.animator.Update(0f); + } + + //Stuff to make bad armatures work (Fuck you Default Robot Kyle) - IKSystem.Instance.animator.cullingMode = AnimatorCullingMode.AlwaysAnimate; avatar.transform.localPosition = Vector3.zero; Quaternion originalRotation = avatar.transform.rotation; avatar.transform.rotation = Quaternion.identity; @@ -69,10 +83,11 @@ public class DesktopVRIK : MonoBehaviour IKSystem.vrik.fixTransforms = false; IKSystem.vrik.solver.plantFeet = false; - IKSystem.vrik.solver.locomotion.weight = 1f; + IKSystem.vrik.solver.locomotion.weight = 0f; IKSystem.vrik.solver.locomotion.angleThreshold = 30f; IKSystem.vrik.solver.locomotion.maxLegStretch = 0.75f; //nuke weights + IKSystem.vrik.AutoDetectReferences(); IKSystem.vrik.solver.spine.headClampWeight = 0f; IKSystem.vrik.solver.spine.minHeadHeight = 0f; IKSystem.vrik.solver.leftArm.positionWeight = 0f; @@ -115,7 +130,15 @@ public class DesktopVRIK : MonoBehaviour IKSystem.vrik.onPreSolverUpdate.AddListener(new UnityAction(this.OnPreSolverUpdate)); } - //(Fuck you Default Robot Kyle).. oh wait nvm, not related + if (ikposeLayerIndex != -1) + { + PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("IKPose", 0f); + if (locoLayerIndex != -1) + { + PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("Locomotion/Emotes", 1f); + } + } + avatar.transform.rotation = originalRotation; IKSystem.Instance.ResetIK(); } diff --git a/DesktopVRIK/DesktopVRIK.csproj b/DesktopVRIK/DesktopVRIK.csproj index c947a92..c432ed3 100644 --- a/DesktopVRIK/DesktopVRIK.csproj +++ b/DesktopVRIK/DesktopVRIK.csproj @@ -18,21 +18,21 @@ ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll + + ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\BTKUILib.dll + ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll - - ..\..\Giamoz\Giamoz\bin\Debug\net472\Giamoz.dll - C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\MelonLoader\MelonLoader.dll - - C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\SteamVR.dll - ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll + + ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AssetBundleModule.dll + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index 07629d0..7f4132e 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -4,7 +4,6 @@ using ABI_RC.Core.Savior; using ABI_RC.Systems.IK; using ABI_RC.Systems.IK.SubSystems; using ABI_RC.Systems.MovementSystem; -using ABI_RC.Core.Player.AvatarTracking.Local; using HarmonyLib; using RootMotion.FinalIK; using UnityEngine; @@ -33,17 +32,17 @@ using UnityEngine; **/ -namespace DesktopVRIK; +namespace NAK.Melons.DesktopVRIK.HarmonyPatches; -[HarmonyPatch] -internal class HarmonyPatches +class PlayerSetupPatches { + private static bool emotePlayed = false; [HarmonyPostfix] [HarmonyPatch(typeof(PlayerSetup), "SetupAvatarGeneral")] - private static void SetupDesktopIKSystem(ref CVRAvatar ____avatarDescriptor, ref Animator ____animator) + static void SetupDesktopIKSystem(ref CVRAvatar ____avatarDescriptor, ref Animator ____animator) { - if (!MetaPort.Instance.isUsingVr && DesktopVRIK.Instance.Setting_Enabled) + if (!MetaPort.Instance.isUsingVr && DesktopVRIK.Setting_Enabled) { if (____avatarDescriptor != null && ____animator != null && ____animator.isHuman) { @@ -53,11 +52,56 @@ internal class HarmonyPatches } } + [HarmonyPostfix] + [HarmonyPatch(typeof(PlayerSetup), "Update")] + private static void CorrectVRIK(ref bool ____emotePlaying, ref LookAtIK ___lookIK) + { + if (!MetaPort.Instance.isUsingVr && DesktopVRIK.Setting_Enabled) + { + bool changed = ____emotePlaying != emotePlayed; + if (changed) + { + emotePlayed = ____emotePlaying; + IKSystem.vrik.transform.localPosition = Vector3.zero; + IKSystem.vrik.transform.localRotation = Quaternion.identity; + if (DesktopVRIK.Setting_EmoteLookAtIK && ___lookIK != null) + { + ___lookIK.enabled = !____emotePlaying; + } + if (DesktopVRIK.Setting_EmoteVRIK) + { + BodySystem.TrackingEnabled = !____emotePlaying; + IKSystem.vrik.solver?.Reset(); + } + } + } + } + + [HarmonyPostfix] + [HarmonyPatch(typeof(PlayerSetup), "HandleDesktopCameraPosition")] + private static void Postfix_PlayerSetup_HandleDesktopCameraPosition(bool ignore, ref PlayerSetup __instance, ref MovementSystem ____movementSystem, ref int ___headBobbingLevel) + { + if (DesktopVRIK.Setting_Enabled && DesktopVRIK.Setting_EnforceViewPosition) + { + if (!____movementSystem.disableCameraControl || ignore) + { + if (___headBobbingLevel == 2 && DesktopVRIK.Instance.viewpoint != null) + { + __instance.desktopCamera.transform.localPosition = Vector3.zero; + __instance.desktopCameraRig.transform.position = DesktopVRIK.Instance.viewpoint.position; + } + } + } + } +} + +class IKSystemPatches +{ [HarmonyPostfix] [HarmonyPatch(typeof(IKSystem), "InitializeAvatar")] private static void InitializeDesktopAvatarVRIK(CVRAvatar avatar, ref VRIK ____vrik, ref HumanPoseHandler ____poseHandler, ref HumanPose ___humanPose) { - if (!MetaPort.Instance.isUsingVr && DesktopVRIK.Instance.Setting_Enabled) + if (!MetaPort.Instance.isUsingVr && DesktopVRIK.Setting_Enabled) { if (IKSystem.Instance.animator != null && IKSystem.Instance.animator.avatar != null && IKSystem.Instance.animator.avatar.isHuman) { @@ -66,11 +110,12 @@ internal class HarmonyPatches { ____poseHandler = new HumanPoseHandler(IKSystem.Instance.animator.avatar, IKSystem.Instance.animator.transform); } + ____poseHandler.GetHumanPose(ref ___humanPose); - for (int i = 0; i < TPoseMuscles.Length; i++) - { - IKSystem.Instance.ApplyMuscleValue((MuscleIndex)i, TPoseMuscles[i], ref ___humanPose.muscles); - } + //for (int i = 0; i < TPoseMuscles.Length; i++) + //{ + // IKSystem.Instance.ApplyMuscleValue((MuscleIndex)i, TPoseMuscles[i], ref ___humanPose.muscles); + //} ____poseHandler.SetHumanPose(ref ___humanPose); //need IKSystem to see VRIK component for setup @@ -85,158 +130,102 @@ internal class HarmonyPatches } } - private static bool emotePlayed = false; - - [HarmonyPostfix] - [HarmonyPatch(typeof(PlayerSetup), "Update")] - private static void CorrectVRIK(ref bool ____emotePlaying, ref LookAtIK ___lookIK) + private static readonly float[] TPoseMuscles = new float[] { - if (MetaPort.Instance.isUsingVr || DesktopVRIK.Instance == null) return; - - //might need to rework this in the future - if (____emotePlaying && !emotePlayed) - { - emotePlayed = true; - if (DesktopVRIK.Instance.Setting_EmoteVRIK) - { - BodySystem.TrackingEnabled = false; - //IKSystem.vrik.solver.Reset(); - } - if (DesktopVRIK.Instance.Setting_EmoteLookAtIK && ___lookIK != null) - { - ___lookIK.enabled = false; - } - IKSystem.vrik.transform.localPosition = Vector3.zero; - IKSystem.vrik.transform.localRotation = Quaternion.identity; - } - else if (!____emotePlaying && emotePlayed) - { - emotePlayed = false; - IKSystem.vrik.solver.Reset(); - BodySystem.TrackingEnabled = true; - if (___lookIK != null) - { - ___lookIK.enabled = true; - } - IKSystem.vrik.transform.localPosition = Vector3.zero; - IKSystem.vrik.transform.localRotation = Quaternion.identity; - } - } - - [HarmonyPostfix] - [HarmonyPatch(typeof(PlayerSetup), "HandleDesktopCameraPosition")] - private static void Postfix_PlayerSetup_HandleDesktopCameraPosition(bool ignore, ref PlayerSetup __instance, ref MovementSystem ____movementSystem, ref int ___headBobbingLevel) - { - if (DesktopVRIK.Instance.Setting_EnforceViewPosition) - { - if (!____movementSystem.disableCameraControl || ignore) - { - if (___headBobbingLevel == 2 && DesktopVRIK.Instance.viewpoint != null) - { - __instance.desktopCamera.transform.localPosition = Vector3.zero; - __instance.desktopCameraRig.transform.position = DesktopVRIK.Instance.viewpoint.position; - } - } - } - } - - private static readonly float[] TPoseMuscles = new float[] - { - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0.6001086f, - 8.6213E-05f, - -0.0003308152f, - 0.9999163f, - -9.559652E-06f, - 3.41413E-08f, - -3.415095E-06f, - -1.024528E-07f, - 0.6001086f, - 8.602679E-05f, - -0.0003311098f, - 0.9999163f, - -9.510122E-06f, - 1.707468E-07f, - -2.732077E-06f, - 2.035554E-15f, - -2.748694E-07f, - 2.619475E-07f, - 0.401967f, - 0.3005583f, - 0.04102772f, - 0.9998822f, - -0.04634236f, - 0.002522987f, - 0.0003842837f, - -2.369134E-07f, - -2.232262E-07f, - 0.4019674f, - 0.3005582f, - 0.04103433f, - 0.9998825f, - -0.04634996f, - 0.00252335f, - 0.000383302f, - -1.52127f, - 0.2634507f, - 0.4322457f, - 0.6443988f, - 0.6669409f, - -0.4663372f, - 0.8116828f, - 0.8116829f, - 0.6678119f, - -0.6186608f, - 0.8116842f, - 0.8116842f, - 0.6677991f, - -0.619225f, - 0.8116842f, - 0.811684f, - 0.6670032f, - -0.465875f, - 0.811684f, - 0.8116836f, - -1.520098f, - 0.2613016f, - 0.432256f, - 0.6444503f, - 0.6668426f, - -0.4670413f, - 0.8116828f, - 0.8116828f, - 0.6677986f, - -0.6192409f, - 0.8116841f, - 0.811684f, - 0.6677839f, - -0.6198869f, - 0.8116839f, - 0.8116838f, - 0.6668782f, - -0.4667901f, - 0.8116842f, - 0.811684f - }; - -} \ No newline at end of file + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0.6001086f, + 8.6213E-05f, + -0.0003308152f, + 0.9999163f, + -9.559652E-06f, + 3.41413E-08f, + -3.415095E-06f, + -1.024528E-07f, + 0.6001086f, + 8.602679E-05f, + -0.0003311098f, + 0.9999163f, + -9.510122E-06f, + 1.707468E-07f, + -2.732077E-06f, + 2.035554E-15f, + -2.748694E-07f, + 2.619475E-07f, + 0.401967f, + 0.3005583f, + 0.04102772f, + 0.9998822f, + -0.04634236f, + 0.002522987f, + 0.0003842837f, + -2.369134E-07f, + -2.232262E-07f, + 0.4019674f, + 0.3005582f, + 0.04103433f, + 0.9998825f, + -0.04634996f, + 0.00252335f, + 0.000383302f, + -1.52127f, + 0.2634507f, + 0.4322457f, + 0.6443988f, + 0.6669409f, + -0.4663372f, + 0.8116828f, + 0.8116829f, + 0.6678119f, + -0.6186608f, + 0.8116842f, + 0.8116842f, + 0.6677991f, + -0.619225f, + 0.8116842f, + 0.811684f, + 0.6670032f, + -0.465875f, + 0.811684f, + 0.8116836f, + -1.520098f, + 0.2613016f, + 0.432256f, + 0.6444503f, + 0.6668426f, + -0.4670413f, + 0.8116828f, + 0.8116828f, + 0.6677986f, + -0.6192409f, + 0.8116841f, + 0.811684f, + 0.6677839f, + -0.6198869f, + 0.8116839f, + 0.8116838f, + 0.6668782f, + -0.4667901f, + 0.8116842f, + 0.811684f + }; +} diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index 6a25069..e236813 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -2,35 +2,42 @@ using MelonLoader; using UnityEngine; -namespace DesktopVRIK; +namespace NAK.Melons.DesktopVRIK; public class DesktopVRIKMod : MelonMod { internal const string SettingsCategory = "DesktopVRIK"; - private static MelonPreferences_Category m_categoryDesktopVRIK; - private static MelonPreferences_Entry m_entryEnabled, - m_entryEmulateHipMovement, - m_entryEnforceViewPosition, - m_entryEmoteVRIK, - m_entryEmoteLookAtIK, - m_entryPlantFeet; - private static MelonPreferences_Entry m_entryEmulateVRChatHipMovementWeight; + internal static MelonPreferences_Category m_categoryDesktopVRIK; + internal static MelonPreferences_Entry m_entryEnabled, + m_entryEnforceViewPosition, + m_entryEmoteVRIK, + m_entryEmoteLookAtIK; + internal static MelonPreferences_Entry m_entryEmulateVRChatHipMovementWeight; public override void OnInitializeMelon() { m_categoryDesktopVRIK = MelonPreferences.CreateCategory(SettingsCategory); - m_entryEnabled = m_categoryDesktopVRIK.CreateEntry("Enabled", true, description: "Attempt to give Desktop VRIK on avatar load."); - m_entryEmulateHipMovement = m_categoryDesktopVRIK.CreateEntry("Emulate Hip Movement", true, description: "Emulates VRChat-like hip movement when moving head up/down on desktop."); - m_entryEmulateVRChatHipMovementWeight = m_categoryDesktopVRIK.CreateEntry("Hip Movement Weight", 0.5f, description: "The weight modifier for the hip movement."); + m_entryEnabled = m_categoryDesktopVRIK.CreateEntry("Enabled", true, description: "Toggle DesktopVRIK entirely. Requires avatar reload."); + m_entryEmulateVRChatHipMovementWeight = m_categoryDesktopVRIK.CreateEntry("Body Movement Weight", 0.5f, description: "Emulates VRChat-like body movement when looking up/down. Set to 0 to disable."); m_entryEnforceViewPosition = m_categoryDesktopVRIK.CreateEntry("Enforce View Position", false, description: "Corrects view position to use VRIK offsets."); m_entryEmoteVRIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote VRIK", true, description: "Disable VRIK while emoting. Only disable if you are ok with looking dumb."); m_entryEmoteLookAtIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote LookAtIK", true, description: "Disable LookAtIK while emoting. This setting doesn't really matter, as LookAtIK isn't networked while doing an emote."); - m_entryPlantFeet = m_categoryDesktopVRIK.CreateEntry("Plant Feet", true, description: "Enables Plant Feet for VRIK while in Desktop. Keeps avatar on ground when entering Idle instead of hovering."); foreach (var setting in m_categoryDesktopVRIK.Entries) { setting.OnEntryValueChangedUntyped.Subscribe(OnUpdateSettings); } + //BTKUILib Misc Support + if (MelonMod.RegisteredMelons.Any(it => it.Info.Name == "BTKUILib")) + { + MelonLogger.Msg("Initializing BTKUILib support."); + BTKUI_Integration.BTKUI_Integration.Init(); + } + + //Apply patches (i stole) + ApplyPatches(typeof(HarmonyPatches.PlayerSetupPatches)); + ApplyPatches(typeof(HarmonyPatches.IKSystemPatches)); + MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); } @@ -47,14 +54,25 @@ public class DesktopVRIKMod : MelonMod private void UpdateAllSettings() { if (!DesktopVRIK.Instance) return; - DesktopVRIK.Instance.Setting_Enabled = m_entryEnabled.Value; - DesktopVRIK.Instance.Setting_EmulateVRChatHipMovement = m_entryEmulateHipMovement.Value; - DesktopVRIK.Instance.Setting_EmulateVRChatHipMovementWeight = Mathf.Clamp01(m_entryEmulateVRChatHipMovementWeight.Value); - DesktopVRIK.Instance.Setting_EmoteVRIK = m_entryEmoteVRIK.Value; - DesktopVRIK.Instance.Setting_EmoteLookAtIK = m_entryEmoteLookAtIK.Value; - DesktopVRIK.Instance.Setting_PlantFeet = m_entryPlantFeet.Value; + DesktopVRIK.Setting_Enabled = m_entryEnabled.Value; + DesktopVRIK.Setting_EmulateVRChatHipMovementWeight = Mathf.Clamp01(m_entryEmulateVRChatHipMovementWeight.Value); + DesktopVRIK.Setting_EmoteVRIK = m_entryEmoteVRIK.Value; + DesktopVRIK.Setting_EmoteLookAtIK = m_entryEmoteLookAtIK.Value; DesktopVRIK.Instance.ChangeViewpointHandling(m_entryEnforceViewPosition.Value); } private void OnUpdateSettings(object arg1, object arg2) => UpdateAllSettings(); + + private void ApplyPatches(Type type) + { + try + { + HarmonyInstance.PatchAll(type); + } + catch (Exception e) + { + LoggerInstance.Msg($"Failed while patching {type.Name}!"); + LoggerInstance.Error(e); + } + } } \ No newline at end of file diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs index 47ffe51..fecfa4f 100644 --- a/DesktopVRIK/Properties/AssemblyInfo.cs +++ b/DesktopVRIK/Properties/AssemblyInfo.cs @@ -6,13 +6,13 @@ using System.Reflection; [assembly: AssemblyVersion(AssemblyInfoParams.Version)] [assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] [assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] -[assembly: AssemblyTitle(nameof(DesktopVRIK))] +[assembly: AssemblyTitle(nameof(NAK.Melons.DesktopVRIK))] [assembly: AssemblyCompany(AssemblyInfoParams.Author)] -[assembly: AssemblyProduct(nameof(DesktopVRIK))] +[assembly: AssemblyProduct(nameof(NAK.Melons.DesktopVRIK))] [assembly: MelonInfo( - typeof(DesktopVRIK.DesktopVRIKMod), - nameof(DesktopVRIK), + typeof(NAK.Melons.DesktopVRIK.DesktopVRIKMod), + nameof(NAK.Melons.DesktopVRIK), AssemblyInfoParams.Version, AssemblyInfoParams.Author, downloadLink: "https://github.com/NotAKidOnSteam/DesktopVRIK" @@ -21,10 +21,11 @@ using System.Reflection; [assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: MelonOptionalDependencies("BTKUILib")] namespace DesktopVRIK.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.4"; + public const string Version = "1.0.5"; public const string Author = "NotAKidoS"; } \ No newline at end of file From 8f4d146ba00185dcf0465bc542dfbc798d0e4585 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Fri, 13 Jan 2023 19:26:40 -0600 Subject: [PATCH 17/60] testing --- DesktopVRIK/DesktopVRIK.cs | 3 +- DesktopVRIK/HarmonyPatches.cs | 202 +++++++++++++++++----------------- 2 files changed, 104 insertions(+), 101 deletions(-) diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index 99c2dee..c2c5b36 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -83,7 +83,7 @@ public class DesktopVRIK : MonoBehaviour IKSystem.vrik.fixTransforms = false; IKSystem.vrik.solver.plantFeet = false; - IKSystem.vrik.solver.locomotion.weight = 0f; + IKSystem.vrik.solver.locomotion.weight = 1f; IKSystem.vrik.solver.locomotion.angleThreshold = 30f; IKSystem.vrik.solver.locomotion.maxLegStretch = 0.75f; //nuke weights @@ -141,6 +141,7 @@ public class DesktopVRIK : MonoBehaviour avatar.transform.rotation = originalRotation; IKSystem.Instance.ResetIK(); + IKSystem.Instance.animator.enabled = true; } //This is built because original build placed IK Targets on all joints. diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index 7f4132e..8ceb5a3 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -105,6 +105,8 @@ class IKSystemPatches { if (IKSystem.Instance.animator != null && IKSystem.Instance.animator.avatar != null && IKSystem.Instance.animator.avatar.isHuman) { + IKSystem.Instance.animator.enabled = false; + //why the fuck does this fix bad armatures and heels in ground ??? (this one is suprisingly not because of Default Robot Kyle) ... (Fuck you Default Robot Kyle) if (____poseHandler == null) { @@ -112,10 +114,10 @@ class IKSystemPatches } ____poseHandler.GetHumanPose(ref ___humanPose); - //for (int i = 0; i < TPoseMuscles.Length; i++) - //{ - // IKSystem.Instance.ApplyMuscleValue((MuscleIndex)i, TPoseMuscles[i], ref ___humanPose.muscles); - //} + for (int i = 0; i < IKPoseMuscles.Length; i++) + { + IKSystem.Instance.ApplyMuscleValue((MuscleIndex)i, IKPoseMuscles[i], ref ___humanPose.muscles); + } ____poseHandler.SetHumanPose(ref ___humanPose); //need IKSystem to see VRIK component for setup @@ -130,102 +132,102 @@ class IKSystemPatches } } - private static readonly float[] TPoseMuscles = new float[] + private static readonly float[] IKPoseMuscles = new float[] { - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0.6001086f, - 8.6213E-05f, - -0.0003308152f, - 0.9999163f, - -9.559652E-06f, - 3.41413E-08f, - -3.415095E-06f, - -1.024528E-07f, - 0.6001086f, - 8.602679E-05f, - -0.0003311098f, - 0.9999163f, - -9.510122E-06f, - 1.707468E-07f, - -2.732077E-06f, - 2.035554E-15f, - -2.748694E-07f, - 2.619475E-07f, - 0.401967f, - 0.3005583f, - 0.04102772f, - 0.9998822f, - -0.04634236f, - 0.002522987f, - 0.0003842837f, - -2.369134E-07f, - -2.232262E-07f, - 0.4019674f, - 0.3005582f, - 0.04103433f, - 0.9998825f, - -0.04634996f, - 0.00252335f, - 0.000383302f, - -1.52127f, - 0.2634507f, - 0.4322457f, - 0.6443988f, - 0.6669409f, - -0.4663372f, - 0.8116828f, - 0.8116829f, - 0.6678119f, - -0.6186608f, - 0.8116842f, - 0.8116842f, - 0.6677991f, - -0.619225f, - 0.8116842f, - 0.811684f, - 0.6670032f, - -0.465875f, - 0.811684f, - 0.8116836f, - -1.520098f, - 0.2613016f, - 0.432256f, - 0.6444503f, - 0.6668426f, - -0.4670413f, - 0.8116828f, - 0.8116828f, - 0.6677986f, - -0.6192409f, - 0.8116841f, - 0.811684f, - 0.6677839f, - -0.6198869f, - 0.8116839f, - 0.8116838f, - 0.6668782f, - -0.4667901f, - 0.8116842f, - 0.811684f + 0.00133321f, + 8.195831E-06f, + 8.537738E-07f, + -0.002669832f, + -7.651234E-06f, + -0.001659694f, + 0f, + 0f, + 0f, + 0.04213953f, + 0.0003007996f, + -0.008032114f, + -0.03059979f, + -0.0003182998f, + 0.009640567f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0.5768794f, + 0.01061097f, + -0.1127839f, + 0.9705755f, + 0.07972051f, + -0.0268422f, + 0.007237188f, + 0f, + 0.5768792f, + 0.01056608f, + -0.1127519f, + 0.9705756f, + 0.07971933f, + -0.02682396f, + 0.007229362f, + 0f, + -5.651802E-06f, + -3.034899E-07f, + 0.4100508f, + 0.3610304f, + -0.0838329f, + 0.9262537f, + 0.1353517f, + -0.03578902f, + 0.06005657f, + -4.95989E-06f, + -1.43007E-06f, + 0.4096187f, + 0.363263f, + -0.08205152f, + 0.9250782f, + 0.1345718f, + -0.03572125f, + 0.06055461f, + -1.079177f, + 0.2095419f, + 0.6140652f, + 0.6365265f, + 0.6683931f, + -0.4764312f, + 0.8099416f, + 0.8099371f, + 0.6658203f, + -0.7327053f, + 0.8113618f, + 0.8114051f, + 0.6643661f, + -0.40341f, + 0.8111364f, + 0.8111367f, + 0.6170399f, + -0.2524227f, + 0.8138723f, + 0.8110135f, + -1.079171f, + 0.2095456f, + 0.6140658f, + 0.6365255f, + 0.6683878f, + -0.4764301f, + 0.8099402f, + 0.8099376f, + 0.6658241f, + -0.7327023f, + 0.8113653f, + 0.8113793f, + 0.664364f, + -0.4034042f, + 0.811136f, + 0.8111364f, + 0.6170469f, + -0.2524345f, + 0.8138595f, + 0.8110138f }; } From 0f485ccaa3ea6138dcd90136ce9bb2f874cc25e0 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Fri, 13 Jan 2023 23:48:21 -0600 Subject: [PATCH 18/60] its working (FUCK) --- DesktopVRIK/AsserHandler.cs | 95 +++++++++++++++++++ DesktopVRIK/DesktopVRIK.cs | 116 ++++++++++++++++++++++- DesktopVRIK/DesktopVRIK.csproj | 8 ++ DesktopVRIK/HarmonyPatches.cs | 12 +-- DesktopVRIK/Main.cs | 1 + DesktopVRIK/resources/IKPose.assetbundle | Bin 0 -> 5847 bytes 6 files changed, 221 insertions(+), 11 deletions(-) create mode 100644 DesktopVRIK/AsserHandler.cs create mode 100644 DesktopVRIK/resources/IKPose.assetbundle diff --git a/DesktopVRIK/AsserHandler.cs b/DesktopVRIK/AsserHandler.cs new file mode 100644 index 0000000..b5e5c7d --- /dev/null +++ b/DesktopVRIK/AsserHandler.cs @@ -0,0 +1,95 @@ +using System.Reflection; +using UnityEngine; +using Object = UnityEngine.Object; + +/* + + Kindly stolen from SDraw's leap motion mod. (MIT) + https://github.com/SDraw/ml_mods_cvr/blob/master/ml_lme/AssetsHandler.cs + + *thank u sdraw, i wont be murderer now* + +*/ + +namespace NAK.Melons.DesktopVRIK; + +static class AssetsHandler +{ + static readonly List ms_assets = new List() + { + "IKPose.assetbundle" + }; + + static Dictionary ms_loadedAssets = new Dictionary(); + static Dictionary ms_loadedObjects = new Dictionary(); + + public static void Load() + { + Assembly l_assembly = Assembly.GetExecutingAssembly(); + string l_assemblyName = l_assembly.GetName().Name; + + foreach (string l_assetName in ms_assets) + { + try + { + Stream l_assetStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + l_assetName); + if (l_assetStream != null) + { + MemoryStream l_memorySteam = new MemoryStream((int)l_assetStream.Length); + l_assetStream.CopyTo(l_memorySteam); + AssetBundle l_assetBundle = AssetBundle.LoadFromMemory(l_memorySteam.ToArray(), 0); + if (l_assetBundle != null) + { + l_assetBundle.hideFlags |= HideFlags.DontUnloadUnusedAsset; + ms_loadedAssets.Add(l_assetName, l_assetBundle); + } + else + MelonLoader.MelonLogger.Warning("Unable to load bundled '" + l_assetName + "' asset"); + } + else + MelonLoader.MelonLogger.Warning("Unable to get bundled '" + l_assetName + "' asset stream"); + } + catch (System.Exception e) + { + MelonLoader.MelonLogger.Warning("Unable to load bundled '" + l_assetName + "' asset, reason: " + e.Message); + } + } + } + + public static Object GetAsset(string p_name) + { + Object l_result = null; + if (ms_loadedObjects.ContainsKey(p_name)) + { + l_result = UnityEngine.Object.Instantiate(ms_loadedObjects[p_name]); + //l_result.SetActive(true); + l_result.hideFlags |= HideFlags.DontUnloadUnusedAsset; + } + else + { + foreach (var l_pair in ms_loadedAssets) + { + if (l_pair.Value.Contains(p_name)) + { + Object l_bundledObject = (Object)l_pair.Value.LoadAsset(p_name, typeof(Object)); + if (l_bundledObject != null) + { + ms_loadedObjects.Add(p_name, l_bundledObject); + l_result = UnityEngine.Object.Instantiate(l_bundledObject); + //l_result.SetActive(true); + l_result.hideFlags |= HideFlags.DontUnloadUnusedAsset; + } + break; + } + } + } + return l_result; + } + + public static void Unload() + { + foreach (var l_pair in ms_loadedAssets) + UnityEngine.Object.Destroy(l_pair.Value); + ms_loadedAssets.Clear(); + } +} \ No newline at end of file diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index c2c5b36..64bf02b 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -16,15 +16,28 @@ public class DesktopVRIK : MonoBehaviour public static bool Setting_Enabled, Setting_EnforceViewPosition, Setting_EmoteVRIK, - Setting_EmoteLookAtIK; + Setting_EmoteLookAtIK, + Setting_AllowRootSlipping, + Setting_TestIKPoseController; public static float Setting_EmulateVRChatHipMovementWeight; public Transform viewpoint; public Vector3 initialCamPos; + Transform headIKTarget; + Transform avatarHeadBone; + + RuntimeAnimatorController ikposeController; + void Start() { Instance = this; + ikposeController = (RuntimeAnimatorController)AssetsHandler.GetAsset("Assets/BundledAssets/IKPose/IKPose.controller"); + // create the shared Head IK Target + headIKTarget = new GameObject("[DesktopVRIK] Head IK Target").transform; + headIKTarget.parent = PlayerSetup.Instance.transform; + headIKTarget.localPosition = new Vector3(0f,1.8f,0f); + headIKTarget.localRotation = Quaternion.identity; } public void ChangeViewpointHandling(bool enabled) @@ -172,4 +185,105 @@ public class DesktopVRIK : MonoBehaviour newTarget.transform.localRotation = Quaternion.identity; return newTarget.transform; } + + public void AlternativeOnPreSolverUpdate() + { + //this order matters, rotation offset will be choppy if avatar is not cenetered first + + if (headIKTarget != null && avatarHeadBone != null) + { + headIKTarget.position = new Vector3(headIKTarget.position.x, avatarHeadBone.position.y, headIKTarget.position.z); + } + + if (!Setting_AllowRootSlipping) + { + //Reset avatar offset (VRIK will literally make you walk away from root otherwise) + IKSystem.vrik.transform.localPosition = Vector3.zero; + IKSystem.vrik.transform.localRotation = Quaternion.identity; + } + + //VRChat hip movement emulation + if (Setting_EmulateVRChatHipMovementWeight != 0) + { + float angle = PlayerSetup.Instance.desktopCamera.transform.localEulerAngles.x; + if (angle > 180) angle -= 360; + float leanAmount = angle * (1 - MovementSystem.Instance.movementVector.magnitude) * Setting_EmulateVRChatHipMovementWeight; + Quaternion rotation = Quaternion.AngleAxis(leanAmount, IKSystem.Instance.avatar.transform.right); + IKSystem.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Head, rotation); + } + + IKSystem.vrik.solver.plantFeet = true; + } + + public Animator animator; + public Quaternion originalRotation; + public RuntimeAnimatorController runtimeAnimatorController; + + public VRIK AlternativeCalibration(CVRAvatar avatar) + { + animator = avatar.GetComponent(); + avatarHeadBone = animator.GetBoneTransform(HumanBodyBones.Head); + + //Stuff to make bad armatures work (Fuck you Default Robot Kyle) + avatar.transform.localPosition = Vector3.zero; + originalRotation = avatar.transform.rotation; + avatar.transform.rotation = Quaternion.identity; + + //force immediate calibration before animator decides to fuck us + VRIK vrik = avatar.gameObject.AddComponent(); + vrik.AutoDetectReferences(); + vrik.solver.SetToReferences(vrik.references); + vrik.solver.Initiate(vrik.transform); + + if (Setting_TestIKPoseController) + { + //Destroy(vrik); + return vrik; + } + + //Generic VRIK calibration shit + + vrik.fixTransforms = true; + vrik.solver.plantFeet = false; + vrik.solver.locomotion.weight = 0f; + vrik.solver.locomotion.angleThreshold = 30f; + vrik.solver.locomotion.maxLegStretch = 0.75f; + //nuke weights + vrik.solver.spine.headClampWeight = 0f; + vrik.solver.spine.minHeadHeight = 0f; + vrik.solver.spine.pelvisPositionWeight = 0f; + vrik.solver.leftArm.positionWeight = 0f; + vrik.solver.leftArm.rotationWeight = 0f; + vrik.solver.rightArm.positionWeight = 0f; + vrik.solver.rightArm.rotationWeight = 0f; + vrik.solver.leftLeg.positionWeight = 0f; + vrik.solver.leftLeg.rotationWeight = 0f; + vrik.solver.rightLeg.positionWeight = 0f; + vrik.solver.rightLeg.rotationWeight = 0f; + vrik.solver.IKPositionWeight = 0f; + + //ChilloutVR specific + BodySystem.TrackingLeftArmEnabled = false; + BodySystem.TrackingRightArmEnabled = false; + BodySystem.TrackingLeftLegEnabled = false; + BodySystem.TrackingRightLegEnabled = false; + IKSystem.Instance.headAnchorRotationOffset = Vector3.zero; + IKSystem.Instance.headAnchorPositionOffset = Vector3.zero; + + //Custom funky AF head ik shit + headIKTarget.position = avatarHeadBone.position; + headIKTarget.rotation = Quaternion.identity; + VRIKCalibrator.CalibrateHead(vrik, headIKTarget.transform, IKSystem.Instance.headAnchorPositionOffset, IKSystem.Instance.headAnchorRotationOffset); + headIKTarget.localRotation = Quaternion.identity; + + if (vrik != null) + { + vrik.onPreSolverUpdate.AddListener(new UnityAction(this.AlternativeOnPreSolverUpdate)); + } + + avatar.transform.rotation = originalRotation; + IKSystem.Instance.ResetIK(); + + return vrik; + } } \ No newline at end of file diff --git a/DesktopVRIK/DesktopVRIK.csproj b/DesktopVRIK/DesktopVRIK.csproj index c432ed3..8442204 100644 --- a/DesktopVRIK/DesktopVRIK.csproj +++ b/DesktopVRIK/DesktopVRIK.csproj @@ -8,6 +8,14 @@ false + + + + + + + + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\MelonLoader\0Harmony.dll diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index 8ceb5a3..9a00ec2 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -105,8 +105,6 @@ class IKSystemPatches { if (IKSystem.Instance.animator != null && IKSystem.Instance.animator.avatar != null && IKSystem.Instance.animator.avatar.isHuman) { - IKSystem.Instance.animator.enabled = false; - //why the fuck does this fix bad armatures and heels in ground ??? (this one is suprisingly not because of Default Robot Kyle) ... (Fuck you Default Robot Kyle) if (____poseHandler == null) { @@ -120,14 +118,8 @@ class IKSystemPatches } ____poseHandler.SetHumanPose(ref ___humanPose); - //need IKSystem to see VRIK component for setup - if (____vrik == null) - { - ____vrik = avatar.gameObject.AddComponent(); - } - - //now I calibrate DesktopVRIK - DesktopVRIK.Instance.CalibrateDesktopVRIK(avatar); + ____vrik = DesktopVRIK.Instance.AlternativeCalibration(avatar); + IKSystem.Instance.ApplyAvatarScaleToIk(avatar.viewPosition.y); } } } diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index e236813..dcc7ebd 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -43,6 +43,7 @@ public class DesktopVRIKMod : MelonMod System.Collections.IEnumerator WaitForLocalPlayer() { + AssetsHandler.Load(); while (PlayerSetup.Instance == null) yield return null; PlayerSetup.Instance.gameObject.AddComponent(); diff --git a/DesktopVRIK/resources/IKPose.assetbundle b/DesktopVRIK/resources/IKPose.assetbundle new file mode 100644 index 0000000000000000000000000000000000000000..156c7e0042ca69d778ed505929dfde316f33ad22 GIT binary patch literal 5847 zcmV;|7AWaeZfSIRMpFO)000LyE_g0@05UK!IW9CVGcjf{000000000M*8l(jK>z>% zTL1t6LjV8(00000000000000U009890RRA;qyPXGRscZ`00;p902%=B7ytxAK|(Dz zHDWk9Vq-LAW@2PzGBPw|VK_1}I5aXgV`4F6Vq!A@T>tjt8ymzOwYHqQho01E=DNGdQ(`dg)QR-iU%D3f!G>xYoo z{>pR|<1;F}$2L}?OH0i;CB13pC%!lwL#O%|=lSJ-jo7b%0%mRt8H!jRd=ZH0LiNSS zt01m63vu3XPMG+uF_O#}!>c0)FP-&B0O^Zcfal7Ne|ZwwSW(V(?xD8R7DwU9Y0H}8 zyJQd7?YRtMuy$m$9h$zj10M$UF%bv_K|ZMC*KJ{Y0`VtL`L6W6pL#bVZf4@syv`5N zUmSm9D>YaP&VLLPGLd5)2K+y{fL?KS zf&!R@Q4lz^|3?G zER+Vnso z3p1$Yr-j9D!UhDYhm45Ib<^*8<_Iaecn`cucjkx#SIk?D_Q#vsuM`kh-}_WR#c5OxZc>h5I=@mng3*P z2huI`vzv5qAOxn(ES0~&c_&z~1!3Gu;roOMhFRDqUdecT(xp+CTJ$5U8&)jDbRaYt z z>p1BY!?|0oejZeP4sl_4%8_&J>!K=&-vt1}?EELWEbTUZ&UaI9G9DR_USscg9a9px zm`#B#_2z)sN{pa}NlDupH-|zDsQ43C-|X5`1~5D|%*+fL*4EGO#4X|SHu&IRc2W$M z2jNP{%=f!jdX2S&XXK^}Km|)z-TdP_ZM>jG>MQV3^xhTbO+A*_rtac3Yx|OJX_Hn4 z*j;eVQkE>-ZDw$ML8B4yY(BR49%qZ;Wd~|lQohyg(5y@e0yB!J!9b78=N}Av`cE|YYW9#JO_9&7-`NhO_KVN)xLLF64ZWo0jHWuWX+E& zyiF}aVxO=8H7y{EO4?Z3%^_b1EkxB>_`Bb>{1)HE*$LGahIZQTxnIGJVB#F^GSRJL z%9c-zm}{%t_5Z>vo{6_090t1V)=PjQ!D?JzKlEO(<`fF4$O0 zsnrl+?wWz|&9n-Q;fIJs6H^y<;4ZTYW~yO1ApuC)RzQ5yvx2it27Knv&tKe1G`|QpUilR(Qu;?LIt4t1D`texDek@8 z&GvkyI(&xKQ{=UvrC4^!neR4Fn5x-yVbUjW$dg^W>LjN_Mct3Qs6nwri`W3-`vDXh ziy1nYc%6W@s%YZ)yP9Tuzy_Xnar6A2o#SIc>oR5hDV&&+T~CA`n}7Pwo^9BG9~wx8 zP)N&#lHI%!!<@ifPo@NUDgVxz4XKau$D=XjNs9YlQo{J%b+ePON=E;W3<|juSPPD@ ztL4IE9ZI9ozAl`c8zZ;PQlc};7Obl#!my*yjK@K2lq`<)7%M@2BdKCh%_YpY27b*4 z<-PD7oZ=$-1pN6XldNP`q8c$B;?Sqdj|z;>rn>kW#lf1Fz7pr3o|&C@!sI9Qps$3! zkzZ8tW#o=*hraMrku#IR2(}@cwc`08JTj$>){;qM`f^$BB`7t4K{G4|;^~8*JENqB zF7TB!h!M&ML~qSi?2rQ0e7;ilmxMj?ayJozp9DBlWX}8R>o=6D79vMX`8P*`MJwc~ zwbD@&w4M4c*b~PR9o5u)?A!vBL-a49=9_P9Wh@)dvwDrFrFSX+X5Cfygr*8I?i8TD z=s2nqOLXnjw+rRJ+`?MxX>LxL(i$klKMWxHFKEQ7R^&_iS7IZ@AhvpINCQ3|1u;*H zhEw8Hxi>#_0Enhp;(|1F&* z%6}IDk`w*rxE*HgHECYtA1a17^}zhc=o-w}#i5OoI&9;jsKmV7MK`aN>e>qe!juEB zhwo384Hj~X-1bgt)HM8z4IVJxa%HDE{r0OL*jsNneok6-Ugj{jf+AM&d?zq1)4H+@ z3@QQrUA6_VFY1l`4A5i5>65Xq(UGe_4a@e5L)P>K%Km|R=Pp{vn1|$q<~cTIaA*_) zJmv=Ww8=Zf3GuPbZdoETf|j2W)MYogr=$GY3x=9NrIps-r)PaW_WC}q6IgCOtghG$ ziDgucX-%y^u_*_I^HfOplsBTD-z5qma%IiEFQZj#8O4qa6ChLl` zLAT0#~$>=uF_m2oQpJ#4-o&NzlB`{rC-kns`dz+$fHQXxx)|B}nr`SE^sSHWF<)Z;o^~4dUzP#8zvoZ0M@rBx$lD!nSj_)Fxek@|BT* zy|1jB^WF<=4I0FLo784h(|^uO)wCW;45|;MAtub0(h*qdeRiJCs;}jXZ2VgV20PZa zeq(;qN}%kPLm-;io46Q-#gxc8zFQYS>y<=}&KUnf8fdaS+oVRov{=RcHkX(g zlqb_Nwk`s6U?&u=&&O@+gvE!#=7cQKteVqDw!Pr^%8`RB|9bDta&EjB1WVt@`6vZ} zAc47WH-3Q~404~4??|?9AeQ;hDujvZ8$q`*4B!yjd3c}iZuC8MUB`7Yh|KP8tU}A6 z-qjs+%i*;e91tvT--E^NG@N;ukhvZ#vmV zL>o{>>p`csN+-T9s+UUpA827CJ6Rb55SgW6aQ2!;D}O zkSm0GB3QCs0Ocmm#A>5iGgA@8c}@%}IL0IzUryK!hlC7{a4qLWJJ!JTt0~c~0ZccW zcf^x;t{Bhby+;Ei#H$JZ61?d@(q=vJ>jC&UguY^vr|rcH?c$92G*a#bO;^0xjIm+8xsRRO!%IEaGg?m{9;y3FC=5 z3tChZggJpBb~Z(rGK$~?p;tom(4bLx&WiT7_74%@b0UCD6Z=0KLNE}amb26(m8$c$ zenEFwjI`GZNb%gCGL59{ecYR%Crr<592NAZ<~=&jhUxN+eKp9W5zcjuw`tmA`U}bA z+`#+~B-jL9aQ|9QZnN5)=fWV*34}R)nL}UUnZVw^vz(3ygVj8@P3cNCbHI3F3&VlX z&q};MW*d@79U`=Yb=xtDpZ@GMvI&$swLnvaFvui91-c4T?>mMLDYz`JEi}EJ`OQ)_ zc*O70#BzE7_>1{kW$3bL#ZnWzc4>hB{aDs1Mct818@ zw9UlMf5VC=M9cFi>~OeZ#=#ME z75{ph4wjQ+Qv)0a}n~7c)o9iWJE?Hn~9HZmdcdgonBr)7?s7mk&g#$|f1DY--_;rKTDe^2sTaf&7 zL==8*bqcPJgpt2+x9^0@2KOD}Fy|Ap8h{&B#o!*D^&L~Vm1}%sbI9J{U9!um7kLUV z&dd)C99U#CE*JPdQ)Ai=DK+knnXoNCz-#Pd{Sp_BDWDV~re}bE#O3CQl2aN?!Dkg= z_F{AT3Pu0CjE--3eTD>I7luWG4n?;9x0rngR%^uNg9|_JP#BBTIxpEQP1a+v%{@co$s9{7Jqg4JwV~Jt1>{g^G zqYC5moLMtaNXWx~8}dC|Iy6o=50^X7cANpecSy{3VsBTb;pbvGCQvW;(f3p&cF67TB7~yB3i34I594Ny56b6v!ZK)tpIe?#vf}D4 z=Z&2-TJP}tx{gpk)p8`FIH>`@8mFdzqh4b7{jrgHeWW1Ze=`z6Qa^a$(u?=z2QjnY z3sTz_Dukbnau*XdQWuPDPvVHqYAxuqOA{E-5HSKK<|+u3Et%k`<&5OTj3Q*ARD$Nv zy4YL+(dryqP$L_QkNBUdCHMj+8L&0-+VQ`6AU;uFeeG}M4k{gZKE9Q2W;!X~)?<6f zfvJKr)dFiC0u@=pX-uy?KRTt}M_)#OU(p^pe!$eP;E&!4m|FHe!wq8-tJ-4b^zn;- zku$dqhH34_v1}cVkXrwgL^l*>pp*3~nQDg?zC1E}R#*^6Au)h>Z>a7bf)tPqh?-I^h6r^eOp2 zC5)e8R+ACNJ^3|Uf~gbi*3ixhw634j5!*#2awynXKzY?GCUBWk&f$W>0-ks$`Q$Dju)KgTJq- z^q~KU4e;Rdv_CW;6Tw&gS1aOTCy)J&`NZ_Zg8p__LPPFSOf=KI)8U^hE6D-1`;M+OcWkaOqxaS!B4A(m&$tn)A05H1As z=-5T+ZgtK)=iX60bD?!IP`fDIU-U)%gBKwrAA?qczsGBoV`LAup3~AApgp1m zvmuz##o;Rq=33Bdk|+s~Ah;T3aR6m0Vq~fR#fihC6B>8n8)gM|9U-iW1#wnjB)v7_*nGI40ePhk0Q(e@!39PZ9_*q_6vq&YUK@H1TtstbQ11OP;piKk=QE?)yM$$(zo4f0iH= zo)qC;q|6qbiTryiB$81DD2^zS7tXo3Z6l6QpadnW?`=7%qOdcD5d%n|X67hTIEIoO zHXT zG|}WL*hHCKh7t)}zV+fYn+!8I-%mTU&a_fwa`nZUEOM)=O38ME_2Z3$1+Dw?TB{X> zjsn-?88TAd95obRMU)cU)`%umHds4$-9@|8#Wib}{x-xn1s6GT#ZH^2%bj+oOl;-{ zi}96=2q(b$HctW=;hk+p(^a60^~FQ{PDwKfEll)Jn68u7Wx7(qb&Xh@9EI@db{o0_ zqCJFV+|j#7nCxHqIhQ*3kQ9%glK`%2WSZVi96|i-y3KNpzW>-^=HD9l;dQ<=o2FkO z2G=Ri=7DpJSG3Bz@}`da!Eg+XcN7t?h457F!ih-<8eq2pr!KoRaxm5PmYUDxDqzd4 z95x#dK-Q^CkCCG@Pp@qI{Bk^f$zwi=?H1Tbop;`|o<&ygB1a?$@@VEL$#p{2 zYeH$aIFchtlN@69G*fgl@JFjy@P9DDnv|}^z@;}HRl`GrD|c4{ZoN+4Okb`N#H9fF zW-=T#4)|39`%d^ZA4?35fdjMCXr}6IL^vQuOt9X?J}POB;s^U9uJ+B=c@AU;A7O&x zqWus)(GT+`4^Cj9CB3gtOYlfPz)s=7aV3N+0}BGF(yK!G%Q)6+EEzTd)BLopQSSYr z-F1JiDdDdgDGHSB1uW}hgw*L6{T$_lOK)LXwJkRMESoZf{^I%1LGe(+I?fNm>BmmV z*JX&Gu-ok9>|GMe)(hV(%oaI~*ge*bIbtb<LrPl1g7u(PGG2%Qb^{> z{NA|vNnB5u>2>?hj<} z;ACpw4YF3AOP|}-Cnp63*O+kc{hAKP>;hmdHUY-+2h-DTl|y=`kU;a>KRYl4lq|8n zk&P^#FIO+e=Yp;ni(-VQ Date: Sat, 14 Jan 2023 00:22:41 -0600 Subject: [PATCH 19/60] still working --- DesktopVRIK/DesktopVRIK.cs | 90 ++++++++++++-------------------------- 1 file changed, 29 insertions(+), 61 deletions(-) diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index 64bf02b..70d0b6a 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -114,26 +114,11 @@ public class DesktopVRIK : MonoBehaviour //ChilloutVR specific stuff - //Find eyeoffset - initialCamPos = PlayerSetup.Instance.desktopCamera.transform.localPosition; - Transform headTransform = IKSystem.Instance.animator.GetBoneTransform(HumanBodyBones.Head); - viewpoint = headTransform.Find("LocalHeadPoint"); - ChangeViewpointHandling(Setting_EnforceViewPosition); - //centerEyeAnchor now is head bone - Transform headAnchor = FindIKTarget(headTransform); - IKSystem.Instance.headAnchorPositionOffset = Vector3.zero; - IKSystem.Instance.headAnchorRotationOffset = headAnchor.rotation.eulerAngles; //set to head bone world rotation (Fuck you Default Robot Kyle) - IKSystem.Instance.ApplyAvatarScaleToIk(avatar.viewPosition.y); - BodySystem.TrackingLeftArmEnabled = false; - BodySystem.TrackingRightArmEnabled = false; - BodySystem.TrackingLeftLegEnabled = false; - BodySystem.TrackingRightLegEnabled = false; - IKSystem.vrik.solver.IKPositionWeight = 0f; + IKSystem.vrik.enabled = false; //Calibrate HeadIKOffset *(this is fucked on some avatars, (Fuck you Default Robot Kyle) but setting headAnchorRotationOffset to head rotation fixes (Fuck you Default Robot Kyle))* - VRIKCalibrator.CalibrateHead(IKSystem.vrik, headAnchor, IKSystem.Instance.headAnchorPositionOffset, IKSystem.Instance.headAnchorRotationOffset); IKSystem.vrik.enabled = true; IKSystem.vrik.solver.IKPositionWeight = 1f; @@ -157,35 +142,6 @@ public class DesktopVRIK : MonoBehaviour IKSystem.Instance.animator.enabled = true; } - //This is built because original build placed IK Targets on all joints. - private static Transform FindIKTarget(Transform targetParent) - { - /** - I want creators to be able to specify their own custom IK Targets, so they can move them around with animations if they want. - We check for existing target objects, and if none are found we make our own. - Naming scheme is parentobject name + " IK Target". - **/ - Transform parentTransform = targetParent.transform; - string targetName = parentTransform.name + " IK Target"; - - //check for existing target - foreach (object obj in parentTransform) - { - Transform childTransform = (Transform)obj; - if (childTransform.name == targetName) - { - return childTransform; - } - } - - //create new target if none are found - GameObject newTarget = new GameObject(targetName); - newTarget.transform.parent = parentTransform; - newTarget.transform.localPosition = Vector3.zero; - newTarget.transform.localRotation = Quaternion.identity; - return newTarget.transform; - } - public void AlternativeOnPreSolverUpdate() { //this order matters, rotation offset will be choppy if avatar is not cenetered first @@ -216,7 +172,7 @@ public class DesktopVRIK : MonoBehaviour } public Animator animator; - public Quaternion originalRotation; + //public Quaternion originalRotation; public RuntimeAnimatorController runtimeAnimatorController; public VRIK AlternativeCalibration(CVRAvatar avatar) @@ -226,22 +182,12 @@ public class DesktopVRIK : MonoBehaviour //Stuff to make bad armatures work (Fuck you Default Robot Kyle) avatar.transform.localPosition = Vector3.zero; - originalRotation = avatar.transform.rotation; - avatar.transform.rotation = Quaternion.identity; - - //force immediate calibration before animator decides to fuck us - VRIK vrik = avatar.gameObject.AddComponent(); - vrik.AutoDetectReferences(); - vrik.solver.SetToReferences(vrik.references); - vrik.solver.Initiate(vrik.transform); - - if (Setting_TestIKPoseController) - { - //Destroy(vrik); - return vrik; - } + //originalRotation = avatar.transform.rotation; + //avatar.transform.rotation = Quaternion.identity; //Generic VRIK calibration shit + VRIK vrik = avatar.gameObject.AddComponent(); + vrik.AutoDetectReferences(); vrik.fixTransforms = true; vrik.solver.plantFeet = false; @@ -271,17 +217,39 @@ public class DesktopVRIK : MonoBehaviour IKSystem.Instance.headAnchorPositionOffset = Vector3.zero; //Custom funky AF head ik shit + foreach (Transform transform in headIKTarget) + { + if (transform.name == "Head IK Target") + { + Destroy(transform.gameObject); + } + } headIKTarget.position = avatarHeadBone.position; headIKTarget.rotation = Quaternion.identity; VRIKCalibrator.CalibrateHead(vrik, headIKTarget.transform, IKSystem.Instance.headAnchorPositionOffset, IKSystem.Instance.headAnchorRotationOffset); headIKTarget.localRotation = Quaternion.identity; + //force immediate calibration before animator decides to fuck us + vrik.solver.SetToReferences(vrik.references); + vrik.solver.Initiate(vrik.transform); + + if (Setting_TestIKPoseController) + { + animator.enabled = false; + return vrik; + } + + //Find eyeoffset + initialCamPos = PlayerSetup.Instance.desktopCamera.transform.localPosition; + viewpoint = avatarHeadBone.Find("LocalHeadPoint"); + ChangeViewpointHandling(Setting_EnforceViewPosition); + if (vrik != null) { vrik.onPreSolverUpdate.AddListener(new UnityAction(this.AlternativeOnPreSolverUpdate)); } - avatar.transform.rotation = originalRotation; + //avatar.transform.rotation = originalRotation; IKSystem.Instance.ResetIK(); return vrik; From 997d1d8d412c29425d28875abe4fd39c6d570334 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Sat, 14 Jan 2023 01:15:32 -0600 Subject: [PATCH 20/60] quick cleanin --- DesktopVRIK/DesktopVRIK.cs | 115 ++++++------------------- DesktopVRIK/Main.cs | 5 +- DesktopVRIK/Properties/AssemblyInfo.cs | 2 +- DesktopVRIK/format.json | 6 +- 4 files changed, 32 insertions(+), 96 deletions(-) diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index 70d0b6a..f329628 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -52,96 +52,6 @@ public class DesktopVRIK : MonoBehaviour PlayerSetup.Instance.desktopCamera.transform.localPosition = initialCamPos; } - public void OnPreSolverUpdate() - { - //this order matters, rotation offset will be choppy if avatar is not cenetered first - //Reset avatar offset (VRIK will literally make you walk away from root otherwise) - IKSystem.vrik.transform.localPosition = Vector3.zero; - IKSystem.vrik.transform.localRotation = Quaternion.identity; - //VRChat hip movement emulation - if (Setting_EmulateVRChatHipMovementWeight != 0) - { - float angle = PlayerSetup.Instance.desktopCamera.transform.localEulerAngles.x; - if (angle > 180) angle -= 360; - float leanAmount = angle * (1 - MovementSystem.Instance.movementVector.magnitude) * Setting_EmulateVRChatHipMovementWeight; - Quaternion rotation = Quaternion.AngleAxis(leanAmount, IKSystem.Instance.avatar.transform.right); - IKSystem.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Head, rotation); - } - IKSystem.vrik.solver.plantFeet = true; - } - - public void CalibrateDesktopVRIK(CVRAvatar avatar) - { - //ikpose layer (specified by avatar author) - int? ikposeLayerIndex = PlayerSetup.Instance.animatorManager.GetAnimatorLayerIndex("IKPose"); - int? locoLayerIndex = PlayerSetup.Instance.animatorManager.GetAnimatorLayerIndex("Locomotion/Emotes"); - - if (ikposeLayerIndex != -1) - { - PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("IKPose", 1f); - if (locoLayerIndex != -1) - { - PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("Locomotion/Emotes", 0f); - } - IKSystem.Instance.animator.Update(0f); - } - - - //Stuff to make bad armatures work (Fuck you Default Robot Kyle) - avatar.transform.localPosition = Vector3.zero; - Quaternion originalRotation = avatar.transform.rotation; - avatar.transform.rotation = Quaternion.identity; - - //Generic VRIK calibration shit - - IKSystem.vrik.fixTransforms = false; - IKSystem.vrik.solver.plantFeet = false; - IKSystem.vrik.solver.locomotion.weight = 1f; - IKSystem.vrik.solver.locomotion.angleThreshold = 30f; - IKSystem.vrik.solver.locomotion.maxLegStretch = 0.75f; - //nuke weights - IKSystem.vrik.AutoDetectReferences(); - IKSystem.vrik.solver.spine.headClampWeight = 0f; - IKSystem.vrik.solver.spine.minHeadHeight = 0f; - IKSystem.vrik.solver.leftArm.positionWeight = 0f; - IKSystem.vrik.solver.leftArm.rotationWeight = 0f; - IKSystem.vrik.solver.rightArm.positionWeight = 0f; - IKSystem.vrik.solver.rightArm.rotationWeight = 0f; - IKSystem.vrik.solver.leftLeg.positionWeight = 0f; - IKSystem.vrik.solver.leftLeg.rotationWeight = 0f; - IKSystem.vrik.solver.rightLeg.positionWeight = 0f; - IKSystem.vrik.solver.rightLeg.rotationWeight = 0f; - - //ChilloutVR specific stuff - - - - IKSystem.vrik.enabled = false; - - //Calibrate HeadIKOffset *(this is fucked on some avatars, (Fuck you Default Robot Kyle) but setting headAnchorRotationOffset to head rotation fixes (Fuck you Default Robot Kyle))* - - IKSystem.vrik.enabled = true; - IKSystem.vrik.solver.IKPositionWeight = 1f; - IKSystem.vrik.solver.spine.maintainPelvisPosition = 0f; - if (IKSystem.vrik != null) - { - IKSystem.vrik.onPreSolverUpdate.AddListener(new UnityAction(this.OnPreSolverUpdate)); - } - - if (ikposeLayerIndex != -1) - { - PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("IKPose", 0f); - if (locoLayerIndex != -1) - { - PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("Locomotion/Emotes", 1f); - } - } - - avatar.transform.rotation = originalRotation; - IKSystem.Instance.ResetIK(); - IKSystem.Instance.animator.enabled = true; - } - public void AlternativeOnPreSolverUpdate() { //this order matters, rotation offset will be choppy if avatar is not cenetered first @@ -185,6 +95,20 @@ public class DesktopVRIK : MonoBehaviour //originalRotation = avatar.transform.rotation; //avatar.transform.rotation = Quaternion.identity; + //ikpose layer (specified by avatar author) + int? ikposeLayerIndex = PlayerSetup.Instance.animatorManager.GetAnimatorLayerIndex("IKPose"); + int? locoLayerIndex = PlayerSetup.Instance.animatorManager.GetAnimatorLayerIndex("Locomotion/Emotes"); + + if (ikposeLayerIndex != -1) + { + PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("IKPose", 1f); + if (locoLayerIndex != -1) + { + PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("Locomotion/Emotes", 0f); + } + IKSystem.Instance.animator.Update(0f); + } + //Generic VRIK calibration shit VRIK vrik = avatar.gameObject.AddComponent(); vrik.AutoDetectReferences(); @@ -197,7 +121,7 @@ public class DesktopVRIK : MonoBehaviour //nuke weights vrik.solver.spine.headClampWeight = 0f; vrik.solver.spine.minHeadHeight = 0f; - vrik.solver.spine.pelvisPositionWeight = 0f; + //vrik.solver.spine.pelvisPositionWeight = 0f; vrik.solver.leftArm.positionWeight = 0f; vrik.solver.leftArm.rotationWeight = 0f; vrik.solver.rightArm.positionWeight = 0f; @@ -233,6 +157,15 @@ public class DesktopVRIK : MonoBehaviour vrik.solver.SetToReferences(vrik.references); vrik.solver.Initiate(vrik.transform); + if (ikposeLayerIndex != -1) + { + PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("IKPose", 0f); + if (locoLayerIndex != -1) + { + PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("Locomotion/Emotes", 1f); + } + } + if (Setting_TestIKPoseController) { animator.enabled = false; diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index dcc7ebd..d77a5ae 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -11,7 +11,8 @@ public class DesktopVRIKMod : MelonMod internal static MelonPreferences_Entry m_entryEnabled, m_entryEnforceViewPosition, m_entryEmoteVRIK, - m_entryEmoteLookAtIK; + m_entryEmoteLookAtIK, + m_entryAllowRootSlipping; internal static MelonPreferences_Entry m_entryEmulateVRChatHipMovementWeight; public override void OnInitializeMelon() { @@ -21,6 +22,7 @@ public class DesktopVRIKMod : MelonMod m_entryEnforceViewPosition = m_categoryDesktopVRIK.CreateEntry("Enforce View Position", false, description: "Corrects view position to use VRIK offsets."); m_entryEmoteVRIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote VRIK", true, description: "Disable VRIK while emoting. Only disable if you are ok with looking dumb."); m_entryEmoteLookAtIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote LookAtIK", true, description: "Disable LookAtIK while emoting. This setting doesn't really matter, as LookAtIK isn't networked while doing an emote."); + m_entryAllowRootSlipping = m_categoryDesktopVRIK.CreateEntry("Allow Root Slipping", false, description: "Allows avatar root to slip out from under itself, to emulate more wacky VRChat behavior."); foreach (var setting in m_categoryDesktopVRIK.Entries) { @@ -59,6 +61,7 @@ public class DesktopVRIKMod : MelonMod DesktopVRIK.Setting_EmulateVRChatHipMovementWeight = Mathf.Clamp01(m_entryEmulateVRChatHipMovementWeight.Value); DesktopVRIK.Setting_EmoteVRIK = m_entryEmoteVRIK.Value; DesktopVRIK.Setting_EmoteLookAtIK = m_entryEmoteLookAtIK.Value; + DesktopVRIK.Setting_AllowRootSlipping = m_entryAllowRootSlipping.Value; DesktopVRIK.Instance.ChangeViewpointHandling(m_entryEnforceViewPosition.Value); } diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs index fecfa4f..c076769 100644 --- a/DesktopVRIK/Properties/AssemblyInfo.cs +++ b/DesktopVRIK/Properties/AssemblyInfo.cs @@ -26,6 +26,6 @@ using System.Reflection; namespace DesktopVRIK.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.5"; + public const string Version = "2.0.0"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json index 0b534f6..ba61c32 100644 --- a/DesktopVRIK/format.json +++ b/DesktopVRIK/format.json @@ -1,7 +1,7 @@ { "_id": 117, "name": "DesktopVRIK", - "modversion": "1.0.4", + "modversion": "2.0.0", "gameversion": "2022r170", "loaderversion": "0.5.7", "modtype": "Mod", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v1.0.3/DesktopVRIK.dll", + "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v2.0.0/DesktopVRIK.dll", "sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRIK/", - "changelog": "- Simplified VRIK calibration to avoid low heel issue.\n- Removed rushed compatibility mode.\n- Added checks for valid Humanoid rigs.\n- Added PlantFeet & EnforceViewPosition Settings.\n- Added Weight option for the VRChat-like hip movement.", + "changelog": "- Simplified VRIK calibration to avoid low heel issue.\n- Removed rushed compatibility mode.\n- Added checks for valid Humanoid rigs.\n- Added PlantFeet & EnforceViewPosition Settings.\n- Added Weight option for the VRChat-like hip movement.\n- Simplified config, added BTKUILib support.\n- Reworked calibration to support almost every avatar.\n- Added custom avatar-defined IKPose support.", "embedcolor": "9b59b6" } \ No newline at end of file From 6433dd7c7863cbab5f51cedfa81686bfe8750a90 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Sat, 14 Jan 2023 01:21:49 -0600 Subject: [PATCH 21/60] a --- DesktopVRIK/AsserHandler.cs | 95 ----------------------- DesktopVRIK/DesktopVRIK.cs | 60 ++++++-------- DesktopVRIK/DesktopVRIK.csproj | 8 -- DesktopVRIK/HarmonyPatches.cs | 2 +- DesktopVRIK/Main.cs | 3 - DesktopVRIK/format.json | 2 +- DesktopVRIK/resources/IKPose.assetbundle | Bin 5847 -> 0 bytes 7 files changed, 25 insertions(+), 145 deletions(-) delete mode 100644 DesktopVRIK/AsserHandler.cs delete mode 100644 DesktopVRIK/resources/IKPose.assetbundle diff --git a/DesktopVRIK/AsserHandler.cs b/DesktopVRIK/AsserHandler.cs deleted file mode 100644 index b5e5c7d..0000000 --- a/DesktopVRIK/AsserHandler.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System.Reflection; -using UnityEngine; -using Object = UnityEngine.Object; - -/* - - Kindly stolen from SDraw's leap motion mod. (MIT) - https://github.com/SDraw/ml_mods_cvr/blob/master/ml_lme/AssetsHandler.cs - - *thank u sdraw, i wont be murderer now* - -*/ - -namespace NAK.Melons.DesktopVRIK; - -static class AssetsHandler -{ - static readonly List ms_assets = new List() - { - "IKPose.assetbundle" - }; - - static Dictionary ms_loadedAssets = new Dictionary(); - static Dictionary ms_loadedObjects = new Dictionary(); - - public static void Load() - { - Assembly l_assembly = Assembly.GetExecutingAssembly(); - string l_assemblyName = l_assembly.GetName().Name; - - foreach (string l_assetName in ms_assets) - { - try - { - Stream l_assetStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + l_assetName); - if (l_assetStream != null) - { - MemoryStream l_memorySteam = new MemoryStream((int)l_assetStream.Length); - l_assetStream.CopyTo(l_memorySteam); - AssetBundle l_assetBundle = AssetBundle.LoadFromMemory(l_memorySteam.ToArray(), 0); - if (l_assetBundle != null) - { - l_assetBundle.hideFlags |= HideFlags.DontUnloadUnusedAsset; - ms_loadedAssets.Add(l_assetName, l_assetBundle); - } - else - MelonLoader.MelonLogger.Warning("Unable to load bundled '" + l_assetName + "' asset"); - } - else - MelonLoader.MelonLogger.Warning("Unable to get bundled '" + l_assetName + "' asset stream"); - } - catch (System.Exception e) - { - MelonLoader.MelonLogger.Warning("Unable to load bundled '" + l_assetName + "' asset, reason: " + e.Message); - } - } - } - - public static Object GetAsset(string p_name) - { - Object l_result = null; - if (ms_loadedObjects.ContainsKey(p_name)) - { - l_result = UnityEngine.Object.Instantiate(ms_loadedObjects[p_name]); - //l_result.SetActive(true); - l_result.hideFlags |= HideFlags.DontUnloadUnusedAsset; - } - else - { - foreach (var l_pair in ms_loadedAssets) - { - if (l_pair.Value.Contains(p_name)) - { - Object l_bundledObject = (Object)l_pair.Value.LoadAsset(p_name, typeof(Object)); - if (l_bundledObject != null) - { - ms_loadedObjects.Add(p_name, l_bundledObject); - l_result = UnityEngine.Object.Instantiate(l_bundledObject); - //l_result.SetActive(true); - l_result.hideFlags |= HideFlags.DontUnloadUnusedAsset; - } - break; - } - } - } - return l_result; - } - - public static void Unload() - { - foreach (var l_pair in ms_loadedAssets) - UnityEngine.Object.Destroy(l_pair.Value); - ms_loadedAssets.Clear(); - } -} \ No newline at end of file diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index f329628..f00ad95 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -16,9 +16,7 @@ public class DesktopVRIK : MonoBehaviour public static bool Setting_Enabled, Setting_EnforceViewPosition, Setting_EmoteVRIK, - Setting_EmoteLookAtIK, - Setting_AllowRootSlipping, - Setting_TestIKPoseController; + Setting_EmoteLookAtIK; public static float Setting_EmulateVRChatHipMovementWeight; public Transform viewpoint; @@ -27,12 +25,9 @@ public class DesktopVRIK : MonoBehaviour Transform headIKTarget; Transform avatarHeadBone; - RuntimeAnimatorController ikposeController; - void Start() { Instance = this; - ikposeController = (RuntimeAnimatorController)AssetsHandler.GetAsset("Assets/BundledAssets/IKPose/IKPose.controller"); // create the shared Head IK Target headIKTarget = new GameObject("[DesktopVRIK] Head IK Target").transform; headIKTarget.parent = PlayerSetup.Instance.transform; @@ -61,12 +56,9 @@ public class DesktopVRIK : MonoBehaviour headIKTarget.position = new Vector3(headIKTarget.position.x, avatarHeadBone.position.y, headIKTarget.position.z); } - if (!Setting_AllowRootSlipping) - { - //Reset avatar offset (VRIK will literally make you walk away from root otherwise) - IKSystem.vrik.transform.localPosition = Vector3.zero; - IKSystem.vrik.transform.localRotation = Quaternion.identity; - } + //Reset avatar offset (VRIK will literally make you walk away from root otherwise) + IKSystem.vrik.transform.localPosition = Vector3.zero; + IKSystem.vrik.transform.localRotation = Quaternion.identity; //VRChat hip movement emulation if (Setting_EmulateVRChatHipMovementWeight != 0) @@ -96,18 +88,18 @@ public class DesktopVRIK : MonoBehaviour //avatar.transform.rotation = Quaternion.identity; //ikpose layer (specified by avatar author) - int? ikposeLayerIndex = PlayerSetup.Instance.animatorManager.GetAnimatorLayerIndex("IKPose"); - int? locoLayerIndex = PlayerSetup.Instance.animatorManager.GetAnimatorLayerIndex("Locomotion/Emotes"); + //int? ikposeLayerIndex = PlayerSetup.Instance.animatorManager.GetAnimatorLayerIndex("IKPose"); + //int? locoLayerIndex = PlayerSetup.Instance.animatorManager.GetAnimatorLayerIndex("Locomotion/Emotes"); - if (ikposeLayerIndex != -1) - { - PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("IKPose", 1f); - if (locoLayerIndex != -1) - { - PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("Locomotion/Emotes", 0f); - } - IKSystem.Instance.animator.Update(0f); - } + //if (ikposeLayerIndex != -1) + //{ + // PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("IKPose", 1f); + // if (locoLayerIndex != -1) + // { + // PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("Locomotion/Emotes", 0f); + // } + // IKSystem.Instance.animator.Update(0f); + //} //Generic VRIK calibration shit VRIK vrik = avatar.gameObject.AddComponent(); @@ -157,20 +149,14 @@ public class DesktopVRIK : MonoBehaviour vrik.solver.SetToReferences(vrik.references); vrik.solver.Initiate(vrik.transform); - if (ikposeLayerIndex != -1) - { - PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("IKPose", 0f); - if (locoLayerIndex != -1) - { - PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("Locomotion/Emotes", 1f); - } - } - - if (Setting_TestIKPoseController) - { - animator.enabled = false; - return vrik; - } + //if (ikposeLayerIndex != -1) + //{ + // PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("IKPose", 0f); + // if (locoLayerIndex != -1) + // { + // PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("Locomotion/Emotes", 1f); + // } + //} //Find eyeoffset initialCamPos = PlayerSetup.Instance.desktopCamera.transform.localPosition; diff --git a/DesktopVRIK/DesktopVRIK.csproj b/DesktopVRIK/DesktopVRIK.csproj index 8442204..c432ed3 100644 --- a/DesktopVRIK/DesktopVRIK.csproj +++ b/DesktopVRIK/DesktopVRIK.csproj @@ -8,14 +8,6 @@ false - - - - - - - - C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\MelonLoader\0Harmony.dll diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index 9a00ec2..9d8c7b2 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -117,7 +117,7 @@ class IKSystemPatches IKSystem.Instance.ApplyMuscleValue((MuscleIndex)i, IKPoseMuscles[i], ref ___humanPose.muscles); } ____poseHandler.SetHumanPose(ref ___humanPose); - + ____vrik = DesktopVRIK.Instance.AlternativeCalibration(avatar); IKSystem.Instance.ApplyAvatarScaleToIk(avatar.viewPosition.y); } diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index d77a5ae..8fd3cc4 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -22,7 +22,6 @@ public class DesktopVRIKMod : MelonMod m_entryEnforceViewPosition = m_categoryDesktopVRIK.CreateEntry("Enforce View Position", false, description: "Corrects view position to use VRIK offsets."); m_entryEmoteVRIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote VRIK", true, description: "Disable VRIK while emoting. Only disable if you are ok with looking dumb."); m_entryEmoteLookAtIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote LookAtIK", true, description: "Disable LookAtIK while emoting. This setting doesn't really matter, as LookAtIK isn't networked while doing an emote."); - m_entryAllowRootSlipping = m_categoryDesktopVRIK.CreateEntry("Allow Root Slipping", false, description: "Allows avatar root to slip out from under itself, to emulate more wacky VRChat behavior."); foreach (var setting in m_categoryDesktopVRIK.Entries) { @@ -45,7 +44,6 @@ public class DesktopVRIKMod : MelonMod System.Collections.IEnumerator WaitForLocalPlayer() { - AssetsHandler.Load(); while (PlayerSetup.Instance == null) yield return null; PlayerSetup.Instance.gameObject.AddComponent(); @@ -61,7 +59,6 @@ public class DesktopVRIKMod : MelonMod DesktopVRIK.Setting_EmulateVRChatHipMovementWeight = Mathf.Clamp01(m_entryEmulateVRChatHipMovementWeight.Value); DesktopVRIK.Setting_EmoteVRIK = m_entryEmoteVRIK.Value; DesktopVRIK.Setting_EmoteLookAtIK = m_entryEmoteLookAtIK.Value; - DesktopVRIK.Setting_AllowRootSlipping = m_entryAllowRootSlipping.Value; DesktopVRIK.Instance.ChangeViewpointHandling(m_entryEnforceViewPosition.Value); } diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json index ba61c32..b13d3cf 100644 --- a/DesktopVRIK/format.json +++ b/DesktopVRIK/format.json @@ -18,6 +18,6 @@ ], "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v2.0.0/DesktopVRIK.dll", "sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRIK/", - "changelog": "- Simplified VRIK calibration to avoid low heel issue.\n- Removed rushed compatibility mode.\n- Added checks for valid Humanoid rigs.\n- Added PlantFeet & EnforceViewPosition Settings.\n- Added Weight option for the VRChat-like hip movement.\n- Simplified config, added BTKUILib support.\n- Reworked calibration to support almost every avatar.\n- Added custom avatar-defined IKPose support.", + "changelog": "- Simplified VRIK calibration to avoid low heel issue.\n- Added checks for valid Humanoid rigs.\n- Added PlantFeet & EnforceViewPosition Settings.\n- Added Weight option for the VRChat-like hip movement.\n- Simplified config, added BTKUILib support.\n- Reworked calibration to support almost every avatar.", "embedcolor": "9b59b6" } \ No newline at end of file diff --git a/DesktopVRIK/resources/IKPose.assetbundle b/DesktopVRIK/resources/IKPose.assetbundle deleted file mode 100644 index 156c7e0042ca69d778ed505929dfde316f33ad22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5847 zcmV;|7AWaeZfSIRMpFO)000LyE_g0@05UK!IW9CVGcjf{000000000M*8l(jK>z>% zTL1t6LjV8(00000000000000U009890RRA;qyPXGRscZ`00;p902%=B7ytxAK|(Dz zHDWk9Vq-LAW@2PzGBPw|VK_1}I5aXgV`4F6Vq!A@T>tjt8ymzOwYHqQho01E=DNGdQ(`dg)QR-iU%D3f!G>xYoo z{>pR|<1;F}$2L}?OH0i;CB13pC%!lwL#O%|=lSJ-jo7b%0%mRt8H!jRd=ZH0LiNSS zt01m63vu3XPMG+uF_O#}!>c0)FP-&B0O^Zcfal7Ne|ZwwSW(V(?xD8R7DwU9Y0H}8 zyJQd7?YRtMuy$m$9h$zj10M$UF%bv_K|ZMC*KJ{Y0`VtL`L6W6pL#bVZf4@syv`5N zUmSm9D>YaP&VLLPGLd5)2K+y{fL?KS zf&!R@Q4lz^|3?G zER+Vnso z3p1$Yr-j9D!UhDYhm45Ib<^*8<_Iaecn`cucjkx#SIk?D_Q#vsuM`kh-}_WR#c5OxZc>h5I=@mng3*P z2huI`vzv5qAOxn(ES0~&c_&z~1!3Gu;roOMhFRDqUdecT(xp+CTJ$5U8&)jDbRaYt z z>p1BY!?|0oejZeP4sl_4%8_&J>!K=&-vt1}?EELWEbTUZ&UaI9G9DR_USscg9a9px zm`#B#_2z)sN{pa}NlDupH-|zDsQ43C-|X5`1~5D|%*+fL*4EGO#4X|SHu&IRc2W$M z2jNP{%=f!jdX2S&XXK^}Km|)z-TdP_ZM>jG>MQV3^xhTbO+A*_rtac3Yx|OJX_Hn4 z*j;eVQkE>-ZDw$ML8B4yY(BR49%qZ;Wd~|lQohyg(5y@e0yB!J!9b78=N}Av`cE|YYW9#JO_9&7-`NhO_KVN)xLLF64ZWo0jHWuWX+E& zyiF}aVxO=8H7y{EO4?Z3%^_b1EkxB>_`Bb>{1)HE*$LGahIZQTxnIGJVB#F^GSRJL z%9c-zm}{%t_5Z>vo{6_090t1V)=PjQ!D?JzKlEO(<`fF4$O0 zsnrl+?wWz|&9n-Q;fIJs6H^y<;4ZTYW~yO1ApuC)RzQ5yvx2it27Knv&tKe1G`|QpUilR(Qu;?LIt4t1D`texDek@8 z&GvkyI(&xKQ{=UvrC4^!neR4Fn5x-yVbUjW$dg^W>LjN_Mct3Qs6nwri`W3-`vDXh ziy1nYc%6W@s%YZ)yP9Tuzy_Xnar6A2o#SIc>oR5hDV&&+T~CA`n}7Pwo^9BG9~wx8 zP)N&#lHI%!!<@ifPo@NUDgVxz4XKau$D=XjNs9YlQo{J%b+ePON=E;W3<|juSPPD@ ztL4IE9ZI9ozAl`c8zZ;PQlc};7Obl#!my*yjK@K2lq`<)7%M@2BdKCh%_YpY27b*4 z<-PD7oZ=$-1pN6XldNP`q8c$B;?Sqdj|z;>rn>kW#lf1Fz7pr3o|&C@!sI9Qps$3! zkzZ8tW#o=*hraMrku#IR2(}@cwc`08JTj$>){;qM`f^$BB`7t4K{G4|;^~8*JENqB zF7TB!h!M&ML~qSi?2rQ0e7;ilmxMj?ayJozp9DBlWX}8R>o=6D79vMX`8P*`MJwc~ zwbD@&w4M4c*b~PR9o5u)?A!vBL-a49=9_P9Wh@)dvwDrFrFSX+X5Cfygr*8I?i8TD z=s2nqOLXnjw+rRJ+`?MxX>LxL(i$klKMWxHFKEQ7R^&_iS7IZ@AhvpINCQ3|1u;*H zhEw8Hxi>#_0Enhp;(|1F&* z%6}IDk`w*rxE*HgHECYtA1a17^}zhc=o-w}#i5OoI&9;jsKmV7MK`aN>e>qe!juEB zhwo384Hj~X-1bgt)HM8z4IVJxa%HDE{r0OL*jsNneok6-Ugj{jf+AM&d?zq1)4H+@ z3@QQrUA6_VFY1l`4A5i5>65Xq(UGe_4a@e5L)P>K%Km|R=Pp{vn1|$q<~cTIaA*_) zJmv=Ww8=Zf3GuPbZdoETf|j2W)MYogr=$GY3x=9NrIps-r)PaW_WC}q6IgCOtghG$ ziDgucX-%y^u_*_I^HfOplsBTD-z5qma%IiEFQZj#8O4qa6ChLl` zLAT0#~$>=uF_m2oQpJ#4-o&NzlB`{rC-kns`dz+$fHQXxx)|B}nr`SE^sSHWF<)Z;o^~4dUzP#8zvoZ0M@rBx$lD!nSj_)Fxek@|BT* zy|1jB^WF<=4I0FLo784h(|^uO)wCW;45|;MAtub0(h*qdeRiJCs;}jXZ2VgV20PZa zeq(;qN}%kPLm-;io46Q-#gxc8zFQYS>y<=}&KUnf8fdaS+oVRov{=RcHkX(g zlqb_Nwk`s6U?&u=&&O@+gvE!#=7cQKteVqDw!Pr^%8`RB|9bDta&EjB1WVt@`6vZ} zAc47WH-3Q~404~4??|?9AeQ;hDujvZ8$q`*4B!yjd3c}iZuC8MUB`7Yh|KP8tU}A6 z-qjs+%i*;e91tvT--E^NG@N;ukhvZ#vmV zL>o{>>p`csN+-T9s+UUpA827CJ6Rb55SgW6aQ2!;D}O zkSm0GB3QCs0Ocmm#A>5iGgA@8c}@%}IL0IzUryK!hlC7{a4qLWJJ!JTt0~c~0ZccW zcf^x;t{Bhby+;Ei#H$JZ61?d@(q=vJ>jC&UguY^vr|rcH?c$92G*a#bO;^0xjIm+8xsRRO!%IEaGg?m{9;y3FC=5 z3tChZggJpBb~Z(rGK$~?p;tom(4bLx&WiT7_74%@b0UCD6Z=0KLNE}amb26(m8$c$ zenEFwjI`GZNb%gCGL59{ecYR%Crr<592NAZ<~=&jhUxN+eKp9W5zcjuw`tmA`U}bA z+`#+~B-jL9aQ|9QZnN5)=fWV*34}R)nL}UUnZVw^vz(3ygVj8@P3cNCbHI3F3&VlX z&q};MW*d@79U`=Yb=xtDpZ@GMvI&$swLnvaFvui91-c4T?>mMLDYz`JEi}EJ`OQ)_ zc*O70#BzE7_>1{kW$3bL#ZnWzc4>hB{aDs1Mct818@ zw9UlMf5VC=M9cFi>~OeZ#=#ME z75{ph4wjQ+Qv)0a}n~7c)o9iWJE?Hn~9HZmdcdgonBr)7?s7mk&g#$|f1DY--_;rKTDe^2sTaf&7 zL==8*bqcPJgpt2+x9^0@2KOD}Fy|Ap8h{&B#o!*D^&L~Vm1}%sbI9J{U9!um7kLUV z&dd)C99U#CE*JPdQ)Ai=DK+knnXoNCz-#Pd{Sp_BDWDV~re}bE#O3CQl2aN?!Dkg= z_F{AT3Pu0CjE--3eTD>I7luWG4n?;9x0rngR%^uNg9|_JP#BBTIxpEQP1a+v%{@co$s9{7Jqg4JwV~Jt1>{g^G zqYC5moLMtaNXWx~8}dC|Iy6o=50^X7cANpecSy{3VsBTb;pbvGCQvW;(f3p&cF67TB7~yB3i34I594Ny56b6v!ZK)tpIe?#vf}D4 z=Z&2-TJP}tx{gpk)p8`FIH>`@8mFdzqh4b7{jrgHeWW1Ze=`z6Qa^a$(u?=z2QjnY z3sTz_Dukbnau*XdQWuPDPvVHqYAxuqOA{E-5HSKK<|+u3Et%k`<&5OTj3Q*ARD$Nv zy4YL+(dryqP$L_QkNBUdCHMj+8L&0-+VQ`6AU;uFeeG}M4k{gZKE9Q2W;!X~)?<6f zfvJKr)dFiC0u@=pX-uy?KRTt}M_)#OU(p^pe!$eP;E&!4m|FHe!wq8-tJ-4b^zn;- zku$dqhH34_v1}cVkXrwgL^l*>pp*3~nQDg?zC1E}R#*^6Au)h>Z>a7bf)tPqh?-I^h6r^eOp2 zC5)e8R+ACNJ^3|Uf~gbi*3ixhw634j5!*#2awynXKzY?GCUBWk&f$W>0-ks$`Q$Dju)KgTJq- z^q~KU4e;Rdv_CW;6Tw&gS1aOTCy)J&`NZ_Zg8p__LPPFSOf=KI)8U^hE6D-1`;M+OcWkaOqxaS!B4A(m&$tn)A05H1As z=-5T+ZgtK)=iX60bD?!IP`fDIU-U)%gBKwrAA?qczsGBoV`LAup3~AApgp1m zvmuz##o;Rq=33Bdk|+s~Ah;T3aR6m0Vq~fR#fihC6B>8n8)gM|9U-iW1#wnjB)v7_*nGI40ePhk0Q(e@!39PZ9_*q_6vq&YUK@H1TtstbQ11OP;piKk=QE?)yM$$(zo4f0iH= zo)qC;q|6qbiTryiB$81DD2^zS7tXo3Z6l6QpadnW?`=7%qOdcD5d%n|X67hTIEIoO zHXT zG|}WL*hHCKh7t)}zV+fYn+!8I-%mTU&a_fwa`nZUEOM)=O38ME_2Z3$1+Dw?TB{X> zjsn-?88TAd95obRMU)cU)`%umHds4$-9@|8#Wib}{x-xn1s6GT#ZH^2%bj+oOl;-{ zi}96=2q(b$HctW=;hk+p(^a60^~FQ{PDwKfEll)Jn68u7Wx7(qb&Xh@9EI@db{o0_ zqCJFV+|j#7nCxHqIhQ*3kQ9%glK`%2WSZVi96|i-y3KNpzW>-^=HD9l;dQ<=o2FkO z2G=Ri=7DpJSG3Bz@}`da!Eg+XcN7t?h457F!ih-<8eq2pr!KoRaxm5PmYUDxDqzd4 z95x#dK-Q^CkCCG@Pp@qI{Bk^f$zwi=?H1Tbop;`|o<&ygB1a?$@@VEL$#p{2 zYeH$aIFchtlN@69G*fgl@JFjy@P9DDnv|}^z@;}HRl`GrD|c4{ZoN+4Okb`N#H9fF zW-=T#4)|39`%d^ZA4?35fdjMCXr}6IL^vQuOt9X?J}POB;s^U9uJ+B=c@AU;A7O&x zqWus)(GT+`4^Cj9CB3gtOYlfPz)s=7aV3N+0}BGF(yK!G%Q)6+EEzTd)BLopQSSYr z-F1JiDdDdgDGHSB1uW}hgw*L6{T$_lOK)LXwJkRMESoZf{^I%1LGe(+I?fNm>BmmV z*JX&Gu-ok9>|GMe)(hV(%oaI~*ge*bIbtb<LrPl1g7u(PGG2%Qb^{> z{NA|vNnB5u>2>?hj<} z;ACpw4YF3AOP|}-Cnp63*O+kc{hAKP>;hmdHUY-+2h-DTl|y=`kU;a>KRYl4lq|8n zk&P^#FIO+e=Yp;ni(-VQ Date: Sat, 14 Jan 2023 01:30:29 -0600 Subject: [PATCH 22/60] quickly add custom IKPose animation support --- .../BTKUI_Integration/BTKUI_Integration.cs | 4 +- DesktopVRIK/DesktopVRIK.cs | 41 +++++++++---------- DesktopVRIK/HarmonyPatches.cs | 2 +- 3 files changed, 23 insertions(+), 24 deletions(-) diff --git a/DesktopVRIK/BTKUI_Integration/BTKUI_Integration.cs b/DesktopVRIK/BTKUI_Integration/BTKUI_Integration.cs index c0b9b1c..a752328 100644 --- a/DesktopVRIK/BTKUI_Integration/BTKUI_Integration.cs +++ b/DesktopVRIK/BTKUI_Integration/BTKUI_Integration.cs @@ -1,6 +1,6 @@ -using System.Runtime.CompilerServices; -using BTKUILib; +using BTKUILib; using BTKUILib.UIObjects; +using System.Runtime.CompilerServices; namespace NAK.Melons.DesktopVRIK.BTKUI_Integration; diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index f00ad95..9af0386 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -31,7 +31,7 @@ public class DesktopVRIK : MonoBehaviour // create the shared Head IK Target headIKTarget = new GameObject("[DesktopVRIK] Head IK Target").transform; headIKTarget.parent = PlayerSetup.Instance.transform; - headIKTarget.localPosition = new Vector3(0f,1.8f,0f); + headIKTarget.localPosition = new Vector3(0f, 1.8f, 0f); headIKTarget.localRotation = Quaternion.identity; } @@ -88,18 +88,17 @@ public class DesktopVRIK : MonoBehaviour //avatar.transform.rotation = Quaternion.identity; //ikpose layer (specified by avatar author) - //int? ikposeLayerIndex = PlayerSetup.Instance.animatorManager.GetAnimatorLayerIndex("IKPose"); - //int? locoLayerIndex = PlayerSetup.Instance.animatorManager.GetAnimatorLayerIndex("Locomotion/Emotes"); - - //if (ikposeLayerIndex != -1) - //{ - // PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("IKPose", 1f); - // if (locoLayerIndex != -1) - // { - // PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("Locomotion/Emotes", 0f); - // } - // IKSystem.Instance.animator.Update(0f); - //} + int ikposeLayerIndex = animator.GetLayerIndex("IKPose"); + int locoLayerIndex = animator.GetLayerIndex("Locomotion/Emotes"); + if (ikposeLayerIndex != -1) + { + animator.SetLayerWeight(ikposeLayerIndex, 1f); + if (locoLayerIndex != -1) + { + animator.SetLayerWeight(locoLayerIndex, 0f); + } + animator.Update(0f); + } //Generic VRIK calibration shit VRIK vrik = avatar.gameObject.AddComponent(); @@ -149,14 +148,14 @@ public class DesktopVRIK : MonoBehaviour vrik.solver.SetToReferences(vrik.references); vrik.solver.Initiate(vrik.transform); - //if (ikposeLayerIndex != -1) - //{ - // PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("IKPose", 0f); - // if (locoLayerIndex != -1) - // { - // PlayerSetup.Instance.animatorManager.SetAnimatorLayerWeight("Locomotion/Emotes", 1f); - // } - //} + if (ikposeLayerIndex != -1) + { + animator.SetLayerWeight(ikposeLayerIndex, 0f); + if (locoLayerIndex != -1) + { + animator.SetLayerWeight(locoLayerIndex, 1f); + } + } //Find eyeoffset initialCamPos = PlayerSetup.Instance.desktopCamera.transform.localPosition; diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index 9d8c7b2..9a00ec2 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -117,7 +117,7 @@ class IKSystemPatches IKSystem.Instance.ApplyMuscleValue((MuscleIndex)i, IKPoseMuscles[i], ref ___humanPose.muscles); } ____poseHandler.SetHumanPose(ref ___humanPose); - + ____vrik = DesktopVRIK.Instance.AlternativeCalibration(avatar); IKSystem.Instance.ApplyAvatarScaleToIk(avatar.viewPosition.y); } From 6c3a1797b553fa2dae33c69846d1cba1b56c1a0f Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Sat, 14 Jan 2023 01:32:14 -0600 Subject: [PATCH 23/60] bump --- DesktopVRIK/Properties/AssemblyInfo.cs | 2 +- DesktopVRIK/format.json | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs index c076769..80bd77c 100644 --- a/DesktopVRIK/Properties/AssemblyInfo.cs +++ b/DesktopVRIK/Properties/AssemblyInfo.cs @@ -26,6 +26,6 @@ using System.Reflection; namespace DesktopVRIK.Properties; internal static class AssemblyInfoParams { - public const string Version = "2.0.0"; + public const string Version = "2.0.1"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json index b13d3cf..b7d981d 100644 --- a/DesktopVRIK/format.json +++ b/DesktopVRIK/format.json @@ -1,7 +1,7 @@ { "_id": 117, "name": "DesktopVRIK", - "modversion": "2.0.0", + "modversion": "2.0.1", "gameversion": "2022r170", "loaderversion": "0.5.7", "modtype": "Mod", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v2.0.0/DesktopVRIK.dll", + "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v2.0.1/DesktopVRIK.dll", "sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRIK/", - "changelog": "- Simplified VRIK calibration to avoid low heel issue.\n- Added checks for valid Humanoid rigs.\n- Added PlantFeet & EnforceViewPosition Settings.\n- Added Weight option for the VRChat-like hip movement.\n- Simplified config, added BTKUILib support.\n- Reworked calibration to support almost every avatar.", + "changelog": "- Simplified VRIK calibration to avoid low heel issue.\n- Added checks for valid Humanoid rigs.\n- Added PlantFeet & EnforceViewPosition Settings.\n- Added Weight option for the VRChat-like hip movement.\n- Simplified config, added BTKUILib support.\n- Reworked calibration to support almost every avatar.\n- Added custom avatar-defined IKPose support.", "embedcolor": "9b59b6" } \ No newline at end of file From 41068ce3fb0154d949dcb342f9f60edc71e1e69d Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Sat, 14 Jan 2023 02:52:08 -0600 Subject: [PATCH 24/60] why is it fucking (literally() fucking one line --- DesktopVRIK/DesktopVRIK.cs | 15 ++++++++++++--- DesktopVRIK/HarmonyPatches.cs | 1 - DesktopVRIK/Properties/AssemblyInfo.cs | 2 +- DesktopVRIK/format.json | 6 +++--- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index 9af0386..ab82ebd 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -18,6 +18,7 @@ public class DesktopVRIK : MonoBehaviour Setting_EmoteVRIK, Setting_EmoteLookAtIK; public static float Setting_EmulateVRChatHipMovementWeight; + public static float Setting_HipThrustMultiplier = 0.1f; public Transform viewpoint; public Vector3 initialCamPos; @@ -60,12 +61,15 @@ public class DesktopVRIK : MonoBehaviour IKSystem.vrik.transform.localPosition = Vector3.zero; IKSystem.vrik.transform.localRotation = Quaternion.identity; + float movementVector = (1 - MovementSystem.Instance.movementVector.magnitude); + IKSystem.vrik.solver.spine.positionWeight = Setting_HipThrustMultiplier * movementVector; + //VRChat hip movement emulation if (Setting_EmulateVRChatHipMovementWeight != 0) { float angle = PlayerSetup.Instance.desktopCamera.transform.localEulerAngles.x; if (angle > 180) angle -= 360; - float leanAmount = angle * (1 - MovementSystem.Instance.movementVector.magnitude) * Setting_EmulateVRChatHipMovementWeight; + float leanAmount = angle * movementVector * Setting_EmulateVRChatHipMovementWeight; Quaternion rotation = Quaternion.AngleAxis(leanAmount, IKSystem.Instance.avatar.transform.right); IKSystem.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Head, rotation); } @@ -110,9 +114,13 @@ public class DesktopVRIK : MonoBehaviour vrik.solver.locomotion.angleThreshold = 30f; vrik.solver.locomotion.maxLegStretch = 0.75f; //nuke weights - vrik.solver.spine.headClampWeight = 0f; + vrik.solver.spine.headClampWeight = 1f; vrik.solver.spine.minHeadHeight = 0f; - //vrik.solver.spine.pelvisPositionWeight = 0f; + + //calm ur ass + vrik.solver.spine.positionWeight = 0.1f; + + vrik.solver.spine.pelvisPositionWeight = 0f; vrik.solver.leftArm.positionWeight = 0f; vrik.solver.leftArm.rotationWeight = 0f; vrik.solver.rightArm.positionWeight = 0f; @@ -128,6 +136,7 @@ public class DesktopVRIK : MonoBehaviour BodySystem.TrackingRightArmEnabled = false; BodySystem.TrackingLeftLegEnabled = false; BodySystem.TrackingRightLegEnabled = false; + BodySystem.TrackingPositionWeight = 0f; IKSystem.Instance.headAnchorRotationOffset = Vector3.zero; IKSystem.Instance.headAnchorPositionOffset = Vector3.zero; diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index 9a00ec2..c32f443 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -105,7 +105,6 @@ class IKSystemPatches { if (IKSystem.Instance.animator != null && IKSystem.Instance.animator.avatar != null && IKSystem.Instance.animator.avatar.isHuman) { - //why the fuck does this fix bad armatures and heels in ground ??? (this one is suprisingly not because of Default Robot Kyle) ... (Fuck you Default Robot Kyle) if (____poseHandler == null) { ____poseHandler = new HumanPoseHandler(IKSystem.Instance.animator.avatar, IKSystem.Instance.animator.transform); diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs index 80bd77c..d04ea4d 100644 --- a/DesktopVRIK/Properties/AssemblyInfo.cs +++ b/DesktopVRIK/Properties/AssemblyInfo.cs @@ -26,6 +26,6 @@ using System.Reflection; namespace DesktopVRIK.Properties; internal static class AssemblyInfoParams { - public const string Version = "2.0.1"; + public const string Version = "2.0.2"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json index b7d981d..d145c52 100644 --- a/DesktopVRIK/format.json +++ b/DesktopVRIK/format.json @@ -1,7 +1,7 @@ { "_id": 117, "name": "DesktopVRIK", - "modversion": "2.0.1", + "modversion": "2.0.2", "gameversion": "2022r170", "loaderversion": "0.5.7", "modtype": "Mod", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v2.0.1/DesktopVRIK.dll", + "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v2.0.2/DesktopVRIK.dll", "sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRIK/", - "changelog": "- Simplified VRIK calibration to avoid low heel issue.\n- Added checks for valid Humanoid rigs.\n- Added PlantFeet & EnforceViewPosition Settings.\n- Added Weight option for the VRChat-like hip movement.\n- Simplified config, added BTKUILib support.\n- Reworked calibration to support almost every avatar.\n- Added custom avatar-defined IKPose support.", + "changelog": "- Fixed butt from slipping out underneath you and thrusting when leaning.\n- Fixed VRIK bleeding into locomotion animations.", "embedcolor": "9b59b6" } \ No newline at end of file From b4fb9e62e618d01eb96e2dc702705706ab96f19c Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Mon, 16 Jan 2023 01:57:30 -0600 Subject: [PATCH 25/60] fucked --- .../BTKUI_Integration/BTKUI_Integration.cs | 32 ++++-- DesktopVRIK/DesktopVRIK.cs | 99 ++++++++-------- DesktopVRIK/DesktopVRIK_Helper.cs | 108 ++++++++++++++++++ DesktopVRIK/HarmonyPatches.cs | 43 +++++-- DesktopVRIK/Main.cs | 14 ++- 5 files changed, 220 insertions(+), 76 deletions(-) create mode 100644 DesktopVRIK/DesktopVRIK_Helper.cs diff --git a/DesktopVRIK/BTKUI_Integration/BTKUI_Integration.cs b/DesktopVRIK/BTKUI_Integration/BTKUI_Integration.cs index a752328..ed962e7 100644 --- a/DesktopVRIK/BTKUI_Integration/BTKUI_Integration.cs +++ b/DesktopVRIK/BTKUI_Integration/BTKUI_Integration.cs @@ -9,22 +9,38 @@ public static class BTKUI_Integration [MethodImpl(MethodImplOptions.NoInlining)] public static void Init() { - Page miscPage = QuickMenuAPI.MiscTabPage; - Category CategoryUI = miscPage.AddCategory("DesktopVRIK"); + //Add myself to the Misc Menu - var setting_Enabled = CategoryUI.AddToggle(DesktopVRIKMod.m_entryEnabled.DisplayName, DesktopVRIKMod.m_entryEnabled.Description, DesktopVRIKMod.m_entryEnabled.Value); + Page miscPage = QuickMenuAPI.MiscTabPage; + Category miscCategory = miscPage.AddCategory("DesktopVRIK"); + + var setting_Enabled = miscCategory.AddToggle(DesktopVRIKMod.m_entryEnabled.DisplayName, DesktopVRIKMod.m_entryEnabled.Description, DesktopVRIKMod.m_entryEnabled.Value); setting_Enabled.OnValueUpdated += b => DesktopVRIKMod.m_entryEnabled.Value = b; - var setting_EnforceViewPosition = CategoryUI.AddToggle(DesktopVRIKMod.m_entryEnforceViewPosition.DisplayName, DesktopVRIKMod.m_entryEnforceViewPosition.Description, DesktopVRIKMod.m_entryEnforceViewPosition.Value); + //Add my own page to not clog up Misc Menu + + Page desktopVRIKPage = miscCategory.AddPage("DesktopVRIK Settings", "", "Configure the settings for DesktopVRIK.", "DesktopVRIK"); + desktopVRIKPage.MenuTitle = "DesktopVRIK Settings"; + desktopVRIKPage.MenuSubtitle = "Simplified settings for VRIK on Desktop."; + + Category desktopVRIKCategory = desktopVRIKPage.AddCategory("DesktopVRIK"); + + var setting_Enabled_2 = desktopVRIKCategory.AddToggle(DesktopVRIKMod.m_entryEnabled.DisplayName, DesktopVRIKMod.m_entryEnabled.Description, DesktopVRIKMod.m_entryEnabled.Value); + setting_Enabled_2.OnValueUpdated += b => DesktopVRIKMod.m_entryEnabled.Value = b; + + var setting_EnforceViewPosition = desktopVRIKCategory.AddToggle(DesktopVRIKMod.m_entryEnforceViewPosition.DisplayName, DesktopVRIKMod.m_entryEnforceViewPosition.Description, DesktopVRIKMod.m_entryEnforceViewPosition.Value); setting_EnforceViewPosition.OnValueUpdated += b => DesktopVRIKMod.m_entryEnforceViewPosition.Value = b; - var setting_DisableEmoteVRIK = CategoryUI.AddToggle(DesktopVRIKMod.m_entryEmoteVRIK.DisplayName, DesktopVRIKMod.m_entryEmoteVRIK.Description, DesktopVRIKMod.m_entryEmoteVRIK.Value); + var setting_DisableEmoteVRIK = desktopVRIKCategory.AddToggle(DesktopVRIKMod.m_entryEmoteVRIK.DisplayName, DesktopVRIKMod.m_entryEmoteVRIK.Description, DesktopVRIKMod.m_entryEmoteVRIK.Value); setting_DisableEmoteVRIK.OnValueUpdated += b => DesktopVRIKMod.m_entryEmoteVRIK.Value = b; - var setting_DisableEmoteLookAtIK = CategoryUI.AddToggle(DesktopVRIKMod.m_entryEmoteLookAtIK.DisplayName, DesktopVRIKMod.m_entryEmoteLookAtIK.Description, DesktopVRIKMod.m_entryEmoteLookAtIK.Value); + var setting_DisableEmoteLookAtIK = desktopVRIKCategory.AddToggle(DesktopVRIKMod.m_entryEmoteLookAtIK.DisplayName, DesktopVRIKMod.m_entryEmoteLookAtIK.Description, DesktopVRIKMod.m_entryEmoteLookAtIK.Value); setting_DisableEmoteLookAtIK.OnValueUpdated += b => DesktopVRIKMod.m_entryEmoteLookAtIK.Value = b; - var setting_EmulateHipMovementWeight = miscPage.AddSlider(DesktopVRIKMod.m_entryEmulateVRChatHipMovementWeight.DisplayName, DesktopVRIKMod.m_entryEmulateVRChatHipMovementWeight.Description, DesktopVRIKMod.m_entryEmulateVRChatHipMovementWeight.Value, 0f, 1f); - setting_EmulateHipMovementWeight.OnValueUpdated += f => DesktopVRIKMod.m_entryEmulateVRChatHipMovementWeight.Value = f; + var setting_BodyLeanWeight = desktopVRIKPage.AddSlider(DesktopVRIKMod.m_entryBodyLeanWeight.DisplayName, DesktopVRIKMod.m_entryBodyLeanWeight.Description, DesktopVRIKMod.m_entryBodyLeanWeight.Value, 0f, 1f, 1); + setting_BodyLeanWeight.OnValueUpdated += f => DesktopVRIKMod.m_entryBodyLeanWeight.Value = f; + + var setting_BodyAngleLimit = desktopVRIKPage.AddSlider(DesktopVRIKMod.m_entryBodyAngleLimit.DisplayName, DesktopVRIKMod.m_entryBodyAngleLimit.Description, DesktopVRIKMod.m_entryBodyAngleLimit.Value, 0f, 90f, 0); + setting_BodyAngleLimit.OnValueUpdated += f => DesktopVRIKMod.m_entryBodyAngleLimit.Value = f; } } \ No newline at end of file diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index ab82ebd..4de314b 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -13,27 +13,23 @@ public class DesktopVRIK : MonoBehaviour { public static DesktopVRIK Instance; - public static bool Setting_Enabled, + public static bool + Setting_Enabled, Setting_EnforceViewPosition, Setting_EmoteVRIK, - Setting_EmoteLookAtIK; - public static float Setting_EmulateVRChatHipMovementWeight; - public static float Setting_HipThrustMultiplier = 0.1f; + Setting_EmoteLookAtIK, + Setting_Internal_PlantFeet = true; + + public static float + Setting_BodyLeanWeight = 0.3f, + Setting_BodyAngleLimit = 45f; public Transform viewpoint; - public Vector3 initialCamPos; - - Transform headIKTarget; - Transform avatarHeadBone; + public Vector3 eyeOffset; void Start() { Instance = this; - // create the shared Head IK Target - headIKTarget = new GameObject("[DesktopVRIK] Head IK Target").transform; - headIKTarget.parent = PlayerSetup.Instance.transform; - headIKTarget.localPosition = new Vector3(0f, 1.8f, 0f); - headIKTarget.localRotation = Quaternion.identity; } public void ChangeViewpointHandling(bool enabled) @@ -45,51 +41,30 @@ public class DesktopVRIK : MonoBehaviour PlayerSetup.Instance.desktopCamera.transform.localPosition = Vector3.zero; return; } - PlayerSetup.Instance.desktopCamera.transform.localPosition = initialCamPos; + PlayerSetup.Instance.desktopCamera.transform.localPosition = eyeOffset; } public void AlternativeOnPreSolverUpdate() { - //this order matters, rotation offset will be choppy if avatar is not cenetered first - - if (headIKTarget != null && avatarHeadBone != null) - { - headIKTarget.position = new Vector3(headIKTarget.position.x, avatarHeadBone.position.y, headIKTarget.position.z); - } + //set IK offsets (this is a really fucking weird way to do this) + DesktopVRIK_Helper.Instance?.OnUpdateVRIK(); //Reset avatar offset (VRIK will literally make you walk away from root otherwise) IKSystem.vrik.transform.localPosition = Vector3.zero; IKSystem.vrik.transform.localRotation = Quaternion.identity; - float movementVector = (1 - MovementSystem.Instance.movementVector.magnitude); - IKSystem.vrik.solver.spine.positionWeight = Setting_HipThrustMultiplier * movementVector; - - //VRChat hip movement emulation - if (Setting_EmulateVRChatHipMovementWeight != 0) - { - float angle = PlayerSetup.Instance.desktopCamera.transform.localEulerAngles.x; - if (angle > 180) angle -= 360; - float leanAmount = angle * movementVector * Setting_EmulateVRChatHipMovementWeight; - Quaternion rotation = Quaternion.AngleAxis(leanAmount, IKSystem.Instance.avatar.transform.right); - IKSystem.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Head, rotation); - } - - IKSystem.vrik.solver.plantFeet = true; + IKSystem.vrik.solver.plantFeet = Setting_Internal_PlantFeet; } public Animator animator; - //public Quaternion originalRotation; - public RuntimeAnimatorController runtimeAnimatorController; public VRIK AlternativeCalibration(CVRAvatar avatar) { animator = avatar.GetComponent(); - avatarHeadBone = animator.GetBoneTransform(HumanBodyBones.Head); + Transform avatarHeadBone = animator.GetBoneTransform(HumanBodyBones.Head); //Stuff to make bad armatures work (Fuck you Default Robot Kyle) avatar.transform.localPosition = Vector3.zero; - //originalRotation = avatar.transform.rotation; - //avatar.transform.rotation = Quaternion.identity; //ikpose layer (specified by avatar author) int ikposeLayerIndex = animator.GetLayerIndex("IKPose"); @@ -114,12 +89,7 @@ public class DesktopVRIK : MonoBehaviour vrik.solver.locomotion.angleThreshold = 30f; vrik.solver.locomotion.maxLegStretch = 0.75f; //nuke weights - vrik.solver.spine.headClampWeight = 1f; vrik.solver.spine.minHeadHeight = 0f; - - //calm ur ass - vrik.solver.spine.positionWeight = 0.1f; - vrik.solver.spine.pelvisPositionWeight = 0f; vrik.solver.leftArm.positionWeight = 0f; vrik.solver.leftArm.rotationWeight = 0f; @@ -131,6 +101,19 @@ public class DesktopVRIK : MonoBehaviour vrik.solver.rightLeg.rotationWeight = 0f; vrik.solver.IKPositionWeight = 0f; + //calm ur ass + vrik.solver.spine.positionWeight = 0f; + + + //related to body & head rotation offset/limit + vrik.solver.spine.headClampWeight = 1f; + vrik.solver.spine.bodyRotStiffness = 0.8f; + //makes chest between feet and head direction + vrik.solver.spine.chestClampWeight = 0.5f; + //needed to make head 1:1 with camera still + vrik.solver.spine.neckStiffness = 1f; + + //ChilloutVR specific BodySystem.TrackingLeftArmEnabled = false; BodySystem.TrackingRightArmEnabled = false; @@ -141,17 +124,19 @@ public class DesktopVRIK : MonoBehaviour IKSystem.Instance.headAnchorPositionOffset = Vector3.zero; //Custom funky AF head ik shit - foreach (Transform transform in headIKTarget) + foreach (Transform transform in DesktopVRIK_Helper.Instance.ik_HeadFollower) { if (transform.name == "Head IK Target") { Destroy(transform.gameObject); } } - headIKTarget.position = avatarHeadBone.position; - headIKTarget.rotation = Quaternion.identity; - VRIKCalibrator.CalibrateHead(vrik, headIKTarget.transform, IKSystem.Instance.headAnchorPositionOffset, IKSystem.Instance.headAnchorRotationOffset); - headIKTarget.localRotation = Quaternion.identity; + + DesktopVRIK_Helper.Instance.avatar_HeadBone = avatarHeadBone; + DesktopVRIK_Helper.Instance.ik_HeadFollower.position = avatarHeadBone.position; + DesktopVRIK_Helper.Instance.ik_HeadFollower.rotation = Quaternion.identity; + VRIKCalibrator.CalibrateHead(vrik, DesktopVRIK_Helper.Instance.ik_HeadFollower.transform, IKSystem.Instance.headAnchorPositionOffset, IKSystem.Instance.headAnchorRotationOffset); + DesktopVRIK_Helper.Instance.ik_HeadFollower.localRotation = Quaternion.identity; //force immediate calibration before animator decides to fuck us vrik.solver.SetToReferences(vrik.references); @@ -167,17 +152,23 @@ public class DesktopVRIK : MonoBehaviour } //Find eyeoffset - initialCamPos = PlayerSetup.Instance.desktopCamera.transform.localPosition; + eyeOffset = PlayerSetup.Instance.desktopCamera.transform.localPosition; viewpoint = avatarHeadBone.Find("LocalHeadPoint"); ChangeViewpointHandling(Setting_EnforceViewPosition); - if (vrik != null) + //reset ikpose layer + if (ikposeLayerIndex != -1) { - vrik.onPreSolverUpdate.AddListener(new UnityAction(this.AlternativeOnPreSolverUpdate)); + animator.SetLayerWeight(ikposeLayerIndex, 0f); + if (locoLayerIndex != -1) + { + animator.SetLayerWeight(locoLayerIndex, 1f); + } } - //avatar.transform.rotation = originalRotation; - IKSystem.Instance.ResetIK(); + vrik?.onPreSolverUpdate.AddListener(new UnityAction(this.AlternativeOnPreSolverUpdate)); + + DesktopVRIK_Helper.Instance?.OnResetIK(); return vrik; } diff --git a/DesktopVRIK/DesktopVRIK_Helper.cs b/DesktopVRIK/DesktopVRIK_Helper.cs new file mode 100644 index 0000000..bcab58f --- /dev/null +++ b/DesktopVRIK/DesktopVRIK_Helper.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using ABI_RC.Core.Player; +using ABI_RC.Systems.IK; +using ABI_RC.Systems.IK.SubSystems; +using ABI_RC.Systems.MovementSystem; +using RootMotion.FinalIK; + +namespace NAK.Melons.DesktopVRIK; + +internal class DesktopVRIK_Helper : MonoBehaviour +{ + public static DesktopVRIK_Helper Instance; + + //Avatar + public Transform avatar_HeadBone; + + //DesktopVRIK + public Transform ik_HeadFollower; + public Quaternion ik_HeadRotation; + + public static void CreateInstance() + { + Transform helper = new GameObject("[DesktopVRIK] Virtual Rig").transform; + helper.parent = PlayerSetup.Instance.transform; + helper.localPosition = Vector3.zero; + helper.localRotation = Quaternion.identity; + helper.gameObject.AddComponent(); + } + + void Start() + { + Instance = this; + + Transform headFollower = new GameObject("HeadBone_Follower").transform; + headFollower.parent = transform; + headFollower.localPosition = new Vector3(0f, 1.8f, 0f); + headFollower.localRotation = Quaternion.identity; + ik_HeadFollower = headFollower; + } + + public void OnUpdateVRIK() + { + if (avatar_HeadBone != null) + { + float globalWeight = (1 - MovementSystem.Instance.movementVector.magnitude); + globalWeight *= IKSystem.vrik.solver.locomotion.weight; + + //the most important thing ever + IKSystem.vrik.solver.spine.rotationWeight = globalWeight; + + HeadIK_FollowPosition(); + + HeadIK_RotateWithWeight(globalWeight); + HeadIK_FollowWithinAngle(globalWeight); + ik_HeadFollower.rotation = ik_HeadRotation; + } + } + + public void OnResetIK() + { + ik_HeadRotation = Quaternion.Euler(transform.eulerAngles.x, transform.eulerAngles.y, transform.eulerAngles.z); + } + + public void HeadIK_FollowPosition() + { + ik_HeadFollower.position = new Vector3(transform.position.x, avatar_HeadBone.position.y, transform.position.z); + } + + public void HeadIK_FollowWithinAngle(float weight) + { + if (DesktopVRIK.Setting_BodyAngleLimit != 0) + { + float weightedAngle = DesktopVRIK.Setting_BodyAngleLimit * weight; + float currentAngle = Mathf.DeltaAngle(transform.eulerAngles.y, ik_HeadRotation.eulerAngles.y); + if (Mathf.Abs(currentAngle) > weightedAngle) + { + float fixedCurrentAngle = currentAngle > 0 ? currentAngle : -currentAngle; + float clampedAngle = Mathf.MoveTowardsAngle(ik_HeadRotation.eulerAngles.y, transform.eulerAngles.y, fixedCurrentAngle - weightedAngle); + ik_HeadRotation = Quaternion.Euler(ik_HeadRotation.eulerAngles.x, clampedAngle, 0); + } + } + else + { + ik_HeadRotation = Quaternion.Euler(ik_HeadRotation.eulerAngles.x, transform.eulerAngles.y, transform.eulerAngles.z); + } + } + + public void HeadIK_RotateWithWeight(float weight) + { + //VRChat hip movement emulation + if (DesktopVRIK.Setting_BodyLeanWeight != 0) + { + float angle = PlayerSetup.Instance.desktopCamera.transform.localEulerAngles.x; + if (angle > 180) angle -= 360; + float leanAmount = angle * weight * DesktopVRIK.Setting_BodyLeanWeight; + ik_HeadRotation = Quaternion.Euler(leanAmount * 0.33f, ik_HeadRotation.eulerAngles.y, 0); + } + else + { + ik_HeadRotation = Quaternion.Euler(transform.eulerAngles.x, ik_HeadRotation.eulerAngles.y, transform.eulerAngles.z); + } + } +} \ No newline at end of file diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index c32f443..6925207 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -72,26 +72,47 @@ class PlayerSetupPatches { BodySystem.TrackingEnabled = !____emotePlaying; IKSystem.vrik.solver?.Reset(); + DesktopVRIK_Helper.Instance?.OnResetIK(); } } } } - [HarmonyPostfix] + + //should probably patch movement system instead + [HarmonyPrefix] [HarmonyPatch(typeof(PlayerSetup), "HandleDesktopCameraPosition")] - private static void Postfix_PlayerSetup_HandleDesktopCameraPosition(bool ignore, ref PlayerSetup __instance, ref MovementSystem ____movementSystem, ref int ___headBobbingLevel) + private static void Prefix_PlayerSetup_HandleDesktopCameraPosition + ( + bool ignore, + ref PlayerSetup __instance, + ref MovementSystem + ____movementSystem, + ref int ___headBobbingLevel + ) { - if (DesktopVRIK.Setting_Enabled && DesktopVRIK.Setting_EnforceViewPosition) + if (___headBobbingLevel != 2) { - if (!____movementSystem.disableCameraControl || ignore) - { - if (___headBobbingLevel == 2 && DesktopVRIK.Instance.viewpoint != null) - { - __instance.desktopCamera.transform.localPosition = Vector3.zero; - __instance.desktopCameraRig.transform.position = DesktopVRIK.Instance.viewpoint.position; - } - } + return; } + + if (!DesktopVRIK.Setting_Enabled || !DesktopVRIK.Setting_EnforceViewPosition) + { + return; + } + + if (____movementSystem.disableCameraControl && !ignore) + { + return; + } + + if (DesktopVRIK.Instance.viewpoint == null) + { + return; + } + + __instance.desktopCamera.transform.position = DesktopVRIK.Instance.viewpoint.position; + return; } } diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index 8fd3cc4..23644b2 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -13,16 +13,20 @@ public class DesktopVRIKMod : MelonMod m_entryEmoteVRIK, m_entryEmoteLookAtIK, m_entryAllowRootSlipping; - internal static MelonPreferences_Entry m_entryEmulateVRChatHipMovementWeight; + internal static MelonPreferences_Entry + m_entryBodyLeanWeight, + m_entryBodyAngleLimit; public override void OnInitializeMelon() { m_categoryDesktopVRIK = MelonPreferences.CreateCategory(SettingsCategory); m_entryEnabled = m_categoryDesktopVRIK.CreateEntry("Enabled", true, description: "Toggle DesktopVRIK entirely. Requires avatar reload."); - m_entryEmulateVRChatHipMovementWeight = m_categoryDesktopVRIK.CreateEntry("Body Movement Weight", 0.5f, description: "Emulates VRChat-like body movement when looking up/down. Set to 0 to disable."); m_entryEnforceViewPosition = m_categoryDesktopVRIK.CreateEntry("Enforce View Position", false, description: "Corrects view position to use VRIK offsets."); m_entryEmoteVRIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote VRIK", true, description: "Disable VRIK while emoting. Only disable if you are ok with looking dumb."); m_entryEmoteLookAtIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote LookAtIK", true, description: "Disable LookAtIK while emoting. This setting doesn't really matter, as LookAtIK isn't networked while doing an emote."); + m_entryBodyLeanWeight = m_categoryDesktopVRIK.CreateEntry("Body Lean Weight", 0.3f, description: "Emulates old VRChat-like body leaning when looking up/down. Set to 0 to disable."); + m_entryBodyAngleLimit = m_categoryDesktopVRIK.CreateEntry("Body Angle Limit", 45f, description: "Emulates VRChat-like body and head offset when rotating left/right. Set to 0 to disable."); + foreach (var setting in m_categoryDesktopVRIK.Entries) { setting.OnEntryValueChangedUntyped.Subscribe(OnUpdateSettings); @@ -46,7 +50,10 @@ public class DesktopVRIKMod : MelonMod { while (PlayerSetup.Instance == null) yield return null; + + DesktopVRIK_Helper.CreateInstance(); PlayerSetup.Instance.gameObject.AddComponent(); + while (DesktopVRIK.Instance == null) yield return null; UpdateAllSettings(); @@ -56,7 +63,8 @@ public class DesktopVRIKMod : MelonMod { if (!DesktopVRIK.Instance) return; DesktopVRIK.Setting_Enabled = m_entryEnabled.Value; - DesktopVRIK.Setting_EmulateVRChatHipMovementWeight = Mathf.Clamp01(m_entryEmulateVRChatHipMovementWeight.Value); + DesktopVRIK.Setting_BodyLeanWeight = Mathf.Clamp01(m_entryBodyLeanWeight.Value); + DesktopVRIK.Setting_BodyAngleLimit = Mathf.Clamp(m_entryBodyAngleLimit.Value, 0f, 90f); DesktopVRIK.Setting_EmoteVRIK = m_entryEmoteVRIK.Value; DesktopVRIK.Setting_EmoteLookAtIK = m_entryEmoteLookAtIK.Value; DesktopVRIK.Instance.ChangeViewpointHandling(m_entryEnforceViewPosition.Value); From d3d058607f660c7733bf94401000d7b4d20d1bb1 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Thu, 2 Feb 2023 20:38:22 -0600 Subject: [PATCH 26/60] tweaks to not make PAM and BID wonky also fuck vrik toes, those literally stink --- .../BTKUI_Integration/BTKUI_Integration.cs | 46 ------------------ DesktopVRIK/DesktopVRIK.cs | 46 ++++++++---------- DesktopVRIK/DesktopVRIK_Helper.cs | 2 +- DesktopVRIK/HarmonyPatches.cs | 2 +- DesktopVRIK/Integrations/BTKUIAddon.cs | 48 +++++++++++++++++++ DesktopVRIK/Main.cs | 11 ++--- DesktopVRIK/format.json | 8 ++-- 7 files changed, 79 insertions(+), 84 deletions(-) delete mode 100644 DesktopVRIK/BTKUI_Integration/BTKUI_Integration.cs create mode 100644 DesktopVRIK/Integrations/BTKUIAddon.cs diff --git a/DesktopVRIK/BTKUI_Integration/BTKUI_Integration.cs b/DesktopVRIK/BTKUI_Integration/BTKUI_Integration.cs deleted file mode 100644 index ed962e7..0000000 --- a/DesktopVRIK/BTKUI_Integration/BTKUI_Integration.cs +++ /dev/null @@ -1,46 +0,0 @@ -using BTKUILib; -using BTKUILib.UIObjects; -using System.Runtime.CompilerServices; - -namespace NAK.Melons.DesktopVRIK.BTKUI_Integration; - -public static class BTKUI_Integration -{ - [MethodImpl(MethodImplOptions.NoInlining)] - public static void Init() - { - //Add myself to the Misc Menu - - Page miscPage = QuickMenuAPI.MiscTabPage; - Category miscCategory = miscPage.AddCategory("DesktopVRIK"); - - var setting_Enabled = miscCategory.AddToggle(DesktopVRIKMod.m_entryEnabled.DisplayName, DesktopVRIKMod.m_entryEnabled.Description, DesktopVRIKMod.m_entryEnabled.Value); - setting_Enabled.OnValueUpdated += b => DesktopVRIKMod.m_entryEnabled.Value = b; - - //Add my own page to not clog up Misc Menu - - Page desktopVRIKPage = miscCategory.AddPage("DesktopVRIK Settings", "", "Configure the settings for DesktopVRIK.", "DesktopVRIK"); - desktopVRIKPage.MenuTitle = "DesktopVRIK Settings"; - desktopVRIKPage.MenuSubtitle = "Simplified settings for VRIK on Desktop."; - - Category desktopVRIKCategory = desktopVRIKPage.AddCategory("DesktopVRIK"); - - var setting_Enabled_2 = desktopVRIKCategory.AddToggle(DesktopVRIKMod.m_entryEnabled.DisplayName, DesktopVRIKMod.m_entryEnabled.Description, DesktopVRIKMod.m_entryEnabled.Value); - setting_Enabled_2.OnValueUpdated += b => DesktopVRIKMod.m_entryEnabled.Value = b; - - var setting_EnforceViewPosition = desktopVRIKCategory.AddToggle(DesktopVRIKMod.m_entryEnforceViewPosition.DisplayName, DesktopVRIKMod.m_entryEnforceViewPosition.Description, DesktopVRIKMod.m_entryEnforceViewPosition.Value); - setting_EnforceViewPosition.OnValueUpdated += b => DesktopVRIKMod.m_entryEnforceViewPosition.Value = b; - - var setting_DisableEmoteVRIK = desktopVRIKCategory.AddToggle(DesktopVRIKMod.m_entryEmoteVRIK.DisplayName, DesktopVRIKMod.m_entryEmoteVRIK.Description, DesktopVRIKMod.m_entryEmoteVRIK.Value); - setting_DisableEmoteVRIK.OnValueUpdated += b => DesktopVRIKMod.m_entryEmoteVRIK.Value = b; - - var setting_DisableEmoteLookAtIK = desktopVRIKCategory.AddToggle(DesktopVRIKMod.m_entryEmoteLookAtIK.DisplayName, DesktopVRIKMod.m_entryEmoteLookAtIK.Description, DesktopVRIKMod.m_entryEmoteLookAtIK.Value); - setting_DisableEmoteLookAtIK.OnValueUpdated += b => DesktopVRIKMod.m_entryEmoteLookAtIK.Value = b; - - var setting_BodyLeanWeight = desktopVRIKPage.AddSlider(DesktopVRIKMod.m_entryBodyLeanWeight.DisplayName, DesktopVRIKMod.m_entryBodyLeanWeight.Description, DesktopVRIKMod.m_entryBodyLeanWeight.Value, 0f, 1f, 1); - setting_BodyLeanWeight.OnValueUpdated += f => DesktopVRIKMod.m_entryBodyLeanWeight.Value = f; - - var setting_BodyAngleLimit = desktopVRIKPage.AddSlider(DesktopVRIKMod.m_entryBodyAngleLimit.DisplayName, DesktopVRIKMod.m_entryBodyAngleLimit.Description, DesktopVRIKMod.m_entryBodyAngleLimit.Value, 0f, 90f, 0); - setting_BodyAngleLimit.OnValueUpdated += f => DesktopVRIKMod.m_entryBodyAngleLimit.Value = f; - } -} \ No newline at end of file diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index 4de314b..5e73a26 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -17,12 +17,11 @@ public class DesktopVRIK : MonoBehaviour Setting_Enabled, Setting_EnforceViewPosition, Setting_EmoteVRIK, - Setting_EmoteLookAtIK, - Setting_Internal_PlantFeet = true; + Setting_EmoteLookAtIK; public static float - Setting_BodyLeanWeight = 0.3f, - Setting_BodyAngleLimit = 45f; + Setting_BodyLeanWeight = 0.5f, + Setting_BodyAngleLimit = 0f; public Transform viewpoint; public Vector3 eyeOffset; @@ -46,14 +45,15 @@ public class DesktopVRIK : MonoBehaviour public void AlternativeOnPreSolverUpdate() { - //set IK offsets (this is a really fucking weird way to do this) + //this order matters, rotation offset will be choppy if avatar is not cenetered first + DesktopVRIK_Helper.Instance?.OnUpdateVRIK(); //Reset avatar offset (VRIK will literally make you walk away from root otherwise) IKSystem.vrik.transform.localPosition = Vector3.zero; IKSystem.vrik.transform.localRotation = Quaternion.identity; - IKSystem.vrik.solver.plantFeet = Setting_Internal_PlantFeet; + IKSystem.vrik.solver.plantFeet = true; } public Animator animator; @@ -79,17 +79,27 @@ public class DesktopVRIK : MonoBehaviour animator.Update(0f); } - //Generic VRIK calibration shit VRIK vrik = avatar.gameObject.AddComponent(); vrik.AutoDetectReferences(); + //fuck toes + vrik.references.leftToes = null; + vrik.references.rightToes = null; + vrik.fixTransforms = true; vrik.solver.plantFeet = false; - vrik.solver.locomotion.weight = 0f; vrik.solver.locomotion.angleThreshold = 30f; vrik.solver.locomotion.maxLegStretch = 0.75f; - //nuke weights - vrik.solver.spine.minHeadHeight = 0f; + vrik.solver.spine.minHeadHeight = -100f; + + vrik.solver.spine.bodyRotStiffness = 0.15f; + vrik.solver.spine.headClampWeight = 1f; + vrik.solver.spine.maintainPelvisPosition = 1f; + vrik.solver.spine.neckStiffness = 0f; + + vrik.solver.locomotion.weight = 0f; + vrik.solver.spine.bodyPosStiffness = 0f; + vrik.solver.spine.positionWeight = 0f; vrik.solver.spine.pelvisPositionWeight = 0f; vrik.solver.leftArm.positionWeight = 0f; vrik.solver.leftArm.rotationWeight = 0f; @@ -101,27 +111,11 @@ public class DesktopVRIK : MonoBehaviour vrik.solver.rightLeg.rotationWeight = 0f; vrik.solver.IKPositionWeight = 0f; - //calm ur ass - vrik.solver.spine.positionWeight = 0f; - - - //related to body & head rotation offset/limit - vrik.solver.spine.headClampWeight = 1f; - vrik.solver.spine.bodyRotStiffness = 0.8f; - //makes chest between feet and head direction - vrik.solver.spine.chestClampWeight = 0.5f; - //needed to make head 1:1 with camera still - vrik.solver.spine.neckStiffness = 1f; - - - //ChilloutVR specific BodySystem.TrackingLeftArmEnabled = false; BodySystem.TrackingRightArmEnabled = false; BodySystem.TrackingLeftLegEnabled = false; BodySystem.TrackingRightLegEnabled = false; BodySystem.TrackingPositionWeight = 0f; - IKSystem.Instance.headAnchorRotationOffset = Vector3.zero; - IKSystem.Instance.headAnchorPositionOffset = Vector3.zero; //Custom funky AF head ik shit foreach (Transform transform in DesktopVRIK_Helper.Instance.ik_HeadFollower) diff --git a/DesktopVRIK/DesktopVRIK_Helper.cs b/DesktopVRIK/DesktopVRIK_Helper.cs index bcab58f..ae4f433 100644 --- a/DesktopVRIK/DesktopVRIK_Helper.cs +++ b/DesktopVRIK/DesktopVRIK_Helper.cs @@ -51,7 +51,7 @@ internal class DesktopVRIK_Helper : MonoBehaviour globalWeight *= IKSystem.vrik.solver.locomotion.weight; //the most important thing ever - IKSystem.vrik.solver.spine.rotationWeight = globalWeight; + //IKSystem.vrik.solver.spine.rotationWeight = globalWeight; HeadIK_FollowPosition(); diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index 6925207..2a9a6b1 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -139,7 +139,7 @@ class IKSystemPatches ____poseHandler.SetHumanPose(ref ___humanPose); ____vrik = DesktopVRIK.Instance.AlternativeCalibration(avatar); - IKSystem.Instance.ApplyAvatarScaleToIk(avatar.viewPosition.y); + IKSystem.Instance.ApplyAvatarScaleToIk(avatar.viewPosition.y); } } } diff --git a/DesktopVRIK/Integrations/BTKUIAddon.cs b/DesktopVRIK/Integrations/BTKUIAddon.cs new file mode 100644 index 0000000..e2ab2ab --- /dev/null +++ b/DesktopVRIK/Integrations/BTKUIAddon.cs @@ -0,0 +1,48 @@ +using BTKUILib; +using BTKUILib.UIObjects; +using System.Runtime.CompilerServices; + +namespace NAK.Melons.DesktopVRIK; + +public static class BTKUIAddon +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static void Init() + { + //Add myself to the Misc Menu + + Page miscPage = QuickMenuAPI.MiscTabPage; + Category miscCategory = miscPage.AddCategory(DesktopVRIKMod.SettingsCategory); + + AddMelonToggle(ref miscCategory, DesktopVRIKMod.m_entryEnabled); + + //Add my own page to not clog up Misc Menu + + Page desktopVRIKPage = miscCategory.AddPage("DesktopVRIK Settings", "", "Configure the settings for DesktopVRIK.", "DesktopVRIK"); + desktopVRIKPage.MenuTitle = "DesktopVRIK Settings"; + desktopVRIKPage.MenuSubtitle = "Simplified settings for VRIK on Desktop."; + + Category desktopVRIKCategory = desktopVRIKPage.AddCategory("DesktopVRIK"); + + AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.m_entryEnabled); + + AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.m_entryEnforceViewPosition); + + AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.m_entryEmoteVRIK); + + AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.m_entryEmoteLookAtIK); + + AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.m_entryBodyLeanWeight, 0, 1f); + + AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.m_entryBodyAngleLimit, 0, 90f); + } + private static void AddMelonToggle(ref Category category, MelonLoader.MelonPreferences_Entry entry) + { + category.AddToggle(entry.DisplayName, entry.Description, entry.Value).OnValueUpdated += b => entry.Value = b; + } + + private static void AddMelonSlider(ref Page page, MelonLoader.MelonPreferences_Entry entry, float min, float max) + { + page.AddSlider(entry.DisplayName, entry.Description, entry.Value, min, max).OnValueUpdated += f => entry.Value = f; + } +} \ No newline at end of file diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index 23644b2..524f85b 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -11,9 +11,8 @@ public class DesktopVRIKMod : MelonMod internal static MelonPreferences_Entry m_entryEnabled, m_entryEnforceViewPosition, m_entryEmoteVRIK, - m_entryEmoteLookAtIK, - m_entryAllowRootSlipping; - internal static MelonPreferences_Entry + m_entryEmoteLookAtIK; + internal static MelonPreferences_Entry m_entryBodyLeanWeight, m_entryBodyAngleLimit; public override void OnInitializeMelon() @@ -24,8 +23,8 @@ public class DesktopVRIKMod : MelonMod m_entryEmoteVRIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote VRIK", true, description: "Disable VRIK while emoting. Only disable if you are ok with looking dumb."); m_entryEmoteLookAtIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote LookAtIK", true, description: "Disable LookAtIK while emoting. This setting doesn't really matter, as LookAtIK isn't networked while doing an emote."); - m_entryBodyLeanWeight = m_categoryDesktopVRIK.CreateEntry("Body Lean Weight", 0.3f, description: "Emulates old VRChat-like body leaning when looking up/down. Set to 0 to disable."); - m_entryBodyAngleLimit = m_categoryDesktopVRIK.CreateEntry("Body Angle Limit", 45f, description: "Emulates VRChat-like body and head offset when rotating left/right. Set to 0 to disable."); + m_entryBodyLeanWeight = m_categoryDesktopVRIK.CreateEntry("Body Lean Weight", 0.5f, description: "Emulates old VRChat-like body leaning when looking up/down. Set to 0 to disable."); + m_entryBodyAngleLimit = m_categoryDesktopVRIK.CreateEntry("Body Angle Limit", 0f, description: "Emulates VRChat-like body and head offset when rotating left/right. Set to 0 to disable. (this setting only affects the feet due to chillout not setting up the player controller for VRIK)"); foreach (var setting in m_categoryDesktopVRIK.Entries) { @@ -36,7 +35,7 @@ public class DesktopVRIKMod : MelonMod if (MelonMod.RegisteredMelons.Any(it => it.Info.Name == "BTKUILib")) { MelonLogger.Msg("Initializing BTKUILib support."); - BTKUI_Integration.BTKUI_Integration.Init(); + BTKUIAddon.Init(); } //Apply patches (i stole) diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json index d145c52..c7ab85f 100644 --- a/DesktopVRIK/format.json +++ b/DesktopVRIK/format.json @@ -1,7 +1,7 @@ { "_id": 117, "name": "DesktopVRIK", - "modversion": "2.0.2", + "modversion": "2.0.3", "gameversion": "2022r170", "loaderversion": "0.5.7", "modtype": "Mod", @@ -14,10 +14,10 @@ "feet" ], "requirements": [ - "None" + "BTKUILib" ], - "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v2.0.2/DesktopVRIK.dll", + "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v2.0.3/DesktopVRIK.dll", "sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRIK/", - "changelog": "- Fixed butt from slipping out underneath you and thrusting when leaning.\n- Fixed VRIK bleeding into locomotion animations.", + "changelog": "- Tweaks to VRIK settings so BetterInteractDesktop & PickupArmMovement better behave alongside VRIK.\n- Tweaks to BTKUI integration.", "embedcolor": "9b59b6" } \ No newline at end of file From 455bf9180cea34062b084a989f18d7823bd3c6f1 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Thu, 9 Feb 2023 19:28:55 -0600 Subject: [PATCH 27/60] att --- DesktopVRIK/DesktopVRIK.csproj | 12 ++++++------ DesktopVRIK/Properties/AssemblyInfo.cs | 3 ++- DesktopVRIK/format.json | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/DesktopVRIK/DesktopVRIK.csproj b/DesktopVRIK/DesktopVRIK.csproj index c432ed3..5a31a95 100644 --- a/DesktopVRIK/DesktopVRIK.csproj +++ b/DesktopVRIK/DesktopVRIK.csproj @@ -16,22 +16,22 @@ C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll - ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll - ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\BTKUILib.dll + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\BTKUILib.dll - ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\MelonLoader\MelonLoader.dll - ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll - ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AssetBundleModule.dll + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AssetBundleModule.dll C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll @@ -40,7 +40,7 @@ C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.InputLegacyModule.dll - ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.PhysicsModule.dll + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.PhysicsModule.dll diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs index d04ea4d..2494ba3 100644 --- a/DesktopVRIK/Properties/AssemblyInfo.cs +++ b/DesktopVRIK/Properties/AssemblyInfo.cs @@ -22,10 +22,11 @@ using System.Reflection; [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] [assembly: MelonOptionalDependencies("BTKUILib")] +[assembly: HarmonyDontPatchAll] namespace DesktopVRIK.Properties; internal static class AssemblyInfoParams { - public const string Version = "2.0.2"; + public const string Version = "2.0.5"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json index c7ab85f..d1d47d6 100644 --- a/DesktopVRIK/format.json +++ b/DesktopVRIK/format.json @@ -1,7 +1,7 @@ { "_id": 117, "name": "DesktopVRIK", - "modversion": "2.0.3", + "modversion": "2.0.5", "gameversion": "2022r170", "loaderversion": "0.5.7", "modtype": "Mod", @@ -16,7 +16,7 @@ "requirements": [ "BTKUILib" ], - "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v2.0.3/DesktopVRIK.dll", + "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v2.0.5/DesktopVRIK.dll", "sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRIK/", "changelog": "- Tweaks to VRIK settings so BetterInteractDesktop & PickupArmMovement better behave alongside VRIK.\n- Tweaks to BTKUI integration.", "embedcolor": "9b59b6" From 16e888c64d8b3873126411bdee2c8dbd6ec003dd Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Thu, 9 Feb 2023 22:59:43 -0600 Subject: [PATCH 28/60] Update README.md --- README.md | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 804a49a..9e5c790 100644 --- a/README.md +++ b/README.md @@ -17,22 +17,9 @@ https://feedback.abinteractive.net/p/pivot-desktop-camera-with-head Here is the block of text where I tell you this mod is not affiliated or endorsed by ABI. https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games -> I am not affiliated with ABI in any official capacity, these mods are not endorsed or outright permitted by ABI and are subject to scrutiny. +> This mod is an independent creation and is not affiliated with, supported by or approved by Alpha Blend Interactive. -> Neither I nor these mods are in any way affiliated with Alpha Blend Interactive and/or ChilloutVR. Using these modifications might cause issues with the performance, security or stability of the game. Use at your own risk. +> Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use. -> Any modifications that are not approved can get your ABI account terminated and such this modification is following the "modding guidelines" at the best it could be. -> They reserve the right to punish users using my mod. -> If you are scared of using modifications in your game do not install mods. +> To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive. -> I do not affiliate ABI and the mod is not supported by ABI. - -> Me and this modification are in no affiliation with ABI and not supported by ABI. - -> This mod is not affiliated with Alpha Blend Interactive. The mod comes with no warranty. Use at your own risk, as I am not responsible for any misuse. - -> I'm not affiliated with Alpha Blend Interactive and this mod is not officially supported by the game. - -> When releasing mods to the public, it is required to state, that the mod authors and modification are in no affiliation with ABI and not supported by ABI. :trollface: - -> i ran out of places to steal disclaimers from From cbd65aa8130d8f2368687aceb593f0a480f2335e Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Fri, 24 Feb 2023 20:07:48 -0600 Subject: [PATCH 29/60] rewrite --- DesktopVRIK/DesktopVRIK.cs | 238 ++++++------- DesktopVRIK/DesktopVRIK.csproj | 7 +- DesktopVRIK/DesktopVRIKCalibrator.cs | 450 +++++++++++++++++++++++++ DesktopVRIK/DesktopVRIK_Helper.cs | 108 ------ DesktopVRIK/HarmonyPatches.cs | 235 ++----------- DesktopVRIK/Integrations/BTKUIAddon.cs | 48 --- DesktopVRIK/Main.cs | 79 ++--- DesktopVRIK/Properties/AssemblyInfo.cs | 9 +- 8 files changed, 635 insertions(+), 539 deletions(-) create mode 100644 DesktopVRIK/DesktopVRIKCalibrator.cs delete mode 100644 DesktopVRIK/DesktopVRIK_Helper.cs delete mode 100644 DesktopVRIK/Integrations/BTKUIAddon.cs diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index 5e73a26..a63d9ce 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -1,169 +1,149 @@ -using ABI.CCK.Components; -using ABI_RC.Core.Player; +using ABI_RC.Core.Player; using ABI_RC.Systems.IK; using ABI_RC.Systems.IK.SubSystems; using ABI_RC.Systems.MovementSystem; using RootMotion.FinalIK; +using System.Reflection; using UnityEngine; -using UnityEngine.Events; namespace NAK.Melons.DesktopVRIK; public class DesktopVRIK : MonoBehaviour { public static DesktopVRIK Instance; + public DesktopVRIKCalibrator Calibrator; - public static bool - Setting_Enabled, - Setting_EnforceViewPosition, - Setting_EmoteVRIK, - Setting_EmoteLookAtIK; + // DesktopVRIK Settings + public bool + Setting_Enabled = true, + Setting_HipMovement = true, + Setting_ResetOnLand = true, + Setting_PlantFeet = true, + Setting_EnforceViewPosition; + public float + Setting_BodyLeanWeight, + Setting_BodyHeadingLimit, + Setting_PelvisHeadingWeight, + Setting_ChestHeadingWeight; - public static float - Setting_BodyLeanWeight = 0.5f, - Setting_BodyAngleLimit = 0f; - - public Transform viewpoint; - public Vector3 eyeOffset; + // Internal Stuff + private float + ik_SimulatedRootAngle; + private bool + ms_lastGrounded, + ps_emoteIsPlaying; + static readonly FieldInfo ms_isGrounded = typeof(MovementSystem).GetField("_isGrounded", BindingFlags.NonPublic | BindingFlags.Instance); void Start() { + Calibrator = new DesktopVRIKCalibrator(); Instance = this; + DesktopVRIKMod.UpdateAllSettings(); } - public void ChangeViewpointHandling(bool enabled) + public void OnSetupAvatarDesktop() { - if (Setting_EnforceViewPosition == enabled) return; - Setting_EnforceViewPosition = enabled; - if (enabled) - { - PlayerSetup.Instance.desktopCamera.transform.localPosition = Vector3.zero; - return; - } - PlayerSetup.Instance.desktopCamera.transform.localPosition = eyeOffset; + if (!Setting_Enabled) return; + Calibrator.SetupDesktopVRIK(); + ik_SimulatedRootAngle = transform.eulerAngles.y; } - public void AlternativeOnPreSolverUpdate() + //public void OnReCalibrateAvatar() + //{ + // Calibrator.RecalibrateDesktopVRIK(); + // ik_SimulatedRootAngle = transform.eulerAngles.y; + //} + + public bool OnApplyAvatarScaleToIk(float height) { - //this order matters, rotation offset will be choppy if avatar is not cenetered first - - DesktopVRIK_Helper.Instance?.OnUpdateVRIK(); - - //Reset avatar offset (VRIK will literally make you walk away from root otherwise) - IKSystem.vrik.transform.localPosition = Vector3.zero; - IKSystem.vrik.transform.localRotation = Quaternion.identity; - - IKSystem.vrik.solver.plantFeet = true; + if (Calibrator.vrik != null) + { + Calibrator.vrik.solver.locomotion.footDistance = Calibrator.initialFootDistance * height; + Calibrator.vrik.solver.locomotion.stepThreshold = Calibrator.initialStepThreshold * height; + return true; + } + return false; } - public Animator animator; - - public VRIK AlternativeCalibration(CVRAvatar avatar) + public void OnPlayerSetupUpdate(bool isEmotePlaying) { - animator = avatar.GetComponent(); - Transform avatarHeadBone = animator.GetBoneTransform(HumanBodyBones.Head); - - //Stuff to make bad armatures work (Fuck you Default Robot Kyle) - avatar.transform.localPosition = Vector3.zero; - - //ikpose layer (specified by avatar author) - int ikposeLayerIndex = animator.GetLayerIndex("IKPose"); - int locoLayerIndex = animator.GetLayerIndex("Locomotion/Emotes"); - if (ikposeLayerIndex != -1) + bool changed = isEmotePlaying != ps_emoteIsPlaying; + if (changed) { - animator.SetLayerWeight(ikposeLayerIndex, 1f); - if (locoLayerIndex != -1) + ps_emoteIsPlaying = isEmotePlaying; + Calibrator.vrik.transform.localPosition = Vector3.zero; + Calibrator.vrik.transform.localRotation = Quaternion.identity; + if (Calibrator.lookAtIK != null) { - animator.SetLayerWeight(locoLayerIndex, 0f); + Calibrator.lookAtIK.enabled = !isEmotePlaying; } - animator.Update(0f); + BodySystem.TrackingEnabled = !isEmotePlaying; + Calibrator.vrik.solver?.Reset(); + } + } + + public void OnPreSolverUpdate() + { + if (ps_emoteIsPlaying) return; + + bool isGrounded = (bool)ms_isGrounded.GetValue(MovementSystem.Instance); + + // Calculate everything that affects weight + float weight = Calibrator.vrik.solver.IKPositionWeight; + weight *= (1 - MovementSystem.Instance.movementVector.magnitude); + weight *= isGrounded ? 1f : 0f; + + // Reset avatar offset (VRIK will literally make you walk away from root otherwise) + Calibrator.vrik.transform.localPosition = Vector3.zero; + Calibrator.vrik.transform.localRotation = Quaternion.identity; + + // Plant feet is nice for Desktop + Calibrator.vrik.solver.plantFeet = Setting_PlantFeet; + + // This is nice for walk cycles + //Calibrator.vrik.solver.spine.rotateChestByHands = Setting_RotateChestByHands * weight; + + //reset solver if weight changes dramatically + if (Setting_ResetOnLand) + { + if (isGrounded && !ms_lastGrounded) + { + Calibrator.vrik.solver.Reset(); + } + ms_lastGrounded = isGrounded; } - VRIK vrik = avatar.gameObject.AddComponent(); - vrik.AutoDetectReferences(); - - //fuck toes - vrik.references.leftToes = null; - vrik.references.rightToes = null; - - vrik.fixTransforms = true; - vrik.solver.plantFeet = false; - vrik.solver.locomotion.angleThreshold = 30f; - vrik.solver.locomotion.maxLegStretch = 0.75f; - vrik.solver.spine.minHeadHeight = -100f; - - vrik.solver.spine.bodyRotStiffness = 0.15f; - vrik.solver.spine.headClampWeight = 1f; - vrik.solver.spine.maintainPelvisPosition = 1f; - vrik.solver.spine.neckStiffness = 0f; - - vrik.solver.locomotion.weight = 0f; - vrik.solver.spine.bodyPosStiffness = 0f; - vrik.solver.spine.positionWeight = 0f; - vrik.solver.spine.pelvisPositionWeight = 0f; - vrik.solver.leftArm.positionWeight = 0f; - vrik.solver.leftArm.rotationWeight = 0f; - vrik.solver.rightArm.positionWeight = 0f; - vrik.solver.rightArm.rotationWeight = 0f; - vrik.solver.leftLeg.positionWeight = 0f; - vrik.solver.leftLeg.rotationWeight = 0f; - vrik.solver.rightLeg.positionWeight = 0f; - vrik.solver.rightLeg.rotationWeight = 0f; - vrik.solver.IKPositionWeight = 0f; - - BodySystem.TrackingLeftArmEnabled = false; - BodySystem.TrackingRightArmEnabled = false; - BodySystem.TrackingLeftLegEnabled = false; - BodySystem.TrackingRightLegEnabled = false; - BodySystem.TrackingPositionWeight = 0f; - - //Custom funky AF head ik shit - foreach (Transform transform in DesktopVRIK_Helper.Instance.ik_HeadFollower) + // Old VRChat hip movement emulation + if (Setting_BodyLeanWeight > 0) { - if (transform.name == "Head IK Target") - { - Destroy(transform.gameObject); - } + float weightedAngle = Setting_BodyLeanWeight * weight; + float angle = PlayerSetup.Instance.desktopCamera.transform.localEulerAngles.x; + angle = (angle > 180) ? angle - 360 : angle; + Quaternion rotation = Quaternion.AngleAxis(angle * weightedAngle, IKSystem.Instance.avatar.transform.right); + Calibrator.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Head, rotation); } - DesktopVRIK_Helper.Instance.avatar_HeadBone = avatarHeadBone; - DesktopVRIK_Helper.Instance.ik_HeadFollower.position = avatarHeadBone.position; - DesktopVRIK_Helper.Instance.ik_HeadFollower.rotation = Quaternion.identity; - VRIKCalibrator.CalibrateHead(vrik, DesktopVRIK_Helper.Instance.ik_HeadFollower.transform, IKSystem.Instance.headAnchorPositionOffset, IKSystem.Instance.headAnchorRotationOffset); - DesktopVRIK_Helper.Instance.ik_HeadFollower.localRotation = Quaternion.identity; - - //force immediate calibration before animator decides to fuck us - vrik.solver.SetToReferences(vrik.references); - vrik.solver.Initiate(vrik.transform); - - if (ikposeLayerIndex != -1) + // Make root heading follow within a set limit + if (Setting_BodyHeadingLimit > 0) { - animator.SetLayerWeight(ikposeLayerIndex, 0f); - if (locoLayerIndex != -1) + float weightedAngleLimit = Setting_BodyHeadingLimit * weight; + float currentAngle = Mathf.DeltaAngle(transform.eulerAngles.y, ik_SimulatedRootAngle); + float angleMaxDelta = Mathf.Abs(currentAngle); + if (angleMaxDelta > weightedAngleLimit) { - animator.SetLayerWeight(locoLayerIndex, 1f); + currentAngle = Mathf.Sign(currentAngle) * weightedAngleLimit; + ik_SimulatedRootAngle = Mathf.MoveTowardsAngle(ik_SimulatedRootAngle, transform.eulerAngles.y, angleMaxDelta - weightedAngleLimit); + } + Calibrator.vrik.solver.spine.rootHeadingOffset = currentAngle; + if (Setting_PelvisHeadingWeight > 0) + { + Calibrator.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Pelvis, new Vector3(0f, currentAngle * Setting_PelvisHeadingWeight, 0f)); + Calibrator.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Chest, new Vector3(0f, -currentAngle * Setting_PelvisHeadingWeight, 0f)); + } + if (Setting_ChestHeadingWeight > 0) + { + Calibrator.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Chest, new Vector3(0f, currentAngle * Setting_ChestHeadingWeight, 0f)); } } - - //Find eyeoffset - eyeOffset = PlayerSetup.Instance.desktopCamera.transform.localPosition; - viewpoint = avatarHeadBone.Find("LocalHeadPoint"); - ChangeViewpointHandling(Setting_EnforceViewPosition); - - //reset ikpose layer - if (ikposeLayerIndex != -1) - { - animator.SetLayerWeight(ikposeLayerIndex, 0f); - if (locoLayerIndex != -1) - { - animator.SetLayerWeight(locoLayerIndex, 1f); - } - } - - vrik?.onPreSolverUpdate.AddListener(new UnityAction(this.AlternativeOnPreSolverUpdate)); - - DesktopVRIK_Helper.Instance?.OnResetIK(); - - return vrik; } } \ No newline at end of file diff --git a/DesktopVRIK/DesktopVRIK.csproj b/DesktopVRIK/DesktopVRIK.csproj index 5a31a95..ea97a04 100644 --- a/DesktopVRIK/DesktopVRIK.csproj +++ b/DesktopVRIK/DesktopVRIK.csproj @@ -18,9 +18,6 @@ C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll - - C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\BTKUILib.dll - C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll @@ -44,6 +41,10 @@ + + + + diff --git a/DesktopVRIK/DesktopVRIKCalibrator.cs b/DesktopVRIK/DesktopVRIKCalibrator.cs new file mode 100644 index 0000000..e16340f --- /dev/null +++ b/DesktopVRIK/DesktopVRIKCalibrator.cs @@ -0,0 +1,450 @@ +using ABI.CCK.Components; +using ABI_RC.Core; +using ABI_RC.Core.Base; +using ABI_RC.Core.Player; +using ABI_RC.Systems.IK; +using ABI_RC.Systems.IK.SubSystems; +using HarmonyLib; +using RootMotion.FinalIK; +using UnityEngine; +using UnityEngine.Events; + +namespace NAK.Melons.DesktopVRIK; + +public class DesktopVRIKCalibrator +{ + public DesktopVRIKCalibrator() + { + // Get base game scripts. + ikSystem = IKSystem.Instance; + playerSetup = PlayerSetup.Instance; + + // Get traverse to private shit in iksystem. + _vrikTraverse = Traverse.Create(ikSystem).Field("_vrik"); + _avatarTraverse = Traverse.Create(ikSystem).Field("_avatar"); + _animatorManagerTraverse = Traverse.Create(ikSystem).Field("_animatorManager"); + _poseHandlerTraverse = Traverse.Create(ikSystem).Field("_poseHandler"); + _avatarRootHeightTraverse = Traverse.Create(ikSystem).Field("_avatarRootHeight"); + + // Get traverse to private shit in playersetup. + _lookIKTraverse = Traverse.Create(playerSetup).Field("lookIK"); + } + + //Settings + public bool Setting_UseVRIKToes = true; + public bool Setting_FindUnmappedToes = true; + + //DesktopVRIK + public CVRAvatar avatar; + public Animator animator; + public Transform avatarTransform; + public VRIK vrik; + public LookAtIK lookAtIK; + public HumanPoseHandler humanPoseHandler; + public HumanPose initialHumanPose; + public bool fixTransformsRequired; + public float initialFootDistance; + public float initialStepThreshold; + + //Traverse + private IKSystem ikSystem; + private PlayerSetup playerSetup; + private Traverse _vrikTraverse; + private Traverse _lookIKTraverse; + private Traverse _avatarTraverse; + private Traverse _animatorManagerTraverse; + private Traverse _poseHandlerTraverse; + private Traverse _avatarRootHeightTraverse; + + //public void RecalibrateDesktopVRIK() + //{ + // if (avatar != null) + // { + // //calibrate VRIK + // CalibrateDesktopVRIK(); + // } + // else + // { + // //we never calibrated + // SetupDesktopVRIK(); + // } + //} + + public void SetupDesktopVRIK() + { + //store avatar root transform & center it + avatar = playerSetup._avatar.GetComponent(); + animator = avatar.GetComponent(); + avatarTransform = avatar.transform; + avatarTransform.localPosition = Vector3.zero; + lookAtIK = _lookIKTraverse.GetValue(); + + //prepare for VRIK + PrepareIKSystem(); + CalibrateDesktopVRIK(); + + //add presolver update listener + vrik.onPreSolverUpdate.AddListener(new UnityAction(DesktopVRIK.Instance.OnPreSolverUpdate)); + } + + private void CalibrateDesktopVRIK() + { + //calibrate VRIK + PrepareAvatarVRIK(); + SetAvatarIKPose(true); + CalculateInitialIKScaling(); + CalibrateHeadIK(); + ForceInitiateVRIKSolver(); + SetAvatarIKPose(false); + } + + private void PrepareIKSystem() + { + // Get the animator manager and human pose handler + var animatorManager = _animatorManagerTraverse.GetValue(); + humanPoseHandler = _poseHandlerTraverse.GetValue(); + + // Store the avatar component + _avatarTraverse.SetValue(avatar); + + // Set the animator for the IK system + ikSystem.animator = animator; + if (ikSystem.animator != null) + { + animatorManager.SetAnimator(ikSystem.animator, ikSystem.animator.runtimeAnimatorController); + } + + // Set the avatar height float + float avatarHeight = ikSystem.vrPlaySpace.transform.InverseTransformPoint(avatarTransform.position).y; + _avatarRootHeightTraverse.SetValue(avatarHeight); + + // Create a new human pose handler and dispose the old one + if (humanPoseHandler != null) + { + humanPoseHandler.Dispose(); + _poseHandlerTraverse.SetValue(null); + } + humanPoseHandler = new HumanPoseHandler(ikSystem.animator.avatar, avatarTransform); + _poseHandlerTraverse.SetValue(humanPoseHandler); + + // Find valid human bones + IKSystem.BoneExists.Clear(); + foreach (HumanBodyBones bone in Enum.GetValues(typeof(HumanBodyBones))) + { + if (bone != HumanBodyBones.LastBone) + { + IKSystem.BoneExists.Add(bone, ikSystem.animator.GetBoneTransform(bone) != null); + } + } + + // Prepare BodySystem for calibration + BodySystem.TrackingLeftArmEnabled = false; + BodySystem.TrackingRightArmEnabled = false; + BodySystem.TrackingLeftLegEnabled = false; + BodySystem.TrackingRightLegEnabled = false; + BodySystem.TrackingPositionWeight = 0f; + } + + private void PrepareAvatarVRIK() + { + //add and configure VRIK + vrik = avatar.gameObject.AddComponentIfMissing(); + vrik.AutoDetectReferences(); + ConfigureVRIKReferences(); + _vrikTraverse.SetValue(vrik); + + //in testing, not really needed + //only required if Setting_FindUnmappedToes + //and non-human mapped toes are found + vrik.fixTransforms = fixTransformsRequired; + + //default solver settings + vrik.solver.locomotion.weight = 0f; + vrik.solver.locomotion.angleThreshold = 30f; + vrik.solver.locomotion.maxLegStretch = 0.75f; + vrik.solver.spine.minHeadHeight = 0f; + vrik.solver.IKPositionWeight = 1f; + //disable to not bleed into anims + vrik.solver.spine.chestClampWeight = 0f; + vrik.solver.spine.maintainPelvisPosition = 0f; + //for body leaning + vrik.solver.spine.neckStiffness = 0.0001f; //cannot be 0 + vrik.solver.spine.bodyPosStiffness = 1f; + vrik.solver.spine.bodyRotStiffness = 0.2f; + //disable so avatar doesnt try and walk away + //fixes nameplate spazzing on remote + vrik.solver.locomotion.velocityFactor = 0f; + vrik.solver.locomotion.maxVelocity = 0f; + //disable so PAM & BID dont make body shake + vrik.solver.spine.rotateChestByHands = 0f; + //enable so knees on fucked models work better + vrik.solver.leftLeg.useAnimatedBendNormal = true; + vrik.solver.rightLeg.useAnimatedBendNormal = true; + //enable to prioritize LookAtIK + vrik.solver.spine.headClampWeight = 0.2f; + //disable to not go on tippytoes + vrik.solver.spine.positionWeight = 0f; + vrik.solver.spine.rotationWeight = 1f; + + //vrik.solver.spine.maintainPelvisPosition = 1f; + //vrik.solver.locomotion.weight = 0f; + //vrik.solver.spine.positionWeight = 0f; + //vrik.solver.spine.pelvisPositionWeight = 0f; + //vrik.solver.leftArm.positionWeight = 0f; + //vrik.solver.leftArm.rotationWeight = 0f; + //vrik.solver.rightArm.positionWeight = 0f; + //vrik.solver.rightArm.rotationWeight = 0f; + //vrik.solver.leftLeg.positionWeight = 0f; + //vrik.solver.leftLeg.rotationWeight = 0f; + //vrik.solver.rightLeg.positionWeight = 0f; + //vrik.solver.rightLeg.rotationWeight = 0f; + //vrik.solver.IKPositionWeight = 0f; + + //THESE ARE CONFIGURABLE IN GAME IK SETTINGS + //vrik.solver.leftLeg.target = null; + //vrik.solver.leftLeg.bendGoal = null; + //vrik.solver.leftLeg.positionWeight = 0f; + //vrik.solver.leftLeg.bendGoalWeight = 0f; + //vrik.solver.rightLeg.target = null; + //vrik.solver.rightLeg.bendGoal = null; + //vrik.solver.rightLeg.positionWeight = 0f; + //vrik.solver.rightLeg.bendGoalWeight = 0f; + //vrik.solver.spine.pelvisTarget = null; + //vrik.solver.spine.chestGoal = null; + //vrik.solver.spine.positionWeight = 0f; + //vrik.solver.spine.rotationWeight = 0f; + //vrik.solver.spine.pelvisPositionWeight = 0f; + //vrik.solver.spine.pelvisRotationWeight = 0f; + //vrik.solver.spine.chestGoalWeight = 0f; + } + + private void CalculateInitialIKScaling() + { + // Get distance between feets and thighs (fixes some weird armatures) + float footDistance = Vector3.Distance(vrik.references.leftFoot.position, vrik.references.rightFoot.position); + float thighDistance = Vector3.Distance(vrik.references.leftThigh.position, vrik.references.rightThigh.position); + float greatestDistance = Mathf.Min(footDistance, thighDistance); + initialFootDistance = greatestDistance * 0.5f; + initialStepThreshold = greatestDistance * 0.4f; + + //set initial values now, as avatars without scaling dont apply it + vrik.solver.locomotion.footDistance = initialFootDistance; + vrik.solver.locomotion.stepThreshold = initialStepThreshold; + } + + private void CalibrateHeadIK() + { + // Lazy HeadIKTarget calibration + if (vrik.solver.spine.headTarget == null) + { + vrik.solver.spine.headTarget = new GameObject("Head IK Target").transform; + } + vrik.solver.spine.headTarget.parent = vrik.references.head; + vrik.solver.spine.headTarget.localPosition = Vector3.zero; + vrik.solver.spine.headTarget.localRotation = Quaternion.identity; + } + + private void SetAvatarIKPose(bool enforceTPose) + { + int ikposeLayerIndex = animator.GetLayerIndex("IKPose"); + int locoLayerIndex = animator.GetLayerIndex("Locomotion/Emotes"); + + // Use custom IKPose if found. + if (ikposeLayerIndex != -1 && locoLayerIndex != -1) + { + animator.SetLayerWeight(ikposeLayerIndex, enforceTPose ? 1f : 0f); + animator.SetLayerWeight(locoLayerIndex, enforceTPose ? 0f : 1f); + animator.Update(0f); + return; + } + + // Otherwise use DesktopVRIK IKPose & revert afterwards. + if (enforceTPose) + { + humanPoseHandler.GetHumanPose(ref initialHumanPose); + humanPoseHandler.GetHumanPose(ref ikSystem.humanPose); + for (int i = 0; i < IKPoseMuscles.Length; i++) + { + IKSystem.Instance.ApplyMuscleValue((MuscleIndex)i, IKPoseMuscles[i], ref ikSystem.humanPose.muscles); + } + humanPoseHandler.SetHumanPose(ref ikSystem.humanPose); + } + else + { + humanPoseHandler.SetHumanPose(ref initialHumanPose); + } + } + + private void ForceInitiateVRIKSolver() + { + //force immediate calibration before animator decides to fuck us + vrik.solver.SetToReferences(vrik.references); + vrik.solver.Initiate(vrik.transform); + } + + private void ConfigureVRIKReferences() + { + fixTransformsRequired = false; + + Transform leftShoulderBone = vrik.references.leftShoulder; + Transform rightShoulderBone = vrik.references.rightShoulder; + Transform assumedChest = leftShoulderBone?.parent; + + // Repair chest & spine bone references (valve models were messed up) + if (assumedChest != null && rightShoulderBone.parent == assumedChest && + vrik.references.chest != assumedChest) + { + vrik.references.chest = assumedChest; + vrik.references.spine = assumedChest.parent; + } + + if (!Setting_UseVRIKToes) + { + vrik.references.leftToes = null; + vrik.references.rightToes = null; + } + else if (Setting_FindUnmappedToes) + { + Transform leftToes = vrik.references.leftToes; + Transform rightToes = vrik.references.rightToes; + if (leftToes == null && rightToes == null) + { + leftToes = FindUnmappedToe(vrik.references.leftFoot); + rightToes = FindUnmappedToe(vrik.references.rightFoot); + if (leftToes != null && rightToes != null) + { + fixTransformsRequired = true; + vrik.references.leftToes = leftToes; + vrik.references.rightToes = rightToes; + } + } + } + + // Fix error when there is no finger bones + // Making up bullshit cause VRIK is evil otherwise + if (vrik.references.leftHand.childCount == 0) + { + vrik.solver.leftArm.wristToPalmAxis = Vector3.up; + vrik.solver.leftArm.palmToThumbAxis = -Vector3.forward; + } + if (vrik.references.rightHand.childCount == 0) + { + vrik.solver.rightArm.wristToPalmAxis = Vector3.up; + vrik.solver.rightArm.palmToThumbAxis = Vector3.forward; + } + } + + private Transform FindUnmappedToe(Transform foot) + { + foreach (Transform bone in foot) + { + if (bone.name.ToLowerInvariant().Contains("toe") || + bone.name.ToLowerInvariant().EndsWith("_end")) + { + return bone; + } + } + + return null; + } + + private static readonly float[] IKPoseMuscles = new float[] + { + 0.00133321f, + 8.195831E-06f, + 8.537738E-07f, + -0.002669832f, + -7.651234E-06f, + -0.001659694f, + 0f, + 0f, + 0f, + 0.04213953f, + 0.0003007996f, + -0.008032114f, + -0.03059979f, + -0.0003182998f, + 0.009640567f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0.5768794f, + 0.01061097f, + -0.1127839f, + 0.9705755f, + 0.07972051f, + -0.0268422f, + 0.007237188f, + 0f, + 0.5768792f, + 0.01056608f, + -0.1127519f, + 0.9705756f, + 0.07971933f, + -0.02682396f, + 0.007229362f, + 0f, + -5.651802E-06f, + -3.034899E-07f, + 0.4100508f, + 0.3610304f, + -0.0838329f, + 0.9262537f, + 0.1353517f, + -0.03578902f, + 0.06005657f, + -4.95989E-06f, + -1.43007E-06f, + 0.4096187f, + 0.363263f, + -0.08205152f, + 0.9250782f, + 0.1345718f, + -0.03572125f, + 0.06055461f, + -1.079177f, + 0.2095419f, + 0.6140652f, + 0.6365265f, + 0.6683931f, + -0.4764312f, + 0.8099416f, + 0.8099371f, + 0.6658203f, + -0.7327053f, + 0.8113618f, + 0.8114051f, + 0.6643661f, + -0.40341f, + 0.8111364f, + 0.8111367f, + 0.6170399f, + -0.2524227f, + 0.8138723f, + 0.8110135f, + -1.079171f, + 0.2095456f, + 0.6140658f, + 0.6365255f, + 0.6683878f, + -0.4764301f, + 0.8099402f, + 0.8099376f, + 0.6658241f, + -0.7327023f, + 0.8113653f, + 0.8113793f, + 0.664364f, + -0.4034042f, + 0.811136f, + 0.8111364f, + 0.6170469f, + -0.2524345f, + 0.8138595f, + 0.8110138f + }; +} + diff --git a/DesktopVRIK/DesktopVRIK_Helper.cs b/DesktopVRIK/DesktopVRIK_Helper.cs deleted file mode 100644 index ae4f433..0000000 --- a/DesktopVRIK/DesktopVRIK_Helper.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using UnityEngine; -using ABI_RC.Core.Player; -using ABI_RC.Systems.IK; -using ABI_RC.Systems.IK.SubSystems; -using ABI_RC.Systems.MovementSystem; -using RootMotion.FinalIK; - -namespace NAK.Melons.DesktopVRIK; - -internal class DesktopVRIK_Helper : MonoBehaviour -{ - public static DesktopVRIK_Helper Instance; - - //Avatar - public Transform avatar_HeadBone; - - //DesktopVRIK - public Transform ik_HeadFollower; - public Quaternion ik_HeadRotation; - - public static void CreateInstance() - { - Transform helper = new GameObject("[DesktopVRIK] Virtual Rig").transform; - helper.parent = PlayerSetup.Instance.transform; - helper.localPosition = Vector3.zero; - helper.localRotation = Quaternion.identity; - helper.gameObject.AddComponent(); - } - - void Start() - { - Instance = this; - - Transform headFollower = new GameObject("HeadBone_Follower").transform; - headFollower.parent = transform; - headFollower.localPosition = new Vector3(0f, 1.8f, 0f); - headFollower.localRotation = Quaternion.identity; - ik_HeadFollower = headFollower; - } - - public void OnUpdateVRIK() - { - if (avatar_HeadBone != null) - { - float globalWeight = (1 - MovementSystem.Instance.movementVector.magnitude); - globalWeight *= IKSystem.vrik.solver.locomotion.weight; - - //the most important thing ever - //IKSystem.vrik.solver.spine.rotationWeight = globalWeight; - - HeadIK_FollowPosition(); - - HeadIK_RotateWithWeight(globalWeight); - HeadIK_FollowWithinAngle(globalWeight); - ik_HeadFollower.rotation = ik_HeadRotation; - } - } - - public void OnResetIK() - { - ik_HeadRotation = Quaternion.Euler(transform.eulerAngles.x, transform.eulerAngles.y, transform.eulerAngles.z); - } - - public void HeadIK_FollowPosition() - { - ik_HeadFollower.position = new Vector3(transform.position.x, avatar_HeadBone.position.y, transform.position.z); - } - - public void HeadIK_FollowWithinAngle(float weight) - { - if (DesktopVRIK.Setting_BodyAngleLimit != 0) - { - float weightedAngle = DesktopVRIK.Setting_BodyAngleLimit * weight; - float currentAngle = Mathf.DeltaAngle(transform.eulerAngles.y, ik_HeadRotation.eulerAngles.y); - if (Mathf.Abs(currentAngle) > weightedAngle) - { - float fixedCurrentAngle = currentAngle > 0 ? currentAngle : -currentAngle; - float clampedAngle = Mathf.MoveTowardsAngle(ik_HeadRotation.eulerAngles.y, transform.eulerAngles.y, fixedCurrentAngle - weightedAngle); - ik_HeadRotation = Quaternion.Euler(ik_HeadRotation.eulerAngles.x, clampedAngle, 0); - } - } - else - { - ik_HeadRotation = Quaternion.Euler(ik_HeadRotation.eulerAngles.x, transform.eulerAngles.y, transform.eulerAngles.z); - } - } - - public void HeadIK_RotateWithWeight(float weight) - { - //VRChat hip movement emulation - if (DesktopVRIK.Setting_BodyLeanWeight != 0) - { - float angle = PlayerSetup.Instance.desktopCamera.transform.localEulerAngles.x; - if (angle > 180) angle -= 360; - float leanAmount = angle * weight * DesktopVRIK.Setting_BodyLeanWeight; - ik_HeadRotation = Quaternion.Euler(leanAmount * 0.33f, ik_HeadRotation.eulerAngles.y, 0); - } - else - { - ik_HeadRotation = Quaternion.Euler(transform.eulerAngles.x, ik_HeadRotation.eulerAngles.y, transform.eulerAngles.z); - } - } -} \ No newline at end of file diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index 2a9a6b1..2a9562e 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -1,34 +1,21 @@ -using ABI.CCK.Components; -using ABI_RC.Core.Player; -using ABI_RC.Core.Savior; +using ABI_RC.Core.Player; using ABI_RC.Systems.IK; -using ABI_RC.Systems.IK.SubSystems; -using ABI_RC.Systems.MovementSystem; using HarmonyLib; -using RootMotion.FinalIK; using UnityEngine; /** The process of calibrating VRIK is fucking painful. - Immediatly doing GetHumanPose() and then SetHumanPose() fixed heels in ground for all avatars. - - Setting the avatars rotation to identity, head rotation offset to head bone world rotation, and then calibrating head IK target (kinda) fixed only robot kyle. - - Enforcing a TPose only fixed my ferret avatars right shoulder. - - Mix and matching these, and changing order, fucks with random specific avatars with fucky armatures. - MOST AVATARS DONT EVEN CHANGE, ITS JUST THESE FEW SPECIFIC ONES - I NEED to look into an IKPose controller... - Avatars of Note: - TurtleNeck Ferret- broken/inverted right shoulder - Space Robot Kyle- head ik target is rotated -90 90 0, so body/neck is fucked (Fuck you Default Robot Kyle) - Exteratta- the knees bend backwards like a fucking chicken... what the fuck im enforcing a tpose nowww + TurtleNeck Ferret- close feet, far shoulders, nonideal rig. + Space Robot Kyle- the worst bone rolls on the planet, tpose/headikcalibration fixed it mostly... ish. + Exteratta- knees bend backwards without proper tpose. + Chito- left foot is far back without proper tpose & foot ik distance, was uploaded in falling anim state. + Atlas (portal2)- Wide stance, proper feet distance needed to be calculated. + Freddy (gmod)- Doesn't have any fingers, wristToPalmAxis & palmToThumbAxis needed to be set manually. - Most other avatars play just fine. Never changes even when adding Tpose, rotating the avatar, headikrotationoffset, ect... - WHY (Fuck you Default Robot Kyle) + Most other avatars play just fine. **/ @@ -36,210 +23,44 @@ namespace NAK.Melons.DesktopVRIK.HarmonyPatches; class PlayerSetupPatches { - private static bool emotePlayed = false; - [HarmonyPostfix] - [HarmonyPatch(typeof(PlayerSetup), "SetupAvatarGeneral")] - static void SetupDesktopIKSystem(ref CVRAvatar ____avatarDescriptor, ref Animator ____animator) + [HarmonyPatch(typeof(PlayerSetup), "SetupAvatarDesktop")] + static void Postfix_PlayerSetup_SetupAvatarDesktop(ref Animator ____animator) { - if (!MetaPort.Instance.isUsingVr && DesktopVRIK.Setting_Enabled) + if (____animator != null && ____animator.avatar != null && ____animator.avatar.isHuman) { - if (____avatarDescriptor != null && ____animator != null && ____animator.isHuman) - { - //this will stop at the useless isVr return (the function is only ever called by vr anyways...) - IKSystem.Instance.InitializeAvatar(____avatarDescriptor); - } + DesktopVRIK.Instance?.OnSetupAvatarDesktop(); } } [HarmonyPostfix] [HarmonyPatch(typeof(PlayerSetup), "Update")] - private static void CorrectVRIK(ref bool ____emotePlaying, ref LookAtIK ___lookIK) + static void Postfix_PlayerSetup_Update(ref bool ____emotePlaying) { - if (!MetaPort.Instance.isUsingVr && DesktopVRIK.Setting_Enabled) - { - bool changed = ____emotePlaying != emotePlayed; - if (changed) - { - emotePlayed = ____emotePlaying; - IKSystem.vrik.transform.localPosition = Vector3.zero; - IKSystem.vrik.transform.localRotation = Quaternion.identity; - if (DesktopVRIK.Setting_EmoteLookAtIK && ___lookIK != null) - { - ___lookIK.enabled = !____emotePlaying; - } - if (DesktopVRIK.Setting_EmoteVRIK) - { - BodySystem.TrackingEnabled = !____emotePlaying; - IKSystem.vrik.solver?.Reset(); - DesktopVRIK_Helper.Instance?.OnResetIK(); - } - } - } + DesktopVRIK.Instance?.OnPlayerSetupUpdate(____emotePlaying); } - - //should probably patch movement system instead - [HarmonyPrefix] - [HarmonyPatch(typeof(PlayerSetup), "HandleDesktopCameraPosition")] - private static void Prefix_PlayerSetup_HandleDesktopCameraPosition - ( - bool ignore, - ref PlayerSetup __instance, - ref MovementSystem - ____movementSystem, - ref int ___headBobbingLevel - ) - { - if (___headBobbingLevel != 2) - { - return; - } - - if (!DesktopVRIK.Setting_Enabled || !DesktopVRIK.Setting_EnforceViewPosition) - { - return; - } - - if (____movementSystem.disableCameraControl && !ignore) - { - return; - } - - if (DesktopVRIK.Instance.viewpoint == null) - { - return; - } - - __instance.desktopCamera.transform.position = DesktopVRIK.Instance.viewpoint.position; - return; - } + //[HarmonyPostfix] + //[HarmonyPatch(typeof(PlayerSetup), "ReCalibrateAvatar")] + //static void Postfix_PlayerSetup_ReCalibrateAvatar() + //{ + // DesktopVRIK.Instance?.OnReCalibrateAvatar(); + //} } class IKSystemPatches { [HarmonyPostfix] - [HarmonyPatch(typeof(IKSystem), "InitializeAvatar")] - private static void InitializeDesktopAvatarVRIK(CVRAvatar avatar, ref VRIK ____vrik, ref HumanPoseHandler ____poseHandler, ref HumanPose ___humanPose) + [HarmonyPatch(typeof(IKSystem), "Start")] + private static void Postfix_IKSystem_Start(ref IKSystem __instance) { - if (!MetaPort.Instance.isUsingVr && DesktopVRIK.Setting_Enabled) - { - if (IKSystem.Instance.animator != null && IKSystem.Instance.animator.avatar != null && IKSystem.Instance.animator.avatar.isHuman) - { - if (____poseHandler == null) - { - ____poseHandler = new HumanPoseHandler(IKSystem.Instance.animator.avatar, IKSystem.Instance.animator.transform); - } - - ____poseHandler.GetHumanPose(ref ___humanPose); - for (int i = 0; i < IKPoseMuscles.Length; i++) - { - IKSystem.Instance.ApplyMuscleValue((MuscleIndex)i, IKPoseMuscles[i], ref ___humanPose.muscles); - } - ____poseHandler.SetHumanPose(ref ___humanPose); - - ____vrik = DesktopVRIK.Instance.AlternativeCalibration(avatar); - IKSystem.Instance.ApplyAvatarScaleToIk(avatar.viewPosition.y); - } - } + __instance.gameObject.AddComponent(); } - private static readonly float[] IKPoseMuscles = new float[] + [HarmonyPrefix] + [HarmonyPatch(typeof(IKSystem), "ApplyAvatarScaleToIk")] + private static bool Prefix_IKSystem_ApplyAvatarScaleToIk(float height) { - 0.00133321f, - 8.195831E-06f, - 8.537738E-07f, - -0.002669832f, - -7.651234E-06f, - -0.001659694f, - 0f, - 0f, - 0f, - 0.04213953f, - 0.0003007996f, - -0.008032114f, - -0.03059979f, - -0.0003182998f, - 0.009640567f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0.5768794f, - 0.01061097f, - -0.1127839f, - 0.9705755f, - 0.07972051f, - -0.0268422f, - 0.007237188f, - 0f, - 0.5768792f, - 0.01056608f, - -0.1127519f, - 0.9705756f, - 0.07971933f, - -0.02682396f, - 0.007229362f, - 0f, - -5.651802E-06f, - -3.034899E-07f, - 0.4100508f, - 0.3610304f, - -0.0838329f, - 0.9262537f, - 0.1353517f, - -0.03578902f, - 0.06005657f, - -4.95989E-06f, - -1.43007E-06f, - 0.4096187f, - 0.363263f, - -0.08205152f, - 0.9250782f, - 0.1345718f, - -0.03572125f, - 0.06055461f, - -1.079177f, - 0.2095419f, - 0.6140652f, - 0.6365265f, - 0.6683931f, - -0.4764312f, - 0.8099416f, - 0.8099371f, - 0.6658203f, - -0.7327053f, - 0.8113618f, - 0.8114051f, - 0.6643661f, - -0.40341f, - 0.8111364f, - 0.8111367f, - 0.6170399f, - -0.2524227f, - 0.8138723f, - 0.8110135f, - -1.079171f, - 0.2095456f, - 0.6140658f, - 0.6365255f, - 0.6683878f, - -0.4764301f, - 0.8099402f, - 0.8099376f, - 0.6658241f, - -0.7327023f, - 0.8113653f, - 0.8113793f, - 0.664364f, - -0.4034042f, - 0.811136f, - 0.8111364f, - 0.6170469f, - -0.2524345f, - 0.8138595f, - 0.8110138f - }; + return !(bool)DesktopVRIK.Instance?.OnApplyAvatarScaleToIk(height); + } } diff --git a/DesktopVRIK/Integrations/BTKUIAddon.cs b/DesktopVRIK/Integrations/BTKUIAddon.cs deleted file mode 100644 index e2ab2ab..0000000 --- a/DesktopVRIK/Integrations/BTKUIAddon.cs +++ /dev/null @@ -1,48 +0,0 @@ -using BTKUILib; -using BTKUILib.UIObjects; -using System.Runtime.CompilerServices; - -namespace NAK.Melons.DesktopVRIK; - -public static class BTKUIAddon -{ - [MethodImpl(MethodImplOptions.NoInlining)] - public static void Init() - { - //Add myself to the Misc Menu - - Page miscPage = QuickMenuAPI.MiscTabPage; - Category miscCategory = miscPage.AddCategory(DesktopVRIKMod.SettingsCategory); - - AddMelonToggle(ref miscCategory, DesktopVRIKMod.m_entryEnabled); - - //Add my own page to not clog up Misc Menu - - Page desktopVRIKPage = miscCategory.AddPage("DesktopVRIK Settings", "", "Configure the settings for DesktopVRIK.", "DesktopVRIK"); - desktopVRIKPage.MenuTitle = "DesktopVRIK Settings"; - desktopVRIKPage.MenuSubtitle = "Simplified settings for VRIK on Desktop."; - - Category desktopVRIKCategory = desktopVRIKPage.AddCategory("DesktopVRIK"); - - AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.m_entryEnabled); - - AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.m_entryEnforceViewPosition); - - AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.m_entryEmoteVRIK); - - AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.m_entryEmoteLookAtIK); - - AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.m_entryBodyLeanWeight, 0, 1f); - - AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.m_entryBodyAngleLimit, 0, 90f); - } - private static void AddMelonToggle(ref Category category, MelonLoader.MelonPreferences_Entry entry) - { - category.AddToggle(entry.DisplayName, entry.Description, entry.Value).OnValueUpdated += b => entry.Value = b; - } - - private static void AddMelonSlider(ref Page page, MelonLoader.MelonPreferences_Entry entry, float min, float max) - { - page.AddSlider(entry.DisplayName, entry.Description, entry.Value, min, max).OnValueUpdated += f => entry.Value = f; - } -} \ No newline at end of file diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index 524f85b..4f2aec4 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -1,5 +1,4 @@ -using ABI_RC.Core.Player; -using MelonLoader; +using MelonLoader; using UnityEngine; namespace NAK.Melons.DesktopVRIK; @@ -8,69 +7,71 @@ public class DesktopVRIKMod : MelonMod { internal const string SettingsCategory = "DesktopVRIK"; internal static MelonPreferences_Category m_categoryDesktopVRIK; - internal static MelonPreferences_Entry m_entryEnabled, + internal static MelonPreferences_Entry + m_entryEnabled, m_entryEnforceViewPosition, - m_entryEmoteVRIK, - m_entryEmoteLookAtIK; + m_entryResetIKOnLand, + m_entryPlantFeet, + m_entryUseVRIKToes, + m_entryFindUnmappedToes; internal static MelonPreferences_Entry m_entryBodyLeanWeight, - m_entryBodyAngleLimit; + m_entryBodyHeadingLimit, + m_entryPelvisHeadingWeight, + m_entryChestHeadingWeight; public override void OnInitializeMelon() { m_categoryDesktopVRIK = MelonPreferences.CreateCategory(SettingsCategory); m_entryEnabled = m_categoryDesktopVRIK.CreateEntry("Enabled", true, description: "Toggle DesktopVRIK entirely. Requires avatar reload."); m_entryEnforceViewPosition = m_categoryDesktopVRIK.CreateEntry("Enforce View Position", false, description: "Corrects view position to use VRIK offsets."); - m_entryEmoteVRIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote VRIK", true, description: "Disable VRIK while emoting. Only disable if you are ok with looking dumb."); - m_entryEmoteLookAtIK = m_categoryDesktopVRIK.CreateEntry("Disable Emote LookAtIK", true, description: "Disable LookAtIK while emoting. This setting doesn't really matter, as LookAtIK isn't networked while doing an emote."); + m_entryResetIKOnLand = m_categoryDesktopVRIK.CreateEntry("Reset IK On Land", true, description: "Reset Solver IK when landing on the ground."); + m_entryPlantFeet = m_categoryDesktopVRIK.CreateEntry("Enforce Plant Feet", true, description: "Forces VRIK Plant Feet enabled. This prevents the little hover when you stop moving."); + m_entryUseVRIKToes = m_categoryDesktopVRIK.CreateEntry("Use VRIK Toes", false, description: "Should VRIK use your humanoid toes for IK solving? This can cause your feet to idle behind you."); + m_entryFindUnmappedToes = m_categoryDesktopVRIK.CreateEntry("Find Unmapped Toes", false, description: "Should DesktopVRIK look for unmapped toe bones if humanoid rig does not have any?"); m_entryBodyLeanWeight = m_categoryDesktopVRIK.CreateEntry("Body Lean Weight", 0.5f, description: "Emulates old VRChat-like body leaning when looking up/down. Set to 0 to disable."); - m_entryBodyAngleLimit = m_categoryDesktopVRIK.CreateEntry("Body Angle Limit", 0f, description: "Emulates VRChat-like body and head offset when rotating left/right. Set to 0 to disable. (this setting only affects the feet due to chillout not setting up the player controller for VRIK)"); + m_entryBodyHeadingLimit = m_categoryDesktopVRIK.CreateEntry("Body Heading Limit", 20f, description: "Emulates VRChat-like body and head offset when rotating left/right. Set to 0 to disable."); + m_entryPelvisHeadingWeight = m_categoryDesktopVRIK.CreateEntry("Pelvis Heading Weight", 0.25f, description: "How much the pelvis will face the heading limit. Set to 0 to align with head."); + m_entryChestHeadingWeight = m_categoryDesktopVRIK.CreateEntry("Chest Heading Weight", 0.75f, description: "How much the chest will face the heading limit. Set to 0 to align with head."); foreach (var setting in m_categoryDesktopVRIK.Entries) { setting.OnEntryValueChangedUntyped.Subscribe(OnUpdateSettings); } - //BTKUILib Misc Support - if (MelonMod.RegisteredMelons.Any(it => it.Info.Name == "BTKUILib")) - { - MelonLogger.Msg("Initializing BTKUILib support."); - BTKUIAddon.Init(); - } - - //Apply patches (i stole) ApplyPatches(typeof(HarmonyPatches.PlayerSetupPatches)); ApplyPatches(typeof(HarmonyPatches.IKSystemPatches)); - MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); + InitializeIntegrations(); } - System.Collections.IEnumerator WaitForLocalPlayer() - { - while (PlayerSetup.Instance == null) - yield return null; - - DesktopVRIK_Helper.CreateInstance(); - PlayerSetup.Instance.gameObject.AddComponent(); - - while (DesktopVRIK.Instance == null) - yield return null; - UpdateAllSettings(); - } - - private void UpdateAllSettings() + internal static void UpdateAllSettings() { if (!DesktopVRIK.Instance) return; - DesktopVRIK.Setting_Enabled = m_entryEnabled.Value; - DesktopVRIK.Setting_BodyLeanWeight = Mathf.Clamp01(m_entryBodyLeanWeight.Value); - DesktopVRIK.Setting_BodyAngleLimit = Mathf.Clamp(m_entryBodyAngleLimit.Value, 0f, 90f); - DesktopVRIK.Setting_EmoteVRIK = m_entryEmoteVRIK.Value; - DesktopVRIK.Setting_EmoteLookAtIK = m_entryEmoteLookAtIK.Value; - DesktopVRIK.Instance.ChangeViewpointHandling(m_entryEnforceViewPosition.Value); + // DesktopVRIK Settings + DesktopVRIK.Instance.Setting_Enabled = m_entryEnabled.Value; + DesktopVRIK.Instance.Setting_BodyLeanWeight = Mathf.Clamp01(m_entryBodyLeanWeight.Value); + DesktopVRIK.Instance.Setting_ResetOnLand = m_entryResetIKOnLand.Value; + DesktopVRIK.Instance.Setting_PlantFeet = m_entryPlantFeet.Value; + DesktopVRIK.Instance.Setting_BodyHeadingLimit = Mathf.Clamp(m_entryBodyHeadingLimit.Value, 0f, 90f); + DesktopVRIK.Instance.Setting_PelvisHeadingWeight = (1f - Mathf.Clamp01(m_entryPelvisHeadingWeight.Value)); + DesktopVRIK.Instance.Setting_ChestHeadingWeight = (1f - Mathf.Clamp01(m_entryChestHeadingWeight.Value)); + // Calibration Settings + DesktopVRIK.Instance.Calibrator.Setting_UseVRIKToes = m_entryUseVRIKToes.Value; + DesktopVRIK.Instance.Calibrator.Setting_FindUnmappedToes = m_entryFindUnmappedToes.Value; } - private void OnUpdateSettings(object arg1, object arg2) => UpdateAllSettings(); + private static void InitializeIntegrations() + { + //BTKUILib Misc Tab + if (MelonMod.RegisteredMelons.Any(it => it.Info.Name == "BTKUILib")) + { + MelonLogger.Msg("Initializing BTKUILib support."); + //BTKUIAddon.Init(); + } + } + private void ApplyPatches(Type type) { try diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs index 2494ba3..879ab4b 100644 --- a/DesktopVRIK/Properties/AssemblyInfo.cs +++ b/DesktopVRIK/Properties/AssemblyInfo.cs @@ -1,8 +1,7 @@ -using DesktopVRIK.Properties; -using MelonLoader; +using MelonLoader; +using NAK.Melons.DesktopVRIK.Properties; using System.Reflection; - [assembly: AssemblyVersion(AssemblyInfoParams.Version)] [assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] [assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] @@ -24,9 +23,9 @@ using System.Reflection; [assembly: MelonOptionalDependencies("BTKUILib")] [assembly: HarmonyDontPatchAll] -namespace DesktopVRIK.Properties; +namespace NAK.Melons.DesktopVRIK.Properties; internal static class AssemblyInfoParams { - public const string Version = "2.0.5"; + public const string Version = "4.0.0"; public const string Author = "NotAKidoS"; } \ No newline at end of file From a27d42d8769d9c79a17e179d66a06575d38912db Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Tue, 28 Feb 2023 07:16:32 -0600 Subject: [PATCH 30/60] push --- DesktopVRIK/DesktopVRIK.cs | 47 +++++---- DesktopVRIK/DesktopVRIKCalibrator.cs | 152 +++++++++++++++------------ DesktopVRIK/HarmonyPatches.cs | 19 ++-- 3 files changed, 113 insertions(+), 105 deletions(-) diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index a63d9ce..47e1a5d 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -30,7 +30,6 @@ public class DesktopVRIK : MonoBehaviour private float ik_SimulatedRootAngle; private bool - ms_lastGrounded, ps_emoteIsPlaying; static readonly FieldInfo ms_isGrounded = typeof(MovementSystem).GetField("_isGrounded", BindingFlags.NonPublic | BindingFlags.Instance); @@ -45,26 +44,31 @@ public class DesktopVRIK : MonoBehaviour { if (!Setting_Enabled) return; Calibrator.SetupDesktopVRIK(); - ik_SimulatedRootAngle = transform.eulerAngles.y; + ResetDesktopVRIK(); } - //public void OnReCalibrateAvatar() - //{ - // Calibrator.RecalibrateDesktopVRIK(); - // ik_SimulatedRootAngle = transform.eulerAngles.y; - //} - - public bool OnApplyAvatarScaleToIk(float height) + public bool OnSetupIKScaling(float avatarHeight, float scaleDifference) { if (Calibrator.vrik != null) { - Calibrator.vrik.solver.locomotion.footDistance = Calibrator.initialFootDistance * height; - Calibrator.vrik.solver.locomotion.stepThreshold = Calibrator.initialStepThreshold * height; + Calibrator.vrik.solver.locomotion.footDistance = Calibrator.initialFootDistance * scaleDifference; + Calibrator.vrik.solver.locomotion.stepThreshold = Calibrator.initialStepThreshold * scaleDifference; + DesktopVRIK.ScaleStepHeight(Calibrator.vrik.solver.locomotion.stepHeight, Calibrator.initialStepHeight * scaleDifference); + Calibrator.vrik.solver.Reset(); + ResetDesktopVRIK(); + return true; } return false; } + public static void ScaleStepHeight(AnimationCurve stepHeightCurve, float mag) + { + Keyframe[] keyframes = stepHeightCurve.keys; + keyframes[1].value = mag; + stepHeightCurve.keys = keyframes; + } + public void OnPlayerSetupUpdate(bool isEmotePlaying) { bool changed = isEmotePlaying != ps_emoteIsPlaying; @@ -79,12 +83,21 @@ public class DesktopVRIK : MonoBehaviour } BodySystem.TrackingEnabled = !isEmotePlaying; Calibrator.vrik.solver?.Reset(); + ResetDesktopVRIK(); } } + public void ResetDesktopVRIK() + { + ik_SimulatedRootAngle = transform.eulerAngles.y; + } + public void OnPreSolverUpdate() { - if (ps_emoteIsPlaying) return; + if (ps_emoteIsPlaying) + { + return; + } bool isGrounded = (bool)ms_isGrounded.GetValue(MovementSystem.Instance); @@ -103,16 +116,6 @@ public class DesktopVRIK : MonoBehaviour // This is nice for walk cycles //Calibrator.vrik.solver.spine.rotateChestByHands = Setting_RotateChestByHands * weight; - //reset solver if weight changes dramatically - if (Setting_ResetOnLand) - { - if (isGrounded && !ms_lastGrounded) - { - Calibrator.vrik.solver.Reset(); - } - ms_lastGrounded = isGrounded; - } - // Old VRChat hip movement emulation if (Setting_BodyLeanWeight > 0) { diff --git a/DesktopVRIK/DesktopVRIKCalibrator.cs b/DesktopVRIK/DesktopVRIKCalibrator.cs index e16340f..abbcba0 100644 --- a/DesktopVRIK/DesktopVRIKCalibrator.cs +++ b/DesktopVRIK/DesktopVRIKCalibrator.cs @@ -30,45 +30,33 @@ public class DesktopVRIKCalibrator _lookIKTraverse = Traverse.Create(playerSetup).Field("lookIK"); } - //Settings + // Settings public bool Setting_UseVRIKToes = true; public bool Setting_FindUnmappedToes = true; - //DesktopVRIK + // DesktopVRIK public CVRAvatar avatar; public Animator animator; public Transform avatarTransform; public VRIK vrik; public LookAtIK lookAtIK; + // Calibration public HumanPoseHandler humanPoseHandler; public HumanPose initialHumanPose; + // Calibrator public bool fixTransformsRequired; - public float initialFootDistance; - public float initialStepThreshold; + public float initialFootDistance, initialStepThreshold, initialStepHeight; - //Traverse + // Traverse private IKSystem ikSystem; private PlayerSetup playerSetup; - private Traverse _vrikTraverse; - private Traverse _lookIKTraverse; - private Traverse _avatarTraverse; - private Traverse _animatorManagerTraverse; - private Traverse _poseHandlerTraverse; - private Traverse _avatarRootHeightTraverse; - - //public void RecalibrateDesktopVRIK() - //{ - // if (avatar != null) - // { - // //calibrate VRIK - // CalibrateDesktopVRIK(); - // } - // else - // { - // //we never calibrated - // SetupDesktopVRIK(); - // } - //} + private Traverse + _vrikTraverse, + _lookIKTraverse, + _avatarTraverse, + _animatorManagerTraverse, + _poseHandlerTraverse, + _avatarRootHeightTraverse; public void SetupDesktopVRIK() { @@ -92,9 +80,9 @@ public class DesktopVRIKCalibrator //calibrate VRIK PrepareAvatarVRIK(); SetAvatarIKPose(true); - CalculateInitialIKScaling(); CalibrateHeadIK(); ForceInitiateVRIKSolver(); + CalculateInitialIKScaling(); SetAvatarIKPose(false); } @@ -220,18 +208,19 @@ public class DesktopVRIKCalibrator private void CalculateInitialIKScaling() { - // Get distance between feets and thighs (fixes some weird armatures) + // Get distance between feets and thighs float footDistance = Vector3.Distance(vrik.references.leftFoot.position, vrik.references.rightFoot.position); - float thighDistance = Vector3.Distance(vrik.references.leftThigh.position, vrik.references.rightThigh.position); - float greatestDistance = Mathf.Min(footDistance, thighDistance); - initialFootDistance = greatestDistance * 0.5f; - initialStepThreshold = greatestDistance * 0.4f; + initialFootDistance = footDistance * 0.5f; + initialStepThreshold = footDistance * 0.4f; + initialStepHeight = Vector3.Distance(vrik.references.leftFoot.position, vrik.references.leftCalf.position) * 0.2f; - //set initial values now, as avatars without scaling dont apply it + // Set initial values vrik.solver.locomotion.footDistance = initialFootDistance; vrik.solver.locomotion.stepThreshold = initialStepThreshold; + DesktopVRIK.ScaleStepHeight(vrik.solver.locomotion.stepHeight, initialStepHeight); } + private void CalibrateHeadIK() { // Lazy HeadIKTarget calibration @@ -262,12 +251,7 @@ public class DesktopVRIKCalibrator if (enforceTPose) { humanPoseHandler.GetHumanPose(ref initialHumanPose); - humanPoseHandler.GetHumanPose(ref ikSystem.humanPose); - for (int i = 0; i < IKPoseMuscles.Length; i++) - { - IKSystem.Instance.ApplyMuscleValue((MuscleIndex)i, IKPoseMuscles[i], ref ikSystem.humanPose.muscles); - } - humanPoseHandler.SetHumanPose(ref ikSystem.humanPose); + SetCustomPose(IKPoseMuscles); } else { @@ -275,6 +259,16 @@ public class DesktopVRIKCalibrator } } + private void SetCustomPose(float[] muscleValues) + { + humanPoseHandler.GetHumanPose(ref ikSystem.humanPose); + for (int i = 0; i < muscleValues.Length; i++) + { + IKSystem.Instance.ApplyMuscleValue((MuscleIndex)i, muscleValues[i], ref ikSystem.humanPose.muscles); + } + humanPoseHandler.SetHumanPose(ref ikSystem.humanPose); + } + private void ForceInitiateVRIKSolver() { //force immediate calibration before animator decides to fuck us @@ -286,17 +280,8 @@ public class DesktopVRIKCalibrator { fixTransformsRequired = false; - Transform leftShoulderBone = vrik.references.leftShoulder; - Transform rightShoulderBone = vrik.references.rightShoulder; - Transform assumedChest = leftShoulderBone?.parent; - - // Repair chest & spine bone references (valve models were messed up) - if (assumedChest != null && rightShoulderBone.parent == assumedChest && - vrik.references.chest != assumedChest) - { - vrik.references.chest = assumedChest; - vrik.references.spine = assumedChest.parent; - } + //might not work over netik + FixChestAndSpineReferences(); if (!Setting_UseVRIKToes) { @@ -305,32 +290,44 @@ public class DesktopVRIKCalibrator } else if (Setting_FindUnmappedToes) { - Transform leftToes = vrik.references.leftToes; - Transform rightToes = vrik.references.rightToes; - if (leftToes == null && rightToes == null) - { - leftToes = FindUnmappedToe(vrik.references.leftFoot); - rightToes = FindUnmappedToe(vrik.references.rightFoot); - if (leftToes != null && rightToes != null) - { - fixTransformsRequired = true; - vrik.references.leftToes = leftToes; - vrik.references.rightToes = rightToes; - } - } + //doesnt work with netik, but its toes... + FindAndSetUnmappedToes(); } - // Fix error when there is no finger bones - // Making up bullshit cause VRIK is evil otherwise - if (vrik.references.leftHand.childCount == 0) + //bullshit fix to not cause death + FixFingerBonesError(); + } + + private void FixChestAndSpineReferences() + { + Transform leftShoulderBone = vrik.references.leftShoulder; + Transform rightShoulderBone = vrik.references.rightShoulder; + Transform assumedChest = leftShoulderBone?.parent; + + if (assumedChest != null && rightShoulderBone.parent == assumedChest && + vrik.references.chest != assumedChest) { - vrik.solver.leftArm.wristToPalmAxis = Vector3.up; - vrik.solver.leftArm.palmToThumbAxis = -Vector3.forward; + vrik.references.chest = assumedChest; + vrik.references.spine = assumedChest.parent; } - if (vrik.references.rightHand.childCount == 0) + } + + private void FindAndSetUnmappedToes() + { + Transform leftToes = vrik.references.leftToes; + Transform rightToes = vrik.references.rightToes; + + if (leftToes == null && rightToes == null) { - vrik.solver.rightArm.wristToPalmAxis = Vector3.up; - vrik.solver.rightArm.palmToThumbAxis = Vector3.forward; + leftToes = FindUnmappedToe(vrik.references.leftFoot); + rightToes = FindUnmappedToe(vrik.references.rightFoot); + + if (leftToes != null && rightToes != null) + { + vrik.references.leftToes = leftToes; + vrik.references.rightToes = rightToes; + fixTransformsRequired = true; + } } } @@ -348,6 +345,21 @@ public class DesktopVRIKCalibrator return null; } + private void FixFingerBonesError() + { + FixFingerBones(vrik.references.leftHand, vrik.solver.leftArm); + FixFingerBones(vrik.references.rightHand, vrik.solver.rightArm); + } + + private void FixFingerBones(Transform hand, IKSolverVR.Arm armSolver) + { + if (hand.childCount == 0) + { + armSolver.wristToPalmAxis = Vector3.up; + armSolver.palmToThumbAxis = hand == vrik.references.leftHand ? -Vector3.forward : Vector3.forward; + } + } + private static readonly float[] IKPoseMuscles = new float[] { 0.00133321f, diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index 2a9562e..9b7d4af 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -40,12 +40,12 @@ class PlayerSetupPatches DesktopVRIK.Instance?.OnPlayerSetupUpdate(____emotePlaying); } - //[HarmonyPostfix] - //[HarmonyPatch(typeof(PlayerSetup), "ReCalibrateAvatar")] - //static void Postfix_PlayerSetup_ReCalibrateAvatar() - //{ - // DesktopVRIK.Instance?.OnReCalibrateAvatar(); - //} + [HarmonyPrefix] + [HarmonyPatch(typeof(PlayerSetup), "SetupIKScaling")] + private static bool Prefix_PlayerSetup_SetupIKScaling(float height, ref Vector3 ___scaleDifference) + { + return !(bool)DesktopVRIK.Instance?.OnSetupIKScaling(height, 1f + ___scaleDifference.y); + } } class IKSystemPatches @@ -56,11 +56,4 @@ class IKSystemPatches { __instance.gameObject.AddComponent(); } - - [HarmonyPrefix] - [HarmonyPatch(typeof(IKSystem), "ApplyAvatarScaleToIk")] - private static bool Prefix_IKSystem_ApplyAvatarScaleToIk(float height) - { - return !(bool)DesktopVRIK.Instance?.OnApplyAvatarScaleToIk(height); - } } From d6c8b3c2e4dc8f2326dc38c5235ca822e9153ac8 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Tue, 28 Feb 2023 07:48:10 -0600 Subject: [PATCH 31/60] Update README.md --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9e5c790..c2d4f73 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,16 @@ Adds VRIK to Desktop ChilloutVR avatars. No longer will you be a liveless slidin (adds the small feet stepping when looking around on Desktop) -Additional option to emulate VRChat-like hip movement if you like becoming a fish. +https://user-images.githubusercontent.com/37721153/221870123-fbe4f5e8-8d6e-4a43-aa5e-f2188e6491a9.mp4 -Control over disabling VRIK & LookAtIK during Emotes. (this can cause funky behavior) +## Configuration: +* Configurable body lean weight. Set to 0 to disable. + +* Configurable max root heading angle with chest/pelvis weight settings. Set to 0 to disable. + +* Options to disable VRIK from using mapped toes &/or find unmapped (non-human) toe bones. + +* Autofixes for avatars without fingers & incorrect chest/spine bone mapping (might not play well with netik). ## Relevant Feedback Posts: https://feedback.abinteractive.net/p/desktop-feet-ik-for-avatars @@ -22,4 +29,3 @@ https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games > Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use. > To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive. - From eae03f0ec2a7a6ba174efe3e1da86ee00242c39a Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Tue, 28 Feb 2023 08:31:23 -0600 Subject: [PATCH 32/60] add back btkui addon --- DesktopVRIK/DesktopVRIK.cs | 5 +-- DesktopVRIK/DesktopVRIK.csproj | 3 ++ DesktopVRIK/Integrations/BTKUIAddon.cs | 52 ++++++++++++++++++++++++++ DesktopVRIK/Main.cs | 10 ++--- 4 files changed, 61 insertions(+), 9 deletions(-) create mode 100644 DesktopVRIK/Integrations/BTKUIAddon.cs diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index 47e1a5d..f402744 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -16,10 +16,7 @@ public class DesktopVRIK : MonoBehaviour // DesktopVRIK Settings public bool Setting_Enabled = true, - Setting_HipMovement = true, - Setting_ResetOnLand = true, - Setting_PlantFeet = true, - Setting_EnforceViewPosition; + Setting_PlantFeet = true; public float Setting_BodyLeanWeight, Setting_BodyHeadingLimit, diff --git a/DesktopVRIK/DesktopVRIK.csproj b/DesktopVRIK/DesktopVRIK.csproj index ea97a04..592135f 100644 --- a/DesktopVRIK/DesktopVRIK.csproj +++ b/DesktopVRIK/DesktopVRIK.csproj @@ -18,6 +18,9 @@ C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll + + ..\..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\BTKUILib.dll + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll diff --git a/DesktopVRIK/Integrations/BTKUIAddon.cs b/DesktopVRIK/Integrations/BTKUIAddon.cs new file mode 100644 index 0000000..7fd4f52 --- /dev/null +++ b/DesktopVRIK/Integrations/BTKUIAddon.cs @@ -0,0 +1,52 @@ +using BTKUILib; +using BTKUILib.UIObjects; +using System.Runtime.CompilerServices; + +namespace NAK.Melons.DesktopVRIK; + +public static class BTKUIAddon +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static void Init() + { + //Add myself to the Misc Menu + + Page miscPage = QuickMenuAPI.MiscTabPage; + Category miscCategory = miscPage.AddCategory(DesktopVRIKMod.SettingsCategory); + + AddMelonToggle(ref miscCategory, DesktopVRIKMod.m_entryEnabled); + + //Add my own page to not clog up Misc Menu + + Page desktopVRIKPage = miscCategory.AddPage("DesktopVRIK Settings", "", "Configure the settings for DesktopVRIK.", "DesktopVRIK"); + desktopVRIKPage.MenuTitle = "DesktopVRIK Settings"; + desktopVRIKPage.MenuSubtitle = "Simplified settings for VRIK on Desktop."; + + Category desktopVRIKCategory = desktopVRIKPage.AddCategory("DesktopVRIK"); + + // General Settings + AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.m_entryEnabled); + AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.m_entryPlantFeet); + + // Calibration Settings + AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.m_entryUseVRIKToes); + AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.m_entryFindUnmappedToes); + + // Body Leaning Weight + AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.m_entryBodyLeanWeight, 0, 1f, 1); + + // Max Root Heading Limit & Weights + AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.m_entryBodyHeadingLimit, 0, 90f, 0); + AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.m_entryPelvisHeadingWeight, 0, 1f, 1); + AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.m_entryChestHeadingWeight, 0, 1f, 1); + } + private static void AddMelonToggle(ref Category category, MelonLoader.MelonPreferences_Entry entry) + { + category.AddToggle(entry.DisplayName, entry.Description, entry.Value).OnValueUpdated += b => entry.Value = b; + } + + private static void AddMelonSlider(ref Page page, MelonLoader.MelonPreferences_Entry entry, float min, float max, int decimalPlaces = 2) + { + page.AddSlider(entry.DisplayName, entry.Description, entry.Value, min, max, decimalPlaces).OnValueUpdated += f => entry.Value = f; + } +} \ No newline at end of file diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index 4f2aec4..5425782 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -23,8 +23,7 @@ public class DesktopVRIKMod : MelonMod { m_categoryDesktopVRIK = MelonPreferences.CreateCategory(SettingsCategory); m_entryEnabled = m_categoryDesktopVRIK.CreateEntry("Enabled", true, description: "Toggle DesktopVRIK entirely. Requires avatar reload."); - m_entryEnforceViewPosition = m_categoryDesktopVRIK.CreateEntry("Enforce View Position", false, description: "Corrects view position to use VRIK offsets."); - m_entryResetIKOnLand = m_categoryDesktopVRIK.CreateEntry("Reset IK On Land", true, description: "Reset Solver IK when landing on the ground."); + //m_entryEnforceViewPosition = m_categoryDesktopVRIK.CreateEntry("Enforce View Position", false, description: "Corrects view position to use VRIK offsets."); m_entryPlantFeet = m_categoryDesktopVRIK.CreateEntry("Enforce Plant Feet", true, description: "Forces VRIK Plant Feet enabled. This prevents the little hover when you stop moving."); m_entryUseVRIKToes = m_categoryDesktopVRIK.CreateEntry("Use VRIK Toes", false, description: "Should VRIK use your humanoid toes for IK solving? This can cause your feet to idle behind you."); m_entryFindUnmappedToes = m_categoryDesktopVRIK.CreateEntry("Find Unmapped Toes", false, description: "Should DesktopVRIK look for unmapped toe bones if humanoid rig does not have any?"); @@ -50,12 +49,13 @@ public class DesktopVRIKMod : MelonMod if (!DesktopVRIK.Instance) return; // DesktopVRIK Settings DesktopVRIK.Instance.Setting_Enabled = m_entryEnabled.Value; - DesktopVRIK.Instance.Setting_BodyLeanWeight = Mathf.Clamp01(m_entryBodyLeanWeight.Value); - DesktopVRIK.Instance.Setting_ResetOnLand = m_entryResetIKOnLand.Value; DesktopVRIK.Instance.Setting_PlantFeet = m_entryPlantFeet.Value; + + DesktopVRIK.Instance.Setting_BodyLeanWeight = Mathf.Clamp01(m_entryBodyLeanWeight.Value); DesktopVRIK.Instance.Setting_BodyHeadingLimit = Mathf.Clamp(m_entryBodyHeadingLimit.Value, 0f, 90f); DesktopVRIK.Instance.Setting_PelvisHeadingWeight = (1f - Mathf.Clamp01(m_entryPelvisHeadingWeight.Value)); DesktopVRIK.Instance.Setting_ChestHeadingWeight = (1f - Mathf.Clamp01(m_entryChestHeadingWeight.Value)); + // Calibration Settings DesktopVRIK.Instance.Calibrator.Setting_UseVRIKToes = m_entryUseVRIKToes.Value; DesktopVRIK.Instance.Calibrator.Setting_FindUnmappedToes = m_entryFindUnmappedToes.Value; @@ -68,7 +68,7 @@ public class DesktopVRIKMod : MelonMod if (MelonMod.RegisteredMelons.Any(it => it.Info.Name == "BTKUILib")) { MelonLogger.Msg("Initializing BTKUILib support."); - //BTKUIAddon.Init(); + BTKUIAddon.Init(); } } From c6c9b712bd87734318f0541b7e3dacee5b4cde7f Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Mon, 6 Mar 2023 19:53:27 -0600 Subject: [PATCH 33/60] implement knee bend normal calculation implemented knee bend normal calculation to fix knee bending at extreme scales, as well as finally fix robot kyle... tweaked ikpose method to also allow for setting to motorcycle pose, as well as resetting hip to default rotation --- DesktopVRIK/DesktopVRIK.cs | 4 +- DesktopVRIK/DesktopVRIKCalibrator.cs | 264 ++++++++++++++++++++------- DesktopVRIK/Main.cs | 11 +- 3 files changed, 209 insertions(+), 70 deletions(-) diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index f402744..093b84f 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -40,7 +40,7 @@ public class DesktopVRIK : MonoBehaviour public void OnSetupAvatarDesktop() { if (!Setting_Enabled) return; - Calibrator.SetupDesktopVRIK(); + Calibrator.CalibrateDesktopVRIK(); ResetDesktopVRIK(); } @@ -51,7 +51,7 @@ public class DesktopVRIK : MonoBehaviour Calibrator.vrik.solver.locomotion.footDistance = Calibrator.initialFootDistance * scaleDifference; Calibrator.vrik.solver.locomotion.stepThreshold = Calibrator.initialStepThreshold * scaleDifference; DesktopVRIK.ScaleStepHeight(Calibrator.vrik.solver.locomotion.stepHeight, Calibrator.initialStepHeight * scaleDifference); - Calibrator.vrik.solver.Reset(); + //Calibrator.vrik.solver.Reset(); ResetDesktopVRIK(); return true; diff --git a/DesktopVRIK/DesktopVRIKCalibrator.cs b/DesktopVRIK/DesktopVRIKCalibrator.cs index abbcba0..798e52c 100644 --- a/DesktopVRIK/DesktopVRIKCalibrator.cs +++ b/DesktopVRIK/DesktopVRIKCalibrator.cs @@ -13,6 +13,42 @@ namespace NAK.Melons.DesktopVRIK; public class DesktopVRIKCalibrator { + // Settings + public bool Setting_UseVRIKToes = true; + public bool Setting_FindUnmappedToes = true; + public bool Setting_ExperimentalKneeBend = true; + public bool Setting_DebugCalibrationPose = false; + + // Avatar Component References + public CVRAvatar avatar; + public Animator animator; + public Transform avatarTransform; + public VRIK vrik; + public LookAtIK lookAtIK; + + // Calibrated Values + public float + initialFootDistance, + initialStepThreshold, + initialStepHeight; + + // Calibration Internals + bool DebugCalibrationPose; + bool fixTransformsRequired; + Vector3 leftKneeNormal, rightKneeNormal; + HumanPose initialHumanPose; + HumanPoseHandler humanPoseHandler; + // Traverse + IKSystem ikSystem; + PlayerSetup playerSetup; + Traverse + _vrikTraverse, + _lookIKTraverse, + _avatarTraverse, + _animatorManagerTraverse, + _poseHandlerTraverse, + _avatarRootHeightTraverse; + public DesktopVRIKCalibrator() { // Get base game scripts. @@ -30,67 +66,102 @@ public class DesktopVRIKCalibrator _lookIKTraverse = Traverse.Create(playerSetup).Field("lookIK"); } - // Settings - public bool Setting_UseVRIKToes = true; - public bool Setting_FindUnmappedToes = true; - - // DesktopVRIK - public CVRAvatar avatar; - public Animator animator; - public Transform avatarTransform; - public VRIK vrik; - public LookAtIK lookAtIK; - // Calibration - public HumanPoseHandler humanPoseHandler; - public HumanPose initialHumanPose; - // Calibrator - public bool fixTransformsRequired; - public float initialFootDistance, initialStepThreshold, initialStepHeight; - - // Traverse - private IKSystem ikSystem; - private PlayerSetup playerSetup; - private Traverse - _vrikTraverse, - _lookIKTraverse, - _avatarTraverse, - _animatorManagerTraverse, - _poseHandlerTraverse, - _avatarRootHeightTraverse; - - public void SetupDesktopVRIK() + public void CalibrateDesktopVRIK() { - //store avatar root transform & center it + PreInitialize(); + + // Don't do anything else if just debugging calibration pose + DebugCalibrationPose = !DebugCalibrationPose; + if (Setting_DebugCalibrationPose && DebugCalibrationPose) + { + ForceCalibrationPose(); + return; + } + + // Add VRIK and configure + PrepareAvatarVRIK(); + + Initialize(); + + PostInitialize(); + } + + public void ForceCalibrationPose(bool toggle = true) + { + animator.enabled = !toggle; + SetHumanPose(0f); + //SetAvatarIKPose(toggle); + } + + private void PreInitialize() + { + // Scan avatar for issues/references + ScanAvatarForCalibration(); + // Prepare CVR IKSystem for external VRIK + PrepareIKSystem(); + } + + private void Initialize() + { + // Calculate bend normals with motorcycle pose + SetHumanPose(0f); + CalculateKneeBendNormals(); + + SetAvatarIKPose(true); + + // Setup HeadIK target & calculate initial footstep values + SetupDesktopHeadIKTarget(); + CalculateInitialIKScaling(); + + // Initiate VRIK manually + ForceInitiateVRIKSolver(); + + SetAvatarIKPose(false); + } + + private void PostInitialize() + { + ApplyKneeBendNormals(); + ApplyInitialIKScaling(); + vrik.onPreSolverUpdate.AddListener(new UnityAction(DesktopVRIK.Instance.OnPreSolverUpdate)); + } + + private void ScanAvatarForCalibration() + { + // Reset some stuff to default + fixTransformsRequired = false; + + // Find required avatar components avatar = playerSetup._avatar.GetComponent(); animator = avatar.GetComponent(); avatarTransform = avatar.transform; - avatarTransform.localPosition = Vector3.zero; lookAtIK = _lookIKTraverse.GetValue(); - //prepare for VRIK - PrepareIKSystem(); - CalibrateDesktopVRIK(); + // Apply some fixes for weird setups + if (!animator.enabled) + { + fixTransformsRequired = true; + DesktopVRIKMod.Logger.Error("Avatar has Animator disabled by default!"); + } - //add presolver update listener - vrik.onPreSolverUpdate.AddListener(new UnityAction(DesktopVRIK.Instance.OnPreSolverUpdate)); - } + // Center avatar local offsets + avatarTransform.localPosition = Vector3.zero; + //avatarTransform.localRotation = Quaternion.identity; - private void CalibrateDesktopVRIK() - { - //calibrate VRIK - PrepareAvatarVRIK(); - SetAvatarIKPose(true); - CalibrateHeadIK(); - ForceInitiateVRIKSolver(); - CalculateInitialIKScaling(); - SetAvatarIKPose(false); + // Store original human pose + if (humanPoseHandler != null) + { + humanPoseHandler.Dispose(); + } + humanPoseHandler = new HumanPoseHandler(animator.avatar, avatarTransform); + humanPoseHandler.GetHumanPose(ref initialHumanPose); } private void PrepareIKSystem() { // Get the animator manager and human pose handler var animatorManager = _animatorManagerTraverse.GetValue(); - humanPoseHandler = _poseHandlerTraverse.GetValue(); + var ikHumanPoseHandler = _poseHandlerTraverse.GetValue(); // Store the avatar component _avatarTraverse.SetValue(avatar); @@ -107,13 +178,13 @@ public class DesktopVRIKCalibrator _avatarRootHeightTraverse.SetValue(avatarHeight); // Create a new human pose handler and dispose the old one - if (humanPoseHandler != null) + if (ikHumanPoseHandler != null) { - humanPoseHandler.Dispose(); + ikHumanPoseHandler.Dispose(); _poseHandlerTraverse.SetValue(null); } - humanPoseHandler = new HumanPoseHandler(ikSystem.animator.avatar, avatarTransform); - _poseHandlerTraverse.SetValue(humanPoseHandler); + ikHumanPoseHandler = new HumanPoseHandler(ikSystem.animator.avatar, avatarTransform); + _poseHandlerTraverse.SetValue(ikHumanPoseHandler); // Find valid human bones IKSystem.BoneExists.Clear(); @@ -160,14 +231,12 @@ public class DesktopVRIKCalibrator vrik.solver.spine.bodyPosStiffness = 1f; vrik.solver.spine.bodyRotStiffness = 0.2f; //disable so avatar doesnt try and walk away - //fixes nameplate spazzing on remote vrik.solver.locomotion.velocityFactor = 0f; vrik.solver.locomotion.maxVelocity = 0f; + //fixes nameplate spazzing on remote & magicacloth + vrik.solver.locomotion.rootSpeed = 1000f; //disable so PAM & BID dont make body shake vrik.solver.spine.rotateChestByHands = 0f; - //enable so knees on fucked models work better - vrik.solver.leftLeg.useAnimatedBendNormal = true; - vrik.solver.rightLeg.useAnimatedBendNormal = true; //enable to prioritize LookAtIK vrik.solver.spine.headClampWeight = 0.2f; //disable to not go on tippytoes @@ -206,6 +275,70 @@ public class DesktopVRIKCalibrator //vrik.solver.spine.chestGoalWeight = 0f; } + private void CalculateKneeBendNormals() + { + // Get assumed left knee normal + Vector3[] leftVectors = new Vector3[] + { + vrik.references.leftThigh?.position ?? Vector3.zero, + vrik.references.leftCalf?.position ?? Vector3.zero, + vrik.references.leftFoot?.position ?? Vector3.zero, + }; + leftKneeNormal = Quaternion.Inverse(vrik.references.root.rotation) * GetNormalFromArray(leftVectors); + + // Get assumed right knee normal + Vector3[] rightVectors = new Vector3[] + { + vrik.references.rightThigh?.position ?? Vector3.zero, + vrik.references.rightCalf?.position ?? Vector3.zero, + vrik.references.rightFoot?.position ?? Vector3.zero, + }; + rightKneeNormal = Quaternion.Inverse(vrik.references.root.rotation) * GetNormalFromArray(rightVectors); + } + + private void ApplyKneeBendNormals() + { + if (!Setting_ExperimentalKneeBend) + { + //enable so knees on fucked models work better + vrik.solver.leftLeg.useAnimatedBendNormal = true; + vrik.solver.rightLeg.useAnimatedBendNormal = true; + return; + } + + vrik.solver.leftLeg.bendToTargetWeight = 0f; + vrik.solver.rightLeg.bendToTargetWeight = 0f; + + Traverse leftLeg_bendNormalRelToPelvisTraverse = Traverse.Create(vrik.solver.leftLeg).Field("bendNormalRelToPelvis"); + Traverse rightLeg_bendNormalRelToPelvisTraverse = Traverse.Create(vrik.solver.rightLeg).Field("bendNormalRelToPelvis"); + + // Calculate knee normal without root rotation but with pelvis rotation + Quaternion pelvisLocalRotationInverse = Quaternion.Inverse(vrik.references.pelvis.localRotation); + Vector3 leftLegBendNormalRelToPelvis = pelvisLocalRotationInverse * leftKneeNormal; + Vector3 rightLegBendNormalRelToPelvis = pelvisLocalRotationInverse * rightKneeNormal; + //Quaternion rootRotation = vrik.references.root.rotation; + //Quaternion pelvisRotationRelativeToRoot = Quaternion.Inverse(rootRotation) * vrik.references.pelvis.rotation; + //Quaternion pelvisRotationInverse = Quaternion.Inverse(pelvisRotationRelativeToRoot); + leftLeg_bendNormalRelToPelvisTraverse.SetValue(leftLegBendNormalRelToPelvis); + rightLeg_bendNormalRelToPelvisTraverse.SetValue(rightLegBendNormalRelToPelvis); + } + + private Vector3 GetNormalFromArray(Vector3[] positions) + { + Vector3 vector = Vector3.zero; + Vector3 vector2 = Vector3.zero; + for (int i = 0; i < positions.Length; i++) + { + vector2 += positions[i]; + } + vector2 /= (float)positions.Length; + for (int j = 0; j < positions.Length - 1; j++) + { + vector += Vector3.Cross(positions[j] - vector2, positions[j + 1] - vector2).normalized; + } + return Vector3.Normalize(vector); + } + private void CalculateInitialIKScaling() { // Get distance between feets and thighs @@ -213,7 +346,10 @@ public class DesktopVRIKCalibrator initialFootDistance = footDistance * 0.5f; initialStepThreshold = footDistance * 0.4f; initialStepHeight = Vector3.Distance(vrik.references.leftFoot.position, vrik.references.leftCalf.position) * 0.2f; + } + private void ApplyInitialIKScaling() + { // Set initial values vrik.solver.locomotion.footDistance = initialFootDistance; vrik.solver.locomotion.stepThreshold = initialStepThreshold; @@ -221,7 +357,7 @@ public class DesktopVRIKCalibrator } - private void CalibrateHeadIK() + private void SetupDesktopHeadIKTarget() { // Lazy HeadIKTarget calibration if (vrik.solver.spine.headTarget == null) @@ -250,8 +386,7 @@ public class DesktopVRIKCalibrator // Otherwise use DesktopVRIK IKPose & revert afterwards. if (enforceTPose) { - humanPoseHandler.GetHumanPose(ref initialHumanPose); - SetCustomPose(IKPoseMuscles); + SetHumanPose(1f); } else { @@ -259,13 +394,15 @@ public class DesktopVRIKCalibrator } } - private void SetCustomPose(float[] muscleValues) + private void SetHumanPose(float ikPoseWeight = 1f) { humanPoseHandler.GetHumanPose(ref ikSystem.humanPose); - for (int i = 0; i < muscleValues.Length; i++) + for (int i = 0; i < ikSystem.humanPose.muscles.Length; i++) { - IKSystem.Instance.ApplyMuscleValue((MuscleIndex)i, muscleValues[i], ref ikSystem.humanPose.muscles); + float weight = ikPoseWeight * IKPoseMuscles[i]; + IKSystem.Instance.ApplyMuscleValue((MuscleIndex)i, weight, ref ikSystem.humanPose.muscles); } + ikSystem.humanPose.bodyRotation = Quaternion.identity; humanPoseHandler.SetHumanPose(ref ikSystem.humanPose); } @@ -278,8 +415,6 @@ public class DesktopVRIKCalibrator private void ConfigureVRIKReferences() { - fixTransformsRequired = false; - //might not work over netik FixChestAndSpineReferences(); @@ -458,5 +593,4 @@ public class DesktopVRIKCalibrator 0.8138595f, 0.8110138f }; -} - +} \ No newline at end of file diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index 5425782..38baece 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -5,6 +5,7 @@ namespace NAK.Melons.DesktopVRIK; public class DesktopVRIKMod : MelonMod { + internal static MelonLogger.Instance Logger; internal const string SettingsCategory = "DesktopVRIK"; internal static MelonPreferences_Category m_categoryDesktopVRIK; internal static MelonPreferences_Entry @@ -13,7 +14,8 @@ public class DesktopVRIKMod : MelonMod m_entryResetIKOnLand, m_entryPlantFeet, m_entryUseVRIKToes, - m_entryFindUnmappedToes; + m_entryFindUnmappedToes, + m_entryExperimentalKneeBend; internal static MelonPreferences_Entry m_entryBodyLeanWeight, m_entryBodyHeadingLimit, @@ -21,12 +23,14 @@ public class DesktopVRIKMod : MelonMod m_entryChestHeadingWeight; public override void OnInitializeMelon() { + Logger = LoggerInstance; m_categoryDesktopVRIK = MelonPreferences.CreateCategory(SettingsCategory); m_entryEnabled = m_categoryDesktopVRIK.CreateEntry("Enabled", true, description: "Toggle DesktopVRIK entirely. Requires avatar reload."); //m_entryEnforceViewPosition = m_categoryDesktopVRIK.CreateEntry("Enforce View Position", false, description: "Corrects view position to use VRIK offsets."); m_entryPlantFeet = m_categoryDesktopVRIK.CreateEntry("Enforce Plant Feet", true, description: "Forces VRIK Plant Feet enabled. This prevents the little hover when you stop moving."); m_entryUseVRIKToes = m_categoryDesktopVRIK.CreateEntry("Use VRIK Toes", false, description: "Should VRIK use your humanoid toes for IK solving? This can cause your feet to idle behind you."); m_entryFindUnmappedToes = m_categoryDesktopVRIK.CreateEntry("Find Unmapped Toes", false, description: "Should DesktopVRIK look for unmapped toe bones if humanoid rig does not have any?"); + m_entryExperimentalKneeBend = m_categoryDesktopVRIK.CreateEntry("Experimental Knee Bend", true, description: "Experimental method to calculate knee bend normal. This may break avatars."); m_entryBodyLeanWeight = m_categoryDesktopVRIK.CreateEntry("Body Lean Weight", 0.5f, description: "Emulates old VRChat-like body leaning when looking up/down. Set to 0 to disable."); m_entryBodyHeadingLimit = m_categoryDesktopVRIK.CreateEntry("Body Heading Limit", 20f, description: "Emulates VRChat-like body and head offset when rotating left/right. Set to 0 to disable."); @@ -59,6 +63,7 @@ public class DesktopVRIKMod : MelonMod // Calibration Settings DesktopVRIK.Instance.Calibrator.Setting_UseVRIKToes = m_entryUseVRIKToes.Value; DesktopVRIK.Instance.Calibrator.Setting_FindUnmappedToes = m_entryFindUnmappedToes.Value; + DesktopVRIK.Instance.Calibrator.Setting_ExperimentalKneeBend = m_entryExperimentalKneeBend.Value; } private void OnUpdateSettings(object arg1, object arg2) => UpdateAllSettings(); @@ -80,8 +85,8 @@ public class DesktopVRIKMod : MelonMod } catch (Exception e) { - LoggerInstance.Msg($"Failed while patching {type.Name}!"); - LoggerInstance.Error(e); + Logger.Msg($"Failed while patching {type.Name}!"); + Logger.Error(e); } } } \ No newline at end of file From 05979d9542103bc7eaca06e99b87fefac5f72241 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Mon, 6 Mar 2023 20:26:42 -0600 Subject: [PATCH 34/60] fix footstep when resetting --- DesktopVRIK/DesktopVRIKCalibrator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DesktopVRIK/DesktopVRIKCalibrator.cs b/DesktopVRIK/DesktopVRIKCalibrator.cs index 798e52c..61e0bd6 100644 --- a/DesktopVRIK/DesktopVRIKCalibrator.cs +++ b/DesktopVRIK/DesktopVRIKCalibrator.cs @@ -344,7 +344,7 @@ public class DesktopVRIKCalibrator // Get distance between feets and thighs float footDistance = Vector3.Distance(vrik.references.leftFoot.position, vrik.references.rightFoot.position); initialFootDistance = footDistance * 0.5f; - initialStepThreshold = footDistance * 0.4f; + initialStepThreshold = footDistance * 0.8f; initialStepHeight = Vector3.Distance(vrik.references.leftFoot.position, vrik.references.leftCalf.position) * 0.2f; } From 20222e563e9c2372c6ad140d4d953758c4c3983e Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Mon, 6 Mar 2023 20:53:23 -0600 Subject: [PATCH 35/60] touchy --- DesktopVRIK/DesktopVRIK.cs | 23 ++++++++++------------- DesktopVRIK/DesktopVRIKCalibrator.cs | 3 +-- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index 093b84f..8a3d15c 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -24,14 +24,14 @@ public class DesktopVRIK : MonoBehaviour Setting_ChestHeadingWeight; // Internal Stuff - private float - ik_SimulatedRootAngle; - private bool - ps_emoteIsPlaying; + bool ps_emoteIsPlaying; + float ik_SimulatedRootAngle; + Transform desktopCameraTransform; static readonly FieldInfo ms_isGrounded = typeof(MovementSystem).GetField("_isGrounded", BindingFlags.NonPublic | BindingFlags.Instance); void Start() { + desktopCameraTransform = PlayerSetup.Instance.desktopCamera.transform; Calibrator = new DesktopVRIKCalibrator(); Instance = this; DesktopVRIKMod.UpdateAllSettings(); @@ -72,8 +72,8 @@ public class DesktopVRIK : MonoBehaviour if (changed) { ps_emoteIsPlaying = isEmotePlaying; - Calibrator.vrik.transform.localPosition = Vector3.zero; - Calibrator.vrik.transform.localRotation = Quaternion.identity; + Calibrator.avatarTransform.localPosition = Vector3.zero; + Calibrator.avatarTransform.localRotation = Quaternion.identity; if (Calibrator.lookAtIK != null) { Calibrator.lookAtIK.enabled = !isEmotePlaying; @@ -104,22 +104,19 @@ public class DesktopVRIK : MonoBehaviour weight *= isGrounded ? 1f : 0f; // Reset avatar offset (VRIK will literally make you walk away from root otherwise) - Calibrator.vrik.transform.localPosition = Vector3.zero; - Calibrator.vrik.transform.localRotation = Quaternion.identity; + Calibrator.avatarTransform.localPosition = Vector3.zero; + Calibrator.avatarTransform.localRotation = Quaternion.identity; // Plant feet is nice for Desktop Calibrator.vrik.solver.plantFeet = Setting_PlantFeet; - // This is nice for walk cycles - //Calibrator.vrik.solver.spine.rotateChestByHands = Setting_RotateChestByHands * weight; - // Old VRChat hip movement emulation if (Setting_BodyLeanWeight > 0) { float weightedAngle = Setting_BodyLeanWeight * weight; - float angle = PlayerSetup.Instance.desktopCamera.transform.localEulerAngles.x; + float angle = desktopCameraTransform.localEulerAngles.x; angle = (angle > 180) ? angle - 360 : angle; - Quaternion rotation = Quaternion.AngleAxis(angle * weightedAngle, IKSystem.Instance.avatar.transform.right); + Quaternion rotation = Quaternion.AngleAxis(angle * weightedAngle, Calibrator.avatarTransform.right); Calibrator.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Head, rotation); } diff --git a/DesktopVRIK/DesktopVRIKCalibrator.cs b/DesktopVRIK/DesktopVRIKCalibrator.cs index 61e0bd6..77a60c7 100644 --- a/DesktopVRIK/DesktopVRIKCalibrator.cs +++ b/DesktopVRIK/DesktopVRIKCalibrator.cs @@ -355,8 +355,7 @@ public class DesktopVRIKCalibrator vrik.solver.locomotion.stepThreshold = initialStepThreshold; DesktopVRIK.ScaleStepHeight(vrik.solver.locomotion.stepHeight, initialStepHeight); } - - + private void SetupDesktopHeadIKTarget() { // Lazy HeadIKTarget calibration From 3807482093ea0cfada297510bb1a1f30707d3f56 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Tue, 7 Mar 2023 15:07:56 -0600 Subject: [PATCH 36/60] clean up --- DesktopVRIK/DesktopVRIK.cs | 103 ++++---- DesktopVRIK/DesktopVRIKCalibrator.cs | 340 ++++--------------------- DesktopVRIK/HarmonyPatches.cs | 2 +- DesktopVRIK/Integrations/BTKUIAddon.cs | 21 +- DesktopVRIK/Main.cs | 78 +++--- DesktopVRIK/Properties/AssemblyInfo.cs | 2 +- DesktopVRIK/VRIKUtils.cs | 183 +++++++++++++ DesktopVRIK/format.json | 14 +- 8 files changed, 347 insertions(+), 396 deletions(-) create mode 100644 DesktopVRIK/VRIKUtils.cs diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index 8a3d15c..60e8371 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -1,5 +1,4 @@ using ABI_RC.Core.Player; -using ABI_RC.Systems.IK; using ABI_RC.Systems.IK.SubSystems; using ABI_RC.Systems.MovementSystem; using RootMotion.FinalIK; @@ -28,6 +27,8 @@ public class DesktopVRIK : MonoBehaviour float ik_SimulatedRootAngle; Transform desktopCameraTransform; static readonly FieldInfo ms_isGrounded = typeof(MovementSystem).GetField("_isGrounded", BindingFlags.NonPublic | BindingFlags.Instance); + bool forceSteps; + bool forceStepsNow; void Start() { @@ -44,46 +45,43 @@ public class DesktopVRIK : MonoBehaviour ResetDesktopVRIK(); } - public bool OnSetupIKScaling(float avatarHeight, float scaleDifference) + public bool OnSetupIKScaling(float scaleDifference) { - if (Calibrator.vrik != null) - { - Calibrator.vrik.solver.locomotion.footDistance = Calibrator.initialFootDistance * scaleDifference; - Calibrator.vrik.solver.locomotion.stepThreshold = Calibrator.initialStepThreshold * scaleDifference; - DesktopVRIK.ScaleStepHeight(Calibrator.vrik.solver.locomotion.stepHeight, Calibrator.initialStepHeight * scaleDifference); - //Calibrator.vrik.solver.Reset(); - ResetDesktopVRIK(); + if (Calibrator.vrik == null) return false; - return true; - } - return false; - } + VRIKUtils.ApplyScaleToVRIK + ( + Calibrator.vrik, + Calibrator.initialFootDistance, + Calibrator.initialStepThreshold, + Calibrator.initialStepHeight, + scaleDifference + ); - public static void ScaleStepHeight(AnimationCurve stepHeightCurve, float mag) - { - Keyframe[] keyframes = stepHeightCurve.keys; - keyframes[1].value = mag; - stepHeightCurve.keys = keyframes; + ResetDesktopVRIK(); + return true; } public void OnPlayerSetupUpdate(bool isEmotePlaying) { bool changed = isEmotePlaying != ps_emoteIsPlaying; - if (changed) - { - ps_emoteIsPlaying = isEmotePlaying; - Calibrator.avatarTransform.localPosition = Vector3.zero; - Calibrator.avatarTransform.localRotation = Quaternion.identity; - if (Calibrator.lookAtIK != null) - { - Calibrator.lookAtIK.enabled = !isEmotePlaying; - } - BodySystem.TrackingEnabled = !isEmotePlaying; - Calibrator.vrik.solver?.Reset(); - ResetDesktopVRIK(); - } + if (!changed) return; + + ps_emoteIsPlaying = isEmotePlaying; + + Calibrator.avatarTransform.localPosition = Vector3.zero; + Calibrator.avatarTransform.localRotation = Quaternion.identity; + + if (Calibrator.lookAtIK != null) + Calibrator.lookAtIK.enabled = !isEmotePlaying; + + BodySystem.TrackingEnabled = !isEmotePlaying; + + Calibrator.vrik.solver?.Reset(); + ResetDesktopVRIK(); } + public void ResetDesktopVRIK() { ik_SimulatedRootAngle = transform.eulerAngles.y; @@ -91,33 +89,34 @@ public class DesktopVRIK : MonoBehaviour public void OnPreSolverUpdate() { - if (ps_emoteIsPlaying) - { - return; - } + if (ps_emoteIsPlaying) return; - bool isGrounded = (bool)ms_isGrounded.GetValue(MovementSystem.Instance); + var movementSystem = MovementSystem.Instance; + var vrikSolver = Calibrator.vrik.solver; + var avatarTransform = Calibrator.avatarTransform; - // Calculate everything that affects weight - float weight = Calibrator.vrik.solver.IKPositionWeight; - weight *= (1 - MovementSystem.Instance.movementVector.magnitude); + bool isGrounded = (bool)ms_isGrounded.GetValue(movementSystem); + + // Calculate weight + float weight = vrikSolver.IKPositionWeight; + weight *= 1f - movementSystem.movementVector.magnitude; weight *= isGrounded ? 1f : 0f; - // Reset avatar offset (VRIK will literally make you walk away from root otherwise) - Calibrator.avatarTransform.localPosition = Vector3.zero; - Calibrator.avatarTransform.localRotation = Quaternion.identity; + // Reset avatar offset + avatarTransform.localPosition = Vector3.zero; + avatarTransform.localRotation = Quaternion.identity; - // Plant feet is nice for Desktop - Calibrator.vrik.solver.plantFeet = Setting_PlantFeet; + // Set plant feet + vrikSolver.plantFeet = Setting_PlantFeet; - // Old VRChat hip movement emulation + // Emulate old VRChat hip movement if (Setting_BodyLeanWeight > 0) { float weightedAngle = Setting_BodyLeanWeight * weight; float angle = desktopCameraTransform.localEulerAngles.x; - angle = (angle > 180) ? angle - 360 : angle; - Quaternion rotation = Quaternion.AngleAxis(angle * weightedAngle, Calibrator.avatarTransform.right); - Calibrator.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Head, rotation); + angle = angle > 180 ? angle - 360 : angle; + Quaternion rotation = Quaternion.AngleAxis(angle * weightedAngle, avatarTransform.right); + vrikSolver.AddRotationOffset(IKSolverVR.RotationOffset.Head, rotation); } // Make root heading follow within a set limit @@ -131,15 +130,15 @@ public class DesktopVRIK : MonoBehaviour currentAngle = Mathf.Sign(currentAngle) * weightedAngleLimit; ik_SimulatedRootAngle = Mathf.MoveTowardsAngle(ik_SimulatedRootAngle, transform.eulerAngles.y, angleMaxDelta - weightedAngleLimit); } - Calibrator.vrik.solver.spine.rootHeadingOffset = currentAngle; + vrikSolver.spine.rootHeadingOffset = currentAngle; if (Setting_PelvisHeadingWeight > 0) { - Calibrator.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Pelvis, new Vector3(0f, currentAngle * Setting_PelvisHeadingWeight, 0f)); - Calibrator.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Chest, new Vector3(0f, -currentAngle * Setting_PelvisHeadingWeight, 0f)); + vrikSolver.AddRotationOffset(IKSolverVR.RotationOffset.Pelvis, new Vector3(0f, currentAngle * Setting_PelvisHeadingWeight, 0f)); + vrikSolver.AddRotationOffset(IKSolverVR.RotationOffset.Chest, new Vector3(0f, -currentAngle * Setting_PelvisHeadingWeight, 0f)); } if (Setting_ChestHeadingWeight > 0) { - Calibrator.vrik.solver.AddRotationOffset(IKSolverVR.RotationOffset.Chest, new Vector3(0f, currentAngle * Setting_ChestHeadingWeight, 0f)); + vrikSolver.AddRotationOffset(IKSolverVR.RotationOffset.Chest, new Vector3(0f, currentAngle * Setting_ChestHeadingWeight, 0f)); } } } diff --git a/DesktopVRIK/DesktopVRIKCalibrator.cs b/DesktopVRIK/DesktopVRIKCalibrator.cs index 77a60c7..03fe096 100644 --- a/DesktopVRIK/DesktopVRIKCalibrator.cs +++ b/DesktopVRIK/DesktopVRIKCalibrator.cs @@ -16,8 +16,6 @@ public class DesktopVRIKCalibrator // Settings public bool Setting_UseVRIKToes = true; public bool Setting_FindUnmappedToes = true; - public bool Setting_ExperimentalKneeBend = true; - public bool Setting_DebugCalibrationPose = false; // Avatar Component References public CVRAvatar avatar; @@ -27,26 +25,26 @@ public class DesktopVRIKCalibrator public LookAtIK lookAtIK; // Calibrated Values - public float - initialFootDistance, - initialStepThreshold, + public float + initialFootDistance, + initialStepThreshold, initialStepHeight; // Calibration Internals - bool DebugCalibrationPose; bool fixTransformsRequired; Vector3 leftKneeNormal, rightKneeNormal; HumanPose initialHumanPose; HumanPoseHandler humanPoseHandler; + // Traverse IKSystem ikSystem; PlayerSetup playerSetup; Traverse - _vrikTraverse, - _lookIKTraverse, - _avatarTraverse, - _animatorManagerTraverse, - _poseHandlerTraverse, + _vrikTraverse, + _lookIKTraverse, + _avatarTraverse, + _animatorManagerTraverse, + _poseHandlerTraverse, _avatarRootHeightTraverse; public DesktopVRIKCalibrator() @@ -68,15 +66,10 @@ public class DesktopVRIKCalibrator public void CalibrateDesktopVRIK() { - PreInitialize(); - - // Don't do anything else if just debugging calibration pose - DebugCalibrationPose = !DebugCalibrationPose; - if (Setting_DebugCalibrationPose && DebugCalibrationPose) - { - ForceCalibrationPose(); - return; - } + // Scan avatar for issues/references + ScanAvatarForCalibration(); + // Prepare CVR IKSystem for external VRIK + PrepareIKSystem(); // Add VRIK and configure PrepareAvatarVRIK(); @@ -86,51 +79,42 @@ public class DesktopVRIKCalibrator PostInitialize(); } - public void ForceCalibrationPose(bool toggle = true) - { - animator.enabled = !toggle; - SetHumanPose(0f); - //SetAvatarIKPose(toggle); - } - - private void PreInitialize() - { - // Scan avatar for issues/references - ScanAvatarForCalibration(); - // Prepare CVR IKSystem for external VRIK - PrepareIKSystem(); - } - private void Initialize() { // Calculate bend normals with motorcycle pose SetHumanPose(0f); - CalculateKneeBendNormals(); + VRIKUtils.CalculateKneeBendNormals(vrik, out leftKneeNormal, out rightKneeNormal); + // Calculate initial IK scaling values with IKPose SetAvatarIKPose(true); + VRIKUtils.CalculateInitialIKScaling(vrik, out initialFootDistance, out initialStepThreshold, out initialStepHeight); // Setup HeadIK target & calculate initial footstep values SetupDesktopHeadIKTarget(); - CalculateInitialIKScaling(); // Initiate VRIK manually - ForceInitiateVRIKSolver(); + VRIKUtils.InitiateVRIKSolver(vrik); + // Return avatar to original pose SetAvatarIKPose(false); } private void PostInitialize() { - ApplyKneeBendNormals(); - ApplyInitialIKScaling(); + VRIKUtils.ApplyScaleToVRIK + ( + vrik, + initialFootDistance, + initialStepThreshold, + initialStepHeight, + 1f + ); + VRIKUtils.ApplyKneeBendNormals(vrik, leftKneeNormal, rightKneeNormal); vrik.onPreSolverUpdate.AddListener(new UnityAction(DesktopVRIK.Instance.OnPreSolverUpdate)); } - + private void ScanAvatarForCalibration() { - // Reset some stuff to default - fixTransformsRequired = false; - // Find required avatar components avatar = playerSetup._avatar.GetComponent(); animator = avatar.GetComponent(); @@ -138,22 +122,15 @@ public class DesktopVRIKCalibrator lookAtIK = _lookIKTraverse.GetValue(); // Apply some fixes for weird setups - if (!animator.enabled) - { - fixTransformsRequired = true; - DesktopVRIKMod.Logger.Error("Avatar has Animator disabled by default!"); - } + fixTransformsRequired = !animator.enabled; - // Center avatar local offsets + // Center avatar local position avatarTransform.localPosition = Vector3.zero; - //avatarTransform.localRotation = Quaternion.identity; - // Store original human pose - if (humanPoseHandler != null) - { - humanPoseHandler.Dispose(); - } + // Create a new human pose handler and dispose the old one + humanPoseHandler?.Dispose(); humanPoseHandler = new HumanPoseHandler(animator.avatar, avatarTransform); + // Store original human pose humanPoseHandler.GetHumanPose(ref initialHumanPose); } @@ -168,21 +145,13 @@ public class DesktopVRIKCalibrator // Set the animator for the IK system ikSystem.animator = animator; - if (ikSystem.animator != null) - { - animatorManager.SetAnimator(ikSystem.animator, ikSystem.animator.runtimeAnimatorController); - } + animatorManager.SetAnimator(ikSystem.animator, ikSystem.animator.runtimeAnimatorController); // Set the avatar height float - float avatarHeight = ikSystem.vrPlaySpace.transform.InverseTransformPoint(avatarTransform.position).y; - _avatarRootHeightTraverse.SetValue(avatarHeight); + _avatarRootHeightTraverse.SetValue(ikSystem.vrPlaySpace.transform.InverseTransformPoint(avatarTransform.position).y); // Create a new human pose handler and dispose the old one - if (ikHumanPoseHandler != null) - { - ikHumanPoseHandler.Dispose(); - _poseHandlerTraverse.SetValue(null); - } + ikHumanPoseHandler?.Dispose(); ikHumanPoseHandler = new HumanPoseHandler(ikSystem.animator.avatar, avatarTransform); _poseHandlerTraverse.SetValue(ikHumanPoseHandler); @@ -206,156 +175,48 @@ public class DesktopVRIKCalibrator private void PrepareAvatarVRIK() { - //add and configure VRIK + // Add and configure VRIK vrik = avatar.gameObject.AddComponentIfMissing(); vrik.AutoDetectReferences(); - ConfigureVRIKReferences(); - _vrikTraverse.SetValue(vrik); - //in testing, not really needed - //only required if Setting_FindUnmappedToes - //and non-human mapped toes are found - vrik.fixTransforms = fixTransformsRequired; + VRIKUtils.ConfigureVRIKReferences(vrik, Setting_UseVRIKToes, Setting_FindUnmappedToes, out bool foundUnmappedToes); - //default solver settings + // Fix animator issue or non-human mapped toes + vrik.fixTransforms = fixTransformsRequired || foundUnmappedToes; + + // Default solver settings vrik.solver.locomotion.weight = 0f; vrik.solver.locomotion.angleThreshold = 30f; - vrik.solver.locomotion.maxLegStretch = 0.75f; + vrik.solver.locomotion.maxLegStretch = 1f; vrik.solver.spine.minHeadHeight = 0f; vrik.solver.IKPositionWeight = 1f; - //disable to not bleed into anims vrik.solver.spine.chestClampWeight = 0f; vrik.solver.spine.maintainPelvisPosition = 0f; - //for body leaning - vrik.solver.spine.neckStiffness = 0.0001f; //cannot be 0 + + // Body leaning settings + vrik.solver.spine.neckStiffness = 0.0001f; vrik.solver.spine.bodyPosStiffness = 1f; vrik.solver.spine.bodyRotStiffness = 0.2f; - //disable so avatar doesnt try and walk away + + // Disable locomotion vrik.solver.locomotion.velocityFactor = 0f; vrik.solver.locomotion.maxVelocity = 0f; - //fixes nameplate spazzing on remote & magicacloth vrik.solver.locomotion.rootSpeed = 1000f; - //disable so PAM & BID dont make body shake + + // Disable chest rotation by hands vrik.solver.spine.rotateChestByHands = 0f; - //enable to prioritize LookAtIK + + // Prioritize LookAtIK vrik.solver.spine.headClampWeight = 0.2f; - //disable to not go on tippytoes + + // Disable going on tippytoes vrik.solver.spine.positionWeight = 0f; vrik.solver.spine.rotationWeight = 1f; - //vrik.solver.spine.maintainPelvisPosition = 1f; - //vrik.solver.locomotion.weight = 0f; - //vrik.solver.spine.positionWeight = 0f; - //vrik.solver.spine.pelvisPositionWeight = 0f; - //vrik.solver.leftArm.positionWeight = 0f; - //vrik.solver.leftArm.rotationWeight = 0f; - //vrik.solver.rightArm.positionWeight = 0f; - //vrik.solver.rightArm.rotationWeight = 0f; - //vrik.solver.leftLeg.positionWeight = 0f; - //vrik.solver.leftLeg.rotationWeight = 0f; - //vrik.solver.rightLeg.positionWeight = 0f; - //vrik.solver.rightLeg.rotationWeight = 0f; - //vrik.solver.IKPositionWeight = 0f; - - //THESE ARE CONFIGURABLE IN GAME IK SETTINGS - //vrik.solver.leftLeg.target = null; - //vrik.solver.leftLeg.bendGoal = null; - //vrik.solver.leftLeg.positionWeight = 0f; - //vrik.solver.leftLeg.bendGoalWeight = 0f; - //vrik.solver.rightLeg.target = null; - //vrik.solver.rightLeg.bendGoal = null; - //vrik.solver.rightLeg.positionWeight = 0f; - //vrik.solver.rightLeg.bendGoalWeight = 0f; - //vrik.solver.spine.pelvisTarget = null; - //vrik.solver.spine.chestGoal = null; - //vrik.solver.spine.positionWeight = 0f; - //vrik.solver.spine.rotationWeight = 0f; - //vrik.solver.spine.pelvisPositionWeight = 0f; - //vrik.solver.spine.pelvisRotationWeight = 0f; - //vrik.solver.spine.chestGoalWeight = 0f; + // Tell IKSystem about new VRIK + _vrikTraverse.SetValue(vrik); } - private void CalculateKneeBendNormals() - { - // Get assumed left knee normal - Vector3[] leftVectors = new Vector3[] - { - vrik.references.leftThigh?.position ?? Vector3.zero, - vrik.references.leftCalf?.position ?? Vector3.zero, - vrik.references.leftFoot?.position ?? Vector3.zero, - }; - leftKneeNormal = Quaternion.Inverse(vrik.references.root.rotation) * GetNormalFromArray(leftVectors); - - // Get assumed right knee normal - Vector3[] rightVectors = new Vector3[] - { - vrik.references.rightThigh?.position ?? Vector3.zero, - vrik.references.rightCalf?.position ?? Vector3.zero, - vrik.references.rightFoot?.position ?? Vector3.zero, - }; - rightKneeNormal = Quaternion.Inverse(vrik.references.root.rotation) * GetNormalFromArray(rightVectors); - } - - private void ApplyKneeBendNormals() - { - if (!Setting_ExperimentalKneeBend) - { - //enable so knees on fucked models work better - vrik.solver.leftLeg.useAnimatedBendNormal = true; - vrik.solver.rightLeg.useAnimatedBendNormal = true; - return; - } - - vrik.solver.leftLeg.bendToTargetWeight = 0f; - vrik.solver.rightLeg.bendToTargetWeight = 0f; - - Traverse leftLeg_bendNormalRelToPelvisTraverse = Traverse.Create(vrik.solver.leftLeg).Field("bendNormalRelToPelvis"); - Traverse rightLeg_bendNormalRelToPelvisTraverse = Traverse.Create(vrik.solver.rightLeg).Field("bendNormalRelToPelvis"); - - // Calculate knee normal without root rotation but with pelvis rotation - Quaternion pelvisLocalRotationInverse = Quaternion.Inverse(vrik.references.pelvis.localRotation); - Vector3 leftLegBendNormalRelToPelvis = pelvisLocalRotationInverse * leftKneeNormal; - Vector3 rightLegBendNormalRelToPelvis = pelvisLocalRotationInverse * rightKneeNormal; - //Quaternion rootRotation = vrik.references.root.rotation; - //Quaternion pelvisRotationRelativeToRoot = Quaternion.Inverse(rootRotation) * vrik.references.pelvis.rotation; - //Quaternion pelvisRotationInverse = Quaternion.Inverse(pelvisRotationRelativeToRoot); - leftLeg_bendNormalRelToPelvisTraverse.SetValue(leftLegBendNormalRelToPelvis); - rightLeg_bendNormalRelToPelvisTraverse.SetValue(rightLegBendNormalRelToPelvis); - } - - private Vector3 GetNormalFromArray(Vector3[] positions) - { - Vector3 vector = Vector3.zero; - Vector3 vector2 = Vector3.zero; - for (int i = 0; i < positions.Length; i++) - { - vector2 += positions[i]; - } - vector2 /= (float)positions.Length; - for (int j = 0; j < positions.Length - 1; j++) - { - vector += Vector3.Cross(positions[j] - vector2, positions[j + 1] - vector2).normalized; - } - return Vector3.Normalize(vector); - } - - private void CalculateInitialIKScaling() - { - // Get distance between feets and thighs - float footDistance = Vector3.Distance(vrik.references.leftFoot.position, vrik.references.rightFoot.position); - initialFootDistance = footDistance * 0.5f; - initialStepThreshold = footDistance * 0.8f; - initialStepHeight = Vector3.Distance(vrik.references.leftFoot.position, vrik.references.leftCalf.position) * 0.2f; - } - - private void ApplyInitialIKScaling() - { - // Set initial values - vrik.solver.locomotion.footDistance = initialFootDistance; - vrik.solver.locomotion.stepThreshold = initialStepThreshold; - DesktopVRIK.ScaleStepHeight(vrik.solver.locomotion.stepHeight, initialStepHeight); - } - private void SetupDesktopHeadIKTarget() { // Lazy HeadIKTarget calibration @@ -405,95 +266,6 @@ public class DesktopVRIKCalibrator humanPoseHandler.SetHumanPose(ref ikSystem.humanPose); } - private void ForceInitiateVRIKSolver() - { - //force immediate calibration before animator decides to fuck us - vrik.solver.SetToReferences(vrik.references); - vrik.solver.Initiate(vrik.transform); - } - - private void ConfigureVRIKReferences() - { - //might not work over netik - FixChestAndSpineReferences(); - - if (!Setting_UseVRIKToes) - { - vrik.references.leftToes = null; - vrik.references.rightToes = null; - } - else if (Setting_FindUnmappedToes) - { - //doesnt work with netik, but its toes... - FindAndSetUnmappedToes(); - } - - //bullshit fix to not cause death - FixFingerBonesError(); - } - - private void FixChestAndSpineReferences() - { - Transform leftShoulderBone = vrik.references.leftShoulder; - Transform rightShoulderBone = vrik.references.rightShoulder; - Transform assumedChest = leftShoulderBone?.parent; - - if (assumedChest != null && rightShoulderBone.parent == assumedChest && - vrik.references.chest != assumedChest) - { - vrik.references.chest = assumedChest; - vrik.references.spine = assumedChest.parent; - } - } - - private void FindAndSetUnmappedToes() - { - Transform leftToes = vrik.references.leftToes; - Transform rightToes = vrik.references.rightToes; - - if (leftToes == null && rightToes == null) - { - leftToes = FindUnmappedToe(vrik.references.leftFoot); - rightToes = FindUnmappedToe(vrik.references.rightFoot); - - if (leftToes != null && rightToes != null) - { - vrik.references.leftToes = leftToes; - vrik.references.rightToes = rightToes; - fixTransformsRequired = true; - } - } - } - - private Transform FindUnmappedToe(Transform foot) - { - foreach (Transform bone in foot) - { - if (bone.name.ToLowerInvariant().Contains("toe") || - bone.name.ToLowerInvariant().EndsWith("_end")) - { - return bone; - } - } - - return null; - } - - private void FixFingerBonesError() - { - FixFingerBones(vrik.references.leftHand, vrik.solver.leftArm); - FixFingerBones(vrik.references.rightHand, vrik.solver.rightArm); - } - - private void FixFingerBones(Transform hand, IKSolverVR.Arm armSolver) - { - if (hand.childCount == 0) - { - armSolver.wristToPalmAxis = Vector3.up; - armSolver.palmToThumbAxis = hand == vrik.references.leftHand ? -Vector3.forward : Vector3.forward; - } - } - private static readonly float[] IKPoseMuscles = new float[] { 0.00133321f, diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index 9b7d4af..5eb1c49 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -44,7 +44,7 @@ class PlayerSetupPatches [HarmonyPatch(typeof(PlayerSetup), "SetupIKScaling")] private static bool Prefix_PlayerSetup_SetupIKScaling(float height, ref Vector3 ___scaleDifference) { - return !(bool)DesktopVRIK.Instance?.OnSetupIKScaling(height, 1f + ___scaleDifference.y); + return !(bool)DesktopVRIK.Instance?.OnSetupIKScaling(1f + ___scaleDifference.y); } } diff --git a/DesktopVRIK/Integrations/BTKUIAddon.cs b/DesktopVRIK/Integrations/BTKUIAddon.cs index 7fd4f52..33a512c 100644 --- a/DesktopVRIK/Integrations/BTKUIAddon.cs +++ b/DesktopVRIK/Integrations/BTKUIAddon.cs @@ -14,31 +14,30 @@ public static class BTKUIAddon Page miscPage = QuickMenuAPI.MiscTabPage; Category miscCategory = miscPage.AddCategory(DesktopVRIKMod.SettingsCategory); - AddMelonToggle(ref miscCategory, DesktopVRIKMod.m_entryEnabled); + AddMelonToggle(ref miscCategory, DesktopVRIKMod.EntryEnabled); //Add my own page to not clog up Misc Menu Page desktopVRIKPage = miscCategory.AddPage("DesktopVRIK Settings", "", "Configure the settings for DesktopVRIK.", "DesktopVRIK"); desktopVRIKPage.MenuTitle = "DesktopVRIK Settings"; - desktopVRIKPage.MenuSubtitle = "Simplified settings for VRIK on Desktop."; - Category desktopVRIKCategory = desktopVRIKPage.AddCategory("DesktopVRIK"); + Category desktopVRIKCategory = desktopVRIKPage.AddCategory(DesktopVRIKMod.SettingsCategory); // General Settings - AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.m_entryEnabled); - AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.m_entryPlantFeet); + AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryEnabled); + AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryPlantFeet); // Calibration Settings - AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.m_entryUseVRIKToes); - AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.m_entryFindUnmappedToes); + AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryUseVRIKToes); + AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryFindUnmappedToes); // Body Leaning Weight - AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.m_entryBodyLeanWeight, 0, 1f, 1); + AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.EntryBodyLeanWeight, 0, 1f, 1); // Max Root Heading Limit & Weights - AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.m_entryBodyHeadingLimit, 0, 90f, 0); - AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.m_entryPelvisHeadingWeight, 0, 1f, 1); - AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.m_entryChestHeadingWeight, 0, 1f, 1); + AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.EntryBodyHeadingLimit, 0, 90f, 0); + AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.EntryPelvisHeadingWeight, 0, 1f, 1); + AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.EntryChestHeadingWeight, 0, 1f, 1); } private static void AddMelonToggle(ref Category category, MelonLoader.MelonPreferences_Entry entry) { diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index 38baece..7adb920 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -6,41 +6,38 @@ namespace NAK.Melons.DesktopVRIK; public class DesktopVRIKMod : MelonMod { internal static MelonLogger.Instance Logger; - internal const string SettingsCategory = "DesktopVRIK"; - internal static MelonPreferences_Category m_categoryDesktopVRIK; - internal static MelonPreferences_Entry - m_entryEnabled, - m_entryEnforceViewPosition, - m_entryResetIKOnLand, - m_entryPlantFeet, - m_entryUseVRIKToes, - m_entryFindUnmappedToes, - m_entryExperimentalKneeBend; - internal static MelonPreferences_Entry - m_entryBodyLeanWeight, - m_entryBodyHeadingLimit, - m_entryPelvisHeadingWeight, - m_entryChestHeadingWeight; + public const string SettingsCategory = "DesktopVRIK"; + public static readonly MelonPreferences_Category CategoryDesktopVRIK = MelonPreferences.CreateCategory(SettingsCategory); + + public static readonly MelonPreferences_Entry EntryEnabled = + CategoryDesktopVRIK.CreateEntry("Enabled", true, description: "Toggle DesktopVRIK entirely. Requires avatar reload."); + + public static readonly MelonPreferences_Entry EntryPlantFeet = + CategoryDesktopVRIK.CreateEntry("Enforce Plant Feet", true, description: "Forces VRIK Plant Feet enabled to prevent hovering when stopping movement."); + + public static readonly MelonPreferences_Entry EntryUseVRIKToes = + CategoryDesktopVRIK.CreateEntry("Use VRIK Toes", false, description: "Determines if VRIK uses humanoid toes for IK solving, which can cause feet to idle behind the avatar."); + + public static readonly MelonPreferences_Entry EntryFindUnmappedToes = + CategoryDesktopVRIK.CreateEntry("Find Unmapped Toes", false, description: "Determines if DesktopVRIK should look for unmapped toe bones if the humanoid rig does not have any."); + + public static readonly MelonPreferences_Entry EntryBodyLeanWeight = + CategoryDesktopVRIK.CreateEntry("Body Lean Weight", 0.5f, description: "Adds rotational influence to the body solver when looking up/down. Set to 0 to disable."); + + public static readonly MelonPreferences_Entry EntryBodyHeadingLimit = + CategoryDesktopVRIK.CreateEntry("Body Heading Limit", 20f, description: "Specifies the maximum angle the lower body can have relative to the head when rotating. Set to 0 to disable."); + + public static readonly MelonPreferences_Entry EntryPelvisHeadingWeight = + CategoryDesktopVRIK.CreateEntry("Pelvis Heading Weight", 0.25f, description: "Determines how much the pelvis will face the Body Heading Limit. Set to 0 to align with head."); + + public static readonly MelonPreferences_Entry EntryChestHeadingWeight = + CategoryDesktopVRIK.CreateEntry("Chest Heading Weight", 0.75f, description: "Determines how much the chest will face the Body Heading Limit. Set to 0 to align with head."); + public override void OnInitializeMelon() { Logger = LoggerInstance; - m_categoryDesktopVRIK = MelonPreferences.CreateCategory(SettingsCategory); - m_entryEnabled = m_categoryDesktopVRIK.CreateEntry("Enabled", true, description: "Toggle DesktopVRIK entirely. Requires avatar reload."); - //m_entryEnforceViewPosition = m_categoryDesktopVRIK.CreateEntry("Enforce View Position", false, description: "Corrects view position to use VRIK offsets."); - m_entryPlantFeet = m_categoryDesktopVRIK.CreateEntry("Enforce Plant Feet", true, description: "Forces VRIK Plant Feet enabled. This prevents the little hover when you stop moving."); - m_entryUseVRIKToes = m_categoryDesktopVRIK.CreateEntry("Use VRIK Toes", false, description: "Should VRIK use your humanoid toes for IK solving? This can cause your feet to idle behind you."); - m_entryFindUnmappedToes = m_categoryDesktopVRIK.CreateEntry("Find Unmapped Toes", false, description: "Should DesktopVRIK look for unmapped toe bones if humanoid rig does not have any?"); - m_entryExperimentalKneeBend = m_categoryDesktopVRIK.CreateEntry("Experimental Knee Bend", true, description: "Experimental method to calculate knee bend normal. This may break avatars."); - m_entryBodyLeanWeight = m_categoryDesktopVRIK.CreateEntry("Body Lean Weight", 0.5f, description: "Emulates old VRChat-like body leaning when looking up/down. Set to 0 to disable."); - m_entryBodyHeadingLimit = m_categoryDesktopVRIK.CreateEntry("Body Heading Limit", 20f, description: "Emulates VRChat-like body and head offset when rotating left/right. Set to 0 to disable."); - m_entryPelvisHeadingWeight = m_categoryDesktopVRIK.CreateEntry("Pelvis Heading Weight", 0.25f, description: "How much the pelvis will face the heading limit. Set to 0 to align with head."); - m_entryChestHeadingWeight = m_categoryDesktopVRIK.CreateEntry("Chest Heading Weight", 0.75f, description: "How much the chest will face the heading limit. Set to 0 to align with head."); - - foreach (var setting in m_categoryDesktopVRIK.Entries) - { - setting.OnEntryValueChangedUntyped.Subscribe(OnUpdateSettings); - } + CategoryDesktopVRIK.Entries.ForEach(e => e.OnEntryValueChangedUntyped.Subscribe(OnUpdateSettings)); ApplyPatches(typeof(HarmonyPatches.PlayerSetupPatches)); ApplyPatches(typeof(HarmonyPatches.IKSystemPatches)); @@ -52,18 +49,17 @@ public class DesktopVRIKMod : MelonMod { if (!DesktopVRIK.Instance) return; // DesktopVRIK Settings - DesktopVRIK.Instance.Setting_Enabled = m_entryEnabled.Value; - DesktopVRIK.Instance.Setting_PlantFeet = m_entryPlantFeet.Value; + DesktopVRIK.Instance.Setting_Enabled = EntryEnabled.Value; + DesktopVRIK.Instance.Setting_PlantFeet = EntryPlantFeet.Value; - DesktopVRIK.Instance.Setting_BodyLeanWeight = Mathf.Clamp01(m_entryBodyLeanWeight.Value); - DesktopVRIK.Instance.Setting_BodyHeadingLimit = Mathf.Clamp(m_entryBodyHeadingLimit.Value, 0f, 90f); - DesktopVRIK.Instance.Setting_PelvisHeadingWeight = (1f - Mathf.Clamp01(m_entryPelvisHeadingWeight.Value)); - DesktopVRIK.Instance.Setting_ChestHeadingWeight = (1f - Mathf.Clamp01(m_entryChestHeadingWeight.Value)); + DesktopVRIK.Instance.Setting_BodyLeanWeight = Mathf.Clamp01(EntryBodyLeanWeight.Value); + DesktopVRIK.Instance.Setting_BodyHeadingLimit = Mathf.Clamp(EntryBodyHeadingLimit.Value, 0f, 90f); + DesktopVRIK.Instance.Setting_PelvisHeadingWeight = (1f - Mathf.Clamp01(EntryPelvisHeadingWeight.Value)); + DesktopVRIK.Instance.Setting_ChestHeadingWeight = (1f - Mathf.Clamp01(EntryChestHeadingWeight.Value)); // Calibration Settings - DesktopVRIK.Instance.Calibrator.Setting_UseVRIKToes = m_entryUseVRIKToes.Value; - DesktopVRIK.Instance.Calibrator.Setting_FindUnmappedToes = m_entryFindUnmappedToes.Value; - DesktopVRIK.Instance.Calibrator.Setting_ExperimentalKneeBend = m_entryExperimentalKneeBend.Value; + DesktopVRIK.Instance.Calibrator.Setting_UseVRIKToes = EntryUseVRIKToes.Value; + DesktopVRIK.Instance.Calibrator.Setting_FindUnmappedToes = EntryFindUnmappedToes.Value; } private void OnUpdateSettings(object arg1, object arg2) => UpdateAllSettings(); @@ -72,7 +68,7 @@ public class DesktopVRIKMod : MelonMod //BTKUILib Misc Tab if (MelonMod.RegisteredMelons.Any(it => it.Info.Name == "BTKUILib")) { - MelonLogger.Msg("Initializing BTKUILib support."); + Logger.Msg("Initializing BTKUILib support."); BTKUIAddon.Init(); } } diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs index 879ab4b..ace74a2 100644 --- a/DesktopVRIK/Properties/AssemblyInfo.cs +++ b/DesktopVRIK/Properties/AssemblyInfo.cs @@ -26,6 +26,6 @@ using System.Reflection; namespace NAK.Melons.DesktopVRIK.Properties; internal static class AssemblyInfoParams { - public const string Version = "4.0.0"; + public const string Version = "4.0.1"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/DesktopVRIK/VRIKUtils.cs b/DesktopVRIK/VRIKUtils.cs new file mode 100644 index 0000000..fcdfaa5 --- /dev/null +++ b/DesktopVRIK/VRIKUtils.cs @@ -0,0 +1,183 @@ +using HarmonyLib; +using RootMotion.FinalIK; +using UnityEngine; + +namespace NAK.Melons.DesktopVRIK; + +public static class VRIKUtils +{ + public static void ConfigureVRIKReferences(VRIK vrik, bool useVRIKToes, bool findUnmappedToes, out bool foundUnmappedToes) + { + foundUnmappedToes = false; + + //might not work over netik + FixChestAndSpineReferences(vrik); + + if (!useVRIKToes) + { + vrik.references.leftToes = null; + vrik.references.rightToes = null; + } + else if (findUnmappedToes) + { + //doesnt work with netik, but its toes... + FindAndSetUnmappedToes(vrik, out foundUnmappedToes); + } + + //bullshit fix to not cause death + FixFingerBonesError(vrik); + } + + private static void FixChestAndSpineReferences(VRIK vrik) + { + Transform leftShoulderBone = vrik.references.leftShoulder; + Transform rightShoulderBone = vrik.references.rightShoulder; + Transform assumedChest = leftShoulderBone?.parent; + + if (assumedChest != null && rightShoulderBone.parent == assumedChest && + vrik.references.chest != assumedChest) + { + vrik.references.chest = assumedChest; + vrik.references.spine = assumedChest.parent; + } + } + + private static void FindAndSetUnmappedToes(VRIK vrik, out bool foundUnmappedToes) + { + foundUnmappedToes = false; + + Transform leftToes = vrik.references.leftToes; + Transform rightToes = vrik.references.rightToes; + + if (leftToes == null && rightToes == null) + { + leftToes = FindUnmappedToe(vrik.references.leftFoot); + rightToes = FindUnmappedToe(vrik.references.rightFoot); + + if (leftToes != null && rightToes != null) + { + vrik.references.leftToes = leftToes; + vrik.references.rightToes = rightToes; + foundUnmappedToes = true; + } + } + } + + private static Transform FindUnmappedToe(Transform foot) + { + foreach (Transform bone in foot) + { + if (bone.name.ToLowerInvariant().Contains("toe") || + bone.name.ToLowerInvariant().EndsWith("_end")) + { + return bone; + } + } + + return null; + } + + private static void FixFingerBonesError(VRIK vrik) + { + FixFingerBones(vrik, vrik.references.leftHand, vrik.solver.leftArm); + FixFingerBones(vrik, vrik.references.rightHand, vrik.solver.rightArm); + } + + private static void FixFingerBones(VRIK vrik, Transform hand, IKSolverVR.Arm armSolver) + { + if (hand.childCount == 0) + { + armSolver.wristToPalmAxis = Vector3.up; + armSolver.palmToThumbAxis = hand == vrik.references.leftHand ? -Vector3.forward : Vector3.forward; + } + } + + public static void CalculateKneeBendNormals(VRIK vrik, out Vector3 leftKneeNormal, out Vector3 rightKneeNormal) + { + // Helper function to get position or default to Vector3.zero + Vector3 GetPositionOrDefault(Transform transform) => transform?.position ?? Vector3.zero; + + // Get assumed left knee normal + Vector3[] leftVectors = { + GetPositionOrDefault(vrik.references.leftThigh), + GetPositionOrDefault(vrik.references.leftCalf), + GetPositionOrDefault(vrik.references.leftFoot) + }; + leftKneeNormal = Quaternion.Inverse(vrik.references.root.rotation) * GetNormalFromArray(leftVectors); + + // Get assumed right knee normal + Vector3[] rightVectors = { + GetPositionOrDefault(vrik.references.rightThigh), + GetPositionOrDefault(vrik.references.rightCalf), + GetPositionOrDefault(vrik.references.rightFoot) + }; + rightKneeNormal = Quaternion.Inverse(vrik.references.root.rotation) * GetNormalFromArray(rightVectors); + } + + public static void ApplyKneeBendNormals(VRIK vrik, Vector3 leftKneeNormal, Vector3 rightKneeNormal) + { + // 0 uses bendNormalRelToPelvis, 1 is bendNormalRelToTarget + // modifying pelvis normal weight is better math + vrik.solver.leftLeg.bendToTargetWeight = 0f; + vrik.solver.rightLeg.bendToTargetWeight = 0f; + + var leftLeg_bendNormalRelToPelvisTraverse = Traverse.Create(vrik.solver.leftLeg).Field("bendNormalRelToPelvis"); + var rightLeg_bendNormalRelToPelvisTraverse = Traverse.Create(vrik.solver.rightLeg).Field("bendNormalRelToPelvis"); + + var pelvis_localRotationInverse = Quaternion.Inverse(vrik.references.pelvis.localRotation); + var leftLeg_bendNormalRelToPelvis = pelvis_localRotationInverse * leftKneeNormal; + var rightLeg_bendNormalRelToPelvis = pelvis_localRotationInverse * rightKneeNormal; + + leftLeg_bendNormalRelToPelvisTraverse.SetValue(leftLeg_bendNormalRelToPelvis); + rightLeg_bendNormalRelToPelvisTraverse.SetValue(rightLeg_bendNormalRelToPelvis); + } + + private static Vector3 GetNormalFromArray(Vector3[] positions) + { + Vector3 centroid = Vector3.zero; + for (int i = 0; i < positions.Length; i++) + { + centroid += positions[i]; + } + centroid /= positions.Length; + + Vector3 normal = Vector3.zero; + for (int i = 0; i < positions.Length - 2; i++) + { + Vector3 side1 = positions[i] - centroid; + Vector3 side2 = positions[i + 1] - centroid; + normal += Vector3.Cross(side1, side2); + } + return normal.normalized; + } + + public static void CalculateInitialIKScaling(VRIK vrik, out float initialFootDistance, out float initialStepThreshold, out float initialStepHeight) + { + // Get distance between feet and thighs + float scaleModifier = Mathf.Max(1f, vrik.references.pelvis.lossyScale.x); + float footDistance = Vector3.Distance(vrik.references.leftFoot.position, vrik.references.rightFoot.position); + initialFootDistance = footDistance * 0.5f; + initialStepThreshold = footDistance * scaleModifier; + initialStepHeight = Vector3.Distance(vrik.references.leftFoot.position, vrik.references.leftCalf.position) * 0.2f; + } + + public static void ApplyScaleToVRIK(VRIK vrik, float footDistance, float stepThreshold, float stepHeight, float modifier) + { + vrik.solver.locomotion.footDistance = footDistance * modifier; + vrik.solver.locomotion.stepThreshold = stepThreshold * modifier; + ScaleStepHeight(vrik.solver.locomotion.stepHeight, stepHeight * modifier); + } + + private static void ScaleStepHeight(AnimationCurve stepHeightCurve, float mag) + { + Keyframe[] keyframes = stepHeightCurve.keys; + keyframes[1].value = mag; + stepHeightCurve.keys = keyframes; + } + + public static void InitiateVRIKSolver(VRIK vrik) + { + vrik.solver.SetToReferences(vrik.references); + vrik.solver.Initiate(vrik.transform); + } +} \ No newline at end of file diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json index d1d47d6..6337a93 100644 --- a/DesktopVRIK/format.json +++ b/DesktopVRIK/format.json @@ -1,23 +1,25 @@ { "_id": 117, "name": "DesktopVRIK", - "modversion": "2.0.5", + "modversion": "4.0.1", "gameversion": "2022r170", "loaderversion": "0.5.7", "modtype": "Mod", "author": "NotAKidoS", - "description": "Adds VRIK to Desktop avatars. No longer will you be a liveless sliding statue~!\nAdds the small feet stepping when looking around on Desktop.\n\nAdditional option to emulate VRChat-like hip movement if you like being fish.", + "description": "Adds VRIK to Desktop avatars. No longer will you be a liveless sliding statue~!\nAdds the small feet stepping when looking around on Desktop.\n\nIt is highly recommended to use AvatarMotionTweaker alongside this mod.", "searchtags": [ "desktop", "vrik", "ik", - "feet" + "feet", + "fish" ], "requirements": [ - "BTKUILib" + "BTKUILib", + "AvatarMotionTweaker" ], - "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v2.0.5/DesktopVRIK.dll", + "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v4.0.1/DesktopVRIK.dll", "sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRIK/", - "changelog": "- Tweaks to VRIK settings so BetterInteractDesktop & PickupArmMovement better behave alongside VRIK.\n- Tweaks to BTKUI integration.", + "changelog": "- Implemented fixes for terrible armatures that had broken knee bending, initial hip rotation, and initial step calculations.\n- Added pelvis & chest weight sliders for heading angle limit option.\n- Implemented bandaid fixes for disabled animator and avatars without fingers.\n- Added options to use or remove toes from VRIK and find unmapped non-humanoid toe bones.\n- Contact me if you find an avatar that is still broken.", "embedcolor": "9b59b6" } \ No newline at end of file From f8d4e3463409ca8af77b56c445606a7738674d5c Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Tue, 7 Mar 2023 17:06:10 -0600 Subject: [PATCH 37/60] Update DesktopVRIK.cs --- DesktopVRIK/DesktopVRIK.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index 60e8371..d6baefb 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -27,8 +27,6 @@ public class DesktopVRIK : MonoBehaviour float ik_SimulatedRootAngle; Transform desktopCameraTransform; static readonly FieldInfo ms_isGrounded = typeof(MovementSystem).GetField("_isGrounded", BindingFlags.NonPublic | BindingFlags.Instance); - bool forceSteps; - bool forceStepsNow; void Start() { From 51ff6e8333e3b82729e51877240de018fde5a0f6 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Tue, 7 Mar 2023 17:22:04 -0600 Subject: [PATCH 38/60] switch to reflection idk traverse seems kinda heavy for this usecase --- DesktopVRIK/VRIKUtils.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/DesktopVRIK/VRIKUtils.cs b/DesktopVRIK/VRIKUtils.cs index fcdfaa5..a455fb6 100644 --- a/DesktopVRIK/VRIKUtils.cs +++ b/DesktopVRIK/VRIKUtils.cs @@ -1,11 +1,13 @@ -using HarmonyLib; -using RootMotion.FinalIK; +using RootMotion.FinalIK; using UnityEngine; +using System.Reflection; namespace NAK.Melons.DesktopVRIK; public static class VRIKUtils { + static readonly FieldInfo vrik_bendNormalRelToPelvis = typeof(IKSolverVR.Leg).GetField("bendNormalRelToPelvis", BindingFlags.NonPublic | BindingFlags.Instance); + public static void ConfigureVRIKReferences(VRIK vrik, bool useVRIKToes, bool findUnmappedToes, out bool foundUnmappedToes) { foundUnmappedToes = false; @@ -121,15 +123,12 @@ public static class VRIKUtils vrik.solver.leftLeg.bendToTargetWeight = 0f; vrik.solver.rightLeg.bendToTargetWeight = 0f; - var leftLeg_bendNormalRelToPelvisTraverse = Traverse.Create(vrik.solver.leftLeg).Field("bendNormalRelToPelvis"); - var rightLeg_bendNormalRelToPelvisTraverse = Traverse.Create(vrik.solver.rightLeg).Field("bendNormalRelToPelvis"); - var pelvis_localRotationInverse = Quaternion.Inverse(vrik.references.pelvis.localRotation); var leftLeg_bendNormalRelToPelvis = pelvis_localRotationInverse * leftKneeNormal; var rightLeg_bendNormalRelToPelvis = pelvis_localRotationInverse * rightKneeNormal; - leftLeg_bendNormalRelToPelvisTraverse.SetValue(leftLeg_bendNormalRelToPelvis); - rightLeg_bendNormalRelToPelvisTraverse.SetValue(rightLeg_bendNormalRelToPelvis); + vrik_bendNormalRelToPelvis.SetValue(vrik.solver.leftLeg, leftLeg_bendNormalRelToPelvis); + vrik_bendNormalRelToPelvis.SetValue(vrik.solver.rightLeg, rightLeg_bendNormalRelToPelvis); } private static Vector3 GetNormalFromArray(Vector3[] positions) From 81a84c125c22fb0cd690ff47bb0e0b2dc3b7c7cf Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Wed, 8 Mar 2023 21:28:53 -0600 Subject: [PATCH 39/60] fix movement parent ik --- DesktopVRIK/DesktopVRIK.cs | 137 ++++++++++++++++++++++++---------- DesktopVRIK/HarmonyPatches.cs | 7 ++ DesktopVRIK/VRIKUtils.cs | 4 +- 3 files changed, 105 insertions(+), 43 deletions(-) diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index d6baefb..720d014 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -1,10 +1,13 @@ -using ABI_RC.Core.Player; +using ABI.CCK.Components; +using ABI_RC.Core.Player; using ABI_RC.Systems.IK.SubSystems; using ABI_RC.Systems.MovementSystem; +using HarmonyLib; using RootMotion.FinalIK; using System.Reflection; using UnityEngine; + namespace NAK.Melons.DesktopVRIK; public class DesktopVRIK : MonoBehaviour @@ -16,127 +19,179 @@ public class DesktopVRIK : MonoBehaviour public bool Setting_Enabled = true, Setting_PlantFeet = true; + public float Setting_BodyLeanWeight, Setting_BodyHeadingLimit, Setting_PelvisHeadingWeight, Setting_ChestHeadingWeight; - // Internal Stuff - bool ps_emoteIsPlaying; - float ik_SimulatedRootAngle; - Transform desktopCameraTransform; - static readonly FieldInfo ms_isGrounded = typeof(MovementSystem).GetField("_isGrounded", BindingFlags.NonPublic | BindingFlags.Instance); + // DesktopVRIK References + bool _isEmotePlaying; + float _simulatedRootAngle; + Transform _avatarTransform; + Transform _cameraTransform; + + // IK Stuff + VRIK _vrik; + LookAtIK _lookAtIK; + IKSolverVR _ikSolver; + + // Movement System Stuff + MovementSystem movementSystem; + Traverse _isGroundedTraverse; + + // Movement Parent Stuff + private Vector3 _previousPosition; + private Quaternion _previousRotation; + private Traverse _currentParentTraverse; + static readonly FieldInfo _referencePointField = typeof(CVRMovementParent).GetField("_referencePoint", BindingFlags.NonPublic | BindingFlags.Instance); void Start() { - desktopCameraTransform = PlayerSetup.Instance.desktopCamera.transform; - Calibrator = new DesktopVRIKCalibrator(); Instance = this; + Calibrator = new DesktopVRIKCalibrator(); DesktopVRIKMod.UpdateAllSettings(); + + movementSystem = GetComponent(); + _cameraTransform = PlayerSetup.Instance.desktopCamera.transform; + _isGroundedTraverse = Traverse.Create(movementSystem).Field("_isGrounded"); + _currentParentTraverse = Traverse.Create(movementSystem).Field("_currentParent"); } public void OnSetupAvatarDesktop() { if (!Setting_Enabled) return; Calibrator.CalibrateDesktopVRIK(); - ResetDesktopVRIK(); + + _vrik = Calibrator.vrik; + _lookAtIK = Calibrator.lookAtIK; + _ikSolver = Calibrator.vrik.solver; + _avatarTransform = Calibrator.avatarTransform; + + _simulatedRootAngle = transform.eulerAngles.y; } public bool OnSetupIKScaling(float scaleDifference) { - if (Calibrator.vrik == null) return false; + if (_vrik == null) return false; VRIKUtils.ApplyScaleToVRIK ( - Calibrator.vrik, + _vrik, Calibrator.initialFootDistance, Calibrator.initialStepThreshold, Calibrator.initialStepHeight, scaleDifference ); + _ikSolver?.Reset(); ResetDesktopVRIK(); return true; } public void OnPlayerSetupUpdate(bool isEmotePlaying) { - bool changed = isEmotePlaying != ps_emoteIsPlaying; + bool changed = isEmotePlaying != _isEmotePlaying; if (!changed) return; - ps_emoteIsPlaying = isEmotePlaying; + _isEmotePlaying = isEmotePlaying; - Calibrator.avatarTransform.localPosition = Vector3.zero; - Calibrator.avatarTransform.localRotation = Quaternion.identity; + _avatarTransform.localPosition = Vector3.zero; + _avatarTransform.localRotation = Quaternion.identity; - if (Calibrator.lookAtIK != null) - Calibrator.lookAtIK.enabled = !isEmotePlaying; + if (_lookAtIK != null) + _lookAtIK.enabled = !isEmotePlaying; BodySystem.TrackingEnabled = !isEmotePlaying; - Calibrator.vrik.solver?.Reset(); + _vrik.solver?.Reset(); ResetDesktopVRIK(); } + public bool OnPlayerSetupResetIk() + { + if (_vrik == null) return false; + + CVRMovementParent currentParent = _currentParentTraverse.GetValue(); + if (currentParent == null) return false; + + Transform referencePoint = (Transform)_referencePointField.GetValue(currentParent); + if (referencePoint == null) return false; + + var currentPosition = referencePoint.position; + var currentRotation = currentParent.transform.rotation; + + // Keep only the Y-axis rotation + currentRotation = Quaternion.Euler(0f, currentRotation.eulerAngles.y, 0f); + + var deltaPosition = currentPosition - _previousPosition; + var deltaRotation = Quaternion.Inverse(_previousRotation) * currentRotation; + + var platformPivot = transform.position; + _ikSolver.AddPlatformMotion(deltaPosition, deltaRotation, platformPivot); + + _previousPosition = currentPosition; + _previousRotation = currentRotation; + + ResetDesktopVRIK(); + return true; + } + public void ResetDesktopVRIK() { - ik_SimulatedRootAngle = transform.eulerAngles.y; + _simulatedRootAngle = transform.eulerAngles.y; } public void OnPreSolverUpdate() { - if (ps_emoteIsPlaying) return; + if (_isEmotePlaying) return; - var movementSystem = MovementSystem.Instance; - var vrikSolver = Calibrator.vrik.solver; - var avatarTransform = Calibrator.avatarTransform; - - bool isGrounded = (bool)ms_isGrounded.GetValue(movementSystem); + bool isGrounded = _isGroundedTraverse.GetValue(); // Calculate weight - float weight = vrikSolver.IKPositionWeight; + float weight = _ikSolver.IKPositionWeight; weight *= 1f - movementSystem.movementVector.magnitude; weight *= isGrounded ? 1f : 0f; // Reset avatar offset - avatarTransform.localPosition = Vector3.zero; - avatarTransform.localRotation = Quaternion.identity; + _avatarTransform.localPosition = Vector3.zero; + _avatarTransform.localRotation = Quaternion.identity; // Set plant feet - vrikSolver.plantFeet = Setting_PlantFeet; + _ikSolver.plantFeet = Setting_PlantFeet; // Emulate old VRChat hip movement if (Setting_BodyLeanWeight > 0) { float weightedAngle = Setting_BodyLeanWeight * weight; - float angle = desktopCameraTransform.localEulerAngles.x; + float angle = _cameraTransform.localEulerAngles.x; angle = angle > 180 ? angle - 360 : angle; - Quaternion rotation = Quaternion.AngleAxis(angle * weightedAngle, avatarTransform.right); - vrikSolver.AddRotationOffset(IKSolverVR.RotationOffset.Head, rotation); + Quaternion rotation = Quaternion.AngleAxis(angle * weightedAngle, _avatarTransform.right); + _ikSolver.spine.headRotationOffset *= rotation; } // Make root heading follow within a set limit if (Setting_BodyHeadingLimit > 0) { float weightedAngleLimit = Setting_BodyHeadingLimit * weight; - float currentAngle = Mathf.DeltaAngle(transform.eulerAngles.y, ik_SimulatedRootAngle); - float angleMaxDelta = Mathf.Abs(currentAngle); - if (angleMaxDelta > weightedAngleLimit) + float deltaAngleRoot = Mathf.DeltaAngle(transform.eulerAngles.y, _simulatedRootAngle); + float absDeltaAngleRoot = Mathf.Abs(deltaAngleRoot); + if (absDeltaAngleRoot > weightedAngleLimit) { - currentAngle = Mathf.Sign(currentAngle) * weightedAngleLimit; - ik_SimulatedRootAngle = Mathf.MoveTowardsAngle(ik_SimulatedRootAngle, transform.eulerAngles.y, angleMaxDelta - weightedAngleLimit); + deltaAngleRoot = Mathf.Sign(deltaAngleRoot) * weightedAngleLimit; + _simulatedRootAngle = Mathf.MoveTowardsAngle(_simulatedRootAngle, transform.eulerAngles.y, absDeltaAngleRoot - weightedAngleLimit); } - vrikSolver.spine.rootHeadingOffset = currentAngle; + _ikSolver.spine.rootHeadingOffset = deltaAngleRoot; if (Setting_PelvisHeadingWeight > 0) { - vrikSolver.AddRotationOffset(IKSolverVR.RotationOffset.Pelvis, new Vector3(0f, currentAngle * Setting_PelvisHeadingWeight, 0f)); - vrikSolver.AddRotationOffset(IKSolverVR.RotationOffset.Chest, new Vector3(0f, -currentAngle * Setting_PelvisHeadingWeight, 0f)); + _ikSolver.spine.pelvisRotationOffset *= Quaternion.Euler(0f, deltaAngleRoot * Setting_PelvisHeadingWeight, 0f); + _ikSolver.spine.chestRotationOffset *= Quaternion.Euler(0f, -deltaAngleRoot * Setting_PelvisHeadingWeight, 0f); } if (Setting_ChestHeadingWeight > 0) { - vrikSolver.AddRotationOffset(IKSolverVR.RotationOffset.Chest, new Vector3(0f, currentAngle * Setting_ChestHeadingWeight, 0f)); + _ikSolver.spine.chestRotationOffset *= Quaternion.Euler(0f, deltaAngleRoot * Setting_ChestHeadingWeight, 0f); } } } diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index 5eb1c49..dcd965a 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -46,6 +46,13 @@ class PlayerSetupPatches { return !(bool)DesktopVRIK.Instance?.OnSetupIKScaling(1f + ___scaleDifference.y); } + + [HarmonyPrefix] + [HarmonyPatch(typeof(PlayerSetup), "ResetIk")] + static bool Prefix_PlayerSetup_ResetIk() + { + return !(bool)DesktopVRIK.Instance?.OnPlayerSetupResetIk(); + } } class IKSystemPatches diff --git a/DesktopVRIK/VRIKUtils.cs b/DesktopVRIK/VRIKUtils.cs index a455fb6..e212622 100644 --- a/DesktopVRIK/VRIKUtils.cs +++ b/DesktopVRIK/VRIKUtils.cs @@ -1,13 +1,13 @@ using RootMotion.FinalIK; -using UnityEngine; using System.Reflection; +using UnityEngine; namespace NAK.Melons.DesktopVRIK; public static class VRIKUtils { static readonly FieldInfo vrik_bendNormalRelToPelvis = typeof(IKSolverVR.Leg).GetField("bendNormalRelToPelvis", BindingFlags.NonPublic | BindingFlags.Instance); - + public static void ConfigureVRIKReferences(VRIK vrik, bool useVRIKToes, bool findUnmappedToes, out bool foundUnmappedToes) { foundUnmappedToes = false; From 5c4bfe4d3f3edefb1e618d733f3b9725553dbf3e Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Wed, 8 Mar 2023 21:30:44 -0600 Subject: [PATCH 40/60] bump vers --- DesktopVRIK/Properties/AssemblyInfo.cs | 2 +- DesktopVRIK/format.json | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs index ace74a2..33ead80 100644 --- a/DesktopVRIK/Properties/AssemblyInfo.cs +++ b/DesktopVRIK/Properties/AssemblyInfo.cs @@ -26,6 +26,6 @@ using System.Reflection; namespace NAK.Melons.DesktopVRIK.Properties; internal static class AssemblyInfoParams { - public const string Version = "4.0.1"; + public const string Version = "4.0.2"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json index 6337a93..1608a59 100644 --- a/DesktopVRIK/format.json +++ b/DesktopVRIK/format.json @@ -1,7 +1,7 @@ { "_id": 117, "name": "DesktopVRIK", - "modversion": "4.0.1", + "modversion": "4.0.2", "gameversion": "2022r170", "loaderversion": "0.5.7", "modtype": "Mod", @@ -18,8 +18,8 @@ "BTKUILib", "AvatarMotionTweaker" ], - "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v4.0.1/DesktopVRIK.dll", + "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v4.0.2/DesktopVRIK.dll", "sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRIK/", - "changelog": "- Implemented fixes for terrible armatures that had broken knee bending, initial hip rotation, and initial step calculations.\n- Added pelvis & chest weight sliders for heading angle limit option.\n- Implemented bandaid fixes for disabled animator and avatars without fingers.\n- Added options to use or remove toes from VRIK and find unmapped non-humanoid toe bones.\n- Contact me if you find an avatar that is still broken.", + "changelog": "- Implemented fixes for terrible armatures that had broken knee bending, initial hip rotation, and initial step calculations.\n- Added pelvis & chest weight sliders for heading angle limit option.\n- Implemented bandaid fixes for disabled animator and avatars without fingers.\n- Added options to use or remove toes from VRIK and find unmapped non-humanoid toe bones.\n- Implemented VRIK platform motion while on a Movement Parent.\n- Contact me if you find an avatar that is still broken.", "embedcolor": "9b59b6" } \ No newline at end of file From ee896a6c6ba51536a5eb4bfb416362211efc9c88 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Wed, 8 Mar 2023 21:44:45 -0600 Subject: [PATCH 41/60] huh --- DesktopVRIK/DesktopVRIK.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs index 720d014..cd30354 100644 --- a/DesktopVRIK/DesktopVRIK.cs +++ b/DesktopVRIK/DesktopVRIK.cs @@ -105,7 +105,7 @@ public class DesktopVRIK : MonoBehaviour BodySystem.TrackingEnabled = !isEmotePlaying; - _vrik.solver?.Reset(); + _ikSolver?.Reset(); ResetDesktopVRIK(); } From 1eeaf4be54a2ccd5ea478cf170ad3045df5a8bef Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Tue, 28 Mar 2023 22:48:44 -0500 Subject: [PATCH 42/60] No longer rely on AMT, IKSystem, or PlayerSetup Partially rewrote everything so it is cleaner, does not need Traverse/Reflection, and no longer piggybacks on the game handling VRIK on Desktop for whatever reason. This version also handles VRIK Locomotion weight standalone instead of requiring AvatarMotionTweaker, but if AMT is found it will rely on it anyways. This can be overwridden in the melonprefs, but its still gonna be double the maths for no reason. --- DesktopVRIK/DesktopVRIK.cs | 198 -------- DesktopVRIK/DesktopVRIK.csproj | 21 +- DesktopVRIK/DesktopVRIKCalibrator.cs | 367 --------------- DesktopVRIK/DesktopVRIKSystem.cs | 646 +++++++++++++++++++++++++++ DesktopVRIK/HarmonyPatches.cs | 26 +- DesktopVRIK/Main.cs | 64 +-- DesktopVRIK/VRIKUtils.cs | 24 +- 7 files changed, 721 insertions(+), 625 deletions(-) delete mode 100644 DesktopVRIK/DesktopVRIK.cs delete mode 100644 DesktopVRIK/DesktopVRIKCalibrator.cs create mode 100644 DesktopVRIK/DesktopVRIKSystem.cs diff --git a/DesktopVRIK/DesktopVRIK.cs b/DesktopVRIK/DesktopVRIK.cs deleted file mode 100644 index cd30354..0000000 --- a/DesktopVRIK/DesktopVRIK.cs +++ /dev/null @@ -1,198 +0,0 @@ -using ABI.CCK.Components; -using ABI_RC.Core.Player; -using ABI_RC.Systems.IK.SubSystems; -using ABI_RC.Systems.MovementSystem; -using HarmonyLib; -using RootMotion.FinalIK; -using System.Reflection; -using UnityEngine; - - -namespace NAK.Melons.DesktopVRIK; - -public class DesktopVRIK : MonoBehaviour -{ - public static DesktopVRIK Instance; - public DesktopVRIKCalibrator Calibrator; - - // DesktopVRIK Settings - public bool - Setting_Enabled = true, - Setting_PlantFeet = true; - - public float - Setting_BodyLeanWeight, - Setting_BodyHeadingLimit, - Setting_PelvisHeadingWeight, - Setting_ChestHeadingWeight; - - // DesktopVRIK References - bool _isEmotePlaying; - float _simulatedRootAngle; - Transform _avatarTransform; - Transform _cameraTransform; - - // IK Stuff - VRIK _vrik; - LookAtIK _lookAtIK; - IKSolverVR _ikSolver; - - // Movement System Stuff - MovementSystem movementSystem; - Traverse _isGroundedTraverse; - - // Movement Parent Stuff - private Vector3 _previousPosition; - private Quaternion _previousRotation; - private Traverse _currentParentTraverse; - static readonly FieldInfo _referencePointField = typeof(CVRMovementParent).GetField("_referencePoint", BindingFlags.NonPublic | BindingFlags.Instance); - - void Start() - { - Instance = this; - Calibrator = new DesktopVRIKCalibrator(); - DesktopVRIKMod.UpdateAllSettings(); - - movementSystem = GetComponent(); - _cameraTransform = PlayerSetup.Instance.desktopCamera.transform; - _isGroundedTraverse = Traverse.Create(movementSystem).Field("_isGrounded"); - _currentParentTraverse = Traverse.Create(movementSystem).Field("_currentParent"); - } - - public void OnSetupAvatarDesktop() - { - if (!Setting_Enabled) return; - Calibrator.CalibrateDesktopVRIK(); - - _vrik = Calibrator.vrik; - _lookAtIK = Calibrator.lookAtIK; - _ikSolver = Calibrator.vrik.solver; - _avatarTransform = Calibrator.avatarTransform; - - _simulatedRootAngle = transform.eulerAngles.y; - } - - public bool OnSetupIKScaling(float scaleDifference) - { - if (_vrik == null) return false; - - VRIKUtils.ApplyScaleToVRIK - ( - _vrik, - Calibrator.initialFootDistance, - Calibrator.initialStepThreshold, - Calibrator.initialStepHeight, - scaleDifference - ); - - _ikSolver?.Reset(); - ResetDesktopVRIK(); - return true; - } - - public void OnPlayerSetupUpdate(bool isEmotePlaying) - { - bool changed = isEmotePlaying != _isEmotePlaying; - if (!changed) return; - - _isEmotePlaying = isEmotePlaying; - - _avatarTransform.localPosition = Vector3.zero; - _avatarTransform.localRotation = Quaternion.identity; - - if (_lookAtIK != null) - _lookAtIK.enabled = !isEmotePlaying; - - BodySystem.TrackingEnabled = !isEmotePlaying; - - _ikSolver?.Reset(); - ResetDesktopVRIK(); - } - - public bool OnPlayerSetupResetIk() - { - if (_vrik == null) return false; - - CVRMovementParent currentParent = _currentParentTraverse.GetValue(); - if (currentParent == null) return false; - - Transform referencePoint = (Transform)_referencePointField.GetValue(currentParent); - if (referencePoint == null) return false; - - var currentPosition = referencePoint.position; - var currentRotation = currentParent.transform.rotation; - - // Keep only the Y-axis rotation - currentRotation = Quaternion.Euler(0f, currentRotation.eulerAngles.y, 0f); - - var deltaPosition = currentPosition - _previousPosition; - var deltaRotation = Quaternion.Inverse(_previousRotation) * currentRotation; - - var platformPivot = transform.position; - _ikSolver.AddPlatformMotion(deltaPosition, deltaRotation, platformPivot); - - _previousPosition = currentPosition; - _previousRotation = currentRotation; - - ResetDesktopVRIK(); - return true; - } - - - public void ResetDesktopVRIK() - { - _simulatedRootAngle = transform.eulerAngles.y; - } - - public void OnPreSolverUpdate() - { - if (_isEmotePlaying) return; - - bool isGrounded = _isGroundedTraverse.GetValue(); - - // Calculate weight - float weight = _ikSolver.IKPositionWeight; - weight *= 1f - movementSystem.movementVector.magnitude; - weight *= isGrounded ? 1f : 0f; - - // Reset avatar offset - _avatarTransform.localPosition = Vector3.zero; - _avatarTransform.localRotation = Quaternion.identity; - - // Set plant feet - _ikSolver.plantFeet = Setting_PlantFeet; - - // Emulate old VRChat hip movement - if (Setting_BodyLeanWeight > 0) - { - float weightedAngle = Setting_BodyLeanWeight * weight; - float angle = _cameraTransform.localEulerAngles.x; - angle = angle > 180 ? angle - 360 : angle; - Quaternion rotation = Quaternion.AngleAxis(angle * weightedAngle, _avatarTransform.right); - _ikSolver.spine.headRotationOffset *= rotation; - } - - // Make root heading follow within a set limit - if (Setting_BodyHeadingLimit > 0) - { - float weightedAngleLimit = Setting_BodyHeadingLimit * weight; - float deltaAngleRoot = Mathf.DeltaAngle(transform.eulerAngles.y, _simulatedRootAngle); - float absDeltaAngleRoot = Mathf.Abs(deltaAngleRoot); - if (absDeltaAngleRoot > weightedAngleLimit) - { - deltaAngleRoot = Mathf.Sign(deltaAngleRoot) * weightedAngleLimit; - _simulatedRootAngle = Mathf.MoveTowardsAngle(_simulatedRootAngle, transform.eulerAngles.y, absDeltaAngleRoot - weightedAngleLimit); - } - _ikSolver.spine.rootHeadingOffset = deltaAngleRoot; - if (Setting_PelvisHeadingWeight > 0) - { - _ikSolver.spine.pelvisRotationOffset *= Quaternion.Euler(0f, deltaAngleRoot * Setting_PelvisHeadingWeight, 0f); - _ikSolver.spine.chestRotationOffset *= Quaternion.Euler(0f, -deltaAngleRoot * Setting_PelvisHeadingWeight, 0f); - } - if (Setting_ChestHeadingWeight > 0) - { - _ikSolver.spine.chestRotationOffset *= Quaternion.Euler(0f, deltaAngleRoot * Setting_ChestHeadingWeight, 0f); - } - } - } -} \ No newline at end of file diff --git a/DesktopVRIK/DesktopVRIK.csproj b/DesktopVRIK/DesktopVRIK.csproj index 592135f..60fc7d3 100644 --- a/DesktopVRIK/DesktopVRIK.csproj +++ b/DesktopVRIK/DesktopVRIK.csproj @@ -6,41 +6,42 @@ enable latest false + True - C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\MelonLoader\0Harmony.dll + C:\Users\krist\Documents\GitHub\_ChilloutVR Modding\_ManagedLibs\0Harmony.dll - C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll + C:\Users\krist\Documents\GitHub\_ChilloutVR Modding\_ManagedLibs\Assembly-CSharp.dll - C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll + C:\Users\krist\Documents\GitHub\_ChilloutVR Modding\_ManagedLibs\Assembly-CSharp-firstpass.dll ..\..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\BTKUILib.dll - C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll + C:\Users\krist\Documents\GitHub\_ChilloutVR Modding\_ManagedLibs\Cohtml.Runtime.dll - C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\MelonLoader\MelonLoader.dll + C:\Users\krist\Documents\GitHub\_ChilloutVR Modding\_ManagedLibs\MelonLoader.dll - C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll + C:\Users\krist\Documents\GitHub\_ChilloutVR Modding\_ManagedLibs\UnityEngine.AnimationModule.dll - C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AssetBundleModule.dll + C:\Users\krist\Documents\GitHub\_ChilloutVR Modding\_ManagedLibs\UnityEngine.AssetBundleModule.dll - C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll + C:\Users\krist\Documents\GitHub\_ChilloutVR Modding\_ManagedLibs\UnityEngine.CoreModule.dll - C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.InputLegacyModule.dll + C:\Users\krist\Documents\GitHub\_ChilloutVR Modding\_ManagedLibs\UnityEngine.InputLegacyModule.dll - C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.PhysicsModule.dll + C:\Users\krist\Documents\GitHub\_ChilloutVR Modding\_ManagedLibs\UnityEngine.PhysicsModule.dll diff --git a/DesktopVRIK/DesktopVRIKCalibrator.cs b/DesktopVRIK/DesktopVRIKCalibrator.cs deleted file mode 100644 index 03fe096..0000000 --- a/DesktopVRIK/DesktopVRIKCalibrator.cs +++ /dev/null @@ -1,367 +0,0 @@ -using ABI.CCK.Components; -using ABI_RC.Core; -using ABI_RC.Core.Base; -using ABI_RC.Core.Player; -using ABI_RC.Systems.IK; -using ABI_RC.Systems.IK.SubSystems; -using HarmonyLib; -using RootMotion.FinalIK; -using UnityEngine; -using UnityEngine.Events; - -namespace NAK.Melons.DesktopVRIK; - -public class DesktopVRIKCalibrator -{ - // Settings - public bool Setting_UseVRIKToes = true; - public bool Setting_FindUnmappedToes = true; - - // Avatar Component References - public CVRAvatar avatar; - public Animator animator; - public Transform avatarTransform; - public VRIK vrik; - public LookAtIK lookAtIK; - - // Calibrated Values - public float - initialFootDistance, - initialStepThreshold, - initialStepHeight; - - // Calibration Internals - bool fixTransformsRequired; - Vector3 leftKneeNormal, rightKneeNormal; - HumanPose initialHumanPose; - HumanPoseHandler humanPoseHandler; - - // Traverse - IKSystem ikSystem; - PlayerSetup playerSetup; - Traverse - _vrikTraverse, - _lookIKTraverse, - _avatarTraverse, - _animatorManagerTraverse, - _poseHandlerTraverse, - _avatarRootHeightTraverse; - - public DesktopVRIKCalibrator() - { - // Get base game scripts. - ikSystem = IKSystem.Instance; - playerSetup = PlayerSetup.Instance; - - // Get traverse to private shit in iksystem. - _vrikTraverse = Traverse.Create(ikSystem).Field("_vrik"); - _avatarTraverse = Traverse.Create(ikSystem).Field("_avatar"); - _animatorManagerTraverse = Traverse.Create(ikSystem).Field("_animatorManager"); - _poseHandlerTraverse = Traverse.Create(ikSystem).Field("_poseHandler"); - _avatarRootHeightTraverse = Traverse.Create(ikSystem).Field("_avatarRootHeight"); - - // Get traverse to private shit in playersetup. - _lookIKTraverse = Traverse.Create(playerSetup).Field("lookIK"); - } - - public void CalibrateDesktopVRIK() - { - // Scan avatar for issues/references - ScanAvatarForCalibration(); - // Prepare CVR IKSystem for external VRIK - PrepareIKSystem(); - - // Add VRIK and configure - PrepareAvatarVRIK(); - - Initialize(); - - PostInitialize(); - } - - private void Initialize() - { - // Calculate bend normals with motorcycle pose - SetHumanPose(0f); - VRIKUtils.CalculateKneeBendNormals(vrik, out leftKneeNormal, out rightKneeNormal); - - // Calculate initial IK scaling values with IKPose - SetAvatarIKPose(true); - VRIKUtils.CalculateInitialIKScaling(vrik, out initialFootDistance, out initialStepThreshold, out initialStepHeight); - - // Setup HeadIK target & calculate initial footstep values - SetupDesktopHeadIKTarget(); - - // Initiate VRIK manually - VRIKUtils.InitiateVRIKSolver(vrik); - - // Return avatar to original pose - SetAvatarIKPose(false); - } - - private void PostInitialize() - { - VRIKUtils.ApplyScaleToVRIK - ( - vrik, - initialFootDistance, - initialStepThreshold, - initialStepHeight, - 1f - ); - VRIKUtils.ApplyKneeBendNormals(vrik, leftKneeNormal, rightKneeNormal); - vrik.onPreSolverUpdate.AddListener(new UnityAction(DesktopVRIK.Instance.OnPreSolverUpdate)); - } - - private void ScanAvatarForCalibration() - { - // Find required avatar components - avatar = playerSetup._avatar.GetComponent(); - animator = avatar.GetComponent(); - avatarTransform = avatar.transform; - lookAtIK = _lookIKTraverse.GetValue(); - - // Apply some fixes for weird setups - fixTransformsRequired = !animator.enabled; - - // Center avatar local position - avatarTransform.localPosition = Vector3.zero; - - // Create a new human pose handler and dispose the old one - humanPoseHandler?.Dispose(); - humanPoseHandler = new HumanPoseHandler(animator.avatar, avatarTransform); - // Store original human pose - humanPoseHandler.GetHumanPose(ref initialHumanPose); - } - - private void PrepareIKSystem() - { - // Get the animator manager and human pose handler - var animatorManager = _animatorManagerTraverse.GetValue(); - var ikHumanPoseHandler = _poseHandlerTraverse.GetValue(); - - // Store the avatar component - _avatarTraverse.SetValue(avatar); - - // Set the animator for the IK system - ikSystem.animator = animator; - animatorManager.SetAnimator(ikSystem.animator, ikSystem.animator.runtimeAnimatorController); - - // Set the avatar height float - _avatarRootHeightTraverse.SetValue(ikSystem.vrPlaySpace.transform.InverseTransformPoint(avatarTransform.position).y); - - // Create a new human pose handler and dispose the old one - ikHumanPoseHandler?.Dispose(); - ikHumanPoseHandler = new HumanPoseHandler(ikSystem.animator.avatar, avatarTransform); - _poseHandlerTraverse.SetValue(ikHumanPoseHandler); - - // Find valid human bones - IKSystem.BoneExists.Clear(); - foreach (HumanBodyBones bone in Enum.GetValues(typeof(HumanBodyBones))) - { - if (bone != HumanBodyBones.LastBone) - { - IKSystem.BoneExists.Add(bone, ikSystem.animator.GetBoneTransform(bone) != null); - } - } - - // Prepare BodySystem for calibration - BodySystem.TrackingLeftArmEnabled = false; - BodySystem.TrackingRightArmEnabled = false; - BodySystem.TrackingLeftLegEnabled = false; - BodySystem.TrackingRightLegEnabled = false; - BodySystem.TrackingPositionWeight = 0f; - } - - private void PrepareAvatarVRIK() - { - // Add and configure VRIK - vrik = avatar.gameObject.AddComponentIfMissing(); - vrik.AutoDetectReferences(); - - VRIKUtils.ConfigureVRIKReferences(vrik, Setting_UseVRIKToes, Setting_FindUnmappedToes, out bool foundUnmappedToes); - - // Fix animator issue or non-human mapped toes - vrik.fixTransforms = fixTransformsRequired || foundUnmappedToes; - - // Default solver settings - vrik.solver.locomotion.weight = 0f; - vrik.solver.locomotion.angleThreshold = 30f; - vrik.solver.locomotion.maxLegStretch = 1f; - vrik.solver.spine.minHeadHeight = 0f; - vrik.solver.IKPositionWeight = 1f; - vrik.solver.spine.chestClampWeight = 0f; - vrik.solver.spine.maintainPelvisPosition = 0f; - - // Body leaning settings - vrik.solver.spine.neckStiffness = 0.0001f; - vrik.solver.spine.bodyPosStiffness = 1f; - vrik.solver.spine.bodyRotStiffness = 0.2f; - - // Disable locomotion - vrik.solver.locomotion.velocityFactor = 0f; - vrik.solver.locomotion.maxVelocity = 0f; - vrik.solver.locomotion.rootSpeed = 1000f; - - // Disable chest rotation by hands - vrik.solver.spine.rotateChestByHands = 0f; - - // Prioritize LookAtIK - vrik.solver.spine.headClampWeight = 0.2f; - - // Disable going on tippytoes - vrik.solver.spine.positionWeight = 0f; - vrik.solver.spine.rotationWeight = 1f; - - // Tell IKSystem about new VRIK - _vrikTraverse.SetValue(vrik); - } - - private void SetupDesktopHeadIKTarget() - { - // Lazy HeadIKTarget calibration - if (vrik.solver.spine.headTarget == null) - { - vrik.solver.spine.headTarget = new GameObject("Head IK Target").transform; - } - vrik.solver.spine.headTarget.parent = vrik.references.head; - vrik.solver.spine.headTarget.localPosition = Vector3.zero; - vrik.solver.spine.headTarget.localRotation = Quaternion.identity; - } - - private void SetAvatarIKPose(bool enforceTPose) - { - int ikposeLayerIndex = animator.GetLayerIndex("IKPose"); - int locoLayerIndex = animator.GetLayerIndex("Locomotion/Emotes"); - - // Use custom IKPose if found. - if (ikposeLayerIndex != -1 && locoLayerIndex != -1) - { - animator.SetLayerWeight(ikposeLayerIndex, enforceTPose ? 1f : 0f); - animator.SetLayerWeight(locoLayerIndex, enforceTPose ? 0f : 1f); - animator.Update(0f); - return; - } - - // Otherwise use DesktopVRIK IKPose & revert afterwards. - if (enforceTPose) - { - SetHumanPose(1f); - } - else - { - humanPoseHandler.SetHumanPose(ref initialHumanPose); - } - } - - private void SetHumanPose(float ikPoseWeight = 1f) - { - humanPoseHandler.GetHumanPose(ref ikSystem.humanPose); - for (int i = 0; i < ikSystem.humanPose.muscles.Length; i++) - { - float weight = ikPoseWeight * IKPoseMuscles[i]; - IKSystem.Instance.ApplyMuscleValue((MuscleIndex)i, weight, ref ikSystem.humanPose.muscles); - } - ikSystem.humanPose.bodyRotation = Quaternion.identity; - humanPoseHandler.SetHumanPose(ref ikSystem.humanPose); - } - - private static readonly float[] IKPoseMuscles = new float[] - { - 0.00133321f, - 8.195831E-06f, - 8.537738E-07f, - -0.002669832f, - -7.651234E-06f, - -0.001659694f, - 0f, - 0f, - 0f, - 0.04213953f, - 0.0003007996f, - -0.008032114f, - -0.03059979f, - -0.0003182998f, - 0.009640567f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0f, - 0.5768794f, - 0.01061097f, - -0.1127839f, - 0.9705755f, - 0.07972051f, - -0.0268422f, - 0.007237188f, - 0f, - 0.5768792f, - 0.01056608f, - -0.1127519f, - 0.9705756f, - 0.07971933f, - -0.02682396f, - 0.007229362f, - 0f, - -5.651802E-06f, - -3.034899E-07f, - 0.4100508f, - 0.3610304f, - -0.0838329f, - 0.9262537f, - 0.1353517f, - -0.03578902f, - 0.06005657f, - -4.95989E-06f, - -1.43007E-06f, - 0.4096187f, - 0.363263f, - -0.08205152f, - 0.9250782f, - 0.1345718f, - -0.03572125f, - 0.06055461f, - -1.079177f, - 0.2095419f, - 0.6140652f, - 0.6365265f, - 0.6683931f, - -0.4764312f, - 0.8099416f, - 0.8099371f, - 0.6658203f, - -0.7327053f, - 0.8113618f, - 0.8114051f, - 0.6643661f, - -0.40341f, - 0.8111364f, - 0.8111367f, - 0.6170399f, - -0.2524227f, - 0.8138723f, - 0.8110135f, - -1.079171f, - 0.2095456f, - 0.6140658f, - 0.6365255f, - 0.6683878f, - -0.4764301f, - 0.8099402f, - 0.8099376f, - 0.6658241f, - -0.7327023f, - 0.8113653f, - 0.8113793f, - 0.664364f, - -0.4034042f, - 0.811136f, - 0.8111364f, - 0.6170469f, - -0.2524345f, - 0.8138595f, - 0.8110138f - }; -} \ No newline at end of file diff --git a/DesktopVRIK/DesktopVRIKSystem.cs b/DesktopVRIK/DesktopVRIKSystem.cs new file mode 100644 index 0000000..52f607e --- /dev/null +++ b/DesktopVRIK/DesktopVRIKSystem.cs @@ -0,0 +1,646 @@ +using ABI.CCK.Components; +using ABI_RC.Core.Base; +using ABI_RC.Core.Player; +using ABI_RC.Systems.IK; +using ABI_RC.Systems.IK.SubSystems; +using ABI_RC.Systems.MovementSystem; +using RootMotion.FinalIK; +using UnityEngine; +using UnityEngine.Events; + +namespace NAK.Melons.DesktopVRIK; + +internal class DesktopVRIKSystem : MonoBehaviour +{ + public static DesktopVRIKSystem Instance; + public static Dictionary BoneExists; + public static readonly float[] IKPoseMuscles = new float[] + { + 0.00133321f, + 8.195831E-06f, + 8.537738E-07f, + -0.002669832f, + -7.651234E-06f, + -0.001659694f, + 0f, + 0f, + 0f, + 0.04213953f, + 0.0003007996f, + -0.008032114f, + -0.03059979f, + -0.0003182998f, + 0.009640567f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0f, + 0.5768794f, + 0.01061097f, + -0.1127839f, + 0.9705755f, + 0.07972051f, + -0.0268422f, + 0.007237188f, + 0f, + 0.5768792f, + 0.01056608f, + -0.1127519f, + 0.9705756f, + 0.07971933f, + -0.02682396f, + 0.007229362f, + 0f, + -5.651802E-06f, + -3.034899E-07f, + 0.4100508f, + 0.3610304f, + -0.0838329f, + 0.9262537f, + 0.1353517f, + -0.03578902f, + 0.06005657f, + -4.95989E-06f, + -1.43007E-06f, + 0.4096187f, + 0.363263f, + -0.08205152f, + 0.9250782f, + 0.1345718f, + -0.03572125f, + 0.06055461f, + -1.079177f, + 0.2095419f, + 0.6140652f, + 0.6365265f, + 0.6683931f, + -0.4764312f, + 0.8099416f, + 0.8099371f, + 0.6658203f, + -0.7327053f, + 0.8113618f, + 0.8114051f, + 0.6643661f, + -0.40341f, + 0.8111364f, + 0.8111367f, + 0.6170399f, + -0.2524227f, + 0.8138723f, + 0.8110135f, + -1.079171f, + 0.2095456f, + 0.6140658f, + 0.6365255f, + 0.6683878f, + -0.4764301f, + 0.8099402f, + 0.8099376f, + 0.6658241f, + -0.7327023f, + 0.8113653f, + 0.8113793f, + 0.664364f, + -0.4034042f, + 0.811136f, + 0.8111364f, + 0.6170469f, + -0.2524345f, + 0.8138595f, + 0.8110138f + }; + enum AvatarPose + { + Default = 0, + Initial = 1, + IKPose = 2, + TPose = 3 + } + + // ChilloutVR Player Components + private PlayerSetup playerSetup; + private MovementSystem movementSystem; + + // DesktopVRIK Settings + public bool Setting_Enabled = true; + public bool Setting_PlantFeet = true; + public float Setting_BodyLeanWeight; + public float Setting_BodyHeadingLimit; + public float Setting_PelvisHeadingWeight; + public float Setting_ChestHeadingWeight; + + // Calibration Settings + public bool Setting_UseVRIKToes = true; + public bool Setting_FindUnmappedToes = true; + + // Integration Settings + public bool Setting_IntegrationAMT = false; + + // Avatar Components + public CVRAvatar avatarDescriptor = null; + public Animator avatarAnimator = null; + public Transform avatarTransform = null; + public LookAtIK avatarLookAtIK = null; + public VRIK avatarVRIK = null; + public IKSolverVR avatarIKSolver = null; + + // Calibration Objects + public HumanPose HumanPose; + public HumanPose InitialHumanPose; + public HumanPoseHandler HumanPoseHandler; + + // Animator Info + public int locomotionLayer = -1; + public int customIKPoseLayer = -1; + public bool requireFixTransforms = false; + + // VRIK Calibration Info + public Vector3 leftKneeNormal; + public Vector3 rightKneeNormal; + public float initialFootDistance; + public float initialStepThreshold; + public float initialStepHeight; + + // Player Info + private Transform _cameraTransform; + private bool _isEmotePlaying; + private float _simulatedRootAngle; + + // Last Movement Parent Info + private Vector3 _previousPosition; + private Quaternion _previousRotation; + + DesktopVRIKSystem() + { + BoneExists = new Dictionary(); + } + + void Start() + { + Instance = this; + + playerSetup = GetComponent(); + movementSystem = GetComponent(); + + _cameraTransform = playerSetup.desktopCamera.transform; + + DesktopVRIKMod.UpdateAllSettings(); + } + + void Update() + { + if (avatarVRIK == null) return; + + HandleLocomotionTracking(); + ApplyBodySystemWeights(); + } + + void HandleLocomotionTracking() + { + bool isMoving = movementSystem.movementVector.magnitude > 0f; + + // AvatarMotionTweaker handles VRIK a bit better than DesktopVRIK + if (Setting_IntegrationAMT && DesktopVRIKMod.integration_AMT) + { + if (isMoving) + { + if (BodySystem.TrackingLocomotionEnabled) + { + BodySystem.TrackingLocomotionEnabled = false; + avatarIKSolver.Reset(); + ResetDesktopVRIK(); + } + } + else + { + if (!BodySystem.TrackingLocomotionEnabled) + { + BodySystem.TrackingLocomotionEnabled = true; + avatarIKSolver.Reset(); + ResetDesktopVRIK(); + } + } + return; + } + + bool isGrounded = movementSystem._isGrounded; + bool isCrouching = movementSystem.crouching; + bool isProne = movementSystem.prone; + bool isFlying = movementSystem.flying; + + // Why do it myself if VRIK already does the maths + Vector3 headLocalPos = avatarIKSolver.spine.headPosition - avatarIKSolver.spine.rootPosition; + float upright = 1f + (headLocalPos.y - avatarIKSolver.spine.headHeight); + + if (isMoving || isCrouching || isProne || isFlying || !isGrounded) + { + if (BodySystem.TrackingLocomotionEnabled) + { + BodySystem.TrackingLocomotionEnabled = false; + avatarIKSolver.Reset(); + ResetDesktopVRIK(); + } + } + else + { + if (!BodySystem.TrackingLocomotionEnabled && upright > 0.8f) + { + BodySystem.TrackingLocomotionEnabled = true; + avatarIKSolver.Reset(); + ResetDesktopVRIK(); + } + } + } + + void ApplyBodySystemWeights() + { + void SetArmWeight(IKSolverVR.Arm arm, bool isTracked) + { + arm.positionWeight = isTracked ? 1f : 0f; + arm.rotationWeight = isTracked ? 1f : 0f; + arm.shoulderRotationWeight = isTracked ? 1f : 0f; + arm.shoulderTwistWeight = isTracked ? 1f : 0f; + } + void SetLegWeight(IKSolverVR.Leg leg, bool isTracked) + { + leg.positionWeight = isTracked ? 1f : 0f; + leg.rotationWeight = isTracked ? 1f : 0f; + } + if (BodySystem.TrackingEnabled) + { + avatarVRIK.enabled = true; + avatarIKSolver.IKPositionWeight = BodySystem.TrackingPositionWeight; + avatarIKSolver.locomotion.weight = BodySystem.TrackingLocomotionEnabled ? 1f : 0f; + + SetArmWeight(avatarIKSolver.leftArm, BodySystem.TrackingLeftArmEnabled && avatarIKSolver.leftArm.target != null); + SetArmWeight(avatarIKSolver.rightArm, BodySystem.TrackingRightArmEnabled && avatarIKSolver.rightArm.target != null); + SetLegWeight(avatarIKSolver.leftLeg, BodySystem.TrackingLeftLegEnabled && avatarIKSolver.leftLeg.target != null); + SetLegWeight(avatarIKSolver.rightLeg, BodySystem.TrackingRightLegEnabled && avatarIKSolver.rightLeg.target != null); + } + else + { + avatarVRIK.enabled = false; + avatarIKSolver.IKPositionWeight = 0f; + avatarIKSolver.locomotion.weight = 0f; + + SetArmWeight(avatarIKSolver.leftArm, false); + SetArmWeight(avatarIKSolver.rightArm, false); + SetLegWeight(avatarIKSolver.leftLeg, false); + SetLegWeight(avatarIKSolver.rightLeg, false); + } + } + + public void OnSetupAvatarDesktop() + { + if (!Setting_Enabled) return; + + CalibrateDesktopVRIK(); + ResetDesktopVRIK(); + } + + public bool OnSetupIKScaling(float scaleDifference) + { + if (avatarVRIK == null) return false; + + VRIKUtils.ApplyScaleToVRIK + ( + avatarVRIK, + initialFootDistance, + initialStepThreshold, + initialStepHeight, + scaleDifference + ); + + avatarIKSolver.Reset(); + ResetDesktopVRIK(); + return true; + } + + public void OnPlayerSetupUpdate(bool isEmotePlaying) + { + if (avatarVRIK == null) return; + + bool changed = isEmotePlaying != _isEmotePlaying; + if (!changed) return; + + _isEmotePlaying = isEmotePlaying; + + avatarTransform.localPosition = Vector3.zero; + avatarTransform.localRotation = Quaternion.identity; + + if (avatarLookAtIK != null) + avatarLookAtIK.enabled = !isEmotePlaying; + + BodySystem.TrackingEnabled = !isEmotePlaying; + + avatarIKSolver.Reset(); + ResetDesktopVRIK(); + } + + public bool OnPlayerSetupResetIk() + { + if (avatarVRIK == null) return false; + + CVRMovementParent currentParent = movementSystem._currentParent; + if (currentParent == null) return false; + + Transform referencePoint = currentParent._referencePoint; + if (referencePoint == null) return false; + + var currentPosition = referencePoint.position; + var currentRotation = currentParent.transform.rotation; + + // Keep only the Y-axis rotation + currentRotation = Quaternion.Euler(0f, currentRotation.eulerAngles.y, 0f); + + var deltaPosition = currentPosition - _previousPosition; + var deltaRotation = Quaternion.Inverse(_previousRotation) * currentRotation; + + var platformPivot = transform.position; + avatarIKSolver.AddPlatformMotion(deltaPosition, deltaRotation, platformPivot); + + _previousPosition = currentPosition; + _previousRotation = currentRotation; + + ResetDesktopVRIK(); + return true; + } + + public void OnPreSolverUpdate() + { + if (_isEmotePlaying) return; + + bool isGrounded = movementSystem._isGrounded; + + // Calculate weight + float weight = avatarIKSolver.IKPositionWeight; + weight *= 1f - movementSystem.movementVector.magnitude; + weight *= isGrounded ? 1f : 0f; + + // Reset avatar offset + avatarTransform.localPosition = Vector3.zero; + avatarTransform.localRotation = Quaternion.identity; + + // Set plant feet + avatarIKSolver.plantFeet = Setting_PlantFeet; + + // Emulate old VRChat hip movementSystem + if (Setting_BodyLeanWeight > 0) + { + float weightedAngle = Setting_BodyLeanWeight * weight; + float angle = _cameraTransform.localEulerAngles.x; + angle = angle > 180 ? angle - 360 : angle; + Quaternion rotation = Quaternion.AngleAxis(angle * weightedAngle, avatarTransform.right); + avatarIKSolver.spine.headRotationOffset *= rotation; + } + + // Make root heading follow within a set limit + if (Setting_BodyHeadingLimit > 0) + { + float weightedAngleLimit = Setting_BodyHeadingLimit * weight; + float deltaAngleRoot = Mathf.DeltaAngle(transform.eulerAngles.y, _simulatedRootAngle); + float absDeltaAngleRoot = Mathf.Abs(deltaAngleRoot); + if (absDeltaAngleRoot > weightedAngleLimit) + { + deltaAngleRoot = Mathf.Sign(deltaAngleRoot) * weightedAngleLimit; + _simulatedRootAngle = Mathf.MoveTowardsAngle(_simulatedRootAngle, transform.eulerAngles.y, absDeltaAngleRoot - weightedAngleLimit); + } + avatarIKSolver.spine.rootHeadingOffset = deltaAngleRoot; + if (Setting_PelvisHeadingWeight > 0) + { + avatarIKSolver.spine.pelvisRotationOffset *= Quaternion.Euler(0f, deltaAngleRoot * Setting_PelvisHeadingWeight, 0f); + avatarIKSolver.spine.chestRotationOffset *= Quaternion.Euler(0f, -deltaAngleRoot * Setting_PelvisHeadingWeight, 0f); + } + if (Setting_ChestHeadingWeight > 0) + { + avatarIKSolver.spine.chestRotationOffset *= Quaternion.Euler(0f, deltaAngleRoot * Setting_ChestHeadingWeight, 0f); + } + } + } + + void ResetDesktopVRIK() + { + _simulatedRootAngle = transform.eulerAngles.y; + } + + void CalibrateDesktopVRIK() + { + ScanAvatar(); + SetupVRIK(); + CalibrateVRIK(); + ConfigureVRIK(); + } + + void ScanAvatar() + { + // Find required avatar components + avatarDescriptor = playerSetup._avatarDescriptor; + avatarAnimator = playerSetup._animator; + avatarTransform = playerSetup._avatar.transform; + avatarLookAtIK = playerSetup.lookIK; + + // Get animator layer inticies + locomotionLayer = avatarAnimator.GetLayerIndex("IKPose"); + customIKPoseLayer = avatarAnimator.GetLayerIndex("Locomotion/Emotes"); + + // Dispose and create new HumanPoseHandler + HumanPoseHandler?.Dispose(); + HumanPoseHandler = new HumanPoseHandler(avatarAnimator.avatar, avatarTransform); + + // Get initial human poses + HumanPoseHandler.GetHumanPose(ref HumanPose); + HumanPoseHandler.GetHumanPose(ref InitialHumanPose); + + // Dumb fix for rare upload issue + requireFixTransforms = !avatarAnimator.enabled; + + // Find available HumanoidBodyBones + BoneExists.Clear(); + foreach (HumanBodyBones bone in Enum.GetValues(typeof(HumanBodyBones))) + { + if (bone != HumanBodyBones.LastBone) + { + BoneExists.Add(bone, avatarAnimator.GetBoneTransform(bone) != null); + } + } + } + + void SetupVRIK() + { + // Add and configure VRIK + avatarVRIK = avatarTransform.AddComponentIfMissing(); + avatarVRIK.AutoDetectReferences(); + avatarIKSolver = avatarVRIK.solver; + + VRIKUtils.ConfigureVRIKReferences(avatarVRIK, Setting_UseVRIKToes, Setting_FindUnmappedToes, out bool foundUnmappedToes); + + // Fix animator issue or non-human mapped toes + avatarVRIK.fixTransforms = requireFixTransforms || foundUnmappedToes; + + // Default solver settings + avatarIKSolver.locomotion.weight = 0f; + avatarIKSolver.locomotion.angleThreshold = 30f; + avatarIKSolver.locomotion.maxLegStretch = 1f; + avatarIKSolver.spine.minHeadHeight = 0f; + avatarIKSolver.IKPositionWeight = 1f; + avatarIKSolver.spine.chestClampWeight = 0f; + avatarIKSolver.spine.maintainPelvisPosition = 0f; + + // Body leaning settings + avatarIKSolver.spine.neckStiffness = 0.0001f; + avatarIKSolver.spine.bodyPosStiffness = 1f; + avatarIKSolver.spine.bodyRotStiffness = 0.2f; + + // Disable locomotion + avatarIKSolver.locomotion.velocityFactor = 0f; + avatarIKSolver.locomotion.maxVelocity = 0f; + avatarIKSolver.locomotion.rootSpeed = 1000f; + + // Disable chest rotation by hands + avatarIKSolver.spine.rotateChestByHands = 0f; + + // Prioritize LookAtIK + avatarIKSolver.spine.headClampWeight = 0.2f; + + // Disable going on tippytoes + avatarIKSolver.spine.positionWeight = 0f; + avatarIKSolver.spine.rotationWeight = 1f; + + // We disable these ourselves now, as we no longer use BodySystem + avatarIKSolver.spine.maintainPelvisPosition = 1f; + avatarIKSolver.spine.positionWeight = 0f; + avatarIKSolver.spine.pelvisPositionWeight = 0f; + avatarIKSolver.leftArm.positionWeight = 0f; + avatarIKSolver.leftArm.rotationWeight = 0f; + avatarIKSolver.rightArm.positionWeight = 0f; + avatarIKSolver.rightArm.rotationWeight = 0f; + avatarIKSolver.leftLeg.positionWeight = 0f; + avatarIKSolver.leftLeg.rotationWeight = 0f; + avatarIKSolver.rightLeg.positionWeight = 0f; + avatarIKSolver.rightLeg.rotationWeight = 0f; + + // This is now our master Locomotion weight + avatarIKSolver.locomotion.weight = 1f; + avatarIKSolver.IKPositionWeight = 1f; + } + + void CalibrateVRIK() + { + SetAvatarPose(AvatarPose.Default); + + // Calculate bend normals with motorcycle pose + VRIKUtils.CalculateKneeBendNormals(avatarVRIK, out leftKneeNormal, out rightKneeNormal); + + SetAvatarPose(AvatarPose.IKPose); + + // Calculate initial IK scaling values with IKPose + VRIKUtils.CalculateInitialIKScaling(avatarVRIK, out initialFootDistance, out initialStepThreshold, out initialStepHeight); + + // Setup HeadIKTarget + VRIKUtils.SetupHeadIKTarget(avatarVRIK); + + // Initiate VRIK manually + VRIKUtils.InitiateVRIKSolver(avatarVRIK); + + SetAvatarPose(AvatarPose.Initial); + } + + void ConfigureVRIK() + { + VRIKUtils.ApplyScaleToVRIK + ( + avatarVRIK, + initialFootDistance, + initialStepThreshold, + initialStepHeight, + 1f + ); + VRIKUtils.ApplyKneeBendNormals(avatarVRIK, leftKneeNormal, rightKneeNormal); + avatarVRIK.onPreSolverUpdate.AddListener(new UnityAction(DesktopVRIKSystem.Instance.OnPreSolverUpdate)); + } + + void SetAvatarPose(AvatarPose pose) + { + switch (pose) + { + case AvatarPose.Default: + if (HasCustomIKPose()) + { + SetCustomLayersWeights(0f, 1f); + avatarAnimator.Update(0f); + } + else + { + SetMusclesToValue(0f); + } + break; + case AvatarPose.Initial: + HumanPoseHandler.SetHumanPose(ref InitialHumanPose); + break; + case AvatarPose.IKPose: + if (HasCustomIKPose()) + { + SetCustomLayersWeights(1f, 0f); + avatarAnimator.Update(0f); + } + else + { + SetMusclesToPose(IKPoseMuscles); + } + break; + case AvatarPose.TPose: + SetMusclesToPose(BodySystem.TPoseMuscles); + break; + default: + break; + } + } + + bool HasCustomIKPose() + { + return locomotionLayer != -1 && customIKPoseLayer != -1; + } + + void SetCustomLayersWeights(float customIKPoseLayerWeight, float locomotionLayerWeight) + { + avatarAnimator.SetLayerWeight(customIKPoseLayer, customIKPoseLayerWeight); + avatarAnimator.SetLayerWeight(locomotionLayer, locomotionLayerWeight); + } + + void SetMusclesToValue(float value) + { + HumanPoseHandler.GetHumanPose(ref HumanPose); + + for (int i = 0; i < HumanPose.muscles.Length; i++) + { + ApplyMuscleValue((MuscleIndex)i, value, ref HumanPose.muscles); + } + + HumanPose.bodyRotation = Quaternion.identity; + HumanPoseHandler.SetHumanPose(ref HumanPose); + } + + void SetMusclesToPose(float[] muscles) + { + HumanPoseHandler.GetHumanPose(ref HumanPose); + + for (int i = 0; i < HumanPose.muscles.Length; i++) + { + ApplyMuscleValue((MuscleIndex)i, muscles[i], ref HumanPose.muscles); + } + + HumanPose.bodyRotation = Quaternion.identity; + HumanPoseHandler.SetHumanPose(ref HumanPose); + } + + void ApplyMuscleValue(MuscleIndex index, float value, ref float[] muscles) + { + if (BoneExists.ContainsKey(IKSystem.MusclesToHumanBodyBones[(int)index]) && BoneExists[IKSystem.MusclesToHumanBodyBones[(int)index]]) + { + muscles[(int)index] = value; + } + } +} diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index dcd965a..7b03dc1 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -1,5 +1,4 @@ using ABI_RC.Core.Player; -using ABI_RC.Systems.IK; using HarmonyLib; using UnityEngine; @@ -23,13 +22,20 @@ namespace NAK.Melons.DesktopVRIK.HarmonyPatches; class PlayerSetupPatches { + [HarmonyPostfix] + [HarmonyPatch(typeof(PlayerSetup), "Start")] + static void Postfix_PlayerSetup_Start(ref PlayerSetup __instance) + { + __instance.gameObject.AddComponent(); + } + [HarmonyPostfix] [HarmonyPatch(typeof(PlayerSetup), "SetupAvatarDesktop")] static void Postfix_PlayerSetup_SetupAvatarDesktop(ref Animator ____animator) { if (____animator != null && ____animator.avatar != null && ____animator.avatar.isHuman) { - DesktopVRIK.Instance?.OnSetupAvatarDesktop(); + DesktopVRIKSystem.Instance?.OnSetupAvatarDesktop(); } } @@ -37,30 +43,20 @@ class PlayerSetupPatches [HarmonyPatch(typeof(PlayerSetup), "Update")] static void Postfix_PlayerSetup_Update(ref bool ____emotePlaying) { - DesktopVRIK.Instance?.OnPlayerSetupUpdate(____emotePlaying); + DesktopVRIKSystem.Instance?.OnPlayerSetupUpdate(____emotePlaying); } [HarmonyPrefix] [HarmonyPatch(typeof(PlayerSetup), "SetupIKScaling")] private static bool Prefix_PlayerSetup_SetupIKScaling(float height, ref Vector3 ___scaleDifference) { - return !(bool)DesktopVRIK.Instance?.OnSetupIKScaling(1f + ___scaleDifference.y); + return !(bool)DesktopVRIKSystem.Instance?.OnSetupIKScaling(1f + ___scaleDifference.y); } [HarmonyPrefix] [HarmonyPatch(typeof(PlayerSetup), "ResetIk")] static bool Prefix_PlayerSetup_ResetIk() { - return !(bool)DesktopVRIK.Instance?.OnPlayerSetupResetIk(); - } -} - -class IKSystemPatches -{ - [HarmonyPostfix] - [HarmonyPatch(typeof(IKSystem), "Start")] - private static void Postfix_IKSystem_Start(ref IKSystem __instance) - { - __instance.gameObject.AddComponent(); + return !(bool)DesktopVRIKSystem.Instance?.OnPlayerSetupResetIk(); } } diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index 7adb920..bb88c21 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -13,7 +13,7 @@ public class DesktopVRIKMod : MelonMod CategoryDesktopVRIK.CreateEntry("Enabled", true, description: "Toggle DesktopVRIK entirely. Requires avatar reload."); public static readonly MelonPreferences_Entry EntryPlantFeet = - CategoryDesktopVRIK.CreateEntry("Enforce Plant Feet", true, description: "Forces VRIK Plant Feet enabled to prevent hovering when stopping movement."); + CategoryDesktopVRIK.CreateEntry("Enforce Plant Feet", true, description: "Forces VRIK Plant Feet enabled to prevent hovering when stopping movementSystem."); public static readonly MelonPreferences_Entry EntryUseVRIKToes = CategoryDesktopVRIK.CreateEntry("Use VRIK Toes", false, description: "Determines if VRIK uses humanoid toes for IK solving, which can cause feet to idle behind the avatar."); @@ -33,6 +33,11 @@ public class DesktopVRIKMod : MelonMod public static readonly MelonPreferences_Entry EntryChestHeadingWeight = CategoryDesktopVRIK.CreateEntry("Chest Heading Weight", 0.75f, description: "Determines how much the chest will face the Body Heading Limit. Set to 0 to align with head."); + public static readonly MelonPreferences_Entry EntryIntegrationAMT = + CategoryDesktopVRIK.CreateEntry("AMT Integration", true, description: "Relies on AvatarMotionTweaker to handle VRIK Locomotion weights if available."); + + public static bool integration_AMT = false; + public override void OnInitializeMelon() { Logger = LoggerInstance; @@ -40,40 +45,47 @@ public class DesktopVRIKMod : MelonMod CategoryDesktopVRIK.Entries.ForEach(e => e.OnEntryValueChangedUntyped.Subscribe(OnUpdateSettings)); ApplyPatches(typeof(HarmonyPatches.PlayerSetupPatches)); - ApplyPatches(typeof(HarmonyPatches.IKSystemPatches)); - InitializeIntegrations(); - } - - internal static void UpdateAllSettings() - { - if (!DesktopVRIK.Instance) return; - // DesktopVRIK Settings - DesktopVRIK.Instance.Setting_Enabled = EntryEnabled.Value; - DesktopVRIK.Instance.Setting_PlantFeet = EntryPlantFeet.Value; - - DesktopVRIK.Instance.Setting_BodyLeanWeight = Mathf.Clamp01(EntryBodyLeanWeight.Value); - DesktopVRIK.Instance.Setting_BodyHeadingLimit = Mathf.Clamp(EntryBodyHeadingLimit.Value, 0f, 90f); - DesktopVRIK.Instance.Setting_PelvisHeadingWeight = (1f - Mathf.Clamp01(EntryPelvisHeadingWeight.Value)); - DesktopVRIK.Instance.Setting_ChestHeadingWeight = (1f - Mathf.Clamp01(EntryChestHeadingWeight.Value)); - - // Calibration Settings - DesktopVRIK.Instance.Calibrator.Setting_UseVRIKToes = EntryUseVRIKToes.Value; - DesktopVRIK.Instance.Calibrator.Setting_FindUnmappedToes = EntryFindUnmappedToes.Value; - } - private void OnUpdateSettings(object arg1, object arg2) => UpdateAllSettings(); - - private static void InitializeIntegrations() - { //BTKUILib Misc Tab if (MelonMod.RegisteredMelons.Any(it => it.Info.Name == "BTKUILib")) { Logger.Msg("Initializing BTKUILib support."); BTKUIAddon.Init(); } + //AvatarMotionTweaker Handling + if (MelonMod.RegisteredMelons.Any(it => it.Info.Name == "AvatarMotionTweaker")) + { + Logger.Msg("AvatarMotionTweaker was found. Relying on it to handle VRIK locomotion."); + integration_AMT = true; + } + else + { + Logger.Msg("AvatarMotionTweaker was not found. Using built-in VRIK locomotion handling."); + } } - private void ApplyPatches(Type type) + internal static void UpdateAllSettings() + { + if (!DesktopVRIKSystem.Instance) return; + // DesktopVRIK Settings + DesktopVRIKSystem.Instance.Setting_Enabled = EntryEnabled.Value; + DesktopVRIKSystem.Instance.Setting_PlantFeet = EntryPlantFeet.Value; + + DesktopVRIKSystem.Instance.Setting_BodyLeanWeight = Mathf.Clamp01(EntryBodyLeanWeight.Value); + DesktopVRIKSystem.Instance.Setting_BodyHeadingLimit = Mathf.Clamp(EntryBodyHeadingLimit.Value, 0f, 90f); + DesktopVRIKSystem.Instance.Setting_PelvisHeadingWeight = (1f - Mathf.Clamp01(EntryPelvisHeadingWeight.Value)); + DesktopVRIKSystem.Instance.Setting_ChestHeadingWeight = (1f - Mathf.Clamp01(EntryChestHeadingWeight.Value)); + + // Calibration Settings + DesktopVRIKSystem.Instance.Setting_UseVRIKToes = EntryUseVRIKToes.Value; + DesktopVRIKSystem.Instance.Setting_FindUnmappedToes = EntryFindUnmappedToes.Value; + + // Integration Settings + DesktopVRIKSystem.Instance.Setting_IntegrationAMT = EntryIntegrationAMT.Value; + } + void OnUpdateSettings(object arg1, object arg2) => UpdateAllSettings(); + + void ApplyPatches(Type type) { try { diff --git a/DesktopVRIK/VRIKUtils.cs b/DesktopVRIK/VRIKUtils.cs index e212622..0444c79 100644 --- a/DesktopVRIK/VRIKUtils.cs +++ b/DesktopVRIK/VRIKUtils.cs @@ -1,13 +1,10 @@ using RootMotion.FinalIK; -using System.Reflection; using UnityEngine; namespace NAK.Melons.DesktopVRIK; public static class VRIKUtils { - static readonly FieldInfo vrik_bendNormalRelToPelvis = typeof(IKSolverVR.Leg).GetField("bendNormalRelToPelvis", BindingFlags.NonPublic | BindingFlags.Instance); - public static void ConfigureVRIKReferences(VRIK vrik, bool useVRIKToes, bool findUnmappedToes, out bool foundUnmappedToes) { foundUnmappedToes = false; @@ -119,16 +116,13 @@ public static class VRIKUtils public static void ApplyKneeBendNormals(VRIK vrik, Vector3 leftKneeNormal, Vector3 rightKneeNormal) { // 0 uses bendNormalRelToPelvis, 1 is bendNormalRelToTarget - // modifying pelvis normal weight is better math + // modifying pelvis normal weight is easier math vrik.solver.leftLeg.bendToTargetWeight = 0f; vrik.solver.rightLeg.bendToTargetWeight = 0f; var pelvis_localRotationInverse = Quaternion.Inverse(vrik.references.pelvis.localRotation); - var leftLeg_bendNormalRelToPelvis = pelvis_localRotationInverse * leftKneeNormal; - var rightLeg_bendNormalRelToPelvis = pelvis_localRotationInverse * rightKneeNormal; - - vrik_bendNormalRelToPelvis.SetValue(vrik.solver.leftLeg, leftLeg_bendNormalRelToPelvis); - vrik_bendNormalRelToPelvis.SetValue(vrik.solver.rightLeg, rightLeg_bendNormalRelToPelvis); + vrik.solver.leftLeg.bendNormalRelToPelvis = pelvis_localRotationInverse * leftKneeNormal; + vrik.solver.rightLeg.bendNormalRelToPelvis = pelvis_localRotationInverse * rightKneeNormal; } private static Vector3 GetNormalFromArray(Vector3[] positions) @@ -160,6 +154,18 @@ public static class VRIKUtils initialStepHeight = Vector3.Distance(vrik.references.leftFoot.position, vrik.references.leftCalf.position) * 0.2f; } + public static void SetupHeadIKTarget(VRIK vrik) + { + // Lazy HeadIKTarget calibration + if (vrik.solver.spine.headTarget == null) + { + vrik.solver.spine.headTarget = new GameObject("Head IK Target").transform; + } + vrik.solver.spine.headTarget.parent = vrik.references.head; + vrik.solver.spine.headTarget.localPosition = Vector3.zero; + vrik.solver.spine.headTarget.localRotation = Quaternion.identity; + } + public static void ApplyScaleToVRIK(VRIK vrik, float footDistance, float stepThreshold, float stepHeight, float modifier) { vrik.solver.locomotion.footDistance = footDistance * modifier; From 42b068bd80d5ff5d280435cb67b978b5dcf4e557 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Tue, 28 Mar 2023 22:54:32 -0500 Subject: [PATCH 43/60] fix annoyances --- DesktopVRIK/DesktopVRIKSystem.cs | 1 + DesktopVRIK/Main.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/DesktopVRIK/DesktopVRIKSystem.cs b/DesktopVRIK/DesktopVRIKSystem.cs index 52f607e..b17973c 100644 --- a/DesktopVRIK/DesktopVRIKSystem.cs +++ b/DesktopVRIK/DesktopVRIKSystem.cs @@ -112,6 +112,7 @@ internal class DesktopVRIKSystem : MonoBehaviour 0.8138595f, 0.8110138f }; + enum AvatarPose { Default = 0, diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index bb88c21..8dff84b 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -13,7 +13,7 @@ public class DesktopVRIKMod : MelonMod CategoryDesktopVRIK.CreateEntry("Enabled", true, description: "Toggle DesktopVRIK entirely. Requires avatar reload."); public static readonly MelonPreferences_Entry EntryPlantFeet = - CategoryDesktopVRIK.CreateEntry("Enforce Plant Feet", true, description: "Forces VRIK Plant Feet enabled to prevent hovering when stopping movementSystem."); + CategoryDesktopVRIK.CreateEntry("Enforce Plant Feet", true, description: "Forces VRIK Plant Feet enabled to prevent hovering when stopping movement."); public static readonly MelonPreferences_Entry EntryUseVRIKToes = CategoryDesktopVRIK.CreateEntry("Use VRIK Toes", false, description: "Determines if VRIK uses humanoid toes for IK solving, which can cause feet to idle behind the avatar."); From 96684582bb3307dd8f6c69c35ac72985bb0f608c Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Tue, 28 Mar 2023 23:12:03 -0500 Subject: [PATCH 44/60] bump --- DesktopVRIK/Properties/AssemblyInfo.cs | 2 +- DesktopVRIK/format.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs index 33ead80..cb56c25 100644 --- a/DesktopVRIK/Properties/AssemblyInfo.cs +++ b/DesktopVRIK/Properties/AssemblyInfo.cs @@ -26,6 +26,6 @@ using System.Reflection; namespace NAK.Melons.DesktopVRIK.Properties; internal static class AssemblyInfoParams { - public const string Version = "4.0.2"; + public const string Version = "4.1.0"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json index 1608a59..fe01f10 100644 --- a/DesktopVRIK/format.json +++ b/DesktopVRIK/format.json @@ -1,12 +1,12 @@ { "_id": 117, "name": "DesktopVRIK", - "modversion": "4.0.2", + "modversion": "4.1.0", "gameversion": "2022r170", "loaderversion": "0.5.7", "modtype": "Mod", "author": "NotAKidoS", - "description": "Adds VRIK to Desktop avatars. No longer will you be a liveless sliding statue~!\nAdds the small feet stepping when looking around on Desktop.\n\nIt is highly recommended to use AvatarMotionTweaker alongside this mod.", + "description": "Adds VRIK to Desktop avatars. No longer will you be a liveless sliding statue~!\nAdds the small feet stepping when looking around on Desktop.", "searchtags": [ "desktop", "vrik", @@ -18,8 +18,8 @@ "BTKUILib", "AvatarMotionTweaker" ], - "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v4.0.2/DesktopVRIK.dll", + "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v4.1.0/DesktopVRIK.dll", "sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRIK/", - "changelog": "- Implemented fixes for terrible armatures that had broken knee bending, initial hip rotation, and initial step calculations.\n- Added pelvis & chest weight sliders for heading angle limit option.\n- Implemented bandaid fixes for disabled animator and avatars without fingers.\n- Added options to use or remove toes from VRIK and find unmapped non-humanoid toe bones.\n- Implemented VRIK platform motion while on a Movement Parent.\n- Contact me if you find an avatar that is still broken.", + "changelog": "- No longer requires AvatarMotionTweaker.\n- No longer piggybacks on IKSystem.\n- DesktopVRIK will now handle VRIK Locomotion weight instead of relying on the game to handle it. This means LeapMotionExtension will now work properly while crouched/prone.", "embedcolor": "9b59b6" } \ No newline at end of file From 1cb0e143e954311b0d34d9739ff69310451a1a5c Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Wed, 29 Mar 2023 00:13:05 -0500 Subject: [PATCH 45/60] Update format.json --- DesktopVRIK/format.json | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json index fe01f10..53afde0 100644 --- a/DesktopVRIK/format.json +++ b/DesktopVRIK/format.json @@ -6,7 +6,7 @@ "loaderversion": "0.5.7", "modtype": "Mod", "author": "NotAKidoS", - "description": "Adds VRIK to Desktop avatars. No longer will you be a liveless sliding statue~!\nAdds the small feet stepping when looking around on Desktop.", + "description": "Adds VRIK to Desktop avatars. No longer will you be a liveless sliding statue~!\nAdds the small feet stepping when looking around on Desktop.\n\nOptional BTKUILib and AvatarMotionTweaker integrations.", "searchtags": [ "desktop", "vrik", @@ -15,11 +15,10 @@ "fish" ], "requirements": [ - "BTKUILib", - "AvatarMotionTweaker" + "BTKUILib" ], "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v4.1.0/DesktopVRIK.dll", "sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRIK/", - "changelog": "- No longer requires AvatarMotionTweaker.\n- No longer piggybacks on IKSystem.\n- DesktopVRIK will now handle VRIK Locomotion weight instead of relying on the game to handle it. This means LeapMotionExtension will now work properly while crouched/prone.", + "changelog": "- No longer requires AvatarMotionTweaker.\n- No longer piggybacks on IKSystem/PlayerSetup.\n\n DesktopVRIK will now handle VRIK Locomotion weight instead of relying on CVR & AMT to handle it. This means LeapMotionExtension & CVRLimbGrabber will now work properly while in crouch/prone.", "embedcolor": "9b59b6" } \ No newline at end of file From 7d2ced73e9bc598a6c06a583087ed009e9b58059 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Wed, 29 Mar 2023 01:12:35 -0500 Subject: [PATCH 46/60] ocd --- DesktopVRIK/DesktopVRIKSystem.cs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/DesktopVRIK/DesktopVRIKSystem.cs b/DesktopVRIK/DesktopVRIKSystem.cs index b17973c..105bb08 100644 --- a/DesktopVRIK/DesktopVRIKSystem.cs +++ b/DesktopVRIK/DesktopVRIKSystem.cs @@ -571,12 +571,9 @@ internal class DesktopVRIKSystem : MonoBehaviour if (HasCustomIKPose()) { SetCustomLayersWeights(0f, 1f); - avatarAnimator.Update(0f); - } - else - { - SetMusclesToValue(0f); + return; } + SetMusclesToValue(0f); break; case AvatarPose.Initial: HumanPoseHandler.SetHumanPose(ref InitialHumanPose); @@ -585,12 +582,9 @@ internal class DesktopVRIKSystem : MonoBehaviour if (HasCustomIKPose()) { SetCustomLayersWeights(1f, 0f); - avatarAnimator.Update(0f); - } - else - { - SetMusclesToPose(IKPoseMuscles); + return; } + SetMusclesToPose(IKPoseMuscles); break; case AvatarPose.TPose: SetMusclesToPose(BodySystem.TPoseMuscles); @@ -609,6 +603,7 @@ internal class DesktopVRIKSystem : MonoBehaviour { avatarAnimator.SetLayerWeight(customIKPoseLayer, customIKPoseLayerWeight); avatarAnimator.SetLayerWeight(locomotionLayer, locomotionLayerWeight); + avatarAnimator.Update(0f); } void SetMusclesToValue(float value) From 59799c0ccde3a289f86f85f7f777dc3aaafd21ef Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Wed, 29 Mar 2023 01:16:29 -0500 Subject: [PATCH 47/60] more ocd --- DesktopVRIK/DesktopVRIKSystem.cs | 120 +++++++++++++++---------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/DesktopVRIK/DesktopVRIKSystem.cs b/DesktopVRIK/DesktopVRIKSystem.cs index 105bb08..6e9354f 100644 --- a/DesktopVRIK/DesktopVRIKSystem.cs +++ b/DesktopVRIK/DesktopVRIKSystem.cs @@ -112,18 +112,6 @@ internal class DesktopVRIKSystem : MonoBehaviour 0.8138595f, 0.8110138f }; - - enum AvatarPose - { - Default = 0, - Initial = 1, - IKPose = 2, - TPose = 3 - } - - // ChilloutVR Player Components - private PlayerSetup playerSetup; - private MovementSystem movementSystem; // DesktopVRIK Settings public bool Setting_Enabled = true; @@ -148,31 +136,43 @@ internal class DesktopVRIKSystem : MonoBehaviour public VRIK avatarVRIK = null; public IKSolverVR avatarIKSolver = null; + // ChilloutVR Player Components + PlayerSetup playerSetup; + MovementSystem movementSystem; + // Calibration Objects - public HumanPose HumanPose; - public HumanPose InitialHumanPose; - public HumanPoseHandler HumanPoseHandler; + HumanPose _humanPose; + HumanPose _initialHumanPose; + HumanPoseHandler _humanPoseHandler; // Animator Info - public int locomotionLayer = -1; - public int customIKPoseLayer = -1; - public bool requireFixTransforms = false; + int _locomotionLayer = -1; + int _customIKPoseLayer = -1; + bool _requireFixTransforms = false; // VRIK Calibration Info - public Vector3 leftKneeNormal; - public Vector3 rightKneeNormal; - public float initialFootDistance; - public float initialStepThreshold; - public float initialStepHeight; + Vector3 _leftKneeNormal; + Vector3 _rightKneeNormal; + float _initialFootDistance; + float _initialStepThreshold; + float _initialStepHeight; // Player Info - private Transform _cameraTransform; - private bool _isEmotePlaying; - private float _simulatedRootAngle; + Transform _cameraTransform; + bool _isEmotePlaying; + float _simulatedRootAngle; // Last Movement Parent Info - private Vector3 _previousPosition; - private Quaternion _previousRotation; + Vector3 _previousPosition; + Quaternion _previousRotation; + + enum AvatarPose + { + Default = 0, + Initial = 1, + IKPose = 2, + TPose = 3 + } DesktopVRIKSystem() { @@ -309,9 +309,9 @@ internal class DesktopVRIKSystem : MonoBehaviour VRIKUtils.ApplyScaleToVRIK ( avatarVRIK, - initialFootDistance, - initialStepThreshold, - initialStepHeight, + _initialFootDistance, + _initialStepThreshold, + _initialStepHeight, scaleDifference ); @@ -444,19 +444,19 @@ internal class DesktopVRIKSystem : MonoBehaviour avatarLookAtIK = playerSetup.lookIK; // Get animator layer inticies - locomotionLayer = avatarAnimator.GetLayerIndex("IKPose"); - customIKPoseLayer = avatarAnimator.GetLayerIndex("Locomotion/Emotes"); + _locomotionLayer = avatarAnimator.GetLayerIndex("IKPose"); + _customIKPoseLayer = avatarAnimator.GetLayerIndex("Locomotion/Emotes"); - // Dispose and create new HumanPoseHandler - HumanPoseHandler?.Dispose(); - HumanPoseHandler = new HumanPoseHandler(avatarAnimator.avatar, avatarTransform); + // Dispose and create new _humanPoseHandler + _humanPoseHandler?.Dispose(); + _humanPoseHandler = new HumanPoseHandler(avatarAnimator.avatar, avatarTransform); // Get initial human poses - HumanPoseHandler.GetHumanPose(ref HumanPose); - HumanPoseHandler.GetHumanPose(ref InitialHumanPose); + _humanPoseHandler.GetHumanPose(ref _humanPose); + _humanPoseHandler.GetHumanPose(ref _initialHumanPose); // Dumb fix for rare upload issue - requireFixTransforms = !avatarAnimator.enabled; + _requireFixTransforms = !avatarAnimator.enabled; // Find available HumanoidBodyBones BoneExists.Clear(); @@ -479,7 +479,7 @@ internal class DesktopVRIKSystem : MonoBehaviour VRIKUtils.ConfigureVRIKReferences(avatarVRIK, Setting_UseVRIKToes, Setting_FindUnmappedToes, out bool foundUnmappedToes); // Fix animator issue or non-human mapped toes - avatarVRIK.fixTransforms = requireFixTransforms || foundUnmappedToes; + avatarVRIK.fixTransforms = _requireFixTransforms || foundUnmappedToes; // Default solver settings avatarIKSolver.locomotion.weight = 0f; @@ -533,12 +533,12 @@ internal class DesktopVRIKSystem : MonoBehaviour SetAvatarPose(AvatarPose.Default); // Calculate bend normals with motorcycle pose - VRIKUtils.CalculateKneeBendNormals(avatarVRIK, out leftKneeNormal, out rightKneeNormal); + VRIKUtils.CalculateKneeBendNormals(avatarVRIK, out _leftKneeNormal, out _rightKneeNormal); SetAvatarPose(AvatarPose.IKPose); // Calculate initial IK scaling values with IKPose - VRIKUtils.CalculateInitialIKScaling(avatarVRIK, out initialFootDistance, out initialStepThreshold, out initialStepHeight); + VRIKUtils.CalculateInitialIKScaling(avatarVRIK, out _initialFootDistance, out _initialStepThreshold, out _initialStepHeight); // Setup HeadIKTarget VRIKUtils.SetupHeadIKTarget(avatarVRIK); @@ -554,12 +554,12 @@ internal class DesktopVRIKSystem : MonoBehaviour VRIKUtils.ApplyScaleToVRIK ( avatarVRIK, - initialFootDistance, - initialStepThreshold, - initialStepHeight, + _initialFootDistance, + _initialStepThreshold, + _initialStepHeight, 1f ); - VRIKUtils.ApplyKneeBendNormals(avatarVRIK, leftKneeNormal, rightKneeNormal); + VRIKUtils.ApplyKneeBendNormals(avatarVRIK, _leftKneeNormal, _rightKneeNormal); avatarVRIK.onPreSolverUpdate.AddListener(new UnityAction(DesktopVRIKSystem.Instance.OnPreSolverUpdate)); } @@ -576,7 +576,7 @@ internal class DesktopVRIKSystem : MonoBehaviour SetMusclesToValue(0f); break; case AvatarPose.Initial: - HumanPoseHandler.SetHumanPose(ref InitialHumanPose); + _humanPoseHandler.SetHumanPose(ref _initialHumanPose); break; case AvatarPose.IKPose: if (HasCustomIKPose()) @@ -596,40 +596,40 @@ internal class DesktopVRIKSystem : MonoBehaviour bool HasCustomIKPose() { - return locomotionLayer != -1 && customIKPoseLayer != -1; + return _locomotionLayer != -1 && _customIKPoseLayer != -1; } void SetCustomLayersWeights(float customIKPoseLayerWeight, float locomotionLayerWeight) { - avatarAnimator.SetLayerWeight(customIKPoseLayer, customIKPoseLayerWeight); - avatarAnimator.SetLayerWeight(locomotionLayer, locomotionLayerWeight); + avatarAnimator.SetLayerWeight(_customIKPoseLayer, customIKPoseLayerWeight); + avatarAnimator.SetLayerWeight(_locomotionLayer, locomotionLayerWeight); avatarAnimator.Update(0f); } void SetMusclesToValue(float value) { - HumanPoseHandler.GetHumanPose(ref HumanPose); + _humanPoseHandler.GetHumanPose(ref _humanPose); - for (int i = 0; i < HumanPose.muscles.Length; i++) + for (int i = 0; i < _humanPose.muscles.Length; i++) { - ApplyMuscleValue((MuscleIndex)i, value, ref HumanPose.muscles); + ApplyMuscleValue((MuscleIndex)i, value, ref _humanPose.muscles); } - HumanPose.bodyRotation = Quaternion.identity; - HumanPoseHandler.SetHumanPose(ref HumanPose); + _humanPose.bodyRotation = Quaternion.identity; + _humanPoseHandler.SetHumanPose(ref _humanPose); } void SetMusclesToPose(float[] muscles) { - HumanPoseHandler.GetHumanPose(ref HumanPose); + _humanPoseHandler.GetHumanPose(ref _humanPose); - for (int i = 0; i < HumanPose.muscles.Length; i++) + for (int i = 0; i < _humanPose.muscles.Length; i++) { - ApplyMuscleValue((MuscleIndex)i, muscles[i], ref HumanPose.muscles); + ApplyMuscleValue((MuscleIndex)i, muscles[i], ref _humanPose.muscles); } - HumanPose.bodyRotation = Quaternion.identity; - HumanPoseHandler.SetHumanPose(ref HumanPose); + _humanPose.bodyRotation = Quaternion.identity; + _humanPoseHandler.SetHumanPose(ref _humanPose); } void ApplyMuscleValue(MuscleIndex index, float value, ref float[] muscles) From b71bff051cbc71ee045247fb230a27806b917990 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Wed, 29 Mar 2023 01:19:24 -0500 Subject: [PATCH 48/60] Update DesktopVRIKSystem.cs --- DesktopVRIK/DesktopVRIKSystem.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/DesktopVRIK/DesktopVRIKSystem.cs b/DesktopVRIK/DesktopVRIKSystem.cs index 6e9354f..06464ee 100644 --- a/DesktopVRIK/DesktopVRIKSystem.cs +++ b/DesktopVRIK/DesktopVRIKSystem.cs @@ -113,6 +113,14 @@ internal class DesktopVRIKSystem : MonoBehaviour 0.8110138f }; + enum AvatarPose + { + Default = 0, + Initial = 1, + IKPose = 2, + TPose = 3 + } + // DesktopVRIK Settings public bool Setting_Enabled = true; public bool Setting_PlantFeet = true; @@ -166,14 +174,6 @@ internal class DesktopVRIKSystem : MonoBehaviour Vector3 _previousPosition; Quaternion _previousRotation; - enum AvatarPose - { - Default = 0, - Initial = 1, - IKPose = 2, - TPose = 3 - } - DesktopVRIKSystem() { BoneExists = new Dictionary(); From 04d9152d9c33ad43a16fa090e874c5f232c09970 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Wed, 29 Mar 2023 04:00:42 -0500 Subject: [PATCH 49/60] fix desktop thrusting --- DesktopVRIK/DesktopVRIKSystem.cs | 68 ++++++++++---------------------- DesktopVRIK/Main.cs | 18 --------- 2 files changed, 21 insertions(+), 65 deletions(-) diff --git a/DesktopVRIK/DesktopVRIKSystem.cs b/DesktopVRIK/DesktopVRIKSystem.cs index 06464ee..50a0cec 100644 --- a/DesktopVRIK/DesktopVRIKSystem.cs +++ b/DesktopVRIK/DesktopVRIKSystem.cs @@ -166,9 +166,12 @@ internal class DesktopVRIKSystem : MonoBehaviour float _initialStepHeight; // Player Info - Transform _cameraTransform; - bool _isEmotePlaying; - float _simulatedRootAngle; + Transform _cameraTransform = null; + bool _isEmotePlaying = false; + float _simulatedRootAngle = 0f; + float _locomotionWeight = 1f; + float _locomotionWeightLerp = 1f; + float _locomotionLerpSpeed = 10f; // Last Movement Parent Info Vector3 _previousPosition; @@ -196,37 +199,13 @@ internal class DesktopVRIKSystem : MonoBehaviour if (avatarVRIK == null) return; HandleLocomotionTracking(); + LerpLocomotionWeight(); ApplyBodySystemWeights(); } void HandleLocomotionTracking() { bool isMoving = movementSystem.movementVector.magnitude > 0f; - - // AvatarMotionTweaker handles VRIK a bit better than DesktopVRIK - if (Setting_IntegrationAMT && DesktopVRIKMod.integration_AMT) - { - if (isMoving) - { - if (BodySystem.TrackingLocomotionEnabled) - { - BodySystem.TrackingLocomotionEnabled = false; - avatarIKSolver.Reset(); - ResetDesktopVRIK(); - } - } - else - { - if (!BodySystem.TrackingLocomotionEnabled) - { - BodySystem.TrackingLocomotionEnabled = true; - avatarIKSolver.Reset(); - ResetDesktopVRIK(); - } - } - return; - } - bool isGrounded = movementSystem._isGrounded; bool isCrouching = movementSystem.crouching; bool isProne = movementSystem.prone; @@ -256,6 +235,12 @@ internal class DesktopVRIKSystem : MonoBehaviour } } + void LerpLocomotionWeight() + { + _locomotionWeight = BodySystem.TrackingEnabled && BodySystem.TrackingLocomotionEnabled ? 1.0f : 0.0f; + _locomotionWeightLerp = Mathf.Lerp(_locomotionWeightLerp, _locomotionWeight, Time.deltaTime * _locomotionLerpSpeed); + } + void ApplyBodySystemWeights() { void SetArmWeight(IKSolverVR.Arm arm, bool isTracked) @@ -274,7 +259,7 @@ internal class DesktopVRIKSystem : MonoBehaviour { avatarVRIK.enabled = true; avatarIKSolver.IKPositionWeight = BodySystem.TrackingPositionWeight; - avatarIKSolver.locomotion.weight = BodySystem.TrackingLocomotionEnabled ? 1f : 0f; + avatarIKSolver.locomotion.weight = _locomotionWeight; SetArmWeight(avatarIKSolver.leftArm, BodySystem.TrackingLeftArmEnabled && avatarIKSolver.leftArm.target != null); SetArmWeight(avatarIKSolver.rightArm, BodySystem.TrackingRightArmEnabled && avatarIKSolver.rightArm.target != null); @@ -324,19 +309,15 @@ internal class DesktopVRIKSystem : MonoBehaviour { if (avatarVRIK == null) return; - bool changed = isEmotePlaying != _isEmotePlaying; - if (!changed) return; - + if (isEmotePlaying == _isEmotePlaying) return; + _isEmotePlaying = isEmotePlaying; - avatarTransform.localPosition = Vector3.zero; - avatarTransform.localRotation = Quaternion.identity; - if (avatarLookAtIK != null) avatarLookAtIK.enabled = !isEmotePlaying; + // Disable tracking completely while emoting BodySystem.TrackingEnabled = !isEmotePlaying; - avatarIKSolver.Reset(); ResetDesktopVRIK(); } @@ -372,26 +353,19 @@ internal class DesktopVRIKSystem : MonoBehaviour public void OnPreSolverUpdate() { - if (_isEmotePlaying) return; - - bool isGrounded = movementSystem._isGrounded; - - // Calculate weight - float weight = avatarIKSolver.IKPositionWeight; - weight *= 1f - movementSystem.movementVector.magnitude; - weight *= isGrounded ? 1f : 0f; - // Reset avatar offset avatarTransform.localPosition = Vector3.zero; avatarTransform.localRotation = Quaternion.identity; + if (_isEmotePlaying) return; + // Set plant feet avatarIKSolver.plantFeet = Setting_PlantFeet; // Emulate old VRChat hip movementSystem if (Setting_BodyLeanWeight > 0) { - float weightedAngle = Setting_BodyLeanWeight * weight; + float weightedAngle = Setting_BodyLeanWeight * _locomotionWeightLerp; float angle = _cameraTransform.localEulerAngles.x; angle = angle > 180 ? angle - 360 : angle; Quaternion rotation = Quaternion.AngleAxis(angle * weightedAngle, avatarTransform.right); @@ -401,7 +375,7 @@ internal class DesktopVRIKSystem : MonoBehaviour // Make root heading follow within a set limit if (Setting_BodyHeadingLimit > 0) { - float weightedAngleLimit = Setting_BodyHeadingLimit * weight; + float weightedAngleLimit = Setting_BodyHeadingLimit * _locomotionWeightLerp; float deltaAngleRoot = Mathf.DeltaAngle(transform.eulerAngles.y, _simulatedRootAngle); float absDeltaAngleRoot = Mathf.Abs(deltaAngleRoot); if (absDeltaAngleRoot > weightedAngleLimit) diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index 8dff84b..bb82623 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -33,11 +33,6 @@ public class DesktopVRIKMod : MelonMod public static readonly MelonPreferences_Entry EntryChestHeadingWeight = CategoryDesktopVRIK.CreateEntry("Chest Heading Weight", 0.75f, description: "Determines how much the chest will face the Body Heading Limit. Set to 0 to align with head."); - public static readonly MelonPreferences_Entry EntryIntegrationAMT = - CategoryDesktopVRIK.CreateEntry("AMT Integration", true, description: "Relies on AvatarMotionTweaker to handle VRIK Locomotion weights if available."); - - public static bool integration_AMT = false; - public override void OnInitializeMelon() { Logger = LoggerInstance; @@ -52,16 +47,6 @@ public class DesktopVRIKMod : MelonMod Logger.Msg("Initializing BTKUILib support."); BTKUIAddon.Init(); } - //AvatarMotionTweaker Handling - if (MelonMod.RegisteredMelons.Any(it => it.Info.Name == "AvatarMotionTweaker")) - { - Logger.Msg("AvatarMotionTweaker was found. Relying on it to handle VRIK locomotion."); - integration_AMT = true; - } - else - { - Logger.Msg("AvatarMotionTweaker was not found. Using built-in VRIK locomotion handling."); - } } internal static void UpdateAllSettings() @@ -79,9 +64,6 @@ public class DesktopVRIKMod : MelonMod // Calibration Settings DesktopVRIKSystem.Instance.Setting_UseVRIKToes = EntryUseVRIKToes.Value; DesktopVRIKSystem.Instance.Setting_FindUnmappedToes = EntryFindUnmappedToes.Value; - - // Integration Settings - DesktopVRIKSystem.Instance.Setting_IntegrationAMT = EntryIntegrationAMT.Value; } void OnUpdateSettings(object arg1, object arg2) => UpdateAllSettings(); From 193ac760ab2e7a168114dfcb473a8ab5eb4ca357 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Wed, 29 Mar 2023 04:01:18 -0500 Subject: [PATCH 50/60] Update AssemblyInfo.cs --- DesktopVRIK/Properties/AssemblyInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs index cb56c25..56e4878 100644 --- a/DesktopVRIK/Properties/AssemblyInfo.cs +++ b/DesktopVRIK/Properties/AssemblyInfo.cs @@ -26,6 +26,6 @@ using System.Reflection; namespace NAK.Melons.DesktopVRIK.Properties; internal static class AssemblyInfoParams { - public const string Version = "4.1.0"; + public const string Version = "4.1.1"; public const string Author = "NotAKidoS"; } \ No newline at end of file From fbd767036b503389ceb8464f64b8c96e8cb51b45 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Wed, 29 Mar 2023 04:01:37 -0500 Subject: [PATCH 51/60] Update format.json --- DesktopVRIK/format.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json index 53afde0..5bd9d3f 100644 --- a/DesktopVRIK/format.json +++ b/DesktopVRIK/format.json @@ -1,7 +1,7 @@ { "_id": 117, "name": "DesktopVRIK", - "modversion": "4.1.0", + "modversion": "4.1.1", "gameversion": "2022r170", "loaderversion": "0.5.7", "modtype": "Mod", @@ -17,7 +17,7 @@ "requirements": [ "BTKUILib" ], - "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v4.1.0/DesktopVRIK.dll", + "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v4.1.1/DesktopVRIK.dll", "sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRIK/", "changelog": "- No longer requires AvatarMotionTweaker.\n- No longer piggybacks on IKSystem/PlayerSetup.\n\n DesktopVRIK will now handle VRIK Locomotion weight instead of relying on CVR & AMT to handle it. This means LeapMotionExtension & CVRLimbGrabber will now work properly while in crouch/prone.", "embedcolor": "9b59b6" From d3c2365a1d591cb11d16f2962296f81e17c3c3e1 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Wed, 29 Mar 2023 06:10:25 -0500 Subject: [PATCH 52/60] test reset footsteps option --- DesktopVRIK/DesktopVRIKSystem.cs | 31 +++++++++++++++++++++++--- DesktopVRIK/Integrations/BTKUIAddon.cs | 1 + DesktopVRIK/Main.cs | 4 ++++ DesktopVRIK/VRIKUtils.cs | 6 +++++ 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/DesktopVRIK/DesktopVRIKSystem.cs b/DesktopVRIK/DesktopVRIKSystem.cs index 50a0cec..bc11fa0 100644 --- a/DesktopVRIK/DesktopVRIKSystem.cs +++ b/DesktopVRIK/DesktopVRIKSystem.cs @@ -124,6 +124,7 @@ internal class DesktopVRIKSystem : MonoBehaviour // DesktopVRIK Settings public bool Setting_Enabled = true; public bool Setting_PlantFeet = true; + public bool Setting_ResetFootsteps; public float Setting_BodyLeanWeight; public float Setting_BodyHeadingLimit; public float Setting_PelvisHeadingWeight; @@ -161,6 +162,8 @@ internal class DesktopVRIKSystem : MonoBehaviour // VRIK Calibration Info Vector3 _leftKneeNormal; Vector3 _rightKneeNormal; + Vector3 _initialFootStepLeft; + Vector3 _initialFootStepRight; float _initialFootDistance; float _initialStepThreshold; float _initialStepHeight; @@ -212,8 +215,8 @@ internal class DesktopVRIKSystem : MonoBehaviour bool isFlying = movementSystem.flying; // Why do it myself if VRIK already does the maths - Vector3 headLocalPos = avatarIKSolver.spine.headPosition - avatarIKSolver.spine.rootPosition; - float upright = 1f + (headLocalPos.y - avatarIKSolver.spine.headHeight); + Vector3 headLocalPos = avatarTransform.TransformPoint(avatarIKSolver.spine.headPosition); + float upright = 1f + (avatarIKSolver.spine.headHeight - headLocalPos.y); if (isMoving || isCrouching || isProne || isFlying || !isGrounded) { @@ -310,7 +313,7 @@ internal class DesktopVRIKSystem : MonoBehaviour if (avatarVRIK == null) return; if (isEmotePlaying == _isEmotePlaying) return; - + _isEmotePlaying = isEmotePlaying; if (avatarLookAtIK != null) @@ -359,6 +362,12 @@ internal class DesktopVRIKSystem : MonoBehaviour if (_isEmotePlaying) return; + // Constantly reset footsteps until fully idle + if (_locomotionWeightLerp < 0.99f) + { + ResetFootsteps(); + } + // Set plant feet avatarIKSolver.plantFeet = Setting_PlantFeet; @@ -401,6 +410,19 @@ internal class DesktopVRIKSystem : MonoBehaviour _simulatedRootAngle = transform.eulerAngles.y; } + void ResetFootsteps() + { + if (!Setting_ResetFootsteps) return; + IKSolverVR.Footstep footstepLeft = avatarIKSolver.locomotion.footsteps[0]; + IKSolverVR.Footstep footstepRight = avatarIKSolver.locomotion.footsteps[1]; + Vector3 globalLeft = movementSystem.transform.TransformPoint(_initialFootStepLeft); + Vector3 globalRight = movementSystem.transform.TransformPoint(_initialFootStepRight); + footstepLeft.Reset(avatarTransform.rotation, globalLeft, footstepLeft.stepToRot); + footstepRight.Reset(avatarTransform.rotation, globalRight, footstepRight.stepToRot); + //footstepRight.StepTo(globalRight, avatarTransform.rotation, 100f); + //footstepLeft.StepTo(globalLeft, avatarTransform.rotation, 100f); + } + void CalibrateDesktopVRIK() { ScanAvatar(); @@ -514,6 +536,9 @@ internal class DesktopVRIKSystem : MonoBehaviour // Calculate initial IK scaling values with IKPose VRIKUtils.CalculateInitialIKScaling(avatarVRIK, out _initialFootDistance, out _initialStepThreshold, out _initialStepHeight); + // Calculate initial Footstep positions + VRIKUtils.CalculateInitialFootsteps(avatarVRIK, out _initialFootStepLeft, out _initialFootStepRight); + // Setup HeadIKTarget VRIKUtils.SetupHeadIKTarget(avatarVRIK); diff --git a/DesktopVRIK/Integrations/BTKUIAddon.cs b/DesktopVRIK/Integrations/BTKUIAddon.cs index 33a512c..a0b4ea7 100644 --- a/DesktopVRIK/Integrations/BTKUIAddon.cs +++ b/DesktopVRIK/Integrations/BTKUIAddon.cs @@ -26,6 +26,7 @@ public static class BTKUIAddon // General Settings AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryEnabled); AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryPlantFeet); + AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryResetFootstepsOnIdle); // Calibration Settings AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryUseVRIKToes); diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index bb82623..109bf76 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -18,6 +18,9 @@ public class DesktopVRIKMod : MelonMod public static readonly MelonPreferences_Entry EntryUseVRIKToes = CategoryDesktopVRIK.CreateEntry("Use VRIK Toes", false, description: "Determines if VRIK uses humanoid toes for IK solving, which can cause feet to idle behind the avatar."); + public static readonly MelonPreferences_Entry EntryResetFootstepsOnIdle = + CategoryDesktopVRIK.CreateEntry("Reset Footsteps on Idle", false, description: "Forces Locomotion Footsteps to reset to their initial position on return to idle. This is a bit aggressive."); + public static readonly MelonPreferences_Entry EntryFindUnmappedToes = CategoryDesktopVRIK.CreateEntry("Find Unmapped Toes", false, description: "Determines if DesktopVRIK should look for unmapped toe bones if the humanoid rig does not have any."); @@ -55,6 +58,7 @@ public class DesktopVRIKMod : MelonMod // DesktopVRIK Settings DesktopVRIKSystem.Instance.Setting_Enabled = EntryEnabled.Value; DesktopVRIKSystem.Instance.Setting_PlantFeet = EntryPlantFeet.Value; + DesktopVRIKSystem.Instance.Setting_ResetFootsteps = EntryResetFootstepsOnIdle.Value; DesktopVRIKSystem.Instance.Setting_BodyLeanWeight = Mathf.Clamp01(EntryBodyLeanWeight.Value); DesktopVRIKSystem.Instance.Setting_BodyHeadingLimit = Mathf.Clamp(EntryBodyHeadingLimit.Value, 0f, 90f); diff --git a/DesktopVRIK/VRIKUtils.cs b/DesktopVRIK/VRIKUtils.cs index 0444c79..32fedd7 100644 --- a/DesktopVRIK/VRIKUtils.cs +++ b/DesktopVRIK/VRIKUtils.cs @@ -154,6 +154,12 @@ public static class VRIKUtils initialStepHeight = Vector3.Distance(vrik.references.leftFoot.position, vrik.references.leftCalf.position) * 0.2f; } + public static void CalculateInitialFootsteps(VRIK vrik, out Vector3 initialFootstepLeft, out Vector3 initialFootstepRight) + { + initialFootstepLeft = vrik.references.root.InverseTransformPoint(vrik.references.leftFoot.position); + initialFootstepRight = vrik.references.root.InverseTransformPoint(vrik.references.rightFoot.position); + } + public static void SetupHeadIKTarget(VRIK vrik) { // Lazy HeadIKTarget calibration From 5acd10b5f25ed3ed3deab2805f5b2cd67d0b8f28 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Wed, 29 Mar 2023 16:39:40 -0500 Subject: [PATCH 53/60] Update BTKUIAddon.cs --- DesktopVRIK/Integrations/BTKUIAddon.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DesktopVRIK/Integrations/BTKUIAddon.cs b/DesktopVRIK/Integrations/BTKUIAddon.cs index a0b4ea7..62387c5 100644 --- a/DesktopVRIK/Integrations/BTKUIAddon.cs +++ b/DesktopVRIK/Integrations/BTKUIAddon.cs @@ -24,7 +24,7 @@ public static class BTKUIAddon Category desktopVRIKCategory = desktopVRIKPage.AddCategory(DesktopVRIKMod.SettingsCategory); // General Settings - AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryEnabled); + //AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryEnabled); AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryPlantFeet); AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryResetFootstepsOnIdle); From 9368db6bf1db1995b69c09c7794e34691b7e5101 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Wed, 29 Mar 2023 16:42:04 -0500 Subject: [PATCH 54/60] Update format.json --- DesktopVRIK/format.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json index 5bd9d3f..0290432 100644 --- a/DesktopVRIK/format.json +++ b/DesktopVRIK/format.json @@ -1,12 +1,12 @@ { "_id": 117, "name": "DesktopVRIK", - "modversion": "4.1.1", + "modversion": "4.1.2", "gameversion": "2022r170", "loaderversion": "0.5.7", "modtype": "Mod", "author": "NotAKidoS", - "description": "Adds VRIK to Desktop avatars. No longer will you be a liveless sliding statue~!\nAdds the small feet stepping when looking around on Desktop.\n\nOptional BTKUILib and AvatarMotionTweaker integrations.", + "description": "Adds VRIK to Desktop avatars. No longer will you be a liveless sliding statue~!\nAdds the small feet stepping when looking around on Desktop.\n\nOptional BTKUILib integration.", "searchtags": [ "desktop", "vrik", @@ -17,8 +17,8 @@ "requirements": [ "BTKUILib" ], - "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v4.1.1/DesktopVRIK.dll", + "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v4.1.2/DesktopVRIK.dll", "sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRIK/", - "changelog": "- No longer requires AvatarMotionTweaker.\n- No longer piggybacks on IKSystem/PlayerSetup.\n\n DesktopVRIK will now handle VRIK Locomotion weight instead of relying on CVR & AMT to handle it. This means LeapMotionExtension & CVRLimbGrabber will now work properly while in crouch/prone.", + "changelog": "- No longer requires AvatarMotionTweaker.\n- No longer piggybacks on IKSystem/PlayerSetup.\n\n DesktopVRIK will now handle VRIK Locomotion weight instead of relying on CVR & AMT to handle it. This means LeapMotionExtension, PickupArmMovement, and CVRLimbGrabber will now work while in crouch/prone.", "embedcolor": "9b59b6" } \ No newline at end of file From 34df5c667cc6c56709e1cca1a58b3950893a8bfc Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Wed, 29 Mar 2023 16:42:47 -0500 Subject: [PATCH 55/60] Update AssemblyInfo.cs --- DesktopVRIK/Properties/AssemblyInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs index 56e4878..3cd7c04 100644 --- a/DesktopVRIK/Properties/AssemblyInfo.cs +++ b/DesktopVRIK/Properties/AssemblyInfo.cs @@ -26,6 +26,6 @@ using System.Reflection; namespace NAK.Melons.DesktopVRIK.Properties; internal static class AssemblyInfoParams { - public const string Version = "4.1.1"; + public const string Version = "4.1.2"; public const string Author = "NotAKidoS"; } \ No newline at end of file From 7454efdb2fb4b6be7a2591c181d103cbae2a3ea8 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Thu, 30 Mar 2023 18:02:05 -0500 Subject: [PATCH 56/60] touchups --- DesktopVRIK/DesktopVRIKSystem.cs | 223 ++++++++++++++++--------------- 1 file changed, 114 insertions(+), 109 deletions(-) diff --git a/DesktopVRIK/DesktopVRIKSystem.cs b/DesktopVRIK/DesktopVRIKSystem.cs index bc11fa0..0e06308 100644 --- a/DesktopVRIK/DesktopVRIKSystem.cs +++ b/DesktopVRIK/DesktopVRIKSystem.cs @@ -151,34 +151,34 @@ internal class DesktopVRIKSystem : MonoBehaviour // Calibration Objects HumanPose _humanPose; - HumanPose _initialHumanPose; + HumanPose _humanPoseInitial; HumanPoseHandler _humanPoseHandler; // Animator Info - int _locomotionLayer = -1; - int _customIKPoseLayer = -1; - bool _requireFixTransforms = false; + int _animLocomotionLayer = -1; + int _animIKPoseLayer = -1; // VRIK Calibration Info - Vector3 _leftKneeNormal; - Vector3 _rightKneeNormal; - Vector3 _initialFootStepLeft; - Vector3 _initialFootStepRight; - float _initialFootDistance; - float _initialStepThreshold; - float _initialStepHeight; + Vector3 _vrikKneeNormalLeft; + Vector3 _vrikKneeNormalRight; + Vector3 _vrikInitialFootStepLeft; + Vector3 _vrikInitialFootStepRight; + float _vrikInitialFootDistance; + float _vrikInitialStepThreshold; + float _vrikInitialStepHeight; + bool _vrikFixTransformsRequired; // Player Info Transform _cameraTransform = null; - bool _isEmotePlaying = false; - float _simulatedRootAngle = 0f; + bool _ikEmotePlaying = false; + float _ikSimulatedRootAngle = 0f; float _locomotionWeight = 1f; float _locomotionWeightLerp = 1f; float _locomotionLerpSpeed = 10f; // Last Movement Parent Info - Vector3 _previousPosition; - Quaternion _previousRotation; + Vector3 _movementPosition; + Quaternion _movementRotation; DesktopVRIKSystem() { @@ -214,27 +214,13 @@ internal class DesktopVRIKSystem : MonoBehaviour bool isProne = movementSystem.prone; bool isFlying = movementSystem.flying; - // Why do it myself if VRIK already does the maths - Vector3 headLocalPos = avatarTransform.TransformPoint(avatarIKSolver.spine.headPosition); - float upright = 1f + (avatarIKSolver.spine.headHeight - headLocalPos.y); + bool shouldTrackLocomotion = !(isMoving || isCrouching || isProne || isFlying || !isGrounded); - if (isMoving || isCrouching || isProne || isFlying || !isGrounded) + if (shouldTrackLocomotion != BodySystem.TrackingLocomotionEnabled) { - if (BodySystem.TrackingLocomotionEnabled) - { - BodySystem.TrackingLocomotionEnabled = false; - avatarIKSolver.Reset(); - ResetDesktopVRIK(); - } - } - else - { - if (!BodySystem.TrackingLocomotionEnabled && upright > 0.8f) - { - BodySystem.TrackingLocomotionEnabled = true; - avatarIKSolver.Reset(); - ResetDesktopVRIK(); - } + BodySystem.TrackingLocomotionEnabled = shouldTrackLocomotion; + avatarIKSolver.Reset(); + ResetDesktopVRIK(); } } @@ -297,9 +283,9 @@ internal class DesktopVRIKSystem : MonoBehaviour VRIKUtils.ApplyScaleToVRIK ( avatarVRIK, - _initialFootDistance, - _initialStepThreshold, - _initialStepHeight, + _vrikInitialFootDistance, + _vrikInitialStepThreshold, + _vrikInitialStepHeight, scaleDifference ); @@ -312,9 +298,9 @@ internal class DesktopVRIKSystem : MonoBehaviour { if (avatarVRIK == null) return; - if (isEmotePlaying == _isEmotePlaying) return; + if (isEmotePlaying == _ikEmotePlaying) return; - _isEmotePlaying = isEmotePlaying; + _ikEmotePlaying = isEmotePlaying; if (avatarLookAtIK != null) avatarLookAtIK.enabled = !isEmotePlaying; @@ -329,26 +315,27 @@ internal class DesktopVRIKSystem : MonoBehaviour { if (avatarVRIK == null) return false; + // Check if PlayerSetup.ResetIk() was called for movement parent CVRMovementParent currentParent = movementSystem._currentParent; - if (currentParent == null) return false; + if (currentParent == null || currentParent._referencePoint == null) return false; - Transform referencePoint = currentParent._referencePoint; - if (referencePoint == null) return false; + // Get current position + var currentPosition = currentParent._referencePoint.position; + var currentRotation = Quaternion.Euler(0f, currentParent.transform.rotation.eulerAngles.y, 0f); - var currentPosition = referencePoint.position; - var currentRotation = currentParent.transform.rotation; - - // Keep only the Y-axis rotation - currentRotation = Quaternion.Euler(0f, currentRotation.eulerAngles.y, 0f); - - var deltaPosition = currentPosition - _previousPosition; - var deltaRotation = Quaternion.Inverse(_previousRotation) * currentRotation; + // Convert to delta position (how much changed since last frame) + var deltaPosition = currentPosition - _movementPosition; + var deltaRotation = Quaternion.Inverse(_movementRotation) * currentRotation; + // desktop pivots from playerlocal transform var platformPivot = transform.position; + + // Add platform motion to IK solver avatarIKSolver.AddPlatformMotion(deltaPosition, deltaRotation, platformPivot); - _previousPosition = currentPosition; - _previousRotation = currentRotation; + // Store for next frame + _movementPosition = currentPosition; + _movementRotation = currentRotation; ResetDesktopVRIK(); return true; @@ -360,69 +347,87 @@ internal class DesktopVRIKSystem : MonoBehaviour avatarTransform.localPosition = Vector3.zero; avatarTransform.localRotation = Quaternion.identity; - if (_isEmotePlaying) return; - - // Constantly reset footsteps until fully idle - if (_locomotionWeightLerp < 0.99f) - { - ResetFootsteps(); - } + // Don't run during emotes + if (_ikEmotePlaying) return; // Set plant feet avatarIKSolver.plantFeet = Setting_PlantFeet; - // Emulate old VRChat hip movementSystem - if (Setting_BodyLeanWeight > 0) + // Apply custom VRIK solving effects + if (_locomotionWeightLerp > 0) { - float weightedAngle = Setting_BodyLeanWeight * _locomotionWeightLerp; - float angle = _cameraTransform.localEulerAngles.x; - angle = angle > 180 ? angle - 360 : angle; - Quaternion rotation = Quaternion.AngleAxis(angle * weightedAngle, avatarTransform.right); - avatarIKSolver.spine.headRotationOffset *= rotation; + IKBodyLeaningOffset(); + IKBodyHeadingOffset(); } + // Reset footsteps while transitioning + if (_locomotionWeightLerp < 0.99f) + { + IKResetFootsteps(); + } + } + + void IKBodyLeaningOffset() + { + // Emulate old VRChat hip movement + if (Setting_BodyLeanWeight <= 0) return; + + float weightedAngle = Setting_BodyLeanWeight * _locomotionWeightLerp; + float angle = _cameraTransform.localEulerAngles.x; + angle = angle > 180 ? angle - 360 : angle; + Quaternion rotation = Quaternion.AngleAxis(angle * weightedAngle, avatarTransform.right); + avatarIKSolver.spine.headRotationOffset *= rotation; + } + + void IKBodyHeadingOffset() + { // Make root heading follow within a set limit - if (Setting_BodyHeadingLimit > 0) + if (Setting_BodyHeadingLimit <= 0) return; + + float weightedAngleLimit = Setting_BodyHeadingLimit * _locomotionWeightLerp; + float deltaAngleRoot = Mathf.DeltaAngle(transform.eulerAngles.y, _ikSimulatedRootAngle); + float absDeltaAngleRoot = Mathf.Abs(deltaAngleRoot); + + if (absDeltaAngleRoot > weightedAngleLimit) { - float weightedAngleLimit = Setting_BodyHeadingLimit * _locomotionWeightLerp; - float deltaAngleRoot = Mathf.DeltaAngle(transform.eulerAngles.y, _simulatedRootAngle); - float absDeltaAngleRoot = Mathf.Abs(deltaAngleRoot); - if (absDeltaAngleRoot > weightedAngleLimit) - { - deltaAngleRoot = Mathf.Sign(deltaAngleRoot) * weightedAngleLimit; - _simulatedRootAngle = Mathf.MoveTowardsAngle(_simulatedRootAngle, transform.eulerAngles.y, absDeltaAngleRoot - weightedAngleLimit); - } - avatarIKSolver.spine.rootHeadingOffset = deltaAngleRoot; - if (Setting_PelvisHeadingWeight > 0) - { - avatarIKSolver.spine.pelvisRotationOffset *= Quaternion.Euler(0f, deltaAngleRoot * Setting_PelvisHeadingWeight, 0f); - avatarIKSolver.spine.chestRotationOffset *= Quaternion.Euler(0f, -deltaAngleRoot * Setting_PelvisHeadingWeight, 0f); - } - if (Setting_ChestHeadingWeight > 0) - { - avatarIKSolver.spine.chestRotationOffset *= Quaternion.Euler(0f, deltaAngleRoot * Setting_ChestHeadingWeight, 0f); - } + deltaAngleRoot = Mathf.Sign(deltaAngleRoot) * weightedAngleLimit; + _ikSimulatedRootAngle = Mathf.MoveTowardsAngle(_ikSimulatedRootAngle, transform.eulerAngles.y, absDeltaAngleRoot - weightedAngleLimit); + } + + avatarIKSolver.spine.rootHeadingOffset = deltaAngleRoot; + + if (Setting_PelvisHeadingWeight > 0) + { + avatarIKSolver.spine.pelvisRotationOffset *= Quaternion.Euler(0f, deltaAngleRoot * Setting_PelvisHeadingWeight, 0f); + avatarIKSolver.spine.chestRotationOffset *= Quaternion.Euler(0f, -deltaAngleRoot * Setting_PelvisHeadingWeight, 0f); + } + + if (Setting_ChestHeadingWeight > 0) + { + avatarIKSolver.spine.chestRotationOffset *= Quaternion.Euler(0f, deltaAngleRoot * Setting_ChestHeadingWeight, 0f); } } - void ResetDesktopVRIK() - { - _simulatedRootAngle = transform.eulerAngles.y; - } - - void ResetFootsteps() + void IKResetFootsteps() { + // Attempt to skip footstep transition if (!Setting_ResetFootsteps) return; + IKSolverVR.Footstep footstepLeft = avatarIKSolver.locomotion.footsteps[0]; IKSolverVR.Footstep footstepRight = avatarIKSolver.locomotion.footsteps[1]; - Vector3 globalLeft = movementSystem.transform.TransformPoint(_initialFootStepLeft); - Vector3 globalRight = movementSystem.transform.TransformPoint(_initialFootStepRight); + Vector3 globalLeft = movementSystem.transform.TransformPoint(_vrikInitialFootStepLeft); + Vector3 globalRight = movementSystem.transform.TransformPoint(_vrikInitialFootStepRight); footstepLeft.Reset(avatarTransform.rotation, globalLeft, footstepLeft.stepToRot); footstepRight.Reset(avatarTransform.rotation, globalRight, footstepRight.stepToRot); //footstepRight.StepTo(globalRight, avatarTransform.rotation, 100f); //footstepLeft.StepTo(globalLeft, avatarTransform.rotation, 100f); } + void ResetDesktopVRIK() + { + _ikSimulatedRootAngle = transform.eulerAngles.y; + } + void CalibrateDesktopVRIK() { ScanAvatar(); @@ -440,8 +445,8 @@ internal class DesktopVRIKSystem : MonoBehaviour avatarLookAtIK = playerSetup.lookIK; // Get animator layer inticies - _locomotionLayer = avatarAnimator.GetLayerIndex("IKPose"); - _customIKPoseLayer = avatarAnimator.GetLayerIndex("Locomotion/Emotes"); + _animIKPoseLayer = avatarAnimator.GetLayerIndex("IKPose"); + _animLocomotionLayer = avatarAnimator.GetLayerIndex("Locomotion/Emotes"); // Dispose and create new _humanPoseHandler _humanPoseHandler?.Dispose(); @@ -449,10 +454,10 @@ internal class DesktopVRIKSystem : MonoBehaviour // Get initial human poses _humanPoseHandler.GetHumanPose(ref _humanPose); - _humanPoseHandler.GetHumanPose(ref _initialHumanPose); + _humanPoseHandler.GetHumanPose(ref _humanPoseInitial); // Dumb fix for rare upload issue - _requireFixTransforms = !avatarAnimator.enabled; + _vrikFixTransformsRequired = !avatarAnimator.enabled; // Find available HumanoidBodyBones BoneExists.Clear(); @@ -475,7 +480,7 @@ internal class DesktopVRIKSystem : MonoBehaviour VRIKUtils.ConfigureVRIKReferences(avatarVRIK, Setting_UseVRIKToes, Setting_FindUnmappedToes, out bool foundUnmappedToes); // Fix animator issue or non-human mapped toes - avatarVRIK.fixTransforms = _requireFixTransforms || foundUnmappedToes; + avatarVRIK.fixTransforms = _vrikFixTransformsRequired || foundUnmappedToes; // Default solver settings avatarIKSolver.locomotion.weight = 0f; @@ -529,15 +534,15 @@ internal class DesktopVRIKSystem : MonoBehaviour SetAvatarPose(AvatarPose.Default); // Calculate bend normals with motorcycle pose - VRIKUtils.CalculateKneeBendNormals(avatarVRIK, out _leftKneeNormal, out _rightKneeNormal); + VRIKUtils.CalculateKneeBendNormals(avatarVRIK, out _vrikKneeNormalLeft, out _vrikKneeNormalRight); SetAvatarPose(AvatarPose.IKPose); // Calculate initial IK scaling values with IKPose - VRIKUtils.CalculateInitialIKScaling(avatarVRIK, out _initialFootDistance, out _initialStepThreshold, out _initialStepHeight); + VRIKUtils.CalculateInitialIKScaling(avatarVRIK, out _vrikInitialFootDistance, out _vrikInitialStepThreshold, out _vrikInitialStepHeight); // Calculate initial Footstep positions - VRIKUtils.CalculateInitialFootsteps(avatarVRIK, out _initialFootStepLeft, out _initialFootStepRight); + VRIKUtils.CalculateInitialFootsteps(avatarVRIK, out _vrikInitialFootStepLeft, out _vrikInitialFootStepRight); // Setup HeadIKTarget VRIKUtils.SetupHeadIKTarget(avatarVRIK); @@ -553,12 +558,12 @@ internal class DesktopVRIKSystem : MonoBehaviour VRIKUtils.ApplyScaleToVRIK ( avatarVRIK, - _initialFootDistance, - _initialStepThreshold, - _initialStepHeight, + _vrikInitialFootDistance, + _vrikInitialStepThreshold, + _vrikInitialStepHeight, 1f ); - VRIKUtils.ApplyKneeBendNormals(avatarVRIK, _leftKneeNormal, _rightKneeNormal); + VRIKUtils.ApplyKneeBendNormals(avatarVRIK, _vrikKneeNormalLeft, _vrikKneeNormalRight); avatarVRIK.onPreSolverUpdate.AddListener(new UnityAction(DesktopVRIKSystem.Instance.OnPreSolverUpdate)); } @@ -575,7 +580,7 @@ internal class DesktopVRIKSystem : MonoBehaviour SetMusclesToValue(0f); break; case AvatarPose.Initial: - _humanPoseHandler.SetHumanPose(ref _initialHumanPose); + _humanPoseHandler.SetHumanPose(ref _humanPoseInitial); break; case AvatarPose.IKPose: if (HasCustomIKPose()) @@ -595,13 +600,13 @@ internal class DesktopVRIKSystem : MonoBehaviour bool HasCustomIKPose() { - return _locomotionLayer != -1 && _customIKPoseLayer != -1; + return _animLocomotionLayer != -1 && _animIKPoseLayer != -1; } void SetCustomLayersWeights(float customIKPoseLayerWeight, float locomotionLayerWeight) { - avatarAnimator.SetLayerWeight(_customIKPoseLayer, customIKPoseLayerWeight); - avatarAnimator.SetLayerWeight(_locomotionLayer, locomotionLayerWeight); + avatarAnimator.SetLayerWeight(_animIKPoseLayer, customIKPoseLayerWeight); + avatarAnimator.SetLayerWeight(_animLocomotionLayer, locomotionLayerWeight); avatarAnimator.Update(0f); } From 09cb3838a6425fc19447579bb41f8c4a729a1501 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Thu, 30 Mar 2023 23:34:18 -0500 Subject: [PATCH 57/60] weight bump --- DesktopVRIK/DesktopVRIKSystem.cs | 106 +++++++++++++++---------- DesktopVRIK/Integrations/BTKUIAddon.cs | 17 ++-- DesktopVRIK/Main.cs | 32 +++++++- DesktopVRIK/Properties/AssemblyInfo.cs | 2 +- DesktopVRIK/VRIKUtils.cs | 29 ++++++- DesktopVRIK/format.json | 6 +- 6 files changed, 134 insertions(+), 58 deletions(-) diff --git a/DesktopVRIK/DesktopVRIKSystem.cs b/DesktopVRIK/DesktopVRIKSystem.cs index 0e06308..d6e0b53 100644 --- a/DesktopVRIK/DesktopVRIKSystem.cs +++ b/DesktopVRIK/DesktopVRIKSystem.cs @@ -123,19 +123,20 @@ internal class DesktopVRIKSystem : MonoBehaviour // DesktopVRIK Settings public bool Setting_Enabled = true; - public bool Setting_PlantFeet = true; + public bool Setting_PlantFeet; public bool Setting_ResetFootsteps; public float Setting_BodyLeanWeight; public float Setting_BodyHeadingLimit; public float Setting_PelvisHeadingWeight; public float Setting_ChestHeadingWeight; + public float Setting_IKLerpSpeed; // Calibration Settings - public bool Setting_UseVRIKToes = true; - public bool Setting_FindUnmappedToes = true; + public bool Setting_UseVRIKToes; + public bool Setting_FindUnmappedToes; // Integration Settings - public bool Setting_IntegrationAMT = false; + public bool Setting_IntegrationAMT; // Avatar Components public CVRAvatar avatarDescriptor = null; @@ -161,20 +162,21 @@ internal class DesktopVRIKSystem : MonoBehaviour // VRIK Calibration Info Vector3 _vrikKneeNormalLeft; Vector3 _vrikKneeNormalRight; - Vector3 _vrikInitialFootStepLeft; - Vector3 _vrikInitialFootStepRight; + Vector3 _vrikInitialFootPosLeft; + Vector3 _vrikInitialFootPosRight; + Quaternion _vrikInitialFootRotLeft; + Quaternion _vrikInitialFootRotRight; float _vrikInitialFootDistance; float _vrikInitialStepThreshold; float _vrikInitialStepHeight; bool _vrikFixTransformsRequired; // Player Info - Transform _cameraTransform = null; - bool _ikEmotePlaying = false; + Transform _cameraTransform; + bool _ikEmotePlaying; + float _ikWeightLerp = 1f; float _ikSimulatedRootAngle = 0f; float _locomotionWeight = 1f; - float _locomotionWeightLerp = 1f; - float _locomotionLerpSpeed = 10f; // Last Movement Parent Info Vector3 _movementPosition; @@ -202,32 +204,60 @@ internal class DesktopVRIKSystem : MonoBehaviour if (avatarVRIK == null) return; HandleLocomotionTracking(); - LerpLocomotionWeight(); + UpdateLocomotionWeight(); ApplyBodySystemWeights(); } void HandleLocomotionTracking() { - bool isMoving = movementSystem.movementVector.magnitude > 0f; - bool isGrounded = movementSystem._isGrounded; - bool isCrouching = movementSystem.crouching; - bool isProne = movementSystem.prone; - bool isFlying = movementSystem.flying; - - bool shouldTrackLocomotion = !(isMoving || isCrouching || isProne || isFlying || !isGrounded); + bool shouldTrackLocomotion = ShouldTrackLocomotion(); if (shouldTrackLocomotion != BodySystem.TrackingLocomotionEnabled) { BodySystem.TrackingLocomotionEnabled = shouldTrackLocomotion; avatarIKSolver.Reset(); ResetDesktopVRIK(); + if (shouldTrackLocomotion) IKResetFootsteps(); } } - void LerpLocomotionWeight() + bool ShouldTrackLocomotion() { - _locomotionWeight = BodySystem.TrackingEnabled && BodySystem.TrackingLocomotionEnabled ? 1.0f : 0.0f; - _locomotionWeightLerp = Mathf.Lerp(_locomotionWeightLerp, _locomotionWeight, Time.deltaTime * _locomotionLerpSpeed); + bool isMoving = movementSystem.movementVector.magnitude > 0f; + bool isGrounded = movementSystem._isGrounded; + bool isCrouching = movementSystem.crouching; + bool isProne = movementSystem.prone; + bool isFlying = movementSystem.flying; + bool isStanding = IsStanding(); + + return !(isMoving || isCrouching || isProne || isFlying || !isGrounded || !isStanding); + } + + bool IsStanding() + { + // Let AMT handle it if available + if (Setting_IntegrationAMT) return true; + + // Get Upright value + Vector3 delta = avatarIKSolver.spine.headPosition - avatarTransform.position; + Vector3 deltaRotated = Quaternion.Euler(0, avatarTransform.rotation.eulerAngles.y, 0) * delta; + float upright = Mathf.InverseLerp(0f, avatarIKSolver.spine.headHeight, deltaRotated.y); + return upright > 0.85f; + } + + void UpdateLocomotionWeight() + { + float targetWeight = BodySystem.TrackingEnabled && BodySystem.TrackingLocomotionEnabled ? 1.0f : 0.0f; + if (Setting_IKLerpSpeed > 0) + { + _ikWeightLerp = Mathf.Lerp(_ikWeightLerp, targetWeight, Time.deltaTime * Setting_IKLerpSpeed); + _locomotionWeight = Mathf.Lerp(_locomotionWeight, targetWeight, Time.deltaTime * Setting_IKLerpSpeed * 2f); + } + else + { + _ikWeightLerp = targetWeight; + _locomotionWeight = targetWeight; + } } void ApplyBodySystemWeights() @@ -354,17 +384,11 @@ internal class DesktopVRIKSystem : MonoBehaviour avatarIKSolver.plantFeet = Setting_PlantFeet; // Apply custom VRIK solving effects - if (_locomotionWeightLerp > 0) + if (_ikWeightLerp > 0) { IKBodyLeaningOffset(); IKBodyHeadingOffset(); } - - // Reset footsteps while transitioning - if (_locomotionWeightLerp < 0.99f) - { - IKResetFootsteps(); - } } void IKBodyLeaningOffset() @@ -372,7 +396,7 @@ internal class DesktopVRIKSystem : MonoBehaviour // Emulate old VRChat hip movement if (Setting_BodyLeanWeight <= 0) return; - float weightedAngle = Setting_BodyLeanWeight * _locomotionWeightLerp; + float weightedAngle = Setting_BodyLeanWeight * _ikWeightLerp; float angle = _cameraTransform.localEulerAngles.x; angle = angle > 180 ? angle - 360 : angle; Quaternion rotation = Quaternion.AngleAxis(angle * weightedAngle, avatarTransform.right); @@ -384,7 +408,7 @@ internal class DesktopVRIKSystem : MonoBehaviour // Make root heading follow within a set limit if (Setting_BodyHeadingLimit <= 0) return; - float weightedAngleLimit = Setting_BodyHeadingLimit * _locomotionWeightLerp; + float weightedAngleLimit = Setting_BodyHeadingLimit * _ikWeightLerp; float deltaAngleRoot = Mathf.DeltaAngle(transform.eulerAngles.y, _ikSimulatedRootAngle); float absDeltaAngleRoot = Mathf.Abs(deltaAngleRoot); @@ -410,17 +434,17 @@ internal class DesktopVRIKSystem : MonoBehaviour void IKResetFootsteps() { - // Attempt to skip footstep transition + // Reset footsteps immediatly to initial if (!Setting_ResetFootsteps) return; - IKSolverVR.Footstep footstepLeft = avatarIKSolver.locomotion.footsteps[0]; - IKSolverVR.Footstep footstepRight = avatarIKSolver.locomotion.footsteps[1]; - Vector3 globalLeft = movementSystem.transform.TransformPoint(_vrikInitialFootStepLeft); - Vector3 globalRight = movementSystem.transform.TransformPoint(_vrikInitialFootStepRight); - footstepLeft.Reset(avatarTransform.rotation, globalLeft, footstepLeft.stepToRot); - footstepRight.Reset(avatarTransform.rotation, globalRight, footstepRight.stepToRot); - //footstepRight.StepTo(globalRight, avatarTransform.rotation, 100f); - //footstepLeft.StepTo(globalLeft, avatarTransform.rotation, 100f); + VRIKUtils.SetFootsteps + ( + avatarVRIK, + _vrikInitialFootPosLeft, + _vrikInitialFootPosRight, + _vrikInitialFootRotLeft, + _vrikInitialFootRotRight + ); } void ResetDesktopVRIK() @@ -542,7 +566,7 @@ internal class DesktopVRIKSystem : MonoBehaviour VRIKUtils.CalculateInitialIKScaling(avatarVRIK, out _vrikInitialFootDistance, out _vrikInitialStepThreshold, out _vrikInitialStepHeight); // Calculate initial Footstep positions - VRIKUtils.CalculateInitialFootsteps(avatarVRIK, out _vrikInitialFootStepLeft, out _vrikInitialFootStepRight); + VRIKUtils.CalculateInitialFootsteps(avatarVRIK, out _vrikInitialFootPosLeft, out _vrikInitialFootPosRight, out _vrikInitialFootRotLeft, out _vrikInitialFootRotRight); // Setup HeadIKTarget VRIKUtils.SetupHeadIKTarget(avatarVRIK); @@ -643,4 +667,4 @@ internal class DesktopVRIKSystem : MonoBehaviour muscles[(int)index] = value; } } -} +} \ No newline at end of file diff --git a/DesktopVRIK/Integrations/BTKUIAddon.cs b/DesktopVRIK/Integrations/BTKUIAddon.cs index 62387c5..5c25427 100644 --- a/DesktopVRIK/Integrations/BTKUIAddon.cs +++ b/DesktopVRIK/Integrations/BTKUIAddon.cs @@ -17,21 +17,20 @@ public static class BTKUIAddon AddMelonToggle(ref miscCategory, DesktopVRIKMod.EntryEnabled); //Add my own page to not clog up Misc Menu - Page desktopVRIKPage = miscCategory.AddPage("DesktopVRIK Settings", "", "Configure the settings for DesktopVRIK.", "DesktopVRIK"); desktopVRIKPage.MenuTitle = "DesktopVRIK Settings"; - Category desktopVRIKCategory = desktopVRIKPage.AddCategory(DesktopVRIKMod.SettingsCategory); - + // General Settings - //AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryEnabled); AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryPlantFeet); - AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryResetFootstepsOnIdle); - + // Calibration Settings AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryUseVRIKToes); AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryFindUnmappedToes); - + + // Fine-tuning Settings + AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryResetFootstepsOnIdle); + // Body Leaning Weight AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.EntryBodyLeanWeight, 0, 1f, 1); @@ -39,7 +38,11 @@ public static class BTKUIAddon AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.EntryBodyHeadingLimit, 0, 90f, 0); AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.EntryPelvisHeadingWeight, 0, 1f, 1); AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.EntryChestHeadingWeight, 0, 1f, 1); + + // Lerp Speed + AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.EntryIKLerpSpeed, 0, 20f, 0); } + private static void AddMelonToggle(ref Category category, MelonLoader.MelonPreferences_Entry entry) { category.AddToggle(entry.DisplayName, entry.Description, entry.Value).OnValueUpdated += b => entry.Value = b; diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index 109bf76..09cfcea 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -15,12 +15,12 @@ public class DesktopVRIKMod : MelonMod public static readonly MelonPreferences_Entry EntryPlantFeet = CategoryDesktopVRIK.CreateEntry("Enforce Plant Feet", true, description: "Forces VRIK Plant Feet enabled to prevent hovering when stopping movement."); + public static readonly MelonPreferences_Entry EntryResetFootstepsOnIdle = + CategoryDesktopVRIK.CreateEntry("Reset Footsteps on Idle", true, description: "Determins if the Locomotion Footsteps will be reset to their calibration position when entering idle."); + public static readonly MelonPreferences_Entry EntryUseVRIKToes = CategoryDesktopVRIK.CreateEntry("Use VRIK Toes", false, description: "Determines if VRIK uses humanoid toes for IK solving, which can cause feet to idle behind the avatar."); - public static readonly MelonPreferences_Entry EntryResetFootstepsOnIdle = - CategoryDesktopVRIK.CreateEntry("Reset Footsteps on Idle", false, description: "Forces Locomotion Footsteps to reset to their initial position on return to idle. This is a bit aggressive."); - public static readonly MelonPreferences_Entry EntryFindUnmappedToes = CategoryDesktopVRIK.CreateEntry("Find Unmapped Toes", false, description: "Determines if DesktopVRIK should look for unmapped toe bones if the humanoid rig does not have any."); @@ -36,6 +36,14 @@ public class DesktopVRIKMod : MelonMod public static readonly MelonPreferences_Entry EntryChestHeadingWeight = CategoryDesktopVRIK.CreateEntry("Chest Heading Weight", 0.75f, description: "Determines how much the chest will face the Body Heading Limit. Set to 0 to align with head."); + public static readonly MelonPreferences_Entry EntryIKLerpSpeed = + CategoryDesktopVRIK.CreateEntry("IK Lerp Speed", 10f, description: "Determines fast the IK & Locomotion weights blend after entering idle. Set to 0 to disable."); + + public static readonly MelonPreferences_Entry EntryIntegrationAMT = + CategoryDesktopVRIK.CreateEntry("AMT Integration", true, description: "Relies on AvatarMotionTweaker to handle VRIK Locomotion weights if available."); + + public static bool integration_AMT = false; + public override void OnInitializeMelon() { Logger = LoggerInstance; @@ -50,6 +58,16 @@ public class DesktopVRIKMod : MelonMod Logger.Msg("Initializing BTKUILib support."); BTKUIAddon.Init(); } + //AvatarMotionTweaker Handling + if (MelonMod.RegisteredMelons.Any(it => it.Info.Name == "AvatarMotionTweaker")) + { + Logger.Msg("AvatarMotionTweaker was found. Relying on it to handle VRIK locomotion."); + integration_AMT = true; + } + else + { + Logger.Msg("AvatarMotionTweaker was not found. Using built-in VRIK locomotion handling."); + } } internal static void UpdateAllSettings() @@ -64,10 +82,18 @@ public class DesktopVRIKMod : MelonMod DesktopVRIKSystem.Instance.Setting_BodyHeadingLimit = Mathf.Clamp(EntryBodyHeadingLimit.Value, 0f, 90f); DesktopVRIKSystem.Instance.Setting_PelvisHeadingWeight = (1f - Mathf.Clamp01(EntryPelvisHeadingWeight.Value)); DesktopVRIKSystem.Instance.Setting_ChestHeadingWeight = (1f - Mathf.Clamp01(EntryChestHeadingWeight.Value)); + DesktopVRIKSystem.Instance.Setting_ChestHeadingWeight = (1f - Mathf.Clamp01(EntryChestHeadingWeight.Value)); + DesktopVRIKSystem.Instance.Setting_IKLerpSpeed = Mathf.Clamp(EntryIKLerpSpeed.Value, 0f, 20f); // Calibration Settings DesktopVRIKSystem.Instance.Setting_UseVRIKToes = EntryUseVRIKToes.Value; DesktopVRIKSystem.Instance.Setting_FindUnmappedToes = EntryFindUnmappedToes.Value; + + // Fine-tuning Settings + DesktopVRIKSystem.Instance.Setting_ResetFootsteps = EntryResetFootstepsOnIdle.Value; + + // Integration Settings + DesktopVRIKSystem.Instance.Setting_IntegrationAMT = EntryIntegrationAMT.Value && integration_AMT; } void OnUpdateSettings(object arg1, object arg2) => UpdateAllSettings(); diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs index 3cd7c04..0fefe61 100644 --- a/DesktopVRIK/Properties/AssemblyInfo.cs +++ b/DesktopVRIK/Properties/AssemblyInfo.cs @@ -26,6 +26,6 @@ using System.Reflection; namespace NAK.Melons.DesktopVRIK.Properties; internal static class AssemblyInfoParams { - public const string Version = "4.1.2"; + public const string Version = "4.1.3"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/DesktopVRIK/VRIKUtils.cs b/DesktopVRIK/VRIKUtils.cs index 32fedd7..21c36c3 100644 --- a/DesktopVRIK/VRIKUtils.cs +++ b/DesktopVRIK/VRIKUtils.cs @@ -154,10 +154,33 @@ public static class VRIKUtils initialStepHeight = Vector3.Distance(vrik.references.leftFoot.position, vrik.references.leftCalf.position) * 0.2f; } - public static void CalculateInitialFootsteps(VRIK vrik, out Vector3 initialFootstepLeft, out Vector3 initialFootstepRight) + public static void CalculateInitialFootsteps(VRIK vrik, out Vector3 initialFootPosLeft, out Vector3 initialFootPosRight, out Quaternion initialFootRotLeft, out Quaternion initialFootRotRight) { - initialFootstepLeft = vrik.references.root.InverseTransformPoint(vrik.references.leftFoot.position); - initialFootstepRight = vrik.references.root.InverseTransformPoint(vrik.references.rightFoot.position); + Transform root = vrik.references.root; + Transform leftFoot = vrik.references.leftFoot; + Transform rightFoot = vrik.references.rightFoot; + + // Calculate the world rotation of the root bone at the current frame + Quaternion rootWorldRot = root.rotation; + + // Calculate the world rotation of the left and right feet relative to the root bone + initialFootPosLeft = root.InverseTransformPoint(leftFoot.position); + initialFootPosRight = root.InverseTransformPoint(rightFoot.position); + initialFootRotLeft = Quaternion.Inverse(rootWorldRot) * leftFoot.rotation; + initialFootRotRight = Quaternion.Inverse(rootWorldRot) * rightFoot.rotation; + } + + public static void SetFootsteps(VRIK vrik, Vector3 footPosLeft, Vector3 footPosRight, Quaternion footRotLeft, Quaternion footRotRight) + { + var locomotionSolver = vrik.solver.locomotion; + + var footsteps = locomotionSolver.footsteps; + var footstepLeft = footsteps[0]; + var footstepRight = footsteps[1]; + + var rootWorldRot = vrik.references.root.rotation; + footstepLeft.Reset(rootWorldRot, vrik.transform.TransformPoint(footPosLeft), rootWorldRot * footRotLeft); + footstepRight.Reset(rootWorldRot, vrik.transform.TransformPoint(footPosRight), rootWorldRot * footRotRight); } public static void SetupHeadIKTarget(VRIK vrik) diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json index 0290432..acd5fa4 100644 --- a/DesktopVRIK/format.json +++ b/DesktopVRIK/format.json @@ -1,7 +1,7 @@ { "_id": 117, "name": "DesktopVRIK", - "modversion": "4.1.2", + "modversion": "4.1.3", "gameversion": "2022r170", "loaderversion": "0.5.7", "modtype": "Mod", @@ -17,8 +17,8 @@ "requirements": [ "BTKUILib" ], - "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v4.1.2/DesktopVRIK.dll", + "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v4.1.3/DesktopVRIK.dll", "sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRIK/", - "changelog": "- No longer requires AvatarMotionTweaker.\n- No longer piggybacks on IKSystem/PlayerSetup.\n\n DesktopVRIK will now handle VRIK Locomotion weight instead of relying on CVR & AMT to handle it. This means LeapMotionExtension, PickupArmMovement, and CVRLimbGrabber will now work while in crouch/prone.", + "changelog": "- No longer requires AvatarMotionTweaker.\n- No longer piggybacks on IKSystem/PlayerSetup.\n- Tweaks to Locomotion & IKSolver weight blending.\n\n DesktopVRIK will now handle VRIK Locomotion weight instead of relying on CVR & AMT to handle it. This means LeapMotionExtension, PickupArmMovement, and CVRLimbGrabber will now work while in crouch/prone.", "embedcolor": "9b59b6" } \ No newline at end of file From 57e7cfd35a93af9cd15b31ea7556db51d2d77b9d Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Sat, 1 Apr 2023 16:31:29 -0500 Subject: [PATCH 58/60] fix small cheese emotes and layer weights --- DesktopVRIK/DesktopVRIKSystem.cs | 10 ++++++---- DesktopVRIK/HarmonyPatches.cs | 1 + DesktopVRIK/Properties/AssemblyInfo.cs | 2 +- DesktopVRIK/format.json | 4 ++-- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/DesktopVRIK/DesktopVRIKSystem.cs b/DesktopVRIK/DesktopVRIKSystem.cs index d6e0b53..d24d14a 100644 --- a/DesktopVRIK/DesktopVRIKSystem.cs +++ b/DesktopVRIK/DesktopVRIKSystem.cs @@ -329,7 +329,6 @@ internal class DesktopVRIKSystem : MonoBehaviour if (avatarVRIK == null) return; if (isEmotePlaying == _ikEmotePlaying) return; - _ikEmotePlaying = isEmotePlaying; if (avatarLookAtIK != null) @@ -535,6 +534,9 @@ internal class DesktopVRIKSystem : MonoBehaviour avatarIKSolver.spine.positionWeight = 0f; avatarIKSolver.spine.rotationWeight = 1f; + // Set so emotes play properly + avatarIKSolver.spine.maxRootAngle = 180f; + // We disable these ourselves now, as we no longer use BodySystem avatarIKSolver.spine.maintainPelvisPosition = 1f; avatarIKSolver.spine.positionWeight = 0f; @@ -596,14 +598,14 @@ internal class DesktopVRIKSystem : MonoBehaviour switch (pose) { case AvatarPose.Default: + SetMusclesToValue(0f); + break; + case AvatarPose.Initial: if (HasCustomIKPose()) { SetCustomLayersWeights(0f, 1f); return; } - SetMusclesToValue(0f); - break; - case AvatarPose.Initial: _humanPoseHandler.SetHumanPose(ref _humanPoseInitial); break; case AvatarPose.IKPose: diff --git a/DesktopVRIK/HarmonyPatches.cs b/DesktopVRIK/HarmonyPatches.cs index 7b03dc1..a72b331 100644 --- a/DesktopVRIK/HarmonyPatches.cs +++ b/DesktopVRIK/HarmonyPatches.cs @@ -13,6 +13,7 @@ using UnityEngine; Chito- left foot is far back without proper tpose & foot ik distance, was uploaded in falling anim state. Atlas (portal2)- Wide stance, proper feet distance needed to be calculated. Freddy (gmod)- Doesn't have any fingers, wristToPalmAxis & palmToThumbAxis needed to be set manually. + Small Cheese- Emotes are angled wrong due to maxRootAngle..??? Most other avatars play just fine. diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs index 0fefe61..7264cb4 100644 --- a/DesktopVRIK/Properties/AssemblyInfo.cs +++ b/DesktopVRIK/Properties/AssemblyInfo.cs @@ -26,6 +26,6 @@ using System.Reflection; namespace NAK.Melons.DesktopVRIK.Properties; internal static class AssemblyInfoParams { - public const string Version = "4.1.3"; + public const string Version = "4.1.4"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json index acd5fa4..a51be6a 100644 --- a/DesktopVRIK/format.json +++ b/DesktopVRIK/format.json @@ -1,7 +1,7 @@ { "_id": 117, "name": "DesktopVRIK", - "modversion": "4.1.3", + "modversion": "4.1.4", "gameversion": "2022r170", "loaderversion": "0.5.7", "modtype": "Mod", @@ -17,7 +17,7 @@ "requirements": [ "BTKUILib" ], - "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v4.1.3/DesktopVRIK.dll", + "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v4.1.4/DesktopVRIK.dll", "sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRIK/", "changelog": "- No longer requires AvatarMotionTweaker.\n- No longer piggybacks on IKSystem/PlayerSetup.\n- Tweaks to Locomotion & IKSolver weight blending.\n\n DesktopVRIK will now handle VRIK Locomotion weight instead of relying on CVR & AMT to handle it. This means LeapMotionExtension, PickupArmMovement, and CVRLimbGrabber will now work while in crouch/prone.", "embedcolor": "9b59b6" From b4aab6bf4a4dcba27a31a29435070f5276086ee0 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Fri, 7 Apr 2023 19:13:10 -0500 Subject: [PATCH 59/60] Add Prone Thrust option & Fix scaling disabling IK without AMT Add Prone Thrust option & Fix scaling disabling IK without AMT --- DesktopVRIK/DesktopVRIKSystem.cs | 27 +++++++++++++++----------- DesktopVRIK/Main.cs | 3 +++ DesktopVRIK/Properties/AssemblyInfo.cs | 2 +- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/DesktopVRIK/DesktopVRIKSystem.cs b/DesktopVRIK/DesktopVRIKSystem.cs index d24d14a..7c25cd4 100644 --- a/DesktopVRIK/DesktopVRIKSystem.cs +++ b/DesktopVRIK/DesktopVRIKSystem.cs @@ -125,6 +125,7 @@ internal class DesktopVRIKSystem : MonoBehaviour public bool Setting_Enabled = true; public bool Setting_PlantFeet; public bool Setting_ResetFootsteps; + public bool Setting_ProneThrusting; public float Setting_BodyLeanWeight; public float Setting_BodyHeadingLimit; public float Setting_PelvisHeadingWeight; @@ -177,6 +178,7 @@ internal class DesktopVRIKSystem : MonoBehaviour float _ikWeightLerp = 1f; float _ikSimulatedRootAngle = 0f; float _locomotionWeight = 1f; + float _scaleDifference = 1f; // Last Movement Parent Info Vector3 _movementPosition; @@ -198,7 +200,7 @@ internal class DesktopVRIKSystem : MonoBehaviour DesktopVRIKMod.UpdateAllSettings(); } - + void Update() { if (avatarVRIK == null) return; @@ -241,10 +243,11 @@ internal class DesktopVRIKSystem : MonoBehaviour // Get Upright value Vector3 delta = avatarIKSolver.spine.headPosition - avatarTransform.position; Vector3 deltaRotated = Quaternion.Euler(0, avatarTransform.rotation.eulerAngles.y, 0) * delta; - float upright = Mathf.InverseLerp(0f, avatarIKSolver.spine.headHeight, deltaRotated.y); + float upright = Mathf.InverseLerp(0f, avatarIKSolver.spine.headHeight * _scaleDifference, deltaRotated.y); return upright > 0.85f; } + void UpdateLocomotionWeight() { float targetWeight = BodySystem.TrackingEnabled && BodySystem.TrackingLocomotionEnabled ? 1.0f : 0.0f; @@ -319,6 +322,8 @@ internal class DesktopVRIKSystem : MonoBehaviour scaleDifference ); + _scaleDifference = scaleDifference; + avatarIKSolver.Reset(); ResetDesktopVRIK(); return true; @@ -383,31 +388,29 @@ internal class DesktopVRIKSystem : MonoBehaviour avatarIKSolver.plantFeet = Setting_PlantFeet; // Apply custom VRIK solving effects - if (_ikWeightLerp > 0) - { - IKBodyLeaningOffset(); - IKBodyHeadingOffset(); - } + IKBodyLeaningOffset(_ikWeightLerp); + IKBodyHeadingOffset(_ikWeightLerp); } - void IKBodyLeaningOffset() + void IKBodyLeaningOffset(float weight) { // Emulate old VRChat hip movement if (Setting_BodyLeanWeight <= 0) return; - float weightedAngle = Setting_BodyLeanWeight * _ikWeightLerp; + if (Setting_ProneThrusting) weight = 1f; + float weightedAngle = Setting_BodyLeanWeight * weight; float angle = _cameraTransform.localEulerAngles.x; angle = angle > 180 ? angle - 360 : angle; Quaternion rotation = Quaternion.AngleAxis(angle * weightedAngle, avatarTransform.right); avatarIKSolver.spine.headRotationOffset *= rotation; } - void IKBodyHeadingOffset() + void IKBodyHeadingOffset(float weight) { // Make root heading follow within a set limit if (Setting_BodyHeadingLimit <= 0) return; - float weightedAngleLimit = Setting_BodyHeadingLimit * _ikWeightLerp; + float weightedAngleLimit = Setting_BodyHeadingLimit * weight; float deltaAngleRoot = Mathf.DeltaAngle(transform.eulerAngles.y, _ikSimulatedRootAngle); float absDeltaAngleRoot = Mathf.Abs(deltaAngleRoot); @@ -581,6 +584,8 @@ internal class DesktopVRIKSystem : MonoBehaviour void ConfigureVRIK() { + // Reset scale diffrence + _scaleDifference = 1f; VRIKUtils.ApplyScaleToVRIK ( avatarVRIK, diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index 09cfcea..cc3ed1c 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -39,6 +39,9 @@ public class DesktopVRIKMod : MelonMod public static readonly MelonPreferences_Entry EntryIKLerpSpeed = CategoryDesktopVRIK.CreateEntry("IK Lerp Speed", 10f, description: "Determines fast the IK & Locomotion weights blend after entering idle. Set to 0 to disable."); + public static readonly MelonPreferences_Entry EntryProneThrusting = + CategoryDesktopVRIK.CreateEntry("Prone Thrusting", false, description: "Allows Body Lean Weight to take affect while crouched or prone."); + public static readonly MelonPreferences_Entry EntryIntegrationAMT = CategoryDesktopVRIK.CreateEntry("AMT Integration", true, description: "Relies on AvatarMotionTweaker to handle VRIK Locomotion weights if available."); diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs index 7264cb4..25bdf29 100644 --- a/DesktopVRIK/Properties/AssemblyInfo.cs +++ b/DesktopVRIK/Properties/AssemblyInfo.cs @@ -26,6 +26,6 @@ using System.Reflection; namespace NAK.Melons.DesktopVRIK.Properties; internal static class AssemblyInfoParams { - public const string Version = "4.1.4"; + public const string Version = "4.1.5"; public const string Author = "NotAKidoS"; } \ No newline at end of file From 529105feac6bfb292f250e40db877a18b8c0f866 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Fri, 7 Apr 2023 19:18:43 -0500 Subject: [PATCH 60/60] add funny settings --- DesktopVRIK/Main.cs | 3 +++ DesktopVRIK/format.json | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index cc3ed1c..c7739b4 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -97,6 +97,9 @@ public class DesktopVRIKMod : MelonMod // Integration Settings DesktopVRIKSystem.Instance.Setting_IntegrationAMT = EntryIntegrationAMT.Value && integration_AMT; + + // Funny Settings + DesktopVRIKSystem.Instance.Setting_ProneThrusting = EntryProneThrusting.Value; } void OnUpdateSettings(object arg1, object arg2) => UpdateAllSettings(); diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json index a51be6a..f1305c7 100644 --- a/DesktopVRIK/format.json +++ b/DesktopVRIK/format.json @@ -1,7 +1,7 @@ { "_id": 117, "name": "DesktopVRIK", - "modversion": "4.1.4", + "modversion": "4.1.5", "gameversion": "2022r170", "loaderversion": "0.5.7", "modtype": "Mod", @@ -17,7 +17,7 @@ "requirements": [ "BTKUILib" ], - "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v4.1.4/DesktopVRIK.dll", + "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v4.1.5/DesktopVRIK.dll", "sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRIK/", "changelog": "- No longer requires AvatarMotionTweaker.\n- No longer piggybacks on IKSystem/PlayerSetup.\n- Tweaks to Locomotion & IKSolver weight blending.\n\n DesktopVRIK will now handle VRIK Locomotion weight instead of relying on CVR & AMT to handle it. This means LeapMotionExtension, PickupArmMovement, and CVRLimbGrabber will now work while in crouch/prone.", "embedcolor": "9b59b6"