last minute refactor

This commit is contained in:
NotAKidoS 2022-12-25 21:05:13 -06:00
parent 407af39155
commit 50c5016cc6
7 changed files with 513 additions and 0 deletions

108
DesktopVRIK/DesktopVRIK.cs Normal file
View file

@ -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<VRIK>();
if (vrik == null)
{
vrik = avatar.gameObject.AddComponent<VRIK>();
}
//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;
}
}

View file

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<ItemGroup>
<Reference Include="0Harmony">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\MelonLoader\0Harmony.dll</HintPath>
</Reference>
<Reference Include="Assembly-CSharp">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll</HintPath>
</Reference>
<Reference Include="Assembly-CSharp-firstpass">
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>
</Reference>
<Reference Include="Cohtml.Runtime">
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll</HintPath>
</Reference>
<Reference Include="Giamoz">
<HintPath>..\..\Giamoz\Giamoz\bin\Debug\net472\Giamoz.dll</HintPath>
</Reference>
<Reference Include="MelonLoader">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\MelonLoader\MelonLoader.dll</HintPath>
</Reference>
<Reference Include="SteamVR">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\SteamVR.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AnimationModule">
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.CoreModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.InputLegacyModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.InputLegacyModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.PhysicsModule">
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath>
</Reference>
</ItemGroup>
<Target Name="Deploy" AfterTargets="Build">
<Copy SourceFiles="$(TargetPath)" DestinationFolder="C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\" />
<Message Text="Copied $(TargetPath) to C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\" Importance="high" />
</Target>
</Project>

View file

@ -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

View file

@ -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<VRIK>();
//now i add my own VRIK stuff
NAKDesktopVRIK NAKVRIK = avatar.gameObject.AddComponent<NAKDesktopVRIK>();
NAKVRIK.CalibrateAvatarVRIK(avatar);
}
}

240
DesktopVRIK/Main.cs Normal file
View file

@ -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<bool> m_entryEnabled;
private static MelonPreferences_Entry<bool> m_entryEmulateHipMovement;
private static MelonPreferences_Entry<bool> m_entryEmoteVRIK;
private static MelonPreferences_Entry<bool> m_entryEmoteLookAtIK;
public override void OnApplicationStart()
{
m_categoryDesktopVRIK = MelonPreferences.CreateCategory(nameof(DesktopVRIK));
m_entryEnabled = m_categoryDesktopVRIK.CreateEntry<bool>("Enabled", true, description: "Attempt to give Desktop VRIK.");
m_entryEmulateHipMovement = m_categoryDesktopVRIK.CreateEntry<bool>("Emulate Hip Movement", true, description: "Emulates VRChat-like hip movement when moving head up/down on desktop.");
m_entryEmoteVRIK = m_categoryDesktopVRIK.CreateEntry<bool>("Disable Emote VRIK", true, description: "Disable VRIK while emoting.");
m_entryEmoteLookAtIK = m_categoryDesktopVRIK.CreateEntry<bool>("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>();
____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<Animator>();
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<TwistRelaxer>() == null)
//{
// TwistRelaxer twistRelaxer = boneTransform.gameObject.AddComponent<TwistRelaxer>();
// 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<TwistRelaxer>() == null)
//{
// TwistRelaxer twistRelaxer2 = boneTransform2.gameObject.AddComponent<TwistRelaxer>();
// 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;
}
}
}

View file

@ -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";
}

23
DesktopVRIK/format.json Normal file
View file

@ -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"
}