From a1d73bf156aef3116aa123f39def61199ed214a2 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Fri, 6 Sep 2024 01:17:59 -0500 Subject: [PATCH] deleted unfinished mods --- BetterShadowClone/BetterShadowClone.csproj | 8 - BetterShadowClone/Koneko/BoneHider.cs | 130 -------- BetterShadowClone/Main.cs | 144 --------- BetterShadowClone/ModSettings.cs | 60 ---- BetterShadowClone/Properties/AssemblyInfo.cs | 29 -- BetterShadowClone/README.md | 16 - .../Resources/bettershadowclone.assets | Bin 9661 -> 0 bytes .../Resources/bettershadowclone.assets_OLD | Bin 9425 -> 0 bytes .../ShadowClone/IShadowClone/IShadowClone.cs | 12 - .../IShadowClone/MeshShadowClone.cs | 158 ---------- .../IShadowClone/SkinnedShadowClone.cs | 296 ------------------ .../ShadowClone/ShadowCloneManager.cs | 251 --------------- BetterShadowClone/ShadowCloneHelper.cs | 168 ---------- .../TransformHider/FPRExclusion.cs | 35 --- .../ITransformHider/ITransformHider.cs | 11 - .../ITransformHider/MeshTransformHider.cs | 98 ------ .../ITransformHider/SkinnedTransformHider.cs | 253 --------------- .../TransformHider/TransformHiderManager.cs | 213 ------------- BetterShadowClone/format.json | 23 -- .../FuckCameraIndicator.csproj | 2 - FuckCameraIndicator/Main.cs | 34 -- .../Properties/AssemblyInfo.cs | 29 -- FuckCameraIndicator/README.md | 16 - FuckCameraIndicator/format.json | 23 -- MirrorClone/Main.cs | 80 ----- MirrorClone/MirrorClone.csproj | 2 - MirrorClone/MirrorClone/MirrorCloneManager.cs | 247 --------------- MirrorClone/ModSettings.cs | 31 -- MirrorClone/Properties/AssemblyInfo.cs | 29 -- MirrorClone/README.md | 16 - MirrorClone/format.json | 23 -- NAK_CVR_Mods.sln | 24 -- 32 files changed, 2461 deletions(-) delete mode 100644 BetterShadowClone/BetterShadowClone.csproj delete mode 100644 BetterShadowClone/Koneko/BoneHider.cs delete mode 100644 BetterShadowClone/Main.cs delete mode 100644 BetterShadowClone/ModSettings.cs delete mode 100644 BetterShadowClone/Properties/AssemblyInfo.cs delete mode 100644 BetterShadowClone/README.md delete mode 100644 BetterShadowClone/Resources/bettershadowclone.assets delete mode 100644 BetterShadowClone/Resources/bettershadowclone.assets_OLD delete mode 100644 BetterShadowClone/ShadowClone/IShadowClone/IShadowClone.cs delete mode 100644 BetterShadowClone/ShadowClone/IShadowClone/MeshShadowClone.cs delete mode 100644 BetterShadowClone/ShadowClone/IShadowClone/SkinnedShadowClone.cs delete mode 100644 BetterShadowClone/ShadowClone/ShadowCloneManager.cs delete mode 100644 BetterShadowClone/ShadowCloneHelper.cs delete mode 100644 BetterShadowClone/TransformHider/FPRExclusion.cs delete mode 100644 BetterShadowClone/TransformHider/ITransformHider/ITransformHider.cs delete mode 100644 BetterShadowClone/TransformHider/ITransformHider/MeshTransformHider.cs delete mode 100644 BetterShadowClone/TransformHider/ITransformHider/SkinnedTransformHider.cs delete mode 100644 BetterShadowClone/TransformHider/TransformHiderManager.cs delete mode 100644 BetterShadowClone/format.json delete mode 100644 FuckCameraIndicator/FuckCameraIndicator.csproj delete mode 100644 FuckCameraIndicator/Main.cs delete mode 100644 FuckCameraIndicator/Properties/AssemblyInfo.cs delete mode 100644 FuckCameraIndicator/README.md delete mode 100644 FuckCameraIndicator/format.json delete mode 100644 MirrorClone/Main.cs delete mode 100644 MirrorClone/MirrorClone.csproj delete mode 100644 MirrorClone/MirrorClone/MirrorCloneManager.cs delete mode 100644 MirrorClone/ModSettings.cs delete mode 100644 MirrorClone/Properties/AssemblyInfo.cs delete mode 100644 MirrorClone/README.md delete mode 100644 MirrorClone/format.json diff --git a/BetterShadowClone/BetterShadowClone.csproj b/BetterShadowClone/BetterShadowClone.csproj deleted file mode 100644 index 09ffc35..0000000 --- a/BetterShadowClone/BetterShadowClone.csproj +++ /dev/null @@ -1,8 +0,0 @@ - - - - - bettershadowclone.assets - - - diff --git a/BetterShadowClone/Koneko/BoneHider.cs b/BetterShadowClone/Koneko/BoneHider.cs deleted file mode 100644 index 0e0c57d..0000000 --- a/BetterShadowClone/Koneko/BoneHider.cs +++ /dev/null @@ -1,130 +0,0 @@ -// using System.Collections.Generic; -// using System.Linq; -// using NAK.BetterShadowClone; -// using UnityEngine; -// using UnityEngine.Serialization; -// -// namespace Koneko.BetterHeadHider; -// -// public class BoneHider : MonoBehaviour { -// public static ComputeShader shader; -// -// public SkinnedMeshRenderer[] targets; -// public Transform shrinkBone; -// private ComputeBuffer[] weightedBuffers; -// private int[] weightedCounts; -// private int[] bufferLayouts; -// private int[] threadGroups; -// private bool Initialized; -// -// -// #region Public Methods -// public static void SetupAvatar(GameObject avatar, Transform shrinkBone, SkinnedMeshRenderer[] targets) { -// BoneHider shrink = avatar.AddComponent(); -// shrink.shrinkBone = shrinkBone; -// shrink.targets = targets; -// } -// #endregion -// -// #region Private Methods -// private void Initialize() { -// Dispose(); -// -// weightedBuffers = new ComputeBuffer[targets.Length]; -// weightedCounts = new int[targets.Length]; -// bufferLayouts = new int[targets.Length]; -// threadGroups = new int[targets.Length]; -// -// for (int i = 0; i < targets.Length; i++) { -// List weighted = FindHeadVertices(targets[i]); -// if (weighted.Count == 0) continue; -// -// targets[i].sharedMesh.vertexBufferTarget |= GraphicsBuffer.Target.Raw; -// weightedBuffers[i] = new(weighted.Count, sizeof(int)); -// weightedBuffers[i].SetData(weighted.ToArray()); -// weightedCounts[i] = weighted.Count; -// -// int bufferLayout = 0; -// if (targets[i].sharedMesh.HasVertexAttribute(UnityEngine.Rendering.VertexAttribute.Position)) bufferLayout += 3; -// if (targets[i].sharedMesh.HasVertexAttribute(UnityEngine.Rendering.VertexAttribute.Normal)) bufferLayout += 3; -// if (targets[i].sharedMesh.HasVertexAttribute(UnityEngine.Rendering.VertexAttribute.Tangent)) bufferLayout += 4; -// bufferLayouts[i] = bufferLayout; -// -// threadGroups[i] = Mathf.CeilToInt(weighted.Count / 64.0f); -// Debug.Log(threadGroups[i]); -// } -// -// Initialized = true; -// } -// -// private List FindHeadVertices(SkinnedMeshRenderer target) { -// List headVertices = new(); -// BoneWeight[] boneWeights = target.sharedMesh.boneWeights; -// HashSet bones = new(); -// -// bones = shrinkBone.GetComponentsInChildren(true).ToHashSet(); -// -// //get indexs of child bones -// HashSet weights = new(); -// for (int i = 0; i < target.bones.Length; i++) { -// if (bones.Contains(target.bones[i])) weights.Add(i); -// } -// -// for (int i = 0; i < boneWeights.Length; i++) { -// BoneWeight weight = boneWeights[i]; -// if (weights.Contains(weight.boneIndex0) || weights.Contains(weight.boneIndex1) || -// weights.Contains(weight.boneIndex2) || weights.Contains(weight.boneIndex3)) { -// headVertices.Add(i); -// } -// } -// return headVertices; -// } -// -// private void MyOnPreRender(Camera cam) { -// if (!Initialized) -// return; -// -// // NOTE: We only hide head once, so any camera rendered after wont see the head! -// -// if (cam != ShadowCloneMod.PlayerCamera // only hide in player cam, or in portable cam if debug is on -// && (!ModSettings.EntryHideInPortableCamera.Value || cam != ShadowCloneMod.HandCamera)) -// return; -// -// if (!ShadowCloneMod.CheckWantsToHideHead(cam)) -// return; // listener said no (Third Person, etc) -// -// for (int i = 0; i < targets.Length; i++) { -// SkinnedMeshRenderer target = targets[i]; -// -// if (target == null -// || !target.gameObject.activeInHierarchy -// || weightedBuffers[i] == null) continue; -// -// GraphicsBuffer vertexBuffer = targets[i].GetVertexBuffer(); -// if(vertexBuffer == null) continue; -// -// shader.SetVector(s_Pos, Vector3.positiveInfinity); // todo: fix -// shader.SetInt(s_WeightedCount, weightedCounts[i]); -// shader.SetInt(s_BufferLayout, bufferLayouts[i]); -// shader.SetBuffer(0, s_WeightedVertices, weightedBuffers[i]); -// shader.SetBuffer(0, s_VertexBuffer, vertexBuffer); -// shader.Dispatch(0, threadGroups[i], 1, 1); -// vertexBuffer.Dispose(); -// } -// } -// -// private void Dispose() { -// Initialized = false; -// if (weightedBuffers == null) return; -// foreach (ComputeBuffer c in weightedBuffers) -// c?.Dispose(); -// } -// #endregion -// -// #region Unity Events -// private void OnEnable() => Camera.onPreRender += MyOnPreRender; -// private void OnDisable() => Camera.onPreRender -= MyOnPreRender; -// private void OnDestroy() => Dispose(); -// private void Start() => Initialize(); -// #endregion -// } \ No newline at end of file diff --git a/BetterShadowClone/Main.cs b/BetterShadowClone/Main.cs deleted file mode 100644 index 81591fd..0000000 --- a/BetterShadowClone/Main.cs +++ /dev/null @@ -1,144 +0,0 @@ -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.BetterShadowClone; - -public class ShadowCloneMod : MelonMod -{ - internal static MelonLogger.Instance Logger; - - - public override void OnInitializeMelon() - { - Logger = LoggerInstance; - - ModSettings.Initialize(); - //VRModeSwitchEvents.OnCompletedVRModeSwitch.AddListener(_ => FindCameras()); - - SharedFilter._avatarWhitelist.Add(typeof(FPRExclusion)); - SharedFilter._localComponentWhitelist.Add(typeof(FPRExclusion)); - - try - { - LoadAssetBundle(); - InitializePatches(); - } - catch (Exception e) - { - Logger.Error(e); - } - } - - #region Hide Head Override - - /// - /// Return false to prevent the head from being hidden. - /// - public static WantsToHideHeadDelegate wantsToHideHead; - public delegate bool WantsToHideHeadDelegate(Camera cam); - - public static bool CheckWantsToHideHead(Camera cam) - { - if (wantsToHideHead == null) - return true; - - foreach (Delegate @delegate in wantsToHideHead.GetInvocationList()) - { - WantsToHideHeadDelegate method = (WantsToHideHeadDelegate)@delegate; - if (!method(cam)) return false; - } - - return true; - } - - #endregion - - #region Asset Bundle Loading - - private const string BetterShadowCloneAssets = "bettershadowclone.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(BetterShadowCloneAssets); - using MemoryStream memoryStream = new(); - if (resourceStream == null) { - Logger.Error($"Failed to load {BetterShadowCloneAssets}!"); - return; - } - - resourceStream.CopyTo(memoryStream); - AssetBundle assetBundle = AssetBundle.LoadFromMemory(memoryStream.ToArray()); - if (assetBundle == null) { - Logger.Error($"Failed to load {BetterShadowCloneAssets}! Asset bundle is null!"); - return; - } - - // load shaders - ComputeShader shader = assetBundle.LoadAsset(BoneHiderComputePath); - shader.hideFlags |= HideFlags.DontUnloadUnusedAsset; - TransformHiderManager.shader = shader; - Logger.Msg($"Loaded {BoneHiderComputePath}!"); - - // load shadow clone shader - ComputeShader shadowCloneCompute = assetBundle.LoadAsset(ShadowCloneComputePath); - shadowCloneCompute.hideFlags |= HideFlags.DontUnloadUnusedAsset; - ShadowCloneHelper.shader = shadowCloneCompute; - Logger.Msg($"Loaded {ShadowCloneComputePath}!"); - - // load shadow clone material - Shader shadowCloneShader = assetBundle.LoadAsset(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(ShadowCloneMod).GetMethod(nameof(OnTransformHiderForMainCamera_ProcessHierarchy_Prefix), BindingFlags.NonPublic | BindingFlags.Static)) - ); - - HarmonyInstance.Patch( - typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar)), - prefix: new HarmonyLib.HarmonyMethod(typeof(ShadowCloneMod).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 -} \ No newline at end of file diff --git a/BetterShadowClone/ModSettings.cs b/BetterShadowClone/ModSettings.cs deleted file mode 100644 index de687fa..0000000 --- a/BetterShadowClone/ModSettings.cs +++ /dev/null @@ -1,60 +0,0 @@ -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 EntryEnabled = - Category.CreateEntry("Enabled", true, - description: "Enable Mirror Clone."); - - internal static readonly MelonPreferences_Entry EntryUseShadowClone = - Category.CreateEntry("Use Shadow Clone", true, - description: "Should you have shadow clones?"); - - internal static readonly MelonPreferences_Entry 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 EntryDontRespectFPR = - Category.CreateEntry("Dont Respect FPR", false, - description: "Should the transform hider not respect FPR?"); - - internal static readonly MelonPreferences_Entry EntryDebugHeadHide = - Category.CreateEntry("Debug Head Hide", false, - description: "Should head be hidden for first render?"); - - internal static readonly MelonPreferences_Entry EntryDebugShowShadow = - Category.CreateEntry("Debug Show Shadow", false, - description: "Should the shadow clone be shown?"); - - internal static readonly MelonPreferences_Entry 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; - } -} \ No newline at end of file diff --git a/BetterShadowClone/Properties/AssemblyInfo.cs b/BetterShadowClone/Properties/AssemblyInfo.cs deleted file mode 100644 index 58368ed..0000000 --- a/BetterShadowClone/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,29 +0,0 @@ -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/NotAKidoS/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"; -} \ No newline at end of file diff --git a/BetterShadowClone/README.md b/BetterShadowClone/README.md deleted file mode 100644 index af9d39c..0000000 --- a/BetterShadowClone/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# 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. diff --git a/BetterShadowClone/Resources/bettershadowclone.assets b/BetterShadowClone/Resources/bettershadowclone.assets deleted file mode 100644 index 42c173453cae0026e57c0f831dbca9a40ff90d1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9661 zcmV;uB|_R&ZfSIRMpFO)000OzE_g0@05UK#F)lMMGBai|000000000by#N3JK>z>% zTL1t8LjV8(00000000000000U009880RRDk&;S4>EdW6d00|rb02%=B7ytxAK|(EM zIAu3sW@9!mGd40dG&wghV>C87HZw9|Fk?4jH#uSe00000000000000000018000O8 z003+OBZ0CeO+FJDEPwjs>BXr1#|CA`$TS-HsW@ClCtiO*e39f}l%l<+cp*5B&r8qK z3ge!(fxxjxLJ3ht#GOdz)W^$O;1i1a)xV@C-r3N^pp#A87=A4U5Dey?kf8EPF~!#Xi(BQ!O~1K}9k?coA82{4(xH628w@BszEFW#>dlwx+s=ev8+N-Ac9$-?;GH}8aP zY#O;2deV?Vgk~w!>{FygSYwS>a8GCtNhXFm{qP>?nUV_9m{I-`v?g|+-r6w6h>ydSa0a{|05B2FjTZO~Q9O(4Hy38-u zZQQE>8_}%KO2<*#oasrIc4Wi};rYV$3`KUy+TUBwB9|r6YOvzL%z`~s^0mC{M#_e~ zCV0{r#7)58?0P!{{(@yF*I9xyYFP`Yx9-c(qFmxqkQ?; z$VP}F9>OV9;3yo<(7f`qaEPGb<^m>^`zoVToF)q zKj)QS(Lk$U5amhrk;PF`;eoP-RDWFLSwilfciXUBs*8b#)we;811F$ z(}Zj=!tZwnkp=7{6cmB$y2L;-zE0Ezij*@zV)p0VAy{vYgWNhd=F1g8%3=0Xoz8J} zk`mSn-&uo29Wdoht&_QF!xoUl4`(7*|EXnRPetd3qt~l?^M0H# z*VMV911e>Jg?bI3JWXO@Jp=l3EBoP?v6p40d;Ys=*8{^NC*KekJBpf@1rnaP0D?^* zqU+A?7|gq)yiN>mCUa9{sRK=!6AqdB(O9G0U%1$nx8q6!y22=5nBy&CU;iz@qC;iL zS7jelD>yuljPGUOl$ORt-}O!5nl1Vky%oz^nAAc#HbD|?{MWazzUwJ46I-am+^0&X zVsa%TWWcDCpSjG$A3b8{Ccwz+9-OPyo(vSFeJE)%athpA2>)E>DMY~f8ecT#>e1ju=9Xxh1VNq-IN+eSq+FAOaJka!(Th6tk|sD|U%$}u_P>YO)r zCPawB2>x{zS6>Z{*d=HXFO{Ng5X^ZicO>p{3#<1fGw)HO`c!sQ&60~o|dXbd9F`H4`Bm=n$# z?MM5~`bzcLRbnse9Z(-kYt(BE>i$C?RZ+)D%Z0J}1WcqEE_~p8rFw97jiPedmO`tcjwN-x!rQdyBx1(CWz%p9|=y{I-tjqNkOl)poTZ2LLE#QKLTy~E;`)Th@ zv3xnK{q)VFWtsdwp}Kv||2(8CjyMs>Qy{H>ap99bREjQMtoa`7`D_IEkK-pOR2oy% z8TY|3jcP2skZDdd%fqWZwJ)|LzQ0P18U@(WX#9Wa4%7$gxx{7<;NVBm)^A0EP)|q} zNAl=OYAD0d{vPst*`SNMb9I)Rfq-)c5G%~7&=Hu)SZ^$$*L)bX*TrswBd{BKIbVJ$ z0xpb*@tAw*9jrE(l4OS{HGSlOBRYV=1pTuZb0J3dcN2vgccQc>yyemVE9DD8;bN&M z$dCIimZO0^75u<6E@e!7aC1lI1TwW-$(I$b%9ewkyGa+9I2)VBJBXAhWwUCP z{uXG-0COXLJ~`{9>C=TyKd%QrFDyc|l(?WFqVD4~VdlYRSD>T{s#EdS^#7mc9&Otk zW2X{!OXGkv7CYYB#eO?#GBTi`t5Z|fY!%l$EY7EB$i|aF@{d}kR$J0Bds2c^CY)x( zyGNVj4?UP`an3QI;NE{JKQV8hY%7zhj{3HcR>@YX z?=PnSlw@nqEddJ=$ZyATUa;Vj;MxX6^R?oo7^8CJ9G#4Qaeqbi&9qIx$yg6gjA*C+ zp&B|{Nu|<~X|vU!kc%ByjjT2)?Q1Rl1RQKAypedZibpo|dni}j)droPzA_+nRh;SH1 zG0Kht9{s7^(hfvACS=gHeJV?Pv z;gmp5mVh`zl_W|A+Ae>2mMwJ~Q>)X#@o(<%nuz^IlV5OxOYcI^IoViW`mJ@S+&>#% z?d;x!l*pggCi(cm_Q-h^vHH4Fb3?)m!h(d%_N#kL&yNC#P5cT| z)^CCx*;g9e3#$r;xTM0=VV8~OepZO>UiW?)2(P%+H+udat-UuX}E5dSrugM@`*-Xxese3nHb5OzL z;Ht5TT-vhd!ayu<*S(o0{oIl+K+KiPJ88HdQbJBUfElyDi7QRb{R%g>^QAWQz;Ua-Gpq5SZxS+{=8~;f}0gn_soF7ll*y@sws#_5Wp$C@lsoIPwpifRFz^b zx>ETb_Q8B8Mq+-VEXqB48jj+Y%9YzjJ1x^W72ZSD{M$w!qnSmP|EjWQm>fsSg%S1n zyes!a7IWc?o-KsTZP~vNlT;gmy8#3(CR@e+CyEPWM!K!z9(_$3 zkD6=!sJAG4OwpOc@?Ym*OCi&?fG=)PAioY~*X`pQOFy=#OvQ?Gm^+xEkIMHETTCk? z0eYJFx%okB9eT^nx;fgWFJ^356iR3lX{`Y>HTp!1gY)7Z9IoEpNIKTOdg*7fK%Xj+ zYXsK*SSM9mBo|eog$?pSw~~tz#FM^RYsHO&e(sm}aaHhWYXIPuTyHTb);2f2>p($m znXbnQ@4cycFf#p_x>FlxTP`Ntk+$k>1feXg+g>;doTkXGuI-nXAslZ0C|rmHnJBG9 z-o;f`vVlOh$N!jw6|@dC4)tWmzQjsxHfXSdUdEDR7#}tz=Q4=1QnKDHF8%U>&qN@_ zpc%tBic~5<1ZK!YTzPQ@2s#Df4(PVjYdy7kRd{6n%N!l*Y+emOm@$XQYL{P`64s2_ z8UD(|3_r|kr0uE8!$>A=IFcjTlo_&+JBcqO*WNriJr*u6qX-jtJ`xBy=#KTErP4%w zp$l1zp*n++co$xRrr4B{e4Vk2;*E>~z~)c-X_N$K@SJt#*BT40Aw?0hyURkp0pf8tTlKQzC`H$X#rs@4b~^mNDQjo_b5)u|y%$%AK} zNRW?6a;L)zaBN1sQ&H3IPP%g{=v?3g+=tMR$2lQ~mVM^2v#I&q>Ype*+5RD02#axe zL<(Ph(+}SWrhx9nKtIp0CUhkc>0I+>jWPxCg_bcVu>E_>e?Ko8_!&sECd!jdjD6~j z&lE-_?gzmGx6HL`(eO*}=Vb=VZ!0dle?;!+Lc3J1|DUf=lJ6K(h)S6-Vbr*RtzqN-|vQ}m1=H(RhXof%O*cj3h3*9@P&wo>TH z)E6-83d#4-1kpLu2Mdl_*Y)h%L#bOJ#}Z06I9o)?oqbT{=72{0yJ0C$gPJc^&zVFYZb^d0%^}TG% zr5y1m6@gA`3FW|gjTj$Y{!P``P0wt7%FWcdW6dXltU!hC;e*Sr8^CvH7RB{Ofj>Fb_B2 zM^g~9vJ*>qA$^PdkZk6PQ(f;lH!aw1@Qqh4g2$nY+M+KImT~Wd@ZprFSYNR?v?awC z+?H*t2j0z+4F9>a>wqHc^8;jt@vwdL((hA;j_Z6BhRM}?LP+Ylj2lB{orQ(EL5|Yr zv6JN=E}Z1|foAriVa5il>gbJ=Q1I>Qu0q|dU=Mf2P9Qj__9TsI^Z>7K`U=-qt#^!X zH%1ym{0sE?k@0&IQuqs&T+iY&Gt0V+j4#s)6oeD!*3269OyX-N<#c{ju*Qx*j(BqD zkgN*wWRL)Qz{z?i_n#^|w3Y4sr$LGIA{H}s(2A6o!+VIw#QgTBrRjm3_9Kabkt`A$BDl8*$#VoV{BQN|Xy8 zq`;GfP|0N7;6g=0lDJDoZ<>$&ge-x@))%^dtmN8lmnqstLl>+OvDzRN&O6346nE48 z<>wR(WEwL%0sMUA;L$fw5Owj2n5F8soD=}(g4L6M2N!KcQyap^*W0dj-EuC7^!oAt zBt)D$HIUHX@sut#et5Gkj+X^o2{g!vfor-c-l2#%1Q%kEK2D4s$Jtk-9!`gy0ho}# z=`O*XO2;SR`6!_|!z#P=jZJfRm(a{nT~I(A&HorUk@iWVsFbkxPX3ik8f(rg7JYI1 z+v$N)#{nK|xKf+W3?5>)^f>>=9NI;3_zOiC@Q4xuVQQm!Dw~}Vk@c;({DZJ+yHafo9;27IaxG+N~wn96{?Zz zNnA;lg>i99K!$?xhCjW3%Lm6MLQ~ER9TxjBcADgZ@YNif5jXr~(5=xP7$ZrCJi%5p~KVOif!_DH#t^0xZr0kh&M7+~wHj0HLDo zO0PA^r#XlljP@|f8U*oc^|q^3)Zc$HP9T>dWf@XYKw}4q1i=#WaY0aOK+}7MnMlUB*GSpfC5xA};mMHoLVl(0CnoKuZed1+x_>of;iV`ZMyCRAx&^B_ea+3QK>k z$5vHf@sTv)u~^V}GxlHG66NaD@wv9bR0_bFR`p?K1dnR*?wstF)oW(i!@`QC2$B-E zfN^{tXgZ-(_RWaBucAR90R>*ky%--LQE-Z%SJ23ihmyTSHy` zL)t)wb+&xdiB9{}i#d48VvM$Uo;p;(ls=&L!!&Db%Tzz$M9#@s9xm>IC#YWq-!v!} zi@`WH(|-f#?0gz_B4O4aDZy6`<(|{>6Sc$-FMvHp(k{CQo#10PW)cP`gma?LcSdFY z_WU#3-#97*n^GY9<>B;*O6k#@1*P>W@TO z=Gp5`LMY`?5Tcjf80ewvh|8kA@Hx@I-=xi=BQev-v7wY4YjvD}4xVY=lG}mD)0e~P ziU@|oe*YQ(&9HS05+!18tK1#ZqUG510doW_fr*N7-Wr9UV;GTp;y}Qljw3>c0qQXp zu#p|Dx2);g`-mn9LHKX7ZfM;uc9X1F7LRFdD_79<96mhskMln$aX?yV*4jkP{Std7 z@d#U98u3WSOkn0eo6VZ_>HEWSn!>yP3RTktcyEghsao}V-X>sn!K?OH@x$7=_$%>Wn@I0Jlni48a-m8RF)z z+I3xHavcn9IsPT6V9Rmp=4NBBs{#3dLWqWt1SS49Bp6VY=WCGIrEw+B!H@dt&-aO* zhR77wo=nWx7tr;Q9VYXIV51;Z&hbA`F}quM@b*Kua$w|S&yI*P14g0G z{f+^iO|hp3Nn<}sRg2Quj$gFAPxx`*5MK{kZ>D)9Q= zjD2EY#iemS+iS4f2#db>H@adB;acULHc_V60hG084xZL2G&Q8rk$_W7r{WU)@tV7f zpVb(DWB5hHF5}HSJZ)yU7Jl_UUBe)m9PtpQVy?$}EUmo+Y!M{<#ar%U-@2jh&ofOY z@Mp##8O)OG`SlM2{MsC{@8f5^d5;DG?*Jv!<{RK8C`Pu<71pwA+Fdpfn+lRScVl>| z=#$?-J)@iMLm#dpZstTk1>p6FsjQ}P%SOsVZU1raHe*f9QGyGJ)PA^5H1aQYD=CiG($W^2^#rBv{GWV?UaWC%2Sfv#qq)Ph}|E=fxtjQngeg z^4jv*;{&=q6i%_QEXOP^mU#pDIQgX4RV$Wk#M#cptPcM0vBjEjPV? zs0be=Z<44J|My*)QCrM72&}m#WX(A~!8LL?BJM}|5RkgFs>TK2=sR6Wg!1LXb>etl zzxKmrP@11QZzj>&><_cY#;(Kg@-NVl4i@Lo;7R24Pj(4x@YNam#EC)-bwM`l0KI@8 zrj@n?IdYI)mY90t=aa*ZW3R4K{x~p6Q2TD;Wk!ybPtt1*7^jYC!|z&&SwjjFX*PXA)eEiT3VSvjJDPC8Hww0)+Ck#`*5Q0V#M&BJ+^0~ z6D0LWpfZj-G2V2 z&wOVfS=c()1P1ArPTt`NU2 z6C3QaLJ--ly>O2}k-#V`B1xL9#U^B1c3{E|<1VTEns>EQB-u9@FXllFc`umhFU)5l zb>zWJSRh5kj)S`{^TlTlTDohML&**tR8yVggZcL^p;@!sDg+@Lzx&ga`^>{4;exib<3AAg?S#cB%h12PG*gBdrbK~mi)*hq&dn>^#P|Tv7 zjZk>i8`dR}(BBXcwK;cJK>X&}g0uMWqI*o%ciOQuEASY6NHvP<&ogGKaN8zFR%FY@ zuZxiGFgWHps?K2+Ieem3XQ=92hJU@?GbqpF#|q;oL7;z`(%Gh~auZ=8#VL5A0D+BW z;y4j`SJz#u!7c#9+N31Shy?$+eX;fMR_>@_KoWp2bQ2#>I8D?cRs8*ksc2bTF9HvFvqtpBC zx@!!zr)-CFH1<{qZbR4k=^)GdA&7~H8R^qGe_Z%_G7%6|oP|koWs>7(u=*LNT{Msv zgv-ER!r{L+3k|Rh5CN&)A-Tv|_+Ftxr_I2w8+ZC56_6Du>1dwym1vfL1%s6B@~_}1 zFUTe|S9~Cf=r7gqrU~m^QnQ!#2pI^K=hod_l7Hr=8l&QxIbQu%_mZ; zQUJGuM&QGWCXqf^Ub+e3W(qbGfwv1KwcyHMs7b1TjG%V^kp=(VFwxxVb|+t zT~`0hY&V7hm~Y-l8$#XUKJPQNgdM)?Hkr>_VNC1(z1T(C$Z-wb4 z2`XJlUrdKb!d-Cw_;g-oDd7BwozX-;N#0BH-o*!P#b8kXb_&&{`fIVISN=dR($+`! zQtf($l{|#sD^~{S>IdD8sk}X5Hcb!vDw0>+5eTvzcz-j>vB94fo}I^A3H89e3#hQzigiZ-N3! z;p|&>^&B91E(AhX>xo@YL($7ov~=-b1F>7uhc+H=yzL{fit-bFoCdY|r?0hHsM_a9 zUw~z8lCk+ay2zeiY|F)Nk6oCA2a|8*oUR_b`h3dx&FEKiZPLL4cfKk|&;E$H8Ql$+`9Rr6dg zB&=|m6D*I(zBH*gK=x0!UWN{bUhKQl)9VW>Q@TW&RzHG6CkO>FqU_5mX)4*D zDpgwJqqIkdB@W0qykEx(!Fmt>pX+W`N)M41!x@AF z1f$%qN%EoC_AG5&z8A;nuHNojMttsyyA6t=mQ44d(f_0H&Vo}}O{Y5oj!@sQ`D~sV z08@fshO5XA(tR0!!2Tdg`r8Y!ocrrQ`<%fn9dQilS=PRB-!2lzsY85*a?KBEXbKCu zpeGpueM5}TF4q1^xFtFH8lp9d$e61t11atGdx-BzA-^(iF#`SQCWA#|SRXMnnV;OF zD=?mdKoS}TJwK@QSaIRobSjB$p`e_IpbZ9$%T_WIb|B?Ju}e?c^uhkMvz>% zTL1t8LjV8(00000000000000U009880RRDeJOBVBK>$Gx00|rb02%=B7ytxAK|(EM zIAu3sW@9!mGd40dG&wghV>C87HZw9|Fk?4jH#uSe00000000000000000018000O8 z003+OBZ0CeHz7k8D{H6j7TVTPWlO0A%w-=sCA_7;%2Mhu;o$g4{0Oe?^m}z+vbaw$ z0;I#>CTTpy5(}ND5(w zfIHYMs1N-R_<&E@HI@5;I=@S=RC_187-4Yq+G`~|P>kio>(pybT!rf}e=1jlal-Zv zUDJrT80FjF6g-sbQdQE#bemH6U|u9?=2L0#tM?C(pkIK2CgeWCPXB7q1rXsfo{Sfk z<-~ibQK z%Aw+@a6cx8NQAmDmz`W4C`3Ab4S6XILE7cs?-et4gMwwDV^ZOe+>+8t?9n1)1(Qy_ zXyW29Ny9QRDN(igbG}s!%gN>Xf@bCbXO+qcYf0iei~aNhI!x20w+S1^XE4qBlu=#d z`FHral4556A6V+kc8M4vTA@47-;Q699o3OU30^3N)BR_1-5&Qf;AR$6afhZeqao@Y zhCxN!MoNEnn*I=*SZx^zV7UapPgJMZce6)c3wB}HZlQk#a=Tb`9xTvjfBf;(&*>#6;AUx}cY2l38rX;0zis5SjO zri=%H{=Mhql`v(Fd5GwmB8o7c@-AdQ-kN85_5IZ3*1Pe1kbHM5MSm9$;UfdsVzrH$ zB!o})*+zKb8`oI15xM7+W0hfUNn&*$=;HYZq^u_Px)jQ0kABv?l1aX3d%*2OXO{2S z31>Q0GozCH0yFs2y+PId%j?@!K_$TdQ<;XhjG7& z3OWym4UT>4F30{Gst-1ulNwO)n)|a_)!NYgJkO0>6~fVVM2J5b^8`Q)_q2M;S6Dt5 zP>QjPSNJd5w6|M)EtTr`dzuBHphM{gPq!9UMgVqnLlKLv*z9_KkPeRydw z=P=%g;?ULeWi5&WZ9rcD0w9p)>qlgYi+m(;FM+*(m&keD6SgsHM?2$GYg81~>1eWS z`A_)}X|Wf5gg^@5*&v=udi$GBO(t9Z%RgwLu|K_MqZZPO9V{mJ*_!>DL!WM3kP8Mf z!a#k;u>V4|8WfLxcePwB(UsLO!pe#jQZLc53o&$&X6t4UhX}xpGeqF`oeTVsS0p7i z^kYv$;Cn(}bzT3-68wVZbrz6`des9mq2oDFeDx}MP{ujN+QG^qa9 zm9l(NaDDe5OlequMp5JO3PF+Vyi0HFH^4;)sEf~OxAFFFU?0K92-Bb6Dj%7eJ~Ld` z5R$F62amJiI@phDbfld1{kDS({iBX$E|tnF0*S$(kfqM6v}VZUO6De%O2L|4mbHQH zI{CsW9o`c^cS^T>vG^qaGfTdVs!Yx%Lkg6Xz$Nvl2L0+UL@G-l(Gu-~%TP2n2yG1h zy$S8glu&h3Na_SBZXGA_{&i|4eN3aT1of&LJ1X1z|2P;uMcjNi!pJ#({+HgT5~^J> zNUpwO8TJ!>`M7`|O7!b8C8wn(0C3e?@I8JM{F0&Kzmd+sS7XFaFy-UDQ^|+IrG3OQP^JL~Vg~q7#tz2C;WB0>$_M3$xhfxoo@g@nFCyu6Xesj2jO^Yb)Gbh9K@7Hm=KM7=7eBA2fE27?VvaHy2jE zv#1azl@9e3L4_p^c$)cb+7suHvk{nHtalJtj(CXSnplxd6JO}mi%0^@Wm3$AT9KxN z)e+@qwp+pv*}Nd?o*n2wpDrXW)$z-s6?NW4AZ0G-C-#>KSQ)hv;N*`G=q?){IwRWh z^s0sNK+3UfZW?J>v4}5rx&>WU1G+Ygy7%9vVi-XEL6X|c?(zb4UJY$$DF`cMxSzzU z-b#pNJ}nrvLPznyWA{+v=CzPHC0DRd>i1OK7#eZJ4IPi~{s(!r-tdK_0Cm!8>|f4` z4Eu>1V*t9>b3Gl<4Y{;|xDPF>Jddjlae7;xX*$Ty*VxWFGfbYL3KGs|BsISq%h(0e z%=sJye+MAhxhv<02CWDyvNmt1{XD)FZ=VZ;y$fl-)=FU2;t(|=4zmh`1l&0$&Q*HI z34SrCpp?avYa_DnC$wIhJDf&?cWYP}cS7LJ_;1V`sUG)1zV3ys=hF8FE?T#=G+T>c zuGXr~=cavh*Q+BY)#0t=$M87X;m!^6)N8YQgU^E@6jQx@&q7E0m$d+iu2DPwbUuW? zXod0sBmx>jb0JZwFk!@e=J^Mll=8#j2YRi^*!uqi#pJw)G<+GX0DNK%VI@qZ%}Ec< zjZuUeH&m)caPaageJ3x<8|pXLeqj|zD#~?EeKiWIH|a_`G@LzY4W6@W@Z^KM4Cx^$ z(o8aaPxA8rN^uKY`&S<>4Pqy>+YxKlNH7sr-y((qd0%<%e_mF3DeL`9Z@dZ0Plv9z zS`;S#5}=RZLA{Zg{-D+KPn<26iuw4_PKYY|-DdhAJ@*?A>CZWm61t~^>^0;YHjxOD zW{-E^IjTO?7R;}nvs(ET_I?2gmFryhhN;$G9far_264oL-n1@jOrARHZlSrQ_P#lS z{uPUtuW39i7U*@$PDPN%cd(f~zw1#BuV5ereSUZ4Lo{Jl7k2I%Sc~ng@%*%XFlqBe zGrBCWyK24IVc941dzP5*Q*nY$Bl%#%C;)b~Rwy%5+0qREg}G(?$raf*%;^_)Hb-a? zm?-7=+IC)DgsmtO21IS6r_p0n5d&+LLqxcQpGP~s>3HfXr1cc5l&Fu1R`p|$Cf*a z;VLr~hf^~0cB3QPC;1jj^GJ(bOPrZ)NuQKP`T%%FyNrN%JI-S=ft_Ms%u(IGBLX(B zOkF+Q5sJ)nfYUJZsy6Gz%?FZqXn$4WGx#*5w2Be)FI0MNKl~lL!ys zvHF}`4{$qW0>4u>Q>;r1gq4ywa@}Wi@BPS0JiT>PvO?>;;zVvWgex0&z;-rAhT+6* zY5LDmE>!#-40G%RYBbF8$QRfSnky8d(`Q<^x%c1Ht(54f4CNwd{h8Gi@KAy69l>~l z5)+$g1=&G$)kgjQOuZP-UO4`s&xRogDiIC$6!auC!zis;O(m@G8$TthZ^$VVyraDc z%vJr~(3`20n@rOipn@myd`h8~@FZeqewHP%;iGAjT^Yk|?o4PWs?e8x8c4{dnLF(C z0RAo*X0Rh-mD!V7{R^SQMlPLfCo-?Ci(CEJ9I4`lLsY*m5ufg>rv47GzrsXP?8*d# zM=OzXgk7MZS_BJ(i`_t(yk{Oc`EMOMqD3pt-qmy2sv!*16#=A-6YSO*LmWQg9q0Jd zw@mn!l@@Ahf5@Sg1=lDY(f}k`4-&I^ygl3bEO$DhbE))o(x#wMX%UM>6qJh#ZR*ZS zAiSQq`fiu5bSamsWb>2h;nM*GbG-V}K#S6vzG&`!ULO4uxRw^2q?bF-B?M(pPETl$p{#>wb+jOp(|<*mX7Bt zbv5>PiuLqv0rI?a-mh|9d??rbAA^RD(fW)%R7yr9FQ2F&2`ZFvvNy zZ-_7;TXI>XtOnh=Fsuns(~1GdLXf%;DZrojjUyn-k^`V(pxvdT@3d5=Xdxh=Z@lqO%lT1Gx3NgG(puDe+|vG=Co#CYaB@o+ zo6Y!pcaXUt#^NvX0kqdmNX)xX|2WVs?gv9c_GO;Z7}z9i+Ji+q)*sZFMK~YUBh^dn zBOdIZL_w)|!2V2vu1J=xL*+?h#tq&iNpfmE(5RmX$?1HNQ(%1bZt7O!w!7+HbrJc4{-4@zRyDg_df-*QOydFD6 zPJQ?;RUqqji{M$!4Me(Jf%X9-fZl<#-$`308-lxj|E?=go3tbUzIXrFs$7_MwGamx z*h6?+ID7jGig%t#U<2;Jo55kZlSxD6doxe@R}%8sQ(&e+`@rq@1E1qenbOQ%)O-8a>iq83v8d#57ar$BRwCnBx@q z!K;>?fax692ZdNJ|9@N(S3}~Xd8Dcj-|51jc_CQ$Y4j8b#oW#ohKZnFxgXUD6FfUV z=4-c5FTlp{FCq_lynO1+TG9*q_JT@v(g?kCUy-8~{WaV6Uc+5m$7Epl%|wy7#zJN3 z0$5*4_G=iriuMbb{nHVcOTR2rodj{)P0I5iPZ<_^Wf6#_`>;pwRiIZEE8uB5=m8H- zBnNSPeg8It0{}X2!_GdubJi3KxqIr+)<}>Pbab#+5i^*IqRTJ5&hJ6XS#GiSFu2sa zI&Y4X#-CGv6XS`!miB z{o$aBr~Q^hBpoA$|CYz($y{E2oiKH6`Ia3ZiL4t<~spHK9%cLccd8-=Yjl`-b)vZ+diW676|3 z82NGzn){dmhe^rvKUSx)s&_V%xH$ZaCHo7I&H4Nw!teugLS@%D#2hPFTeL)~!r+h( zofwds=7VC@a8hjG)OSG)%|yjmyjNmXax*3qqrtyUQu(@~&3ekmw%{~{4@BEK3#{yg zBEPyuPeHZk*85goh2yVT&q;x%je+;p0%}2EM1UH0yfH(W(FAdlrR4+N)wrEU#H7|d zpu^Kps+`-zN`z~jX6)SzGGZ7l3K>&U0*1w?e*nlA0{{k+gRjfXhf4 zL0cj4;;QIu$B9;*4}wj+O{*&1ReSc6p^X#3qG>y`NYw-b{3jSkq^;FkZ2w#UhZT=W zD~gEdKsOKfkPM)FdE#>!Dm(%t<^(oS%a$E#-bZ%S&OhC}TEs<`WuIDH4sMfw2t3S6qHROdDV6d&{^k6# zEE3_FRp0t4@&n>$LV0#+@U72oJTUa5Y^hGcgbWtHjcE5;ar5wO2BEF%#HO<*cgY^% zzj`AqjSwFy;L%i9$!GNe-)q+$^r%m~@#Ev_Cuo7inx|kcad!?uk zUb`RL%f-xF!nn4$Eei(&l+*sIP5S#G`!B&G+{R9uYi^juj#%#Fx;Oh!i*>*@RT-tP zmVLiip^`Q(MjP4x;ztTxbge$*eW^e5GHZ~2#S z$u&J)01j5)F{N(!R=|YN#Fr&&mk3;T0>Mo-L>q;3=fT!8hync0;;tz@VT%0;yGv`p z>iA!!+Kt)oUFsdKup<LVbs7Ro66fD%}D{oUk6Z~EVK$AYDIpdAwQGu-kp}?OnE0Mm}bckbl--om+nb7$Qwr+R+yIF zc`4pkr8#4reT#{1!GZ+764>SHA57WcHpjO8rkFt`^X|Xwb23t3xS$$QkX6gL@`H%B z2W7CH^Neoo3pKrYUcwg{P(4d^Y#gaGDz3~IgYua{75d#x4_pSI*g=Z3%4McHy;pbI z6wvpU0Fl_GC<={c>{uq@Nl_awMqth*K%H^gCd263Vb|v}t}*^sAuz3pEr3C=gj!XA zo8r-9tZNC3$!;9Hk?uZ47xLhwW^S{Ng!_PbfrnuIjP(6Ud4&fPKLe03;dx5#4e(qb z&ua?84_DD0>h<%LYiBs?vMx`vWV1MDKK5trptGTKMb)4U6kLse*Ug~zqsJ~ zG-T0F=7Lu?S{Vn-D6InF-=+6zZH139f?zt?0&_F`)XZ-6h?O2%%TmTIePaf!EztM3 zm*yBh=+$fi0UY>a1$uOr7!4%5U7d70T&RDm0-cvJM#YAqJZYiTc(Nmt%=9eiv6@Xd zR5xbAwdpOB&C?CQ7YH;DXfL3EIWyH0a-p~{FT@I-6RyiJMz(onbp0U8#+T%qjN>) zmq=@fCX?cyRpllao77 z63oCJ*-&XEegc`40tT(OjZo%9o^$kPzVA&T4 zYpC*_vuaIxN`8+y#!GhZqhOR|#^(OVo}6z(Prx7k4?);Gq$-4;r%L)fJzzfA0O3Q_ znxB$1c3wXi_HaG{r|%Kdo6g$b+6Sw6 zI@xP5S8x|0vuuELgrS1k24xOJYm6Gqt%0mZu10pp&37|j|KsIA;}Coul2nN!s^Ju8 z_E;B3Lea4Z3*J4A3pH$F@*V%&Gz!jq~Uw=?*4K zOZVjb$%peVS9*Mz&~{a7+NSNzBF`)5bT< z6~`0*KewXpTe*;x0{pz|juw!JCqW7c*#(!q)L-ZU66+b(lDZI)TD962@;4k2>YYc{ zQa-y?3~B>~)+^zI`o&&>4~nKpx{H5wgW)`j zhM!=ay?lbcA}+oxbBMt%cB%aOQlG}s>4#1(=wvS^nEwPis8vKn71CZJ^>X!Ze$W1t+I4oM7&hv#d{;teH)epR)u# z@o+y?>A!NZg6h_1zf9fyM9mVgEX{27ZBOUA%L*2C(&K($u>xNgqZt7osV_cn^+!n} zWv==*s<6QT%n{snO^@l)ppKG#5=cF}Ks5Y~U_|U9I2MG)vWP2ogSa|l&6ozVJ7)p; zEmSRy!-+>#=Ym{C_Mc~4LP1u#dzQU_(6!dVYUL~o^whbcFOsi7wV3|5WJAxd$7Si= z-+!Ru2BOGprfOK!wduii%xM)jdSpdGi?aDy%oEh{Sn+GclL9ur$uiaN6#Pa@%q9v` z$^CHZ#{bh|o$_lIO~|xtajPiMFW6jt31Z*SFT2wPo9u z77PS3wW0B65C@Wdidrh_VGRQO2?PU)EvFK5^;k<|B0rGOC-?UuJAq|r`m)y?mymV7 zG!0Jn0KxupCHIQuFweJn7az__SHT)N)Jr(vjJkM$ZlupxwnA(7hj!$&*6vt~^Gl7l zC{+52HpD~oWOJ0E?N8_0M}j&80ji0y@h|;PF1MX^BGLG`%P)v62ig;>dB>I9px|Kr z@vVA57+Fzfj7(OE$D8_=DdrRy^(?j3@xg zBx)P}s^k;HPD{HRHB#{hNVgXBm79;96q8`zO_bxYGdAJt-G4ESO) zn*N+CAH*mUv%@sLQ{j%6aDnD5Z&YX{6z2yEl z0ZbtHdcF%vttk5!kEOs@E}VAz zi-}!@!A1Bv!Q{Q{=7iwQ4IZIOL@{$wR-c7}{HVV!PoE&6o`idF$Lv_`uP;Je8SKRsuUXg_Y9mvK{zxNGomTGn1`Ec8 z-rA{ZnQ1-&0?GSzNEFpdxR!EO{W(*bcL+f0Wr7mM3DSGIT?Z1d2`#VsVSKYx5RtCo z-BQCjsWwUH4pSo-n$gm8oto|@en`vFCzB{X(%>lvqUfPKLB8mUFTKH7eAEi7A{DlHS<;sidSZ5*>)Yn+2#Ov&)l^{+>VNHDqdJ5XUroQd z@8zvyf%pNyn>5j!Y{hKo0QO*pt)ltJDH*IvT^dYBsFa3IGO0~a)pc8Y>9W;%V>D6& Xzmy29udSO(taj=*6R@}c{xlMt`RPha diff --git a/BetterShadowClone/ShadowClone/IShadowClone/IShadowClone.cs b/BetterShadowClone/ShadowClone/IShadowClone/IShadowClone.cs deleted file mode 100644 index e6cc161..0000000 --- a/BetterShadowClone/ShadowClone/IShadowClone/IShadowClone.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace NAK.BetterShadowClone; - -public interface IShadowClone : IDisposable -{ - bool IsValid { get; } - bool Process(); - void RenderForShadow(); - void RenderForUiCulling(); - void ResetMainMesh(); -} \ No newline at end of file diff --git a/BetterShadowClone/ShadowClone/IShadowClone/MeshShadowClone.cs b/BetterShadowClone/ShadowClone/IShadowClone/MeshShadowClone.cs deleted file mode 100644 index d27883b..0000000 --- a/BetterShadowClone/ShadowClone/IShadowClone/MeshShadowClone.cs +++ /dev/null @@ -1,158 +0,0 @@ -using System; -using UnityEngine; -using UnityEngine.Rendering; - -namespace NAK.BetterShadowClone; - -public struct MeshShadowClone : IShadowClone -{ - // We technically don't need a clone mesh for MeshRenderer shadow clone handling, - // but as the shadows are also utilized for UI culling, we need to have a clone mesh. - // If we don't stick with UI culling, we can just set the shadowCastingMode to ShadowsOnly when player camera renders. - - // lame 2 frame init stuff - private const int FrameInitCount = 0; - private int _frameInitCounter; - private bool _hasInitialized; - - // shadow is used to cull ui, clone always exists - private readonly bool _shouldCastShadows; - private readonly MeshRenderer _mainMesh; - private readonly MeshRenderer _shadowMesh; - private readonly MeshFilter _shadowMeshFilter; - - // material copying (unity is shit) - private bool _hasShadowMaterials; - private readonly Material[] _shadowMaterials; - private readonly MaterialPropertyBlock _shadowMaterialBlock; - - #region IShadowClone Methods - - public void ResetMainMesh(){} - - public bool IsValid => _mainMesh != null && _shadowMesh != null; - - public MeshShadowClone(MeshRenderer meshRenderer) - { - _mainMesh = meshRenderer; - MeshFilter _mainMeshFilter = meshRenderer.GetComponent(); - - if (_mainMesh == null - || _mainMesh.sharedMaterials == null - || _mainMesh.sharedMaterials.Length == 0 - || _mainMeshFilter == null - || _mainMeshFilter.sharedMesh == null) - { - Dispose(); - return; // no mesh! - } - - _shouldCastShadows = _mainMesh.shadowCastingMode != ShadowCastingMode.Off; - _mainMesh.shadowCastingMode = ShadowCastingMode.Off; // visual mesh doesn't cast shadows - - (_shadowMesh, _shadowMeshFilter) = ShadowCloneManager.InstantiateShadowClone(_mainMesh); - _shadowMesh.forceRenderingOff = true; - - // material copying shit - int materialCount = _mainMesh.sharedMaterials.Length; - Material shadowMaterial = ShadowCloneHelper.shadowMaterial; - - _shadowMaterialBlock = new MaterialPropertyBlock(); - _shadowMaterials = new Material[materialCount]; - for (int i = 0; i < materialCount; i++) _shadowMaterials[i] = shadowMaterial; - } - - public bool Process() - { - bool shouldRender = _mainMesh.enabled && _mainMesh.gameObject.activeInHierarchy; - - // copying behaviour of SkinnedShadowClone, to visually be the same when a mesh toggles - if (!shouldRender) - { - _frameInitCounter = 0; - _hasInitialized = false; - _shadowMesh.forceRenderingOff = true; - return false; - } - - if (_frameInitCounter >= FrameInitCount) - { - if (_hasInitialized) - return true; - - _hasInitialized = true; - return true; - } - - _frameInitCounter++; - return false; - } - - public void RenderForShadow() - { - _shadowMesh.shadowCastingMode = ShadowCloneManager.s_DebugShowShadow - ? ShadowCastingMode.On : ShadowCastingMode.ShadowsOnly; - - _shadowMesh.forceRenderingOff = !_shouldCastShadows; - - // shadow casting needs clone to have original materials (uv discard) - // we also want to respect material swaps... but this is fucking slow :( - - if (!ShadowCloneManager.s_CopyMaterialsToShadow) - return; - - if (_hasShadowMaterials) - { - // NOTE: will not handle material swaps unless Avatar Overrender Ui is on - _shadowMesh.sharedMaterials = _mainMesh.sharedMaterials; - _hasShadowMaterials = false; - } - - UpdateCloneMaterialProperties(); - } - - public void RenderForUiCulling() - { - _shadowMesh.shadowCastingMode = ShadowCastingMode.On; - _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(); - } - - public void Dispose() - { - if (_shadowMesh == null) - return; // uh oh - - // Cleanup instanced Mesh & Materials - GameObject shadowMeshObject = _shadowMesh.gameObject; - UnityEngine.Object.Destroy(_shadowMeshFilter.sharedMesh); - UnityEngine.Object.Destroy(_shadowMeshFilter); - if (!_hasShadowMaterials) - { - var materials = _shadowMesh.sharedMaterials; - foreach (Material mat in materials) UnityEngine.Object.Destroy(mat); - } - UnityEngine.Object.Destroy(_shadowMesh); - UnityEngine.Object.Destroy(shadowMeshObject); - } - - #endregion - - #region Private Methods - - private void UpdateCloneMaterialProperties() - { - // copy material properties to shadow clone materials - _mainMesh.GetPropertyBlock(_shadowMaterialBlock); - _shadowMesh.SetPropertyBlock(_shadowMaterialBlock); - } - - #endregion -} \ No newline at end of file diff --git a/BetterShadowClone/ShadowClone/IShadowClone/SkinnedShadowClone.cs b/BetterShadowClone/ShadowClone/IShadowClone/SkinnedShadowClone.cs deleted file mode 100644 index 89d7494..0000000 --- a/BetterShadowClone/ShadowClone/IShadowClone/SkinnedShadowClone.cs +++ /dev/null @@ -1,296 +0,0 @@ -using System; -using UnityEngine; -using UnityEngine.Rendering; - -namespace NAK.BetterShadowClone; - -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"); - - // lame 2 frame init stuff - private const int FrameInitCount = 0; - private int _frameInitCounter; - private bool _hasInitialized; - - // shadow is used to cull ui, clone always exists - private readonly bool _shouldCastShadows; - private readonly SkinnedMeshRenderer _mainMesh; - private readonly MeshRenderer _shadowMesh; - private readonly MeshFilter _shadowMeshFilter; - private readonly Transform _rootBone; - - // clone copying - private GraphicsBuffer _graphicsBuffer; - private GraphicsBuffer _targetBuffer; - private ComputeBuffer _computeBuffer; - private int _threadGroups; - private int _bufferLayout; - - // material copying (unity is shit) - private bool _hasShadowMaterials; - private readonly Material[] _shadowMaterials; - private readonly MaterialPropertyBlock _shadowMaterialBlock; - - #region IShadowClone Methods - - // anything player can touch is suspect to death - public bool IsValid => _mainMesh != null && _shadowMesh != null && _rootBone != null; - - internal SkinnedShadowClone(SkinnedMeshRenderer renderer, FPRExclusion exclusion) - { - _mainMesh = renderer; - - if (_mainMesh == null - || _mainMesh.sharedMesh == null - || _mainMesh.sharedMaterials == null - || _mainMesh.sharedMaterials.Length == 0) - { - Dispose(); - 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.On; // visual mesh doesn't cast shadows - - (_shadowMesh, _shadowMeshFilter) = ShadowCloneManager.InstantiateShadowClone(_mainMesh); - _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 - - // material copying shit - int materialCount = _mainMesh.sharedMaterials.Length; - Material shadowMaterial = ShadowCloneHelper.shadowMaterial; - - _shadowMaterialBlock = new MaterialPropertyBlock(); // TODO: check if we need one per material on renderer, idk if this is only first index - _shadowMaterials = new Material[materialCount]; - for (int i = 0; i < materialCount; i++) _shadowMaterials[i] = shadowMaterial; - } - - public bool Process() - { - // some people animate renderer.enabled instead of gameObject.activeInHierarchy - // do not disable shadow clone game object, it causes a flicker when re-enabled! - bool shouldRender = _mainMesh.enabled && _mainMesh.gameObject.activeInHierarchy; - - // GraphicsBuffer becomes stale when mesh is disabled - if (!shouldRender) - { - _frameInitCounter = 0; - _hasInitialized = false; - _shadowMesh.forceRenderingOff = true; // force off if mesh is disabled - return false; // TODO: dispose stale buffers - } - - // Unity is weird, so we need to wait 2 frames before we can get the graphics buffer - if (_frameInitCounter >= FrameInitCount) - { - if (_hasInitialized) - return true; - - _hasInitialized = true; - SetupGraphicsBuffer(); - return true; - } - - _frameInitCounter++; - return false; - } - - public void RenderForShadow() - { - ResetShadowClone(); - RenderShadowClone(); - } - - public void RenderForUiCulling() - { - ConfigureShadowCloneForUiCulling(); - RenderShadowClone(); - } - - public void Dispose() - { - if (_shadowMesh != null) - { - // Cleanup instanced Mesh & Materials - GameObject shadowMeshObject = _shadowMesh.gameObject; - UnityEngine.Object.Destroy(_shadowMeshFilter.mesh); - UnityEngine.Object.Destroy(_shadowMeshFilter); - - // explain why this works - if (_hasShadowMaterials) _shadowMesh.sharedMaterials = _mainMesh.sharedMaterials; - foreach (Material mat in _shadowMesh.sharedMaterials) UnityEngine.Object.Destroy(mat); - - UnityEngine.Object.Destroy(_shadowMesh); - UnityEngine.Object.Destroy(shadowMeshObject); - } - - _graphicsBuffer?.Dispose(); - _graphicsBuffer = null; - _targetBuffer?.Dispose(); - _targetBuffer = null; - _computeBuffer?.Dispose(); - _computeBuffer = null; - } - - #endregion - - #region Private Methods - - // Unity is weird, so we need to wait 2 frames before we can get the graphics buffer - private void SetupGraphicsBuffer() - { - Mesh mesh = _mainMesh.sharedMesh; - Mesh shadowMesh = _shadowMesh.GetComponent().mesh; - - _bufferLayout = 0; - if (mesh.HasVertexAttribute(VertexAttribute.Position)) _bufferLayout += 3; - if (mesh.HasVertexAttribute(VertexAttribute.Normal)) _bufferLayout += 3; - if (mesh.HasVertexAttribute(VertexAttribute.Tangent)) _bufferLayout += 4; - _bufferLayout *= 4; // 4 bytes per float - - const float xThreadGroups = 32f; - _threadGroups = Mathf.CeilToInt(mesh.vertexCount / xThreadGroups); - - _mainMesh.vertexBufferTarget |= GraphicsBuffer.Target.Raw; - shadowMesh.vertexBufferTarget |= GraphicsBuffer.Target.Raw; - - _targetBuffer = shadowMesh.GetVertexBuffer(0); - - //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 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() - { - 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 :( - - if (!ShadowCloneManager.s_CopyMaterialsToShadow) - return; - - _shadowMesh.sharedMaterials = _mainMesh.sharedMaterials; - UpdateCloneMaterialProperties(); - } - - private void ConfigureShadowCloneForUiCulling() - { - _shadowMesh.shadowCastingMode = ShadowCastingMode.On; - _shadowMesh.forceRenderingOff = false; - - // UI culling needs clone to have write-to-depth shader - _shadowMesh.sharedMaterials = _shadowMaterials; - - // Not needed- MaterialPropertyBlock applied to renderer in RenderForShadow - UpdateCloneMaterialProperties(); - } - - private void RenderShadowClone() - { - // thanks sdraw, i suck at matrix math - Matrix4x4 rootMatrix = _mainMesh.localToWorldMatrix.inverse * Matrix4x4.TRS(_rootBone.position, _rootBone.rotation, Vector3.one); - - _graphicsBuffer = _mainMesh.GetVertexBuffer(); - 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(); - } - - private void UpdateCloneMaterialProperties() - { - // copy material properties to shadow clone materials - _mainMesh.GetPropertyBlock(_shadowMaterialBlock); - _shadowMesh.SetPropertyBlock(_shadowMaterialBlock); - } - - #endregion -} \ No newline at end of file diff --git a/BetterShadowClone/ShadowClone/ShadowCloneManager.cs b/BetterShadowClone/ShadowClone/ShadowCloneManager.cs deleted file mode 100644 index 4443efd..0000000 --- a/BetterShadowClone/ShadowClone/ShadowCloneManager.cs +++ /dev/null @@ -1,251 +0,0 @@ -using System.Collections.Generic; -using ABI_RC.Core; -using ABI_RC.Core.Player; -using ABI_RC.Core.Savior; -using MagicaCloth; -using UnityEngine; -using UnityEngine.Rendering; - -namespace NAK.BetterShadowClone; - -public class ShadowCloneManager : MonoBehaviour -{ - #region Singleton Implementation - - private static ShadowCloneManager _instance; - public static ShadowCloneManager Instance - { - get - { - if (_instance != null) return _instance; - _instance = new GameObject("NAK.ShadowCloneManager").AddComponent(); - DontDestroyOnLoad(_instance.gameObject); - return _instance; - } - } - - #endregion - - private const string ShadowClonePostfix = "_ShadowClone"; - //public const string CVRIgnoreForUiCulling = "CVRIgnoreForUiCulling"; // TODO: Shader Tag to ignore for UI culling? - - // Game cameras - private static Camera s_MainCamera; - private static Camera s_UiCamera; - - // 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 s_Exclusions = new(); - - // Shadow Clones - private readonly List s_ShadowClones = new(); - public void AddShadowClone(IShadowClone clone) - => s_ShadowClones.Add(clone); - - // Debug - private bool _debugShadowProcessingTime; - private readonly StopWatch _stopWatch = new(); - - #region Unity Events - - private void Start() - { - if (Instance != null - && Instance != this) - { - Destroy(this); - return; - } - - 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.onPreRender += MyOnPreCull; - - private void OnDisable() - => Camera.onPreRender -= MyOnPreCull; - - private void OnDestroy() - { - MetaPort.Instance.settings.settingBoolChanged.RemoveListener(OnSettingsBoolChanged); - } - - #endregion - - #region Shadow Clone Managment - - 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 (cam != s_MainCamera) - return; - - _hasRenderedThisFrame = true; - - _stopWatch.Start(); - - 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 - } - - if (!clone.Process()) continue; // not ready yet or disabled - - clone.RenderForShadow(); // first cam to render - } - - _stopWatch.Stop(); - } - - #endregion - - #region Game Events - - public void OnAvatarCleared() - { - // Dispose all shadow clones BEFORE game unloads avatar - // Otherwise we memory leak the shadow clones mesh & material instances!!! - foreach (IShadowClone clone in s_ShadowClones) - clone.Dispose(); - s_ShadowClones.Clear(); - } - - 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 __) - { - UpdatePlayerCameras(); - } - - #endregion - - #region Private Methods - - private static void UpdatePlayerCameras() - { - s_MainCamera = PlayerSetup.Instance.GetActiveCamera().GetComponent(); - s_UiCamera = s_MainCamera.transform.Find("_UICamera").GetComponent(); - - //s_PortableCamera = PortableCamera.Instance.cameraComponent; - } - - #endregion - - #region Static Helpers - - internal static IShadowClone CreateShadowClone(Renderer renderer, FPRExclusion exclusion) - { - return renderer switch - { - SkinnedMeshRenderer skinnedMeshRenderer => new SkinnedShadowClone(skinnedMeshRenderer, exclusion), - MeshRenderer meshRenderer => new MeshShadowClone(meshRenderer), - _ => null - }; - } - - internal static (MeshRenderer, MeshFilter) InstantiateShadowClone(SkinnedMeshRenderer meshRenderer) - { - GameObject shadowClone = new (meshRenderer.name + ShadowClonePostfix) { layer = CVRLayers.PlayerClone }; - 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(); - MeshFilter newMeshFilter = shadowClone.AddComponent(); - - ShadowCloneHelper.ConfigureRenderer(newMesh, true); - - // only shadow clone should cast shadows - newMesh.shadowCastingMode = ShadowCastingMode.ShadowsOnly; - - // copy mesh and materials - newMeshFilter.sharedMesh = meshRenderer.sharedMesh; - newMesh.sharedMaterials = meshRenderer.sharedMaterials; - - // copy probe anchor - newMesh.probeAnchor = meshRenderer.probeAnchor; - - return (newMesh, newMeshFilter); - } - - internal static (MeshRenderer, MeshFilter) InstantiateShadowClone(MeshRenderer meshRenderer) - { - GameObject shadowClone = new (meshRenderer.name + ShadowClonePostfix) { layer = CVRLayers.PlayerClone }; - shadowClone.transform.SetParent(meshRenderer.transform, false); - shadowClone.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); - shadowClone.transform.localScale = Vector3.one; - - MeshRenderer newMesh = shadowClone.AddComponent(); - MeshFilter newMeshFilter = shadowClone.AddComponent(); - - ShadowCloneHelper.ConfigureRenderer(newMesh, true); - - // only shadow clone should cast shadows - newMesh.shadowCastingMode = ShadowCastingMode.ShadowsOnly; - - // copy mesh and materials - newMeshFilter.sharedMesh = meshRenderer.GetComponent().sharedMesh; - newMesh.sharedMaterials = meshRenderer.sharedMaterials; - - // copy probe anchor - newMesh.probeAnchor = meshRenderer.probeAnchor; - - return (newMesh, newMeshFilter); - } - - #endregion -} \ No newline at end of file diff --git a/BetterShadowClone/ShadowCloneHelper.cs b/BetterShadowClone/ShadowCloneHelper.cs deleted file mode 100644 index 797ebb7..0000000 --- a/BetterShadowClone/ShadowCloneHelper.cs +++ /dev/null @@ -1,168 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using ABI_RC.Core; -using ABI.CCK.Components; -using UnityEngine; -using UnityEngine.Rendering; -using Object = UnityEngine.Object; - -namespace NAK.BetterShadowClone; - -public static class ShadowCloneHelper -{ - public static ComputeShader shader; - public static Material shadowMaterial; - - #region Avatar Setup - - public static void SetupAvatar(GameObject avatar) - { - Animator animator = avatar.GetComponent(); - if (animator == null || animator.avatar == null || animator.avatar.isHuman == false) - { - ShadowCloneMod.Logger.Warning("Avatar is not humanoid!"); - return; - } - - Transform headBone = animator.GetBoneTransform(HumanBodyBones.Head); - if (headBone == null) - { - ShadowCloneMod.Logger.Warning("Head bone not found!"); - return; - } - - var renderers = avatar.GetComponentsInChildren(true); - if (renderers == null || renderers.Length == 0) - { - ShadowCloneMod.Logger.Warning("No renderers found!"); - return; - } - - ShadowCloneMod.Logger.Msg($"Found {renderers.Length} renderers. Processing..."); - - // create shadow clones - ProcessRenderers(renderers, avatar.transform, headBone); - } - - private static void ProcessRenderers(IEnumerable renderers, Transform root, Transform headBone) - { - Stopwatch sw = Stopwatch.StartNew(); - - IReadOnlyDictionary exclusions = CollectTransformToExclusionMap(root, headBone); - var exclusion = headBone.gameObject.GetComponent(); - - // log current time - ShadowCloneMod.Logger.Msg($"CollectTransformToExclusionMap in {sw.ElapsedMilliseconds}ms"); - - foreach (Renderer renderer in renderers) - { - ConfigureRenderer(renderer); - - if (ModSettings.EntryUseShadowClone.Value) - { - 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); - } - - sw.Stop(); - - // log current time - ShadowCloneMod.Logger.Msg($"ProcessRenderers in {sw.ElapsedMilliseconds}ms"); - } - - #endregion - - #region FPR Exclusion Processing - - private static Dictionary CollectTransformToExclusionMap(Component root, Transform headBone) - { - // add an fpr exclusion to the head bone - headBone.gameObject.AddComponent().target = headBone; - - // add an FPRExclusion for all target entries on CVRAvatar (Experimental feature) - CVRAvatar avatar = root.GetComponent(); - if (avatar != null) - { - foreach (CVRAvatarFPREntry fprEntry in avatar.fprSettingsList.Where(fprEntry => fprEntry.transform != null)) - fprEntry.transform.gameObject.AddComponent().target = fprEntry.transform; - } - - // get all FPRExclusions - var fprExclusions = root.GetComponentsInChildren(true).ToList(); - - // get all valid exclusion targets, and destroy invalid exclusions - Dictionary exclusionTargets = new(); - for (int i = fprExclusions.Count - 1; i >= 0; i--) - { - FPRExclusion exclusion = fprExclusions[i]; - if (exclusion.target == null) - { - Object.Destroy(exclusion); - continue; - } - - // first to add wins - exclusionTargets.TryAdd(exclusion.target, exclusion); - } - - // process each FPRExclusion (recursive) - foreach (FPRExclusion exclusion in fprExclusions) - ProcessExclusion(exclusion, exclusion.target); - - // log totals - ShadowCloneMod.Logger.Msg($"Exclusions: {fprExclusions.Count}"); - return exclusionTargets; - - void ProcessExclusion(FPRExclusion exclusion, Transform transform) - { - if (exclusionTargets.ContainsKey(transform) - && exclusionTargets[transform] != exclusion) return; // found other exclusion root - - exclusion.affectedChildren.Add(transform); // associate with the exclusion - exclusionTargets.TryAdd(transform, exclusion); // add to the dictionary (yes its wasteful) - - foreach (Transform child in transform) - ProcessExclusion(exclusion, child); // process children - } - } - - #endregion - - #region Generic Renderer Configuration - - internal static void ConfigureRenderer(Renderer renderer, bool isShadowClone = false) - { - // generic optimizations - renderer.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; - - // don't let visual/shadow mesh cull in weird worlds - renderer.allowOcclusionWhenDynamic = false; // (third person stripped local player naked when camera was slightly occluded) - - // shadow clone optimizations (always MeshRenderer) - if (isShadowClone) - { - // renderer.receiveShadows = false; - // renderer.lightProbeUsage = LightProbeUsage.Off; - // renderer.reflectionProbeUsage = ReflectionProbeUsage.Off; - return; - } - - if (renderer is not SkinnedMeshRenderer skinnedMeshRenderer) - return; - - // GraphicsBuffer becomes stale randomly otherwise ??? - //skinnedMeshRenderer.updateWhenOffscreen = true; - - // skin mesh renderer optimizations - skinnedMeshRenderer.skinnedMotionVectors = false; - skinnedMeshRenderer.forceMatrixRecalculationPerRender = false; // expensive - skinnedMeshRenderer.quality = SkinQuality.Bone4; - } - - #endregion -} \ No newline at end of file diff --git a/BetterShadowClone/TransformHider/FPRExclusion.cs b/BetterShadowClone/TransformHider/FPRExclusion.cs deleted file mode 100644 index b07aeea..0000000 --- a/BetterShadowClone/TransformHider/FPRExclusion.cs +++ /dev/null @@ -1,35 +0,0 @@ -using UnityEngine; - -namespace NAK.BetterShadowClone; - -/// -/// Manual exclusion component for the TransformHider (FPR) system. -/// Allows you to manually hide and show a transform that would otherwise be hidden. -/// -public class FPRExclusion : MonoBehaviour -{ - public Transform target; - - internal readonly List affectedVertexIndices = new(); - - internal readonly List affectedChildren = new(); - internal readonly List relatedTasks = new(); - - private void OnEnable() - => SetFPRState(true); - - private void OnDisable() - => SetFPRState(false); - - private void SetFPRState(bool state) - { - if (relatedTasks == null) return; // no hiders to set - foreach (IFPRExclusionTask task in relatedTasks) - task.IsActive = state; - } -} - -public interface IFPRExclusionTask -{ - public bool IsActive { get; set; } -} \ No newline at end of file diff --git a/BetterShadowClone/TransformHider/ITransformHider/ITransformHider.cs b/BetterShadowClone/TransformHider/ITransformHider/ITransformHider.cs deleted file mode 100644 index 4922adf..0000000 --- a/BetterShadowClone/TransformHider/ITransformHider/ITransformHider.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace NAK.BetterShadowClone; - -public interface ITransformHider : IDisposable -{ - bool IsActive { get; set; } - bool IsValid { get; } - bool Process(); - bool PostProcess(); - void HideTransform(bool forced = false); - void ShowTransform(); -} \ No newline at end of file diff --git a/BetterShadowClone/TransformHider/ITransformHider/MeshTransformHider.cs b/BetterShadowClone/TransformHider/ITransformHider/MeshTransformHider.cs deleted file mode 100644 index 523aab3..0000000 --- a/BetterShadowClone/TransformHider/ITransformHider/MeshTransformHider.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System; -using UnityEngine; -using UnityEngine.Rendering; - -namespace NAK.BetterShadowClone; - -public class MeshTransformHider : ITransformHider, IFPRExclusionTask -{ - // lame 2 frame init stuff - private const int FrameInitCount = 0; - private int _frameInitCounter; - private bool _hasInitialized; - private bool _markedForDeath; - - // mesh - private readonly MeshRenderer _mainMesh; - private bool _enabledState; - - #region ITransformHider Methods - - public bool IsActive { get; set; } = true; // default hide, but FPRExclusion can override - - // anything player can touch is suspect to death - public bool IsValid => _mainMesh != null && !_markedForDeath; - - public MeshTransformHider(MeshRenderer renderer, IReadOnlyDictionary exclusions) - { - Transform rootBone = renderer.transform; - - // if no key found, dispose - if (!exclusions.TryGetValue(rootBone, out FPRExclusion exclusion)) - { - Dispose(); - return; - } - - exclusion.relatedTasks.Add(this); - - _mainMesh = renderer; - - if (_mainMesh == null - || _mainMesh.sharedMaterials == null - || _mainMesh.sharedMaterials.Length == 0) - { - Dispose(); - } - } - - public bool Process() - { - bool shouldRender = _mainMesh.enabled && _mainMesh.gameObject.activeInHierarchy; - - // GraphicsBuffer becomes stale when mesh is disabled - if (!shouldRender) - { - _frameInitCounter = 0; - _hasInitialized = false; - return false; - } - - // Unity is weird, so we need to wait 2 frames before we can get the graphics buffer - if (_frameInitCounter >= FrameInitCount) - { - if (_hasInitialized) - return true; - - _hasInitialized = true; - return true; - } - - _frameInitCounter++; - return false; - } - - public bool PostProcess() - => true; - - public void HideTransform(bool forced = false) - { - if (!forced && !IsActive) - return; - - _enabledState = _mainMesh.enabled; - _mainMesh.enabled = false; - } - - public void ShowTransform() - { - _mainMesh.enabled = _enabledState; - } - - public void Dispose() - { - _markedForDeath = true; - } - - #endregion -} \ No newline at end of file diff --git a/BetterShadowClone/TransformHider/ITransformHider/SkinnedTransformHider.cs b/BetterShadowClone/TransformHider/ITransformHider/SkinnedTransformHider.cs deleted file mode 100644 index 10a32b3..0000000 --- a/BetterShadowClone/TransformHider/ITransformHider/SkinnedTransformHider.cs +++ /dev/null @@ -1,253 +0,0 @@ -using System; -using System.Diagnostics; -using UnityEngine; -using UnityEngine.Rendering; - -namespace NAK.BetterShadowClone; - -public class SkinnedTransformHider : ITransformHider -{ - private static readonly int s_Pos = Shader.PropertyToID("pos"); - private static readonly int s_BufferLayout = Shader.PropertyToID("bufferLayout"); - private static readonly int s_WeightedCount = Shader.PropertyToID("weightedCount"); - private static readonly int s_WeightedVertices = Shader.PropertyToID("weightedVertices"); - private static readonly int s_VertexBuffer = Shader.PropertyToID("VertexBuffer"); - - // lame 2 frame init stuff - private const int FrameInitCount = 0; - private int _frameInitCounter; - private bool _hasInitialized; - private bool _markedForDeath; - - // mesh & bone - private readonly SkinnedMeshRenderer _mainMesh; - private readonly Transform _rootBone; - - // main hider stuff - private GraphicsBuffer _graphicsBuffer; - private int _bufferLayout; - - // subtasks - private readonly List _subTasks = new(); - - #region ITransformHider Methods - - public bool IsActive { get; set; } = true; // default hide, but FPRExclusion can override - - // anything player can touch is suspect to death - public bool IsValid => !_markedForDeath && _mainMesh != null && _rootBone != null; - - public SkinnedTransformHider(SkinnedMeshRenderer renderer, IReadOnlyDictionary exclusions) - { - Stopwatch sw = Stopwatch.StartNew(); - - _mainMesh = renderer; - - if (_mainMesh == null - || _mainMesh.sharedMesh == null - || _mainMesh.sharedMaterials == null - || _mainMesh.sharedMaterials.Length == 0) - { - Dispose(); - return; // no mesh or bone! - } - - _rootBone = _mainMesh.rootBone; - _rootBone ??= _mainMesh.transform; // fallback to transform if no root bone - - // log current time - ShadowCloneMod.Logger.Msg($"SkinnedTransformHider part 1 in {sw.ElapsedMilliseconds}ms"); - - SubTask.FindExclusionVertList(renderer, exclusions); - - foreach (var exclusion in exclusions) - { - FPRExclusion fprExclusion = exclusion.Value; - if (fprExclusion.affectedVertexIndices.Count == 0) - continue; // no affected verts - - SubTask subTask = new(this, fprExclusion, fprExclusion.affectedVertexIndices); - _subTasks.Add(subTask); - fprExclusion.relatedTasks.Add(subTask); - fprExclusion.affectedVertexIndices.Clear(); // clear list for next SkinnedTransformHider - } - - // log current time - ShadowCloneMod.Logger.Msg($"SkinnedTransformHider part 3 in {sw.ElapsedMilliseconds}ms"); - - if (_subTasks.Count == 0) - { - Dispose(); // had the bones, but not the weights :? - ShadowCloneMod.Logger.Warning("SkinnedTransformHider No valid exclusions found!"); - } - - sw.Stop(); - - ShadowCloneMod.Logger.Msg($"SkinnedTransformHider created in {sw.ElapsedMilliseconds}ms"); - } - - public bool Process() - { - bool shouldRender = _mainMesh.enabled && _mainMesh.gameObject.activeInHierarchy; - - // GraphicsBuffer becomes stale when mesh is disabled - if (!shouldRender) - { - _frameInitCounter = 0; - _hasInitialized = false; - return false; - } - - // Unity is weird, so we need to wait 2 frames before we can get the graphics buffer - if (_frameInitCounter >= FrameInitCount) - { - if (_hasInitialized) - return true; - - _hasInitialized = true; - SetupGraphicsBuffer(); - return true; - } - - _mainMesh.forceRenderingOff = true; // force off if mesh is disabled - - _frameInitCounter++; - return false; - } - - public bool PostProcess() - => false; // not needed - - public void HideTransform(bool forced = false) - { - _mainMesh.forceRenderingOff = false; - - _graphicsBuffer = _mainMesh.GetVertexBuffer(); - - foreach (SubTask subTask in _subTasks) - if ((forced || subTask.IsActive) && subTask.IsValid) - subTask.Dispatch(); - - _graphicsBuffer.Release(); - } - - public void ShowTransform() - { - // not needed - } - - public void Dispose() - { - _markedForDeath = true; - foreach (SubTask subTask in _subTasks) - subTask.Dispose(); - - _graphicsBuffer?.Dispose(); - _graphicsBuffer = null; - } - - #endregion - - #region Private Methods - - // Unity is weird, so we need to wait 2 frames before we can get the graphics buffer - private void SetupGraphicsBuffer() - { - Mesh mesh = _mainMesh.sharedMesh; - - _bufferLayout = 0; - if (mesh.HasVertexAttribute(VertexAttribute.Position)) _bufferLayout += 3; - if (mesh.HasVertexAttribute(VertexAttribute.Normal)) _bufferLayout += 3; - if (mesh.HasVertexAttribute(VertexAttribute.Tangent)) _bufferLayout += 4; - // ComputeShader is doing bitshift so we dont need to multiply by 4 - - _mainMesh.vertexBufferTarget |= GraphicsBuffer.Target.Raw; - } - - #endregion - - #region Sub Task Class - - private class SubTask : IFPRExclusionTask - { - public bool IsActive { get; set; } = true; - public bool IsValid => _computeBuffer != null; // TODO: cleanup dead tasks - - private readonly SkinnedTransformHider _parent; - private readonly Transform _shrinkBone; - private readonly int _vertexCount; - private readonly ComputeBuffer _computeBuffer; - private readonly int _threadGroups; - - public SubTask(SkinnedTransformHider parent, FPRExclusion exclusion, List exclusionVerts) - { - _parent = parent; - _shrinkBone = exclusion.target; - - _vertexCount = exclusionVerts.Count; - _computeBuffer = new ComputeBuffer(_vertexCount, sizeof(int)); - _computeBuffer.SetData(exclusionVerts.ToArray()); - - const float xThreadGroups = 64f; - _threadGroups = Mathf.CeilToInt(_vertexCount / xThreadGroups); - } - - public void Dispatch() - { - Vector3 pos = _parent._rootBone.transform.InverseTransformPoint(_shrinkBone.position) * _parent._rootBone.lossyScale.y; - TransformHiderManager.shader.SetVector(s_Pos, pos); - TransformHiderManager.shader.SetInt(s_WeightedCount, _vertexCount); - TransformHiderManager.shader.SetInt(s_BufferLayout, _parent._bufferLayout); - TransformHiderManager.shader.SetBuffer(0, s_WeightedVertices, _computeBuffer); - TransformHiderManager.shader.SetBuffer(0, s_VertexBuffer, _parent._graphicsBuffer); - TransformHiderManager.shader.Dispatch(0, _threadGroups, 1, 1); - } - - public void Dispose() - { - _computeBuffer?.Dispose(); - } - - #region Private Methods - - public static void FindExclusionVertList(SkinnedMeshRenderer renderer, IReadOnlyDictionary exclusions) - { - var boneWeights = renderer.sharedMesh.boneWeights; - - HashSet weights = new(); - for (int i = 0; i < renderer.bones.Length; i++) - { - // if bone == any key in exclusions, add to weights - if (!exclusions.TryGetValue(renderer.bones[i], out FPRExclusion _)) - continue; - - 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]; - - if (bone == null) continue; // no bone found - - // add vertex to exclusion list - exclusions[bone].affectedVertexIndices.Add(i); - } - } - - #endregion - } - - #endregion -} \ No newline at end of file diff --git a/BetterShadowClone/TransformHider/TransformHiderManager.cs b/BetterShadowClone/TransformHider/TransformHiderManager.cs deleted file mode 100644 index 2c14854..0000000 --- a/BetterShadowClone/TransformHider/TransformHiderManager.cs +++ /dev/null @@ -1,213 +0,0 @@ -using ABI_RC.Core.Player; -using ABI_RC.Systems.VRModeSwitch; -using MagicaCloth; -using UnityEngine; - -namespace NAK.BetterShadowClone; - -// Built on top of Koneko's BoneHider but to mimic the ShadowCloneManager - -public class TransformHiderManager : MonoBehaviour -{ - public static ComputeShader shader; - - #region Singleton Implementation - - private static TransformHiderManager _instance; - public static TransformHiderManager Instance - { - get - { - if (_instance != null) return _instance; - _instance = new GameObject("Koneko.TransformHiderManager").AddComponent(); - DontDestroyOnLoad(_instance.gameObject); - return _instance; - } - } - - #endregion - - // Game cameras - private static Camera s_MainCamera; - private static Camera s_UiCamera; - - // Settings - internal static bool s_DebugHeadHide; - internal static bool s_DisallowFprExclusions = true; - - // Implementation - private bool _hasRenderedThisFrame; - - // Shadow Clones - private readonly List s_TransformHider = new(); - public void AddTransformHider(ITransformHider clone) - => s_TransformHider.Add(clone); - - // Debug - private bool _debugHeadHiderProcessingTime; - private readonly StopWatch _stopWatch = new(); - - #region Unity Events - - private void Start() - { - if (Instance != null - && Instance != this) - { - Destroy(this); - return; - } - - UpdatePlayerCameras(); - - s_DisallowFprExclusions = ModSettings.EntryDontRespectFPR.Value; - s_DebugHeadHide = ModSettings.EntryDebugHeadHide.Value; - - VRModeSwitchEvents.OnCompletedVRModeSwitch.AddListener(OnVRModeSwitchCompleted); - } - - private void OnEnable() - { - Camera.onPreRender += MyOnPreRender; - Camera.onPostRender += MyOnPostRender; - } - - private void OnDisable() - { - Camera.onPreRender -= MyOnPreRender; - Camera.onPostRender -= MyOnPostRender; - } - - private void OnDestroy() - { - VRModeSwitchEvents.OnCompletedVRModeSwitch.RemoveListener(OnVRModeSwitchCompleted); - OnAvatarCleared(); - } - - #endregion - - #region Transform Hider Managment - - private void Update() - { - _hasRenderedThisFrame = false; - } - - private void MyOnPreRender(Camera cam) - { - if (_hasRenderedThisFrame) - return; // can only hide head once per frame - - if (cam != s_MainCamera // only hide in player cam, or if debug is on - && !s_DebugHeadHide) - return; - - if (!CheckPlayerCamWithinRange()) - return; // player is too far away (likely HoloPort or Sitting) - - if (!ShadowCloneMod.CheckWantsToHideHead(cam)) - return; // listener said no (Third Person, etc) - - _hasRenderedThisFrame = true; - - _stopWatch.Start(); - - for (int i = s_TransformHider.Count - 1; i >= 0; i--) - { - ITransformHider hider = s_TransformHider[i]; - if (hider is not { IsValid: true }) - { - hider?.Dispose(); - s_TransformHider.RemoveAt(i); - continue; // invalid or dead - } - - if (!hider.Process()) continue; // not ready yet or disabled - - hider.HideTransform(s_DisallowFprExclusions); - } - - _stopWatch.Stop(); - if (_debugHeadHiderProcessingTime) Debug.Log($"TransformHiderManager.MyOnPreRender({s_DebugHeadHide}) took {_stopWatch.ElapsedMilliseconds}ms"); - } - - private void MyOnPostRender(Camera cam) - { - if (cam != s_UiCamera) return; // ui camera is expected to render last - - for (int i = s_TransformHider.Count - 1; i >= 0; i--) - { - ITransformHider hider = s_TransformHider[i]; - if (hider is not { IsValid: true }) - { - hider?.Dispose(); - s_TransformHider.RemoveAt(i); - continue; // invalid or dead - } - - if (!hider.PostProcess()) continue; // does not need post processing - - hider.ShowTransform(); - } - } - - #endregion - - #region Game Events - - public void OnAvatarCleared() - { - // Dispose all shadow clones BEFORE game unloads avatar - // Otherwise we memory leak the shadow clones mesh & material instances!!! - foreach (ITransformHider hider in s_TransformHider) - hider.Dispose(); - s_TransformHider.Clear(); - } - - private void OnVRModeSwitchCompleted(bool _) - => UpdatePlayerCameras(); - - #endregion - - #region Private Methods - - private static void UpdatePlayerCameras() - { - s_MainCamera = PlayerSetup.Instance.GetActiveCamera().GetComponent(); - s_UiCamera = s_MainCamera.transform.Find("_UICamera").GetComponent(); - } - - private static bool CheckPlayerCamWithinRange() - { - if (PlayerSetup.Instance == null) - return false; // hack - - const float MinHeadHidingRange = 0.5f; - Vector3 playerHeadPos = PlayerSetup.Instance.GetViewWorldPosition(); - Vector3 playerCamPos = s_MainCamera.transform.position; - float scaleModifier = PlayerSetup.Instance.GetPlaySpaceScale(); - return (Vector3.Distance(playerHeadPos, playerCamPos) < (MinHeadHidingRange * scaleModifier)); - } - - #endregion - - #region Static Helpers - - internal static bool IsLegacyFPRExcluded(Component renderer) - => renderer.gameObject.name.Contains("[FPR]"); - - internal static ITransformHider CreateTransformHider(Component renderer, IReadOnlyDictionary exclusions) - { - if (IsLegacyFPRExcluded(renderer)) - return null; - - return renderer switch - { - SkinnedMeshRenderer skinnedMeshRenderer => new SkinnedTransformHider(skinnedMeshRenderer, exclusions), - MeshRenderer meshRenderer => new MeshTransformHider(meshRenderer, exclusions), - _ => null - }; - } - - #endregion -} \ No newline at end of file diff --git a/BetterShadowClone/format.json b/BetterShadowClone/format.json deleted file mode 100644 index a2374f1..0000000 --- a/BetterShadowClone/format.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "_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/NotAKidoS/NAK_CVR_Mods/releases/download/r24/EzCurls.dll", - "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/EzCurls/", - "changelog": "- Initial CVRMG release", - "embedcolor": "7d7d7d" -} \ No newline at end of file diff --git a/FuckCameraIndicator/FuckCameraIndicator.csproj b/FuckCameraIndicator/FuckCameraIndicator.csproj deleted file mode 100644 index e94f9dc..0000000 --- a/FuckCameraIndicator/FuckCameraIndicator.csproj +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/FuckCameraIndicator/Main.cs b/FuckCameraIndicator/Main.cs deleted file mode 100644 index a0c7957..0000000 --- a/FuckCameraIndicator/Main.cs +++ /dev/null @@ -1,34 +0,0 @@ -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().forceRenderingOff = true; - } -} \ No newline at end of file diff --git a/FuckCameraIndicator/Properties/AssemblyInfo.cs b/FuckCameraIndicator/Properties/AssemblyInfo.cs deleted file mode 100644 index 05525a7..0000000 --- a/FuckCameraIndicator/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,29 +0,0 @@ -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/NotAKidoS/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"; -} \ No newline at end of file diff --git a/FuckCameraIndicator/README.md b/FuckCameraIndicator/README.md deleted file mode 100644 index af9d39c..0000000 --- a/FuckCameraIndicator/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# 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. diff --git a/FuckCameraIndicator/format.json b/FuckCameraIndicator/format.json deleted file mode 100644 index a2374f1..0000000 --- a/FuckCameraIndicator/format.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "_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/NotAKidoS/NAK_CVR_Mods/releases/download/r24/EzCurls.dll", - "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/EzCurls/", - "changelog": "- Initial CVRMG release", - "embedcolor": "7d7d7d" -} \ No newline at end of file diff --git a/MirrorClone/Main.cs b/MirrorClone/Main.cs deleted file mode 100644 index 87afe20..0000000 --- a/MirrorClone/Main.cs +++ /dev/null @@ -1,80 +0,0 @@ -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 -} \ No newline at end of file diff --git a/MirrorClone/MirrorClone.csproj b/MirrorClone/MirrorClone.csproj deleted file mode 100644 index e94f9dc..0000000 --- a/MirrorClone/MirrorClone.csproj +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/MirrorClone/MirrorClone/MirrorCloneManager.cs b/MirrorClone/MirrorClone/MirrorCloneManager.cs deleted file mode 100644 index 035c9c0..0000000 --- a/MirrorClone/MirrorClone/MirrorCloneManager.cs +++ /dev/null @@ -1,247 +0,0 @@ -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(); - - if (!_mirrorClone.TryGetComponent(out _mirrorAnimator)) - _mirrorAnimator = gameObject.AddComponent(); - _mirrorAnimator.runtimeAnimatorController = baseAnimator.runtimeAnimatorController; - - _animatorManager._copyAnimator = _mirrorAnimator; // thank you for existing - - var cameras = PlayerSetup.Instance.GetComponentsInChildren(true); - foreach (var camera in cameras) - { - // hide PlayerClone layer from all cameras - camera.cullingMask &= ~(1 << CVRLayers.PlayerClone); - } - - var mirrors = Resources.FindObjectsOfTypeAll(); - 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(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(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(true); - // var mirrorCloneTransforms = _mirrorClone.GetComponentsInChildren(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 -} \ No newline at end of file diff --git a/MirrorClone/ModSettings.cs b/MirrorClone/ModSettings.cs deleted file mode 100644 index 05c753a..0000000 --- a/MirrorClone/ModSettings.cs +++ /dev/null @@ -1,31 +0,0 @@ -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 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) - { - - } -} \ No newline at end of file diff --git a/MirrorClone/Properties/AssemblyInfo.cs b/MirrorClone/Properties/AssemblyInfo.cs deleted file mode 100644 index 611ba51..0000000 --- a/MirrorClone/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,29 +0,0 @@ -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/NotAKidoS/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"; -} \ No newline at end of file diff --git a/MirrorClone/README.md b/MirrorClone/README.md deleted file mode 100644 index af9d39c..0000000 --- a/MirrorClone/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# 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. diff --git a/MirrorClone/format.json b/MirrorClone/format.json deleted file mode 100644 index a2374f1..0000000 --- a/MirrorClone/format.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "_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/NotAKidoS/NAK_CVR_Mods/releases/download/r24/EzCurls.dll", - "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/EzCurls/", - "changelog": "- Initial CVRMG release", - "embedcolor": "7d7d7d" -} \ No newline at end of file diff --git a/NAK_CVR_Mods.sln b/NAK_CVR_Mods.sln index cf5c2e2..c602176 100644 --- a/NAK_CVR_Mods.sln +++ b/NAK_CVR_Mods.sln @@ -31,12 +31,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EzCurls", "EzCurls\EzCurls. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhysicsGunMod", "PhysicsGunMod\PhysicsGunMod.csproj", "{F94DDB73-9041-4F5C-AD43-6960701E8417}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MirrorClone", "MirrorClone\MirrorClone.csproj", "{D5E81123-9D3B-4420-9CCD-1861657BE00B}" -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}") = "Nevermind", "Nevermind\Nevermind.csproj", "{AC4857DD-F6D9-436D-A3EE-D148A518E642}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShadowCloneFallback", "ShadowCloneFallback\ShadowCloneFallback.csproj", "{69AF3C10-1BB1-4746-B697-B5A81D78C8D9}" @@ -85,8 +79,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AvatarQueueSystemTweaks", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomSpawnPoint", "CustomSpawnPoint\CustomSpawnPoint.csproj", "{51CA34CA-7684-4819-AC9E-89DFAD63E9AB}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NukePostPresentHandoff", "NukePostPresentHandoff\NukePostPresentHandoff.csproj", "{77F332CD-019A-472F-9269-CFDEB087B3F9}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CVRLuaToolsExtension", "CVRLuaToolsExtension\CVRLuaToolsExtension.csproj", "{FE6BA6EC-2C11-49E1-A2FB-13F2A1C9E7F9}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stickers", "Stickers\Stickers.csproj", "{E5F54B3E-A676-4DD5-A6DB-73AFA54BEC5E}" @@ -157,18 +149,6 @@ Global {F94DDB73-9041-4F5C-AD43-6960701E8417}.Debug|Any CPU.Build.0 = Debug|Any CPU {F94DDB73-9041-4F5C-AD43-6960701E8417}.Release|Any CPU.ActiveCfg = Release|Any CPU {F94DDB73-9041-4F5C-AD43-6960701E8417}.Release|Any CPU.Build.0 = Release|Any CPU - {D5E81123-9D3B-4420-9CCD-1861657BE00B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D5E81123-9D3B-4420-9CCD-1861657BE00B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D5E81123-9D3B-4420-9CCD-1861657BE00B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D5E81123-9D3B-4420-9CCD-1861657BE00B}.Release|Any CPU.Build.0 = Release|Any CPU - {D0C40987-AF16-490A-9304-F99D5A5A774C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {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 {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 @@ -265,10 +245,6 @@ Global {51CA34CA-7684-4819-AC9E-89DFAD63E9AB}.Debug|Any CPU.Build.0 = Debug|Any CPU {51CA34CA-7684-4819-AC9E-89DFAD63E9AB}.Release|Any CPU.ActiveCfg = Release|Any CPU {51CA34CA-7684-4819-AC9E-89DFAD63E9AB}.Release|Any CPU.Build.0 = Release|Any CPU - {77F332CD-019A-472F-9269-CFDEB087B3F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {77F332CD-019A-472F-9269-CFDEB087B3F9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {77F332CD-019A-472F-9269-CFDEB087B3F9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {77F332CD-019A-472F-9269-CFDEB087B3F9}.Release|Any CPU.Build.0 = Release|Any CPU {FE6BA6EC-2C11-49E1-A2FB-13F2A1C9E7F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FE6BA6EC-2C11-49E1-A2FB-13F2A1C9E7F9}.Debug|Any CPU.Build.0 = Debug|Any CPU {FE6BA6EC-2C11-49E1-A2FB-13F2A1C9E7F9}.Release|Any CPU.ActiveCfg = Release|Any CPU