mirror of
https://github.com/NotAKidoS/NAK_CVR_Mods.git
synced 2025-09-01 22:09:23 +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
|
@ -1,36 +0,0 @@
|
|||
using ABI_RC.Core.IO;
|
||||
using MelonLoader;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NAK.Nevermind;
|
||||
|
||||
public class Nevermind : MelonMod
|
||||
{
|
||||
public override void OnUpdate()
|
||||
{
|
||||
if (!Input.GetKeyDown(KeyCode.Home)) return;
|
||||
|
||||
CancelWorldDownloadJoinOnComplete();
|
||||
CancelWorldLoadJoin();
|
||||
}
|
||||
|
||||
void CancelWorldDownloadJoinOnComplete()
|
||||
{
|
||||
var downloadManager = CVRDownloadManager.Instance;
|
||||
downloadManager.ActiveWorldDownload = false;
|
||||
foreach (var download in downloadManager._downloadTasks)
|
||||
download.Value.JoinOnComplete = false;
|
||||
}
|
||||
|
||||
void CancelWorldLoadJoin()
|
||||
{
|
||||
var objectLoader = CVRObjectLoader.Instance;
|
||||
if (!objectLoader._isLoadingWorld)
|
||||
{
|
||||
objectLoader.j.Bytes = null;
|
||||
objectLoader.j.ObjectId = null;
|
||||
objectLoader.IsLoadingWorldToJoin = false;
|
||||
objectLoader.CurrentWorldLoadingStage = -1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
{
|
||||
"_id": 129,
|
||||
"name": "Nevermind",
|
||||
"modversion": "1.0.0",
|
||||
"gameversion": "2022r170p1",
|
||||
"loaderversion": "0.6.1",
|
||||
"modtype": "Mod",
|
||||
"author": "NotAKidoS",
|
||||
"description": "Prevents VRIK from using toe bones in VR & optionaly FBT.\n\nVRIK calculates weird center of mass when toes are mapped, so it is sometimes desired to unmap toes to prevent an avatars feet from resting far back.\n\nPlease see the README for relevant imagery detailing the problem.",
|
||||
"searchtags": [
|
||||
"toes",
|
||||
"vrik",
|
||||
"ik",
|
||||
"feet"
|
||||
],
|
||||
"requirements": [
|
||||
"None"
|
||||
],
|
||||
"downloadlink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/download/r3/Nevermind.dll",
|
||||
"sourcelink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/Nevermind/",
|
||||
"changelog": "- Initial Release\n- No double patching. Bad. Stinky. Dont do it.",
|
||||
"embedcolor": "#ffc700"
|
||||
}
|
|
@ -42,16 +42,48 @@ public class AvatarScaleManager : MonoBehaviour
|
|||
get => _settingUniversalScaling;
|
||||
set
|
||||
{
|
||||
if (value != _settingUniversalScaling && value == false)
|
||||
_localAvatarScaler.UseTargetHeight = false;
|
||||
if (_settingUniversalScaling == value)
|
||||
return;
|
||||
|
||||
_settingUniversalScaling = value;
|
||||
_localAvatarScaler.UseTargetHeight = true;
|
||||
|
||||
if (_localAvatarScaler != null)
|
||||
_localAvatarScaler.UseTargetHeight = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Setting_AnimationClipScalingOverride;
|
||||
public bool Setting_PersistentHeight;
|
||||
private bool _settingAnimationClipScalingOverride;
|
||||
public bool Setting_AnimationClipScalingOverride
|
||||
{
|
||||
get => _settingAnimationClipScalingOverride;
|
||||
set
|
||||
{
|
||||
if (_settingAnimationClipScalingOverride == value)
|
||||
return;
|
||||
|
||||
_settingAnimationClipScalingOverride = value;
|
||||
|
||||
if (_localAvatarScaler != null)
|
||||
_localAvatarScaler.overrideAnimationHeight = value;
|
||||
}
|
||||
}
|
||||
|
||||
private bool _settingPersistentHeight;
|
||||
public bool Setting_PersistentHeight
|
||||
{
|
||||
get => _settingPersistentHeight;
|
||||
set
|
||||
{
|
||||
if (_settingPersistentHeight == value)
|
||||
return;
|
||||
|
||||
_settingPersistentHeight = value;
|
||||
|
||||
// if (_localAvatarScaler != null)
|
||||
// _localAvatarScaler.persistHeight = value;
|
||||
}
|
||||
}
|
||||
|
||||
private float _lastTargetHeight = -1f;
|
||||
public float LastTargetHeight
|
||||
{
|
||||
|
@ -128,11 +160,7 @@ public class AvatarScaleManager : MonoBehaviour
|
|||
// this is to ensure that the height is also set at correct time during frame, no matter when it is called
|
||||
private IEnumerator HeightUpdateCoroutine()
|
||||
{
|
||||
while (enabled)
|
||||
{
|
||||
yield return _heightUpdateYield;
|
||||
}
|
||||
|
||||
while (enabled) yield return _heightUpdateYield;
|
||||
// ReSharper disable once IteratorNeverReturns
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,9 @@ public class LocalScaler : BaseScaler
|
|||
{
|
||||
_animatorManager = GetComponentInParent<PlayerSetup>().animatorManager;
|
||||
_isAvatarInstantiated = false;
|
||||
|
||||
// listen for events
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -73,7 +76,6 @@ public class LocalScaler : BaseScaler
|
|||
_animatedScaleFactor = scaleDifference.y;
|
||||
_animatedHeight = (_initialHeight * _animatedScaleFactor) + _initialHeight;
|
||||
_animatedScale = localScale;
|
||||
InvokeAnimatedHeightChanged();
|
||||
|
||||
if (overrideAnimationHeight
|
||||
|| !_useTargetHeight)
|
||||
|
|
|
@ -28,11 +28,8 @@ public static class AvatarScaleEvents
|
|||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Avatar Scaling Events
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when a remote avatar's height changes.
|
||||
/// </summary>
|
||||
|
|
|
@ -31,6 +31,14 @@ public static class ModSettings
|
|||
internal static readonly MelonPreferences_Entry<bool> EntryDebugHeadHide =
|
||||
Category.CreateEntry("Debug Head Hide", false,
|
||||
description: "Should head be hidden for first render?");
|
||||
|
||||
internal static readonly MelonPreferences_Entry<bool> EntryDebugShowShadow =
|
||||
Category.CreateEntry("Debug Show Shadow", false,
|
||||
description: "Should the shadow clone be shown?");
|
||||
|
||||
internal static readonly MelonPreferences_Entry<bool> EntryDebugShowInFront =
|
||||
Category.CreateEntry("Debug Show in Front", false,
|
||||
description: "Should the shadow clone be shown in front?");
|
||||
|
||||
|
||||
#endregion
|
||||
|
@ -46,5 +54,7 @@ public static class ModSettings
|
|||
TransformHiderManager.s_DisallowFprExclusions = EntryDontRespectFPR.Value;
|
||||
TransformHiderManager.s_DebugHeadHide = EntryDebugHeadHide.Value;
|
||||
ShadowCloneManager.s_CopyMaterialsToShadow = EntryCopyMaterialToShadow.Value;
|
||||
ShadowCloneManager.s_DebugShowShadow = EntryDebugShowShadow.Value;
|
||||
ShadowCloneManager.s_DebugShowInFront = EntryDebugShowInFront.Value;
|
||||
}
|
||||
}
|
Binary file not shown.
BIN
BetterShadowClone/Resources/bettershadowclone.assets_OLD
Normal file
BIN
BetterShadowClone/Resources/bettershadowclone.assets_OLD
Normal file
Binary file not shown.
|
@ -8,4 +8,5 @@ public interface IShadowClone : IDisposable
|
|||
bool Process();
|
||||
void RenderForShadow();
|
||||
void RenderForUiCulling();
|
||||
void ResetMainMesh();
|
||||
}
|
|
@ -28,6 +28,8 @@ public struct MeshShadowClone : IShadowClone
|
|||
|
||||
#region IShadowClone Methods
|
||||
|
||||
public void ResetMainMesh(){}
|
||||
|
||||
public bool IsValid => _mainMesh != null && _shadowMesh != null;
|
||||
|
||||
public MeshShadowClone(MeshRenderer meshRenderer)
|
||||
|
@ -88,7 +90,9 @@ public struct MeshShadowClone : IShadowClone
|
|||
|
||||
public void RenderForShadow()
|
||||
{
|
||||
_shadowMesh.shadowCastingMode = ShadowCastingMode.ShadowsOnly;
|
||||
_shadowMesh.shadowCastingMode = ShadowCloneManager.s_DebugShowShadow
|
||||
? ShadowCastingMode.On : ShadowCastingMode.ShadowsOnly;
|
||||
|
||||
_shadowMesh.forceRenderingOff = !_shouldCastShadows;
|
||||
|
||||
// shadow casting needs clone to have original materials (uv discard)
|
||||
|
|
|
@ -8,6 +8,8 @@ public class SkinnedShadowClone : IShadowClone
|
|||
{
|
||||
private static readonly int s_SourceBufferId = Shader.PropertyToID("_sourceBuffer");
|
||||
private static readonly int s_TargetBufferId = Shader.PropertyToID("_targetBuffer");
|
||||
private static readonly int s_HiddenVerticiesId = Shader.PropertyToID("_hiddenVertices");
|
||||
private static readonly int s_HiddenVertexPos = Shader.PropertyToID("_hiddenVertexPos");
|
||||
private static readonly int s_SourceBufferLayoutId = Shader.PropertyToID("_sourceBufferLayout");
|
||||
private static readonly int s_SourceRootMatrix = Shader.PropertyToID("_rootBoneMatrix");
|
||||
|
||||
|
@ -26,6 +28,7 @@ public class SkinnedShadowClone : IShadowClone
|
|||
// clone copying
|
||||
private GraphicsBuffer _graphicsBuffer;
|
||||
private GraphicsBuffer _targetBuffer;
|
||||
private ComputeBuffer _computeBuffer;
|
||||
private int _threadGroups;
|
||||
private int _bufferLayout;
|
||||
|
||||
|
@ -39,7 +42,7 @@ public class SkinnedShadowClone : IShadowClone
|
|||
// anything player can touch is suspect to death
|
||||
public bool IsValid => _mainMesh != null && _shadowMesh != null && _rootBone != null;
|
||||
|
||||
internal SkinnedShadowClone(SkinnedMeshRenderer renderer)
|
||||
internal SkinnedShadowClone(SkinnedMeshRenderer renderer, FPRExclusion exclusion)
|
||||
{
|
||||
_mainMesh = renderer;
|
||||
|
||||
|
@ -52,11 +55,28 @@ public class SkinnedShadowClone : IShadowClone
|
|||
return; // no mesh!
|
||||
}
|
||||
|
||||
|
||||
FindExclusionVertList(_mainMesh, exclusion);
|
||||
|
||||
if (exclusion.affectedVertexIndices.Count == 0)
|
||||
{
|
||||
Dispose();
|
||||
return; // no affected verts!
|
||||
}
|
||||
|
||||
_computeBuffer = new ComputeBuffer(_mainMesh.sharedMesh.vertexCount, sizeof(int));
|
||||
_computeBuffer.SetData(exclusion.affectedVertexIndices.ToArray());
|
||||
exclusion.affectedVertexIndices.Clear();
|
||||
|
||||
|
||||
|
||||
_shouldCastShadows = _mainMesh.shadowCastingMode != ShadowCastingMode.Off;
|
||||
_mainMesh.shadowCastingMode = ShadowCastingMode.Off; // visual mesh doesn't cast shadows
|
||||
//_mainMesh.shadowCastingMode = ShadowCastingMode.On; // visual mesh doesn't cast shadows
|
||||
|
||||
(_shadowMesh, _shadowMeshFilter) = ShadowCloneManager.InstantiateShadowClone(_mainMesh);
|
||||
_shadowMesh.forceRenderingOff = true;
|
||||
_shadowMesh.shadowCastingMode = ShadowCastingMode.Off; // shadow mesh doesn't cast shadows
|
||||
_shadowMesh.forceRenderingOff = false;
|
||||
|
||||
|
||||
_rootBone = _mainMesh.rootBone;
|
||||
_rootBone ??= _mainMesh.transform; // fallback to transform if no root bone
|
||||
|
@ -133,6 +153,8 @@ public class SkinnedShadowClone : IShadowClone
|
|||
_graphicsBuffer = null;
|
||||
_targetBuffer?.Dispose();
|
||||
_targetBuffer = null;
|
||||
_computeBuffer?.Dispose();
|
||||
_computeBuffer = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -151,7 +173,7 @@ public class SkinnedShadowClone : IShadowClone
|
|||
if (mesh.HasVertexAttribute(VertexAttribute.Tangent)) _bufferLayout += 4;
|
||||
_bufferLayout *= 4; // 4 bytes per float
|
||||
|
||||
const float xThreadGroups = 64f;
|
||||
const float xThreadGroups = 32f;
|
||||
_threadGroups = Mathf.CeilToInt(mesh.vertexCount / xThreadGroups);
|
||||
|
||||
_mainMesh.vertexBufferTarget |= GraphicsBuffer.Target.Raw;
|
||||
|
@ -162,10 +184,66 @@ public class SkinnedShadowClone : IShadowClone
|
|||
//Debug.Log($"Initialized! BufferLayout: {_bufferLayout}, GraphicsBuffer: {_graphicsBuffer != null}, TargetBuffer: {_targetBuffer != null}");
|
||||
}
|
||||
|
||||
public static void FindExclusionVertList(SkinnedMeshRenderer renderer, FPRExclusion exclusion)
|
||||
{
|
||||
var boneWeights = renderer.sharedMesh.boneWeights;
|
||||
|
||||
HashSet<int> weights = new();
|
||||
for (int i = 0; i < renderer.bones.Length; i++)
|
||||
{
|
||||
if (exclusion.affectedChildren.Contains(renderer.bones[i]))
|
||||
weights.Add(i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < boneWeights.Length; i++)
|
||||
{
|
||||
BoneWeight weight = boneWeights[i];
|
||||
|
||||
Transform bone = null;
|
||||
const float minWeightThreshold = 0.2f;
|
||||
if (weights.Contains(weight.boneIndex0) && weight.weight0 > minWeightThreshold)
|
||||
bone = renderer.bones[weight.boneIndex0];
|
||||
else if (weights.Contains(weight.boneIndex1) && weight.weight1 > minWeightThreshold)
|
||||
bone = renderer.bones[weight.boneIndex1];
|
||||
else if (weights.Contains(weight.boneIndex2) && weight.weight2 > minWeightThreshold)
|
||||
bone = renderer.bones[weight.boneIndex2];
|
||||
else if (weights.Contains(weight.boneIndex3) && weight.weight3 > minWeightThreshold)
|
||||
bone = renderer.bones[weight.boneIndex3];
|
||||
|
||||
exclusion.affectedVertexIndices.Add(bone != null ? i : -1);
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetMainMesh()
|
||||
{
|
||||
_mainMesh.shadowCastingMode = ShadowCastingMode.On;
|
||||
_mainMesh.forceRenderingOff = false;
|
||||
|
||||
_shadowMesh.transform.position = Vector3.positiveInfinity; // nan
|
||||
}
|
||||
|
||||
private void ResetShadowClone()
|
||||
{
|
||||
_shadowMesh.shadowCastingMode = ShadowCastingMode.ShadowsOnly;
|
||||
_shadowMesh.forceRenderingOff = !_shouldCastShadows;
|
||||
if (ShadowCloneManager.s_DebugShowShadow)
|
||||
{
|
||||
_mainMesh.shadowCastingMode = ShadowCastingMode.ShadowsOnly;
|
||||
_mainMesh.forceRenderingOff = false;
|
||||
|
||||
_shadowMesh.shadowCastingMode = ShadowCastingMode.On;
|
||||
_shadowMesh.forceRenderingOff = false;
|
||||
|
||||
_shadowMesh.transform.localPosition = Vector3.zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
_mainMesh.shadowCastingMode = ShadowCastingMode.On;
|
||||
_mainMesh.forceRenderingOff = false;
|
||||
|
||||
_shadowMesh.shadowCastingMode = ShadowCastingMode.ShadowsOnly;
|
||||
_shadowMesh.forceRenderingOff = !_shouldCastShadows;
|
||||
}
|
||||
|
||||
//_shadowMesh.enabled = true;
|
||||
|
||||
// shadow casting needs clone to have original materials (uv discard)
|
||||
// we also want to respect material swaps... but this is fucking slow :(
|
||||
|
@ -173,12 +251,7 @@ public class SkinnedShadowClone : IShadowClone
|
|||
if (!ShadowCloneManager.s_CopyMaterialsToShadow)
|
||||
return;
|
||||
|
||||
if (_hasShadowMaterials)
|
||||
{
|
||||
_shadowMesh.sharedMaterials = _mainMesh.sharedMaterials;
|
||||
_hasShadowMaterials = false;
|
||||
}
|
||||
|
||||
_shadowMesh.sharedMaterials = _mainMesh.sharedMaterials;
|
||||
UpdateCloneMaterialProperties();
|
||||
}
|
||||
|
||||
|
@ -188,12 +261,10 @@ public class SkinnedShadowClone : IShadowClone
|
|||
_shadowMesh.forceRenderingOff = false;
|
||||
|
||||
// UI culling needs clone to have write-to-depth shader
|
||||
if (_hasShadowMaterials) return;
|
||||
_shadowMesh.sharedMaterials = _shadowMaterials;
|
||||
_hasShadowMaterials = true;
|
||||
|
||||
// Not needed- MaterialPropertyBlock applied to renderer in RenderForShadow
|
||||
//UpdateCloneMaterialProperties();
|
||||
UpdateCloneMaterialProperties();
|
||||
}
|
||||
|
||||
private void RenderShadowClone()
|
||||
|
@ -205,6 +276,10 @@ public class SkinnedShadowClone : IShadowClone
|
|||
ShadowCloneHelper.shader.SetMatrix(s_SourceRootMatrix, rootMatrix);
|
||||
ShadowCloneHelper.shader.SetBuffer(0, s_SourceBufferId, _graphicsBuffer);
|
||||
ShadowCloneHelper.shader.SetBuffer(0, s_TargetBufferId, _targetBuffer);
|
||||
|
||||
ShadowCloneHelper.shader.SetBuffer(0, s_HiddenVerticiesId, _computeBuffer);
|
||||
ShadowCloneHelper.shader.SetVector(s_HiddenVertexPos, Vector4.positiveInfinity); // temp
|
||||
|
||||
ShadowCloneHelper.shader.SetInt(s_SourceBufferLayoutId, _bufferLayout);
|
||||
ShadowCloneHelper.shader.Dispatch(0, _threadGroups, 1, 1);
|
||||
_graphicsBuffer.Release();
|
||||
|
|
|
@ -35,11 +35,14 @@ public class ShadowCloneManager : MonoBehaviour
|
|||
|
||||
// Settings
|
||||
internal static bool s_CopyMaterialsToShadow = true;
|
||||
internal static bool s_DebugShowShadow = false;
|
||||
internal static bool s_DebugShowInFront = false;
|
||||
private static bool s_UseShadowToCullUi;
|
||||
private const string ShadowCullUiSettingName = "ExperimentalAvatarOverrenderUI";
|
||||
|
||||
// Implementation
|
||||
private bool _hasRenderedThisFrame;
|
||||
public static readonly List<FPRExclusion> s_Exclusions = new();
|
||||
|
||||
// Shadow Clones
|
||||
private readonly List<IShadowClone> s_ShadowClones = new();
|
||||
|
@ -64,15 +67,17 @@ public class ShadowCloneManager : MonoBehaviour
|
|||
UpdatePlayerCameras();
|
||||
|
||||
s_CopyMaterialsToShadow = ModSettings.EntryCopyMaterialToShadow.Value;
|
||||
s_DebugShowShadow = ModSettings.EntryDebugShowShadow.Value;
|
||||
s_DebugShowInFront = ModSettings.EntryDebugShowInFront.Value;
|
||||
s_UseShadowToCullUi = MetaPort.Instance.settings.GetSettingsBool(ShadowCullUiSettingName);
|
||||
MetaPort.Instance.settings.settingBoolChanged.AddListener(OnSettingsBoolChanged);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
=> Camera.onPreCull += MyOnPreCull;
|
||||
=> Camera.onPreRender += MyOnPreCull;
|
||||
|
||||
private void OnDisable()
|
||||
=> Camera.onPreCull -= MyOnPreCull;
|
||||
=> Camera.onPreRender -= MyOnPreCull;
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
|
@ -86,12 +91,25 @@ public class ShadowCloneManager : MonoBehaviour
|
|||
private void Update()
|
||||
{
|
||||
_hasRenderedThisFrame = false;
|
||||
|
||||
for (int i = s_ShadowClones.Count - 1; i >= 0; i--)
|
||||
{
|
||||
IShadowClone clone = s_ShadowClones[i];
|
||||
if (clone is not { IsValid: true })
|
||||
{
|
||||
clone?.Dispose();
|
||||
s_ShadowClones.RemoveAt(i);
|
||||
continue; // invalid or dead
|
||||
}
|
||||
|
||||
clone.ResetMainMesh();
|
||||
}
|
||||
}
|
||||
|
||||
private void MyOnPreCull(Camera cam)
|
||||
{
|
||||
bool forceRenderForUiCull = s_UseShadowToCullUi && cam == s_UiCamera;
|
||||
if (_hasRenderedThisFrame && !forceRenderForUiCull)
|
||||
//bool forceRenderForUiCull = s_UseShadowToCullUi && cam == s_UiCamera;
|
||||
if (cam != s_MainCamera)
|
||||
return;
|
||||
|
||||
_hasRenderedThisFrame = true;
|
||||
|
@ -109,17 +127,13 @@ public class ShadowCloneManager : MonoBehaviour
|
|||
}
|
||||
|
||||
if (!clone.Process()) continue; // not ready yet or disabled
|
||||
|
||||
if (forceRenderForUiCull)
|
||||
clone.RenderForUiCulling(); // last cam to render
|
||||
else
|
||||
clone.RenderForShadow(); // first cam to render
|
||||
|
||||
clone.RenderForShadow(); // first cam to render
|
||||
}
|
||||
|
||||
_stopWatch.Stop();
|
||||
if (_debugShadowProcessingTime) Debug.Log($"ShadowCloneManager.MyOnPreCull({forceRenderForUiCull}) took {_stopWatch.ElapsedMilliseconds}ms");
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Game Events
|
||||
|
@ -136,7 +150,12 @@ public class ShadowCloneManager : MonoBehaviour
|
|||
private void OnSettingsBoolChanged(string settingName, bool settingValue)
|
||||
{
|
||||
if (settingName == ShadowCullUiSettingName)
|
||||
{
|
||||
s_UseShadowToCullUi = settingValue;
|
||||
s_UiCamera.cullingMask = settingValue // make UI camera not see CVRLayers.PlayerClone
|
||||
? s_UiCamera.cullingMask | (1 << CVRLayers.PlayerClone)
|
||||
: s_UiCamera.cullingMask & ~(1 << CVRLayers.PlayerClone);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnVRModeSwitchCompleted(bool _, Camera __)
|
||||
|
@ -152,6 +171,7 @@ public class ShadowCloneManager : MonoBehaviour
|
|||
{
|
||||
s_MainCamera = PlayerSetup.Instance.GetActiveCamera().GetComponent<Camera>();
|
||||
s_UiCamera = s_MainCamera.transform.Find("_UICamera").GetComponent<Camera>();
|
||||
|
||||
//s_PortableCamera = PortableCamera.Instance.cameraComponent;
|
||||
}
|
||||
|
||||
|
@ -159,11 +179,11 @@ public class ShadowCloneManager : MonoBehaviour
|
|||
|
||||
#region Static Helpers
|
||||
|
||||
internal static IShadowClone CreateShadowClone(Renderer renderer)
|
||||
internal static IShadowClone CreateShadowClone(Renderer renderer, FPRExclusion exclusion)
|
||||
{
|
||||
return renderer switch
|
||||
{
|
||||
SkinnedMeshRenderer skinnedMeshRenderer => new SkinnedShadowClone(skinnedMeshRenderer),
|
||||
SkinnedMeshRenderer skinnedMeshRenderer => new SkinnedShadowClone(skinnedMeshRenderer, exclusion),
|
||||
MeshRenderer meshRenderer => new MeshShadowClone(meshRenderer),
|
||||
_ => null
|
||||
};
|
||||
|
@ -175,6 +195,14 @@ public class ShadowCloneManager : MonoBehaviour
|
|||
shadowClone.transform.SetParent(meshRenderer.transform, false);
|
||||
shadowClone.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity);
|
||||
shadowClone.transform.localScale = Vector3.one;
|
||||
|
||||
if (s_DebugShowShadow && s_DebugShowInFront)
|
||||
{
|
||||
float scale = PlayerSetup.Instance.GetPlaySpaceScale();
|
||||
Transform playerTransform = PlayerSetup.Instance.transform;
|
||||
shadowClone.transform.position += playerTransform.forward * scale * 1f;
|
||||
shadowClone.transform.rotation = Quaternion.AngleAxis(180f, playerTransform.up) * shadowClone.transform.rotation;
|
||||
}
|
||||
|
||||
MeshRenderer newMesh = shadowClone.AddComponent<MeshRenderer>();
|
||||
MeshFilter newMeshFilter = shadowClone.AddComponent<MeshFilter>();
|
||||
|
@ -188,6 +216,9 @@ public class ShadowCloneManager : MonoBehaviour
|
|||
newMeshFilter.sharedMesh = meshRenderer.sharedMesh;
|
||||
newMesh.sharedMaterials = meshRenderer.sharedMaterials;
|
||||
|
||||
// copy probe anchor
|
||||
newMesh.probeAnchor = meshRenderer.probeAnchor;
|
||||
|
||||
return (newMesh, newMeshFilter);
|
||||
}
|
||||
|
||||
|
@ -209,6 +240,9 @@ public class ShadowCloneManager : MonoBehaviour
|
|||
// copy mesh and materials
|
||||
newMeshFilter.sharedMesh = meshRenderer.GetComponent<MeshFilter>().sharedMesh;
|
||||
newMesh.sharedMaterials = meshRenderer.sharedMaterials;
|
||||
|
||||
// copy probe anchor
|
||||
newMesh.probeAnchor = meshRenderer.probeAnchor;
|
||||
|
||||
return (newMesh, newMeshFilter);
|
||||
}
|
||||
|
|
|
@ -39,6 +39,8 @@ public static class ShadowCloneHelper
|
|||
return;
|
||||
}
|
||||
|
||||
ShadowCloneMod.Logger.Msg($"Found {renderers.Length} renderers. Processing...");
|
||||
|
||||
// create shadow clones
|
||||
ProcessRenderers(renderers, avatar.transform, headBone);
|
||||
}
|
||||
|
@ -48,6 +50,7 @@ public static class ShadowCloneHelper
|
|||
Stopwatch sw = Stopwatch.StartNew();
|
||||
|
||||
IReadOnlyDictionary<Transform, FPRExclusion> exclusions = CollectTransformToExclusionMap(root, headBone);
|
||||
var exclusion = headBone.gameObject.GetComponent<FPRExclusion>();
|
||||
|
||||
// log current time
|
||||
ShadowCloneMod.Logger.Msg($"CollectTransformToExclusionMap in {sw.ElapsedMilliseconds}ms");
|
||||
|
@ -58,12 +61,12 @@ public static class ShadowCloneHelper
|
|||
|
||||
if (ModSettings.EntryUseShadowClone.Value)
|
||||
{
|
||||
IShadowClone clone = ShadowCloneManager.CreateShadowClone(renderer);
|
||||
IShadowClone clone = ShadowCloneManager.CreateShadowClone(renderer, exclusion);
|
||||
if (clone != null) ShadowCloneManager.Instance.AddShadowClone(clone);
|
||||
}
|
||||
|
||||
ITransformHider hider = TransformHiderManager.CreateTransformHider(renderer, exclusions);
|
||||
if (hider != null) TransformHiderManager.Instance.AddTransformHider(hider);
|
||||
// ITransformHider hider = TransformHiderManager.CreateTransformHider(renderer, exclusions);
|
||||
// if (hider != null) TransformHiderManager.Instance.AddTransformHider(hider);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
|
@ -143,9 +146,9 @@ public static class ShadowCloneHelper
|
|||
// shadow clone optimizations (always MeshRenderer)
|
||||
if (isShadowClone)
|
||||
{
|
||||
renderer.receiveShadows = false;
|
||||
renderer.lightProbeUsage = LightProbeUsage.Off;
|
||||
renderer.reflectionProbeUsage = ReflectionProbeUsage.Off;
|
||||
// renderer.receiveShadows = false;
|
||||
// renderer.lightProbeUsage = LightProbeUsage.Off;
|
||||
// renderer.reflectionProbeUsage = ReflectionProbeUsage.Off;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
BIN
BetterShadowClone_LegacyHideAttempt.7z
Normal file
BIN
BetterShadowClone_LegacyHideAttempt.7z
Normal file
Binary file not shown.
2
FuckCameraIndicator/FuckCameraIndicator.csproj
Normal file
2
FuckCameraIndicator/FuckCameraIndicator.csproj
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk" />
|
34
FuckCameraIndicator/Main.cs
Normal file
34
FuckCameraIndicator/Main.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
using MelonLoader;
|
||||
using System.Reflection;
|
||||
using ABI_RC.Core.Player;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NAK.FuckCameraIndicator;
|
||||
|
||||
public class FuckCameraIndicator : MelonMod
|
||||
{
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PuppetMaster).GetMethod(nameof(PuppetMaster.Start), BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
postfix: new HarmonyLib.HarmonyMethod(typeof(FuckCameraIndicator).GetMethod(nameof(OnPuppetMasterStart_Postfix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
}
|
||||
|
||||
private static void OnPuppetMasterStart_Postfix(PuppetMaster __instance)
|
||||
{
|
||||
// thanks for not making it modular, fucking spaghetti
|
||||
// and why leave it a skinned mesh... lazy fucking implementation
|
||||
|
||||
GameObject indicator = __instance.cameraIndicator;
|
||||
GameObject lens = __instance.cameraIndicatorLense;
|
||||
|
||||
// Disable NamePlate child object
|
||||
const string c_CanvasPath = "[NamePlate]/Canvas";
|
||||
GameObject canvas = indicator.transform.Find(c_CanvasPath).gameObject;
|
||||
canvas.SetActive(false);
|
||||
|
||||
// Disable lens renderer
|
||||
lens.GetComponent<SkinnedMeshRenderer>().forceRenderingOff = true;
|
||||
}
|
||||
}
|
29
FuckCameraIndicator/Properties/AssemblyInfo.cs
Normal file
29
FuckCameraIndicator/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,29 @@
|
|||
using MelonLoader;
|
||||
using NAK.FuckCameraIndicator.Properties;
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyTitle(nameof(NAK.FuckCameraIndicator))]
|
||||
[assembly: AssemblyCompany(AssemblyInfoParams.Author)]
|
||||
[assembly: AssemblyProduct(nameof(NAK.FuckCameraIndicator))]
|
||||
|
||||
[assembly: MelonInfo(
|
||||
typeof(NAK.FuckCameraIndicator.FuckCameraIndicator),
|
||||
nameof(NAK.FuckCameraIndicator),
|
||||
AssemblyInfoParams.Version,
|
||||
AssemblyInfoParams.Author,
|
||||
downloadLink: "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/FuckCameraIndicator"
|
||||
)]
|
||||
|
||||
[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")]
|
||||
[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||
[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
||||
|
||||
namespace NAK.FuckCameraIndicator.Properties;
|
||||
internal static class AssemblyInfoParams
|
||||
{
|
||||
public const string Version = "1.0.0";
|
||||
public const string Author = "NotAKidoS";
|
||||
}
|
16
FuckCameraIndicator/README.md
Normal file
16
FuckCameraIndicator/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
FuckCameraIndicator/format.json
Normal file
23
FuckCameraIndicator/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"
|
||||
}
|
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"
|
||||
}
|
|
@ -35,6 +35,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MirrorClone", "MirrorClone\
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BetterShadowClone", "BetterShadowClone\BetterShadowClone.csproj", "{D0C40987-AF16-490A-9304-F99D5A5A774C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FuckCameraIndicator", "FuckCameraIndicator\FuckCameraIndicator.csproj", "{0BE10630-EA6A-40FB-B3AF-5C2018F22BD3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YouAreAClone", "YouAreAClone\YouAreAClone.csproj", "{7778B600-111E-4C8B-AE2B-E9750CECE02A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nevermind", "Nevermind\Nevermind.csproj", "{AC4857DD-F6D9-436D-A3EE-D148A518E642}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -105,6 +111,18 @@ Global
|
|||
{D0C40987-AF16-490A-9304-F99D5A5A774C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D0C40987-AF16-490A-9304-F99D5A5A774C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D0C40987-AF16-490A-9304-F99D5A5A774C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0BE10630-EA6A-40FB-B3AF-5C2018F22BD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0BE10630-EA6A-40FB-B3AF-5C2018F22BD3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0BE10630-EA6A-40FB-B3AF-5C2018F22BD3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0BE10630-EA6A-40FB-B3AF-5C2018F22BD3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7778B600-111E-4C8B-AE2B-E9750CECE02A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7778B600-111E-4C8B-AE2B-E9750CECE02A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7778B600-111E-4C8B-AE2B-E9750CECE02A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7778B600-111E-4C8B-AE2B-E9750CECE02A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AC4857DD-F6D9-436D-A3EE-D148A518E642}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AC4857DD-F6D9-436D-A3EE-D148A518E642}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AC4857DD-F6D9-436D-A3EE-D148A518E642}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AC4857DD-F6D9-436D-A3EE-D148A518E642}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
53
Nevermind/Main.cs
Normal file
53
Nevermind/Main.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
using ABI_RC.Core.InteractionSystem;
|
||||
using ABI_RC.Core.IO;
|
||||
using MelonLoader;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NAK.Nevermind;
|
||||
|
||||
public class Nevermind : MelonMod
|
||||
{
|
||||
#region Mod Settings
|
||||
|
||||
private static readonly MelonPreferences_Category Category =
|
||||
MelonPreferences.CreateCategory(nameof(Nevermind));
|
||||
|
||||
private static readonly MelonPreferences_Entry<KeyCode> Setting_NevermindKey =
|
||||
Category.CreateEntry("Keybind", KeyCode.Home, description: "Key to cancel world join.");
|
||||
|
||||
#endregion
|
||||
|
||||
#region Melon Events
|
||||
|
||||
public override void OnUpdate()
|
||||
{
|
||||
if (!Input.GetKeyDown(Setting_NevermindKey.Value))
|
||||
return;
|
||||
|
||||
if (CVRObjectLoader.Instance == null
|
||||
|| CVRDownloadManager.Instance == null)
|
||||
return; // game is not ready
|
||||
|
||||
if (!CVRObjectLoader.Instance.IsLoadingWorldToJoin())
|
||||
return; // no world to cancel
|
||||
|
||||
if (CVRObjectLoader.Instance.WorldBundleRequest != null)
|
||||
return; // too late to cancel, world is being loaded
|
||||
|
||||
// Cancel world join if still downloading
|
||||
CVRDownloadManager.Instance.ActiveWorldDownload = false;
|
||||
foreach (var download in CVRDownloadManager.Instance._downloadTasks)
|
||||
download.Value.JoinOnComplete = false;
|
||||
|
||||
// Cancel world join if still loading
|
||||
CVRObjectLoader.Instance.ActiveWorldDownload = null;
|
||||
CVRObjectLoader.Instance._isLoadingWorldToJoin = false;
|
||||
CVRObjectLoader.Instance.worldLoadingState = CVRObjectLoader.WorldLoadingState.None;
|
||||
|
||||
// Notify user of successful cancellation
|
||||
LoggerInstance.Msg("World Join Cancelled!");
|
||||
ViewManager.Instance.NotifyUser("(Local) Client", "World Join Cancelled", 2f);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using Nevermind.Properties;
|
||||
using NAK.Nevermind.Properties;
|
||||
using MelonLoader;
|
||||
using System.Reflection;
|
||||
|
||||
|
@ -20,10 +20,9 @@ using System.Reflection;
|
|||
[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")]
|
||||
[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||
[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
||||
[assembly: MelonOptionalDependencies("BTKUILib")]
|
||||
[assembly: HarmonyDontPatchAll]
|
||||
|
||||
namespace Nevermind.Properties;
|
||||
namespace NAK.Nevermind.Properties;
|
||||
internal static class AssemblyInfoParams
|
||||
{
|
||||
public const string Version = "1.0.0";
|
23
Nevermind/format.json
Normal file
23
Nevermind/format.json
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"_id": -1,
|
||||
"name": "Nevermind",
|
||||
"modversion": "1.0.0",
|
||||
"gameversion": "2024r174",
|
||||
"loaderversion": "0.6.1",
|
||||
"modtype": "Mod",
|
||||
"author": "NotAKidoS",
|
||||
"description": "Simple mod that allows you to cancel joining a world in Desktop.",
|
||||
"searchtags": [
|
||||
"never",
|
||||
"mind",
|
||||
"download",
|
||||
"cancel"
|
||||
],
|
||||
"requirements": [
|
||||
"None"
|
||||
],
|
||||
"downloadlink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/download/r25/Nevermind.dll",
|
||||
"sourcelink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/Nevermind/",
|
||||
"changelog": "- Initial Release",
|
||||
"embedcolor": "#b589ec"
|
||||
}
|
|
@ -23,32 +23,33 @@ public class ObjectSyncBridge : MonoBehaviour
|
|||
_physicsGun.OnPreGrabbedObject = o =>
|
||||
{
|
||||
bool canTakeOwnership = false;
|
||||
|
||||
|
||||
//
|
||||
CVRObjectSync objectSync = o.GetComponentInParent<CVRObjectSync>();
|
||||
if (objectSync != null
|
||||
&& (objectSync.SyncType == 0 // check if physics synced or synced by us
|
||||
|| objectSync.SyncedByMe))
|
||||
canTakeOwnership = true;
|
||||
|
||||
// if (objectSync != null
|
||||
// && (objectSync.SyncType == 0 // check if physics synced or synced by us
|
||||
// || objectSync.SyncedByMe))
|
||||
// canTakeOwnership = true;
|
||||
//
|
||||
CVRSpawnable spawnable = o.GetComponentInParent<CVRSpawnable>();
|
||||
if (spawnable != null)
|
||||
{
|
||||
CVRSyncHelper.PropData propData = CVRSyncHelper.Props.Find(match => match.InstanceId == spawnable.instanceId);
|
||||
if (propData != null
|
||||
&& (propData.syncType == 0 // check if physics synced or synced by us
|
||||
|| propData.syncedBy == MetaPort.Instance.ownerId))
|
||||
canTakeOwnership = true;
|
||||
}
|
||||
|
||||
// if (spawnable != null)
|
||||
// {
|
||||
// CVRSyncHelper.PropData propData = CVRSyncHelper.Props.Find(match => match.InstanceId == spawnable.instanceId);
|
||||
// if (propData != null
|
||||
// && (propData.syncType == 0 // check if physics synced or synced by us
|
||||
// || propData.syncedBy == MetaPort.Instance.ownerId))
|
||||
// canTakeOwnership = true;
|
||||
// }
|
||||
//
|
||||
CVRPickupObject pickup = o.GetComponentInParent<CVRPickupObject>();
|
||||
if (pickup != null
|
||||
&& (pickup.grabbedBy == MetaPort.Instance.ownerId // check if already grabbed by us
|
||||
|| pickup.grabbedBy == "" || !pickup.disallowTheft)) // check if not grabbed or allows theft
|
||||
canTakeOwnership = true;
|
||||
|
||||
if (!canTakeOwnership // if we can't take ownership, don't grab, unless there is no syncing at all (local object)
|
||||
&& (objectSync || spawnable || pickup ))
|
||||
return false;
|
||||
// if (pickup != null
|
||||
// && (pickup.grabbedBy == MetaPort.Instance.ownerId // check if already grabbed by us
|
||||
// || pickup.grabbedBy == "" || !pickup.disallowTheft)) // check if not grabbed or allows theft
|
||||
// canTakeOwnership = true;
|
||||
//
|
||||
// if (!canTakeOwnership // if we can't take ownership, don't grab, unless there is no syncing at all (local object)
|
||||
// && (objectSync || spawnable || pickup ))
|
||||
// return false;
|
||||
|
||||
if (pickup)
|
||||
{
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"_id": 147,
|
||||
"name": "PropUndoButton",
|
||||
"modversion": "1.0.1",
|
||||
"gameversion": "2022r170p1",
|
||||
"modversion": "1.0.2",
|
||||
"gameversion": "2024r175",
|
||||
"loaderversion": "0.6.1",
|
||||
"modtype": "Mod",
|
||||
"author": "NotAKidoS",
|
||||
|
@ -16,8 +16,8 @@
|
|||
"requirements": [
|
||||
"None"
|
||||
],
|
||||
"downloadlink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/download/r3/PropUndoButton.dll",
|
||||
"downloadlink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/download/r25/PropUndoButton.dll",
|
||||
"sourcelink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/PropUndoButton/",
|
||||
"changelog": "- Initial Release\n- Added redo button.\n- Mitigated issue of props getting stuck locally if deleting them before they fully spawn.\n- Lowered SFX volume to match existing UI sounds.",
|
||||
"changelog": "- Recompiled for 2024r175",
|
||||
"embedcolor": "#00FFFF"
|
||||
}
|
|
@ -70,7 +70,7 @@ internal static class CameraLogic
|
|||
return;
|
||||
|
||||
ThirdPerson.Logger.Msg("Copying active camera settings & components.");
|
||||
CVRTools.CopyToDestCam(activePlayerCam, _thirdPersonCam);
|
||||
CVRTools.CopyToDestCam(activePlayerCam, _thirdPersonCam, true);
|
||||
|
||||
if (!CheckIsRestricted())
|
||||
return;
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
using NAK.BetterShadowClone;
|
||||
|
||||
namespace NAK.ThirdPerson.Integrations;
|
||||
|
||||
public static class BSCAddon
|
||||
{
|
||||
public static void Initialize()
|
||||
{
|
||||
ShadowCloneMod.wantsToHideHead += CameraLogic.ShouldNotHideHead_ThirdPerson;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
using MelonLoader;
|
||||
using NAK.ThirdPerson.Properties;
|
||||
using System.Reflection;
|
||||
using CurvedUI;
|
||||
|
||||
[assembly: AssemblyVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)]
|
||||
|
@ -24,11 +23,10 @@ using CurvedUI;
|
|||
[assembly: MelonColor(255, 246, 25, 97)]
|
||||
[assembly: MelonAuthorColor(255, 158, 21, 32)]
|
||||
[assembly: HarmonyDontPatchAll]
|
||||
[assembly: MelonOptionalDependencies("BetterShadowClone")]
|
||||
|
||||
namespace NAK.ThirdPerson.Properties;
|
||||
internal static class AssemblyInfoParams
|
||||
{
|
||||
public const string Version = "1.0.7";
|
||||
public const string Version = "1.0.8";
|
||||
public const string Author = "Davi & NotAKidoS";
|
||||
}
|
|
@ -14,17 +14,6 @@ public class ThirdPerson : MelonMod
|
|||
|
||||
Patches.Apply(HarmonyInstance);
|
||||
MelonCoroutines.Start(SetupCamera());
|
||||
|
||||
InitializeIntegration("BetterShadowClone", Integrations.BSCAddon.Initialize);
|
||||
}
|
||||
|
||||
private static void InitializeIntegration(string modName, Action integrationAction)
|
||||
{
|
||||
if (RegisteredMelons.All(it => it.Info.Name != modName))
|
||||
return;
|
||||
|
||||
Logger.Msg($"Initializing {modName} integration.");
|
||||
integrationAction.Invoke();
|
||||
}
|
||||
|
||||
public override void OnUpdate()
|
||||
|
|
|
@ -1,6 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BetterShadowClone\BetterShadowClone.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
<Project Sdk="Microsoft.NET.Sdk" />
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
{
|
||||
"_id": 16,
|
||||
"name": "ThirdPerson",
|
||||
"modversion": "1.0.7",
|
||||
"gameversion": "2023r173",
|
||||
"modversion": "1.0.8",
|
||||
"gameversion": "2024r175",
|
||||
"loaderversion": "0.6.1",
|
||||
"modtype": "Mod",
|
||||
"author": "Davi & NotAKidoS",
|
||||
|
@ -14,9 +14,9 @@
|
|||
"third person"
|
||||
],
|
||||
"requirements": [],
|
||||
"downloadlink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/download/r23/ThirdPerson.dll",
|
||||
"downloadlink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/download/r25/ThirdPerson.dll",
|
||||
"sourcelink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/ThirdPerson",
|
||||
"changelog": "- Added restriction to worlds with Zoom disabled.",
|
||||
"changelog": "- Recompiled to work with 2024r175",
|
||||
"embedcolor": "#F61961"
|
||||
}
|
||||
]
|
119
YouAreAClone/Main.cs
Normal file
119
YouAreAClone/Main.cs
Normal file
|
@ -0,0 +1,119 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using MelonLoader;
|
||||
using System.Reflection;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Util;
|
||||
using ABI_RC.Core.Util.AssetFiltering;
|
||||
using ABI_RC.Systems.Camera;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NAK.YouAreAClone;
|
||||
|
||||
public class YouAreAClone : MelonMod
|
||||
{
|
||||
internal static MelonLogger.Instance Logger;
|
||||
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
Logger = LoggerInstance;
|
||||
|
||||
//VRModeSwitchEvents.OnCompletedVRModeSwitch.AddListener(_ => FindCameras());
|
||||
|
||||
SharedFilter._avatarWhitelist.Add(typeof(FPRExclusion));
|
||||
SharedFilter._localComponentWhitelist.Add(typeof(FPRExclusion));
|
||||
|
||||
try
|
||||
{
|
||||
LoadAssetBundle();
|
||||
InitializePatches();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
#region Asset Bundle Loading
|
||||
|
||||
private const string YouAreACloneAssets = "YouAreAClone.assets";
|
||||
|
||||
private const string BoneHiderComputePath = "Assets/Koneko/ComputeShaders/BoneHider.compute";
|
||||
//private const string MeshCopyComputePath = "Assets/Koneko/ComputeShaders/MeshCopy.compute";
|
||||
|
||||
private const string ShadowCloneComputePath = "Assets/NotAKid/Shaders/ShadowClone.compute";
|
||||
private const string ShadowCloneShaderPath = "Assets/NotAKid/Shaders/ShadowClone.shader";
|
||||
private const string DummyCloneShaderPath = "Assets/NotAKid/Shaders/DummyClone.shader";
|
||||
|
||||
private void LoadAssetBundle()
|
||||
{
|
||||
Logger.Msg($"Loading required asset bundle...");
|
||||
using Stream resourceStream = MelonAssembly.Assembly.GetManifestResourceStream(YouAreACloneAssets);
|
||||
using MemoryStream memoryStream = new();
|
||||
if (resourceStream == null) {
|
||||
Logger.Error($"Failed to load {YouAreACloneAssets}!");
|
||||
return;
|
||||
}
|
||||
|
||||
resourceStream.CopyTo(memoryStream);
|
||||
AssetBundle assetBundle = AssetBundle.LoadFromMemory(memoryStream.ToArray());
|
||||
if (assetBundle == null) {
|
||||
Logger.Error($"Failed to load {YouAreACloneAssets}! Asset bundle is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
// load shaders
|
||||
ComputeShader shader = assetBundle.LoadAsset<ComputeShader>(BoneHiderComputePath);
|
||||
shader.hideFlags |= HideFlags.DontUnloadUnusedAsset;
|
||||
TransformHiderManager.shader = shader;
|
||||
Logger.Msg($"Loaded {BoneHiderComputePath}!");
|
||||
|
||||
// load shadow clone shader
|
||||
ComputeShader shadowCloneCompute = assetBundle.LoadAsset<ComputeShader>(ShadowCloneComputePath);
|
||||
shadowCloneCompute.hideFlags |= HideFlags.DontUnloadUnusedAsset;
|
||||
ShadowCloneHelper.shader = shadowCloneCompute;
|
||||
Logger.Msg($"Loaded {ShadowCloneComputePath}!");
|
||||
|
||||
// load shadow clone material
|
||||
Shader shadowCloneShader = assetBundle.LoadAsset<Shader>(ShadowCloneShaderPath);
|
||||
shadowCloneShader.hideFlags |= HideFlags.DontUnloadUnusedAsset;
|
||||
ShadowCloneHelper.shadowMaterial = new Material(shadowCloneShader);
|
||||
Logger.Msg($"Loaded {ShadowCloneShaderPath}!");
|
||||
|
||||
Logger.Msg("Asset bundle successfully loaded!");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Harmony Patches
|
||||
|
||||
private void InitializePatches()
|
||||
{
|
||||
HarmonyInstance.Patch(
|
||||
typeof(TransformHiderForMainCamera).GetMethod(nameof(TransformHiderForMainCamera.ProcessHierarchy)),
|
||||
prefix: new HarmonyLib.HarmonyMethod(typeof(YouAreAClone).GetMethod(nameof(OnTransformHiderForMainCamera_ProcessHierarchy_Prefix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)),
|
||||
prefix: new HarmonyLib.HarmonyMethod(typeof(YouAreAClone).GetMethod(nameof(OnPlayerSetup_ClearAvatar_Prefix), BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
}
|
||||
|
||||
private static void OnPlayerSetup_ClearAvatar_Prefix()
|
||||
{
|
||||
TransformHiderManager.Instance.OnAvatarCleared();
|
||||
ShadowCloneManager.Instance.OnAvatarCleared();
|
||||
}
|
||||
|
||||
private static void OnTransformHiderForMainCamera_ProcessHierarchy_Prefix(ref bool __runOriginal)
|
||||
{
|
||||
if (!__runOriginal || (__runOriginal = !ModSettings.EntryEnabled.Value))
|
||||
return; // if something else disabled, or we are disabled, don't run
|
||||
|
||||
ShadowCloneHelper.SetupAvatar(PlayerSetup.Instance._avatar);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
60
YouAreAClone/ModSettings.cs
Normal file
60
YouAreAClone/ModSettings.cs
Normal file
|
@ -0,0 +1,60 @@
|
|||
using MelonLoader;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NAK.BetterShadowClone;
|
||||
|
||||
public static class ModSettings
|
||||
{
|
||||
#region Melon Prefs
|
||||
|
||||
private const string SettingsCategory = nameof(ShadowCloneMod);
|
||||
|
||||
private static readonly MelonPreferences_Category Category =
|
||||
MelonPreferences.CreateCategory(SettingsCategory);
|
||||
|
||||
internal static readonly MelonPreferences_Entry<bool> EntryEnabled =
|
||||
Category.CreateEntry("Enabled", true,
|
||||
description: "Enable Mirror Clone.");
|
||||
|
||||
internal static readonly MelonPreferences_Entry<bool> EntryUseShadowClone =
|
||||
Category.CreateEntry("Use Shadow Clone", true,
|
||||
description: "Should you have shadow clones?");
|
||||
|
||||
internal static readonly MelonPreferences_Entry<bool> EntryCopyMaterialToShadow =
|
||||
Category.CreateEntry("Copy Material to Shadow", true,
|
||||
description: "Should the shadow clone copy the material from the original mesh? Note: This can have a slight performance hit.");
|
||||
|
||||
internal static readonly MelonPreferences_Entry<bool> EntryDontRespectFPR =
|
||||
Category.CreateEntry("Dont Respect FPR", false,
|
||||
description: "Should the transform hider not respect FPR?");
|
||||
|
||||
internal static readonly MelonPreferences_Entry<bool> EntryDebugHeadHide =
|
||||
Category.CreateEntry("Debug Head Hide", false,
|
||||
description: "Should head be hidden for first render?");
|
||||
|
||||
internal static readonly MelonPreferences_Entry<bool> EntryDebugShowShadow =
|
||||
Category.CreateEntry("Debug Show Shadow", false,
|
||||
description: "Should the shadow clone be shown?");
|
||||
|
||||
internal static readonly MelonPreferences_Entry<bool> EntryDebugShowInFront =
|
||||
Category.CreateEntry("Debug Show in Front", false,
|
||||
description: "Should the shadow clone be shown in front?");
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
internal static void Initialize()
|
||||
{
|
||||
foreach (MelonPreferences_Entry setting in Category.Entries)
|
||||
setting.OnEntryValueChangedUntyped.Subscribe(OnSettingsChanged);
|
||||
}
|
||||
|
||||
private static void OnSettingsChanged(object oldValue = null, object newValue = null)
|
||||
{
|
||||
TransformHiderManager.s_DisallowFprExclusions = EntryDontRespectFPR.Value;
|
||||
TransformHiderManager.s_DebugHeadHide = EntryDebugHeadHide.Value;
|
||||
ShadowCloneManager.s_CopyMaterialsToShadow = EntryCopyMaterialToShadow.Value;
|
||||
ShadowCloneManager.s_DebugShowShadow = EntryDebugShowShadow.Value;
|
||||
ShadowCloneManager.s_DebugShowInFront = EntryDebugShowInFront.Value;
|
||||
}
|
||||
}
|
29
YouAreAClone/Properties/AssemblyInfo.cs
Normal file
29
YouAreAClone/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.ShadowCloneMod),
|
||||
nameof(NAK.BetterShadowClone),
|
||||
AssemblyInfoParams.Version,
|
||||
AssemblyInfoParams.Author,
|
||||
downloadLink: "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/ShadowCloneMod"
|
||||
)]
|
||||
|
||||
[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 & Exterrata";
|
||||
}
|
2
YouAreAClone/YouAreAClone.csproj
Normal file
2
YouAreAClone/YouAreAClone.csproj
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk" />
|
Loading…
Add table
Add a link
Reference in a new issue