mirror of
https://github.com/NotAKidoS/NAK_CVR_Mods.git
synced 2025-09-02 14:29:25 +00:00
thirdperson, propundobutton, mirror clone test, you are a clone test, bettershadowclone test, nevermind, anotherlocaltestmod, and some changes to avatarscaling ???
This commit is contained in:
parent
df45fb50d9
commit
9944ad7611
43 changed files with 1076 additions and 173 deletions
80
MirrorClone/Main.cs
Normal file
80
MirrorClone/Main.cs
Normal file
|
@ -0,0 +1,80 @@
|
|||
using MelonLoader;
|
||||
using System.Reflection;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Util;
|
||||
using ABI_RC.Systems.IK;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NAK.BetterShadowClone;
|
||||
|
||||
public class MirrorCloneMod : MelonMod
|
||||
{
|
||||
internal static MelonLogger.Instance Logger;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
Logger = LoggerInstance;
|
||||
|
||||
ModSettings.Initialize();
|
||||
|
||||
try
|
||||
{
|
||||
InitializePatches();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
#region Harmony Patches
|
||||
|
||||
private void InitializePatches()
|
||||
{
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.Awake), BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
postfix: new HarmonyLib.HarmonyMethod(typeof(MirrorCloneMod).GetMethod(nameof(OnPlayerSetup_Awake_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetupAvatar)),
|
||||
prefix: new HarmonyLib.HarmonyMethod(typeof(MirrorCloneMod).GetMethod(nameof(OnPlayerSetup_SetupAvatar_Prefix), BindingFlags.NonPublic | BindingFlags.Static)),
|
||||
postfix: new HarmonyLib.HarmonyMethod(typeof(MirrorCloneMod).GetMethod(nameof(OnPlayerSetup_SetupAvatar_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
prefix: new HarmonyLib.HarmonyMethod(typeof(MirrorCloneMod).GetMethod(nameof(OnPlayerSetup_ClearAvatar_Prefix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
|
||||
HarmonyInstance.Patch(
|
||||
typeof(IKSystem).GetMethod(nameof(IKSystem.OnPostSolverUpdateGeneral), BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
postfix: new HarmonyLib.HarmonyMethod(typeof(MirrorCloneMod).GetMethod(nameof(OnIKSystem_OnPostSolverUpdateGeneral_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
|
||||
HarmonyInstance.Patch(
|
||||
typeof(TransformHiderForMainCamera).GetMethod(nameof(TransformHiderForMainCamera.ProcessHierarchy)),
|
||||
prefix: new HarmonyLib.HarmonyMethod(typeof(MirrorCloneMod).GetMethod(nameof(OnTransformHiderForMainCamera_ProcessHierarchy_Prefix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
}
|
||||
|
||||
private static void OnPlayerSetup_Awake_Postfix()
|
||||
=> MirrorCloneManager.OnPlayerSetupAwake();
|
||||
|
||||
private static void OnPlayerSetup_SetupAvatar_Prefix(GameObject inAvatar)
|
||||
=> MirrorCloneManager.Instance.OnAvatarInitialized(inAvatar);
|
||||
|
||||
private static void OnPlayerSetup_SetupAvatar_Postfix()
|
||||
=> MirrorCloneManager.Instance.OnAvatarConfigured();
|
||||
|
||||
private static void OnPlayerSetup_ClearAvatar_Prefix()
|
||||
=> MirrorCloneManager.Instance.OnAvatarDestroyed();
|
||||
|
||||
private static void OnIKSystem_OnPostSolverUpdateGeneral_Postfix()
|
||||
=> MirrorCloneManager.Instance.OnPostSolverUpdateGeneral();
|
||||
|
||||
private static void OnTransformHiderForMainCamera_ProcessHierarchy_Prefix(ref bool __runOriginal)
|
||||
=> __runOriginal = !ModSettings.EntryEnabled.Value;
|
||||
|
||||
#endregion
|
||||
}
|
2
MirrorClone/MirrorClone.csproj
Normal file
2
MirrorClone/MirrorClone.csproj
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk" />
|
247
MirrorClone/MirrorClone/MirrorCloneManager.cs
Normal file
247
MirrorClone/MirrorClone/MirrorCloneManager.cs
Normal file
|
@ -0,0 +1,247 @@
|
|||
using ABI_RC.Core;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Savior;
|
||||
using ABI_RC.Systems.IK;
|
||||
using ABI.CCK.Components;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace NAK.BetterShadowClone;
|
||||
|
||||
public class MirrorCloneManager : MonoBehaviour
|
||||
{
|
||||
#region Static Instance
|
||||
|
||||
public static MirrorCloneManager Instance { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
private bool _isAvatarConfigured;
|
||||
|
||||
private GameObject _avatar;
|
||||
private GameObject _mirrorClone;
|
||||
private GameObject _initializationTarget;
|
||||
|
||||
private CVRAnimatorManager _animatorManager;
|
||||
private Animator _mirrorAnimator;
|
||||
|
||||
#region Unity Events
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance != null
|
||||
&& Instance != this)
|
||||
{
|
||||
DestroyImmediate(this);
|
||||
return;
|
||||
}
|
||||
|
||||
Instance = this;
|
||||
|
||||
MirrorCloneMod.Logger.Msg("Mirror Clone Manager initialized.");
|
||||
|
||||
_animatorManager = PlayerSetup.Instance.animatorManager;
|
||||
|
||||
// Create initialization target (so no components are initialized before we're ready)
|
||||
_initializationTarget = new GameObject(nameof(MirrorCloneManager) + " Initialization Target");
|
||||
_initializationTarget.transform.SetParent(transform);
|
||||
_initializationTarget.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity);
|
||||
_initializationTarget.transform.localScale = Vector3.one;
|
||||
_initializationTarget.SetActive(false);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (Instance == this)
|
||||
Instance = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Game Events
|
||||
|
||||
public static void OnPlayerSetupAwake()
|
||||
{
|
||||
if (Instance != null)
|
||||
return;
|
||||
|
||||
GameObject manager = new (nameof(MirrorCloneManager), typeof(MirrorCloneManager));
|
||||
DontDestroyOnLoad(manager);
|
||||
}
|
||||
|
||||
public void OnAvatarInitialized(GameObject avatar)
|
||||
{
|
||||
if (!ModSettings.EntryEnabled.Value)
|
||||
return;
|
||||
|
||||
if (avatar == null
|
||||
|| _isAvatarConfigured)
|
||||
return;
|
||||
|
||||
_isAvatarConfigured = true;
|
||||
|
||||
_avatar = avatar;
|
||||
_mirrorClone = InstantiateMirrorCopy(_avatar);
|
||||
}
|
||||
|
||||
public void OnAvatarConfigured()
|
||||
{
|
||||
if (!_isAvatarConfigured)
|
||||
return;
|
||||
|
||||
Animator baseAnimator = _avatar.GetComponent<Animator>();
|
||||
|
||||
if (!_mirrorClone.TryGetComponent(out _mirrorAnimator))
|
||||
_mirrorAnimator = gameObject.AddComponent<Animator>();
|
||||
_mirrorAnimator.runtimeAnimatorController = baseAnimator.runtimeAnimatorController;
|
||||
|
||||
_animatorManager._copyAnimator = _mirrorAnimator; // thank you for existing
|
||||
|
||||
var cameras = PlayerSetup.Instance.GetComponentsInChildren<Camera>(true);
|
||||
foreach (var camera in cameras)
|
||||
{
|
||||
// hide PlayerClone layer from all cameras
|
||||
camera.cullingMask &= ~(1 << CVRLayers.PlayerClone);
|
||||
}
|
||||
|
||||
var mirrors = Resources.FindObjectsOfTypeAll<CVRMirror>();
|
||||
foreach (CVRMirror mirror in mirrors)
|
||||
{
|
||||
// hide PlayerLocal layer from all mirrors
|
||||
mirror.m_ReflectLayers &= ~(1 << CVRLayers.PlayerLocal);
|
||||
}
|
||||
|
||||
// scale avatar head bone to 0 0 0
|
||||
Transform headBone = baseAnimator.GetBoneTransform(HumanBodyBones.Head);
|
||||
headBone.localScale = Vector3.zero;
|
||||
|
||||
CleanupAvatar();
|
||||
CleanupMirrorClone();
|
||||
SetupHumanPoseHandler();
|
||||
|
||||
_initializationTarget.SetActive(true);
|
||||
}
|
||||
|
||||
public void OnAvatarDestroyed()
|
||||
{
|
||||
if (!_isAvatarConfigured)
|
||||
return;
|
||||
|
||||
_avatar = null;
|
||||
_mirrorAnimator = null;
|
||||
if (_mirrorClone != null)
|
||||
Destroy(_mirrorClone);
|
||||
|
||||
_initializationTarget.SetActive(false);
|
||||
|
||||
_isAvatarConfigured = false;
|
||||
}
|
||||
|
||||
public void OnPostSolverUpdateGeneral()
|
||||
{
|
||||
if (!_isAvatarConfigured)
|
||||
return;
|
||||
|
||||
StealTransforms();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private GameObject InstantiateMirrorCopy(GameObject original)
|
||||
{
|
||||
GameObject clone = Instantiate(original, _initializationTarget.transform);
|
||||
clone.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity);
|
||||
clone.name = original.name + " (Mirror Clone)";
|
||||
clone.SetLayerRecursive(CVRLayers.PlayerClone);
|
||||
return clone;
|
||||
}
|
||||
|
||||
private void CleanupAvatar()
|
||||
{
|
||||
// set local avatar mesh to shadow off
|
||||
var avatarMeshes = _avatar.GetComponentsInChildren<SkinnedMeshRenderer>(true);
|
||||
foreach (SkinnedMeshRenderer avatarMesh in avatarMeshes)
|
||||
{
|
||||
avatarMesh.shadowCastingMode = ShadowCastingMode.Off;
|
||||
avatarMesh.forceMatrixRecalculationPerRender = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void CleanupMirrorClone()
|
||||
{
|
||||
// destroy unneeded components
|
||||
// only keep Animator
|
||||
|
||||
var components = _mirrorClone.GetComponentsInChildren<Component>(true);
|
||||
foreach (Component component in components)
|
||||
{
|
||||
if (component == null)
|
||||
continue;
|
||||
|
||||
// skip basic unity components
|
||||
if (component is Animator
|
||||
or Transform
|
||||
or SkinnedMeshRenderer
|
||||
or MeshRenderer
|
||||
or MeshFilter)
|
||||
continue;
|
||||
|
||||
// skip basic CVR components
|
||||
if (component is CVRAvatar or CVRAssetInfo)
|
||||
{
|
||||
(component as MonoBehaviour).enabled = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
Destroy(component);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Job System
|
||||
|
||||
private HumanPoseHandler _humanPoseHandler;
|
||||
private Transform _hipTransform;
|
||||
|
||||
private void SetupHumanPoseHandler()
|
||||
{
|
||||
_hipTransform = _mirrorAnimator.GetBoneTransform(HumanBodyBones.Hips);
|
||||
|
||||
_humanPoseHandler?.Dispose();
|
||||
_humanPoseHandler = new HumanPoseHandler(_mirrorAnimator.avatar, _mirrorAnimator.transform);
|
||||
}
|
||||
|
||||
private void StealTransforms()
|
||||
{
|
||||
// copy transforms from avatar to mirror clone
|
||||
// var avatarTransforms = _avatar.GetComponentsInChildren<Transform>(true);
|
||||
// var mirrorCloneTransforms = _mirrorClone.GetComponentsInChildren<Transform>(true);
|
||||
// for (int i = 0; i < avatarTransforms.Length; i++)
|
||||
// {
|
||||
// Transform avatarTransform = avatarTransforms[i];
|
||||
// Transform mirrorCloneTransform = mirrorCloneTransforms[i];
|
||||
//
|
||||
// mirrorCloneTransform.SetLocalPositionAndRotation(
|
||||
// avatarTransform.localPosition,
|
||||
// avatarTransform.localRotation);
|
||||
// }
|
||||
|
||||
if (!IKSystem.Instance.IsAvatarCalibrated())
|
||||
return;
|
||||
|
||||
IKSystem.Instance._humanPoseHandler.GetHumanPose(ref IKSystem.Instance._humanPose);
|
||||
_humanPoseHandler.SetHumanPose(ref IKSystem.Instance._humanPose);
|
||||
|
||||
if (!MetaPort.Instance.isUsingVr)
|
||||
_mirrorAnimator.transform.SetPositionAndRotation(PlayerSetup.Instance.GetPlayerPosition(), PlayerSetup.Instance.GetPlayerRotation());
|
||||
else
|
||||
_mirrorAnimator.transform.SetPositionAndRotation(_avatar.transform.position, _avatar.transform.rotation);
|
||||
|
||||
_hipTransform.SetPositionAndRotation(IKSystem.Instance._hipTransform.position, IKSystem.Instance._hipTransform.rotation);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
31
MirrorClone/ModSettings.cs
Normal file
31
MirrorClone/ModSettings.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
using MelonLoader;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NAK.BetterShadowClone;
|
||||
|
||||
public static class ModSettings
|
||||
{
|
||||
#region Melon Prefs
|
||||
|
||||
private const string SettingsCategory = nameof(MirrorCloneMod);
|
||||
|
||||
private static readonly MelonPreferences_Category Category =
|
||||
MelonPreferences.CreateCategory(SettingsCategory);
|
||||
|
||||
internal static readonly MelonPreferences_Entry<bool> EntryEnabled =
|
||||
Category.CreateEntry("Enabled", true,
|
||||
description: "Enable Mirror Clone.");
|
||||
|
||||
#endregion
|
||||
|
||||
internal static void Initialize()
|
||||
{
|
||||
foreach (MelonPreferences_Entry setting in Category.Entries)
|
||||
setting.OnEntryValueChangedUntyped.Subscribe(OnSettingsChanged);
|
||||
}
|
||||
|
||||
internal static void OnSettingsChanged(object oldValue = null, object newValue = null)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
29
MirrorClone/Properties/AssemblyInfo.cs
Normal file
29
MirrorClone/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,29 @@
|
|||
using MelonLoader;
|
||||
using NAK.BetterShadowClone.Properties;
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyTitle(nameof(NAK.BetterShadowClone))]
|
||||
[assembly: AssemblyCompany(AssemblyInfoParams.Author)]
|
||||
[assembly: AssemblyProduct(nameof(NAK.BetterShadowClone))]
|
||||
|
||||
[assembly: MelonInfo(
|
||||
typeof(NAK.BetterShadowClone.MirrorCloneMod),
|
||||
nameof(NAK.BetterShadowClone),
|
||||
AssemblyInfoParams.Version,
|
||||
AssemblyInfoParams.Author,
|
||||
downloadLink: "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/MirrorCloneMod"
|
||||
)]
|
||||
|
||||
[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")]
|
||||
[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||
[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
||||
|
||||
namespace NAK.BetterShadowClone.Properties;
|
||||
internal static class AssemblyInfoParams
|
||||
{
|
||||
public const string Version = "1.0.0";
|
||||
public const string Author = "NotAKidoS";
|
||||
}
|
16
MirrorClone/README.md
Normal file
16
MirrorClone/README.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
# EzCurls
|
||||
|
||||
A mod that allows you to tune your finger curls to your liking. Supposedly can help with VR sign language, as raw finger curls are not that great for quick and precise gestures.
|
||||
|
||||
The settings are not too coherent, it is mostly a bunch of things thrown at the wall, but it works for me. I hope it works for you too.
|
||||
|
||||
---
|
||||
|
||||
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
|
||||
|
||||
> This mod is an independent creation and is not affiliated with, supported by or approved by Alpha Blend Interactive.
|
||||
|
||||
> 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.
|
23
MirrorClone/format.json
Normal file
23
MirrorClone/format.json
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"_id": -1,
|
||||
"name": "EzCurls",
|
||||
"modversion": "1.0.0",
|
||||
"gameversion": "2023r173",
|
||||
"loaderversion": "0.6.1",
|
||||
"modtype": "Mod",
|
||||
"author": "NotAKidoS",
|
||||
"description": "A mod that allows you to tune your finger curls to your liking. Supposedly can help with VR sign language, as raw finger curls are not that great for quick and precise gestures.\n\nThe settings are not too coherent, it is mostly a bunch of things thrown at the wall, but it works for me. I hope it works for you too.",
|
||||
"searchtags": [
|
||||
"curls",
|
||||
"fingers",
|
||||
"index",
|
||||
"knuckles"
|
||||
],
|
||||
"requirements": [
|
||||
"UIExpansionKit"
|
||||
],
|
||||
"downloadlink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/download/r24/EzCurls.dll",
|
||||
"sourcelink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/EzCurls/",
|
||||
"changelog": "- Initial CVRMG release",
|
||||
"embedcolor": "7d7d7d"
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue