From 04c4a4590dcf5c3e434232ef01b53650f3d6f242 Mon Sep 17 00:00:00 2001 From: SurprisinglySuspicious Date: Wed, 20 Nov 2024 16:07:52 -0500 Subject: [PATCH 001/119] Issue: If NStrip wasn't found in folder or PATH, it tries to show a message to user, but it doesn't wait for key input, so it just immediately closes. --- copy_and_nstrip_dll.ps1 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/copy_and_nstrip_dll.ps1 b/copy_and_nstrip_dll.ps1 index aa4cb97..d4b95db 100644 --- a/copy_and_nstrip_dll.ps1 +++ b/copy_and_nstrip_dll.ps1 @@ -139,7 +139,7 @@ if ($missingMods.Count -gt 0) { Write-Host "" Write-Host "Copied all libraries!" Write-Host "" -Write-Host "Press any key to strip the Dlls using NStrip" +Write-Host "Press any key to strip the DLLs using NStrip..." $HOST.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") | OUT-NULL $HOST.UI.RawUI.Flushinputbuffer() @@ -156,6 +156,10 @@ else { # Display an error message if NStrip.exe could not be found Write-Host "Could not find NStrip.exe in the current directory nor in the PATH." -ForegroundColor Red Write-Host "Visit https://github.com/bbepis/NStrip/releases/latest to grab a copy." -ForegroundColor Red + Write-Host "" + Write-Host "Press any key to exit..." + $HOST.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") | OUT-NULL + $HOST.UI.RawUI.Flushinputbuffer() return } } @@ -169,6 +173,6 @@ foreach($dllFile in $dllsToStrip) { Write-Host "" Write-Host "Copied all libraries and stripped the DLLs!" Write-Host "" -Write-Host "Press any key to exit" +Write-Host "Press any key to exit..." $HOST.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") | OUT-NULL $HOST.UI.RawUI.Flushinputbuffer() From 70a54b632c819a75805851a44de4edd512fb3fab Mon Sep 17 00:00:00 2001 From: SurprisinglySuspicious <100347264+SurprisinglySuspicious@users.noreply.github.com> Date: Wed, 20 Nov 2024 16:59:19 -0500 Subject: [PATCH 002/119] Add it for PATH too --- copy_and_nstrip_dll.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/copy_and_nstrip_dll.ps1 b/copy_and_nstrip_dll.ps1 index d4b95db..0f2c7f3 100644 --- a/copy_and_nstrip_dll.ps1 +++ b/copy_and_nstrip_dll.ps1 @@ -35,6 +35,10 @@ else { else { Write-Host "[ERROR] ChilloutVR.exe not found in CVRPATH or the default Steam location." Write-Host " Please define the Environment Variable CVRPATH pointing to the ChilloutVR folder!" + Write-Host "" + Write-Host "Press any key to exit..." + $HOST.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") | OUT-NULL + $HOST.UI.RawUI.Flushinputbuffer() return } } From 621321c498938fa4d3778cc4a9629135bcd06f76 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Wed, 15 Jan 2025 16:41:37 -0600 Subject: [PATCH 003/119] ASTExtension: Fixes for 2025r178 --- ASTExtension/Properties/AssemblyInfo.cs | 2 +- ASTExtension/format.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ASTExtension/Properties/AssemblyInfo.cs b/ASTExtension/Properties/AssemblyInfo.cs index faa1dc6..5c617e2 100644 --- a/ASTExtension/Properties/AssemblyInfo.cs +++ b/ASTExtension/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.ASTExtension.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.1"; + public const string Version = "1.0.2"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/ASTExtension/format.json b/ASTExtension/format.json index 55315d6..5ad14ea 100644 --- a/ASTExtension/format.json +++ b/ASTExtension/format.json @@ -1,8 +1,8 @@ { "_id": 223, "name": "ASTExtension", - "modversion": "1.0.1", - "gameversion": "2024r175", + "modversion": "1.0.2", + "gameversion": "2025r178", "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS", @@ -17,8 +17,8 @@ "requirements": [ "BTKUILib" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r35/ASTExtension.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r45/ASTExtension.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ASTExtension/", - "changelog": "- Fixed an issue where the parameter calibration process would sometimes result in the mouth pointer being misplaced when generated.\n- Fixed IsGripping check for Knuckles controllers not requiring *both* hands as intended.", + "changelog": "- Fixes for 2025r178", "embedcolor": "#f61963" } \ No newline at end of file From 40bc88586e8b09fdc69c8023c5b851ec7e48931b Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Wed, 15 Jan 2025 16:42:05 -0600 Subject: [PATCH 004/119] RCCVirtualSteeringWheel: Fixes for 2025r178 --- RCCVirtualSteeringWheel/Patches.cs | 3 +++ RCCVirtualSteeringWheel/Properties/AssemblyInfo.cs | 2 +- .../Components/SteeringWheelRoot.cs | 1 - RCCVirtualSteeringWheel/format.json | 12 ++++++------ 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/RCCVirtualSteeringWheel/Patches.cs b/RCCVirtualSteeringWheel/Patches.cs index c4824ce..b9745d9 100644 --- a/RCCVirtualSteeringWheel/Patches.cs +++ b/RCCVirtualSteeringWheel/Patches.cs @@ -24,6 +24,9 @@ internal static class RCCCarControllerV3_Patches { if (!result.IsValid) return; + + if (!__instance) + return; SteeringWheelRoot.SetupSteeringWheel(__instance, result.LocalBounds); }); diff --git a/RCCVirtualSteeringWheel/Properties/AssemblyInfo.cs b/RCCVirtualSteeringWheel/Properties/AssemblyInfo.cs index c82b5de..616aa81 100644 --- a/RCCVirtualSteeringWheel/Properties/AssemblyInfo.cs +++ b/RCCVirtualSteeringWheel/Properties/AssemblyInfo.cs @@ -28,6 +28,6 @@ using NAK.RCCVirtualSteeringWheel.Properties; namespace NAK.RCCVirtualSteeringWheel.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.0"; + public const string Version = "1.0.3"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/RCCVirtualSteeringWheel/RCCVirtualSteeringWheel/Components/SteeringWheelRoot.cs b/RCCVirtualSteeringWheel/RCCVirtualSteeringWheel/Components/SteeringWheelRoot.cs index b8008b8..0154bd5 100644 --- a/RCCVirtualSteeringWheel/RCCVirtualSteeringWheel/Components/SteeringWheelRoot.cs +++ b/RCCVirtualSteeringWheel/RCCVirtualSteeringWheel/Components/SteeringWheelRoot.cs @@ -27,7 +27,6 @@ public class SteeringWheelRoot : MonoBehaviour public static void SetupSteeringWheel(RCC_CarControllerV3 carController, Bounds steeringWheelBounds) { Transform steeringWheel = carController.SteeringWheel; - if (carController == null) return; SteeringWheelRoot wheel = steeringWheel.gameObject.AddComponent(); wheel._carController = carController; diff --git a/RCCVirtualSteeringWheel/format.json b/RCCVirtualSteeringWheel/format.json index 3f0654c..438f31f 100644 --- a/RCCVirtualSteeringWheel/format.json +++ b/RCCVirtualSteeringWheel/format.json @@ -1,8 +1,8 @@ { - "_id": -1, + "_id": 248, "name": "RCCVirtualSteeringWheel", - "modversion": "1.0.0", - "gameversion": "2024r177", + "modversion": "1.0.3", + "gameversion": "2025r178", "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS", @@ -14,10 +14,10 @@ "car" ], "requirements": [ - "BTKUILib" + "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r44/RCCVirtualSteeringWheel.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r45/RCCVirtualSteeringWheel.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/RCCVirtualSteeringWheel/", - "changelog": "- Initial release", + "changelog": "- Fixes for 2025r178", "embedcolor": "#f61963" } \ No newline at end of file From ac9af46bd69ce6517e249439eba078ebfd71dfff Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Wed, 15 Jan 2025 16:42:27 -0600 Subject: [PATCH 005/119] MutualMute: Stole name idea, now it's MutualMute --- {TwoWayMute => MutualMute}/Main.cs | 6 +++--- .../MutualMute.csproj | 1 + .../Properties/AssemblyInfo.cs | 16 ++++++++-------- {TwoWayMute => MutualMute}/README.md | 4 +++- {TwoWayMute => MutualMute}/format.json | 16 ++++++++-------- 5 files changed, 23 insertions(+), 20 deletions(-) rename {TwoWayMute => MutualMute}/Main.cs (84%) rename TwoWayMute/TwoWayMute.csproj => MutualMute/MutualMute.csproj (86%) rename {TwoWayMute => MutualMute}/Properties/AssemblyInfo.cs (74%) rename {TwoWayMute => MutualMute}/README.md (84%) rename {TwoWayMute => MutualMute}/format.json (55%) diff --git a/TwoWayMute/Main.cs b/MutualMute/Main.cs similarity index 84% rename from TwoWayMute/Main.cs rename to MutualMute/Main.cs index 8d6de3e..d02924b 100644 --- a/TwoWayMute/Main.cs +++ b/MutualMute/Main.cs @@ -3,16 +3,16 @@ using ABI_RC.Systems.Communications.Audio.Components; using HarmonyLib; using MelonLoader; -namespace NAK.TwoWayMute; +namespace NAK.MutualMute; -public class TwoWayMuteMod : MelonMod +public class MutualMuteMod : MelonMod { public override void OnInitializeMelon() { HarmonyInstance.Patch( typeof(Comms_ParticipantPipeline).GetMethod(nameof(Comms_ParticipantPipeline.SetFlowControlState), BindingFlags.NonPublic | BindingFlags.Instance), - prefix: new HarmonyMethod(typeof(TwoWayMuteMod).GetMethod(nameof(OnSetFlowControlState), + prefix: new HarmonyMethod(typeof(MutualMuteMod).GetMethod(nameof(OnSetFlowControlState), BindingFlags.NonPublic | BindingFlags.Static)) ); } diff --git a/TwoWayMute/TwoWayMute.csproj b/MutualMute/MutualMute.csproj similarity index 86% rename from TwoWayMute/TwoWayMute.csproj rename to MutualMute/MutualMute.csproj index 4e44ed3..267718d 100644 --- a/TwoWayMute/TwoWayMute.csproj +++ b/MutualMute/MutualMute.csproj @@ -2,6 +2,7 @@ net48 + TwoWayMute diff --git a/TwoWayMute/Properties/AssemblyInfo.cs b/MutualMute/Properties/AssemblyInfo.cs similarity index 74% rename from TwoWayMute/Properties/AssemblyInfo.cs rename to MutualMute/Properties/AssemblyInfo.cs index 0c53769..6db6d18 100644 --- a/TwoWayMute/Properties/AssemblyInfo.cs +++ b/MutualMute/Properties/AssemblyInfo.cs @@ -1,20 +1,20 @@ -using NAK.TwoWayMute.Properties; +using NAK.MutualMute.Properties; using MelonLoader; using System.Reflection; [assembly: AssemblyVersion(AssemblyInfoParams.Version)] [assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] [assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] -[assembly: AssemblyTitle(nameof(NAK.TwoWayMute))] +[assembly: AssemblyTitle(nameof(NAK.MutualMute))] [assembly: AssemblyCompany(AssemblyInfoParams.Author)] -[assembly: AssemblyProduct(nameof(NAK.TwoWayMute))] +[assembly: AssemblyProduct(nameof(NAK.MutualMute))] [assembly: MelonInfo( - typeof(NAK.TwoWayMute.TwoWayMuteMod), - nameof(NAK.TwoWayMute), + typeof(NAK.MutualMute.MutualMuteMod), + nameof(NAK.MutualMute), AssemblyInfoParams.Version, AssemblyInfoParams.Author, - downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/TwoWayMute" + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/MutualMute" )] [assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] @@ -24,9 +24,9 @@ using System.Reflection; [assembly: MelonAuthorColor(255, 158, 21, 32)] // red [assembly: HarmonyDontPatchAll] -namespace NAK.TwoWayMute.Properties; +namespace NAK.MutualMute.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.0"; + public const string Version = "1.0.1"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/TwoWayMute/README.md b/MutualMute/README.md similarity index 84% rename from TwoWayMute/README.md rename to MutualMute/README.md index 560a022..599d292 100644 --- a/TwoWayMute/README.md +++ b/MutualMute/README.md @@ -1,9 +1,11 @@ -# TwoWayMute +# MutualMute Adjusts the self moderation muting behaviour to also prevent the muted user from hearing you. Basically- if you mute someone, they will also not be able to hear you. +#### This will work even of the other user does not have the mod installed, as it modifies the BBC Flow Control system. + --- Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. diff --git a/TwoWayMute/format.json b/MutualMute/format.json similarity index 55% rename from TwoWayMute/format.json rename to MutualMute/format.json index a2ed4f6..e815ba1 100644 --- a/TwoWayMute/format.json +++ b/MutualMute/format.json @@ -1,12 +1,12 @@ { - "_id": -1, - "name": "TwoWayMute", - "modversion": "1.0.0", - "gameversion": "2024r177", + "_id": 246, + "name": "MutualMute", + "modversion": "1.0.1", + "gameversion": "2025r178", "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS", - "description": "Adjusts the self moderation muting behaviour to also prevent the muted user from hearing you.\n\nBasically- if you mute someone, they will also not be able to hear you.", + "description": "Adjusts the self moderation muting behaviour to also prevent the muted user from hearing you.\n\nBasically- if you mute someone, they will also not be able to hear you.\n-# This will work even of the other user does not have the mod installed, as it modifies the BBC Flow Control system.", "searchtags": [ "mute", "communication", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r44/TwoWayMute.dll", - "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/TwoWayMute/", - "changelog": "- Initial Release", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r45/MutualMute.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/MutualMute/", + "changelog": "- Stole name idea, now it's MutualMute", "embedcolor": "#f61963" } \ No newline at end of file From 6d30fe1f41340c942a903f0b0ce2f25adf865992 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Wed, 15 Jan 2025 16:42:53 -0600 Subject: [PATCH 006/119] ShareBubbles: Fixes for 2025r178 --- ShareBubbles/Patches.cs | 2 +- ShareBubbles/Properties/AssemblyInfo.cs | 2 +- ShareBubbles/ShareBubbles/UI/BubbleInteract.cs | 8 ++++---- ShareBubbles/ShareBubbles/UI/ReturnOnRelease.cs | 4 ++-- ShareBubbles/format.json | 10 +++++----- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/ShareBubbles/Patches.cs b/ShareBubbles/Patches.cs index 4f705e3..162c75b 100644 --- a/ShareBubbles/Patches.cs +++ b/ShareBubbles/Patches.cs @@ -1462,7 +1462,7 @@ ContentShareMod.init(); public static void Postfix_ViewManager_Start(ViewManager __instance) { // Inject the details toolbar patches when the game menu view is loaded - __instance.gameMenuView.Listener.FinishLoad += _ => { + __instance.gameMenuView.Listener.FinishLoad += (_) => { __instance.gameMenuView.View._view.ExecuteScript(DETAILS_TOOLBAR_PATCHES); __instance.gameMenuView.View.BindCall("NAKCallShareContent", OnShareContent); __instance.gameMenuView.View.BindCall("NAKGetContentShares", OnGetContentShares); diff --git a/ShareBubbles/Properties/AssemblyInfo.cs b/ShareBubbles/Properties/AssemblyInfo.cs index 8a1996f..07120d8 100644 --- a/ShareBubbles/Properties/AssemblyInfo.cs +++ b/ShareBubbles/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using NAK.ShareBubbles.Properties; namespace NAK.ShareBubbles.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.3"; + public const string Version = "1.0.4"; public const string Author = "NotAKidoS, Exterrata, Noachi, RaidShadowLily, Tejler"; } \ No newline at end of file diff --git a/ShareBubbles/ShareBubbles/UI/BubbleInteract.cs b/ShareBubbles/ShareBubbles/UI/BubbleInteract.cs index d389a41..ad2b4f4 100644 --- a/ShareBubbles/ShareBubbles/UI/BubbleInteract.cs +++ b/ShareBubbles/ShareBubbles/UI/BubbleInteract.cs @@ -14,12 +14,12 @@ public class BubbleInteract : Interactable return Vector3.Distance(transform.position, sourcePos) < 1.5f; } - public override void OnInteractDown(ControllerRay controllerRay) + public override void OnInteractDown(InteractionContext context, ControllerRay controllerRay) { // Not used } - public override void OnInteractUp(ControllerRay controllerRay) + public override void OnInteractUp(InteractionContext context, ControllerRay controllerRay) { if (PlayerSetup.Instance.GetCurrentPropSelectionMode() != PlayerSetup.PropSelectionMode.None) @@ -39,12 +39,12 @@ public class BubbleInteract : Interactable GetComponentInParent().ViewDetailsPage(); } - public override void OnHoverEnter() + public override void OnHoverEnter(InteractionContext context, ControllerRay controllerRay) { // Not used } - public override void OnHoverExit() + public override void OnHoverExit(InteractionContext context, ControllerRay controllerRay) { // Not used } diff --git a/ShareBubbles/ShareBubbles/UI/ReturnOnRelease.cs b/ShareBubbles/ShareBubbles/UI/ReturnOnRelease.cs index 9c2416c..b6e1eda 100644 --- a/ShareBubbles/ShareBubbles/UI/ReturnOnRelease.cs +++ b/ShareBubbles/ShareBubbles/UI/ReturnOnRelease.cs @@ -30,12 +30,12 @@ public class ReturnOnRelease : MonoBehaviour pickupable.onDrop.AddListener(OnPickupRelease); } - public void OnPickupGrabbed() + public void OnPickupGrabbed(InteractionContext _) { isReturning = false; } - public void OnPickupRelease() + public void OnPickupRelease(InteractionContext _) { isReturning = true; } diff --git a/ShareBubbles/format.json b/ShareBubbles/format.json index a17aa7b..be28ae9 100644 --- a/ShareBubbles/format.json +++ b/ShareBubbles/format.json @@ -1,8 +1,8 @@ { - "_id": -1, + "_id": 244, "name": "ShareBubbles", - "modversion": "1.0.2", - "gameversion": "2024r177", + "modversion": "1.0.4", + "gameversion": "2025r178", "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS, Exterrata, Noachi, RaidShadowLily, Tejler, Luc", @@ -17,8 +17,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r43/ShareBubbles.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r45/ShareBubbles.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ShareBubbles/", - "changelog": "- Initial release.", + "changelog": "- Fixes for 2025r178", "embedcolor": "#f61963" } \ No newline at end of file From 3660b8f68349f7f7cd4beff1148c80c2fd017791 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Wed, 29 Jan 2025 16:37:15 -0600 Subject: [PATCH 007/119] AvatarCloneTest: push so i can reference in an email --- .../AvatarClone/AvatarClone.API.cs | 68 +++++++ .../AvatarClone/AvatarClone.Clones.cs | 103 ++++++++++ .../AvatarClone/AvatarClone.Exclusion.cs | 141 ++++++++++++++ .../AvatarClone/AvatarClone.Fields.cs | 67 +++++++ .../AvatarClone/AvatarClone.Init.cs | 128 +++++++++++++ .../AvatarClone/AvatarClone.MagicaSupport.cs | 34 ++++ .../AvatarClone/AvatarClone.Update.cs | 181 ++++++++++++++++++ .../AvatarClone/AvatarClone.Util.cs | 20 ++ AvatarCloneTest/AvatarClone/AvatarClone.cs | 134 +++++++++++++ .../FPRExclusion/AvatarCloneExclusion.cs | 38 ++++ AvatarCloneTest/AvatarCloneTest.csproj | 9 + AvatarCloneTest/Main.cs | 72 +++++++ AvatarCloneTest/Patches.cs | 87 +++++++++ AvatarCloneTest/Properties/AssemblyInfo.cs | 32 ++++ AvatarCloneTest/README.md | 18 ++ AvatarCloneTest/format.json | 23 +++ 16 files changed, 1155 insertions(+) create mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.API.cs create mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.Clones.cs create mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.Exclusion.cs create mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.Fields.cs create mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.Init.cs create mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.MagicaSupport.cs create mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.Update.cs create mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.Util.cs create mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.cs create mode 100644 AvatarCloneTest/AvatarClone/FPRExclusion/AvatarCloneExclusion.cs create mode 100644 AvatarCloneTest/AvatarCloneTest.csproj create mode 100644 AvatarCloneTest/Main.cs create mode 100644 AvatarCloneTest/Patches.cs create mode 100644 AvatarCloneTest/Properties/AssemblyInfo.cs create mode 100644 AvatarCloneTest/README.md create mode 100644 AvatarCloneTest/format.json diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.API.cs b/AvatarCloneTest/AvatarClone/AvatarClone.API.cs new file mode 100644 index 0000000..89835bd --- /dev/null +++ b/AvatarCloneTest/AvatarClone/AvatarClone.API.cs @@ -0,0 +1,68 @@ +using UnityEngine; + +namespace NAK.AvatarCloneTest; + +public partial class AvatarClone +{ + #region Public API Methods + + /// + /// Sets whether the specific renderer requires additional runtime checks when copying to the clone. + /// For example, Magica Cloth modifies the sharedMesh & bones of the renderer at runtime. This is not needed + /// for most renderers, so copying for all renderers would be inefficient. + /// + public void SetRendererNeedsAdditionalChecks(Renderer rend, bool needsChecks) + { + switch (rend) + { + case MeshRenderer meshRenderer: + { + int index = _standardRenderers.IndexOf(meshRenderer); + if (index == -1) return; + + if (needsChecks && !_standardRenderersNeedingChecks.Contains(index)) + { + int insertIndex = _standardRenderersNeedingChecks.Count; + _standardRenderersNeedingChecks.Add(index); + _cachedSharedMeshes.Insert(insertIndex, null); + } + else if (!needsChecks) + { + int removeIndex = _standardRenderersNeedingChecks.IndexOf(index); + if (removeIndex != -1) + { + _standardRenderersNeedingChecks.RemoveAt(removeIndex); + _cachedSharedMeshes.RemoveAt(removeIndex); + } + } + return; + } + case SkinnedMeshRenderer skinnedRenderer: + { + int index = _skinnedRenderers.IndexOf(skinnedRenderer); + if (index == -1) return; + + if (needsChecks && !_skinnedRenderersNeedingChecks.Contains(index)) + { + int insertIndex = _skinnedRenderersNeedingChecks.Count; + _skinnedRenderersNeedingChecks.Add(index); + _cachedSharedMeshes.Insert(_standardRenderersNeedingChecks.Count + insertIndex, null); + _cachedSkinnedBoneCounts.Add(0); + } + else if (!needsChecks) + { + int removeIndex = _skinnedRenderersNeedingChecks.IndexOf(index); + if (removeIndex != -1) + { + _skinnedRenderersNeedingChecks.RemoveAt(removeIndex); + _cachedSharedMeshes.RemoveAt(_standardRenderersNeedingChecks.Count + removeIndex); + _cachedSkinnedBoneCounts.RemoveAt(removeIndex); + } + } + break; + } + } + } + + #endregion Public API Methods +} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Clones.cs b/AvatarCloneTest/AvatarClone/AvatarClone.Clones.cs new file mode 100644 index 0000000..8fb54ec --- /dev/null +++ b/AvatarCloneTest/AvatarClone/AvatarClone.Clones.cs @@ -0,0 +1,103 @@ +using ABI_RC.Core; +using UnityEngine; +using UnityEngine.Rendering; + +namespace NAK.AvatarCloneTest; + +public partial class AvatarClone +{ + #region Clone Creation + + private void CreateClones() + { + int standardCount = _standardRenderers.Count; + _standardClones = new List(standardCount); + _standardCloneFilters = new List(standardCount); + for (int i = 0; i < standardCount; i++) CreateStandardClone(i); + + int skinnedCount = _skinnedRenderers.Count; + _skinnedClones = new List(skinnedCount); + for (int i = 0; i < skinnedCount; i++) CreateSkinnedClone(i); + } + + private void CreateStandardClone(int index) + { + MeshRenderer sourceRenderer = _standardRenderers[index]; + MeshFilter sourceFilter = _standardFilters[index]; + + GameObject go = new(sourceRenderer.name + "_VisualClone") + { + layer = CVRLayers.PlayerClone + }; + + go.transform.SetParent(sourceRenderer.transform, false); + //go.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); + + MeshRenderer cloneRenderer = go.AddComponent(); + MeshFilter cloneFilter = go.AddComponent(); + + // Initial setup + cloneRenderer.sharedMaterials = sourceRenderer.sharedMaterials; + cloneRenderer.shadowCastingMode = ShadowCastingMode.Off; + cloneRenderer.probeAnchor = sourceRenderer.probeAnchor; + cloneRenderer.localBounds = new Bounds(Vector3.zero, Vector3.positiveInfinity); + cloneFilter.sharedMesh = sourceFilter.sharedMesh; + + // Optimizations to enforce + cloneRenderer.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; + cloneRenderer.allowOcclusionWhenDynamic = false; + + // Optimizations to enforce + sourceRenderer.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; + sourceRenderer.allowOcclusionWhenDynamic = false; + + _standardClones.Add(cloneRenderer); + _standardCloneFilters.Add(cloneFilter); + } + + private void CreateSkinnedClone(int index) + { + SkinnedMeshRenderer source = _skinnedRenderers[index]; + + GameObject go = new(source.name + "_VisualClone") + { + layer = CVRLayers.PlayerClone + }; + + go.transform.SetParent(source.transform, false); + //go.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); + + SkinnedMeshRenderer clone = go.AddComponent(); + + // Initial setup + clone.sharedMaterials = source.sharedMaterials; + clone.shadowCastingMode = ShadowCastingMode.Off; + clone.probeAnchor = source.probeAnchor; + clone.localBounds = new Bounds(Vector3.zero, Vector3.positiveInfinity); + clone.sharedMesh = source.sharedMesh; + clone.rootBone = source.rootBone; + clone.bones = source.bones; + clone.quality = source.quality; + clone.updateWhenOffscreen = source.updateWhenOffscreen; + + // Optimizations to enforce + clone.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; + clone.allowOcclusionWhenDynamic = false; + clone.updateWhenOffscreen = false; + clone.skinnedMotionVectors = false; + clone.forceMatrixRecalculationPerRender = false; + clone.quality = SkinQuality.Bone4; + + // Optimizations to enforce + source.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; + source.allowOcclusionWhenDynamic = false; + source.updateWhenOffscreen = false; + source.skinnedMotionVectors = false; + source.forceMatrixRecalculationPerRender = false; + source.quality = SkinQuality.Bone4; + + _skinnedClones.Add(clone); + } + + #endregion Clone Creation +} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Exclusion.cs b/AvatarCloneTest/AvatarClone/AvatarClone.Exclusion.cs new file mode 100644 index 0000000..d5136e3 --- /dev/null +++ b/AvatarCloneTest/AvatarClone/AvatarClone.Exclusion.cs @@ -0,0 +1,141 @@ +using ABI.CCK.Components; +using UnityEngine; + +namespace NAK.AvatarCloneTest; + +public partial class AvatarClone +{ + private readonly Dictionary> _exclusionDirectRenderers = new(); + private readonly Dictionary> _exclusionControlledBones = new(); + + private void InitializeExclusions() + { + // Add head exclusion for humanoid avatars if not present + var animator = GetComponent(); + if (animator != null && animator.isHuman) + { + var headBone = animator.GetBoneTransform(HumanBodyBones.Head); + if (headBone != null && headBone.GetComponent() == null) + { + var exclusion = headBone.gameObject.AddComponent(); + exclusion.isShown = false; + exclusion.target = headBone; + exclusion.shrinkToZero = true; + } + } + + // Process existing exclusions bottom-up + var exclusions = GetComponentsInChildren(true); + + for (int i = exclusions.Length - 1; i >= 0; i--) + { + var exclusion = exclusions[i]; + if (exclusion.target == null) + exclusion.target = exclusion.transform; + + // Skip invalid exclusions or already processed targets + if (exclusion.target == null || _exclusionDirectRenderers.ContainsKey(exclusion.target)) + { + Destroy(exclusion); + continue; + } + + // Initialize data for this exclusion + _exclusionDirectRenderers[exclusion.target] = new HashSet(); + _exclusionControlledBones[exclusion.target] = new HashSet(); + + // Set up our behaviour + exclusion.behaviour = new AvatarCloneExclusion(this, exclusion.target); + + // Collect affected renderers and bones + CollectExclusionData(exclusion.target); + + // Initial update + exclusion.UpdateExclusions(); + } + } + + private void CollectExclusionData(Transform target) + { + var stack = new Stack(); + stack.Push(target); + + while (stack.Count > 0) + { + var current = stack.Pop(); + + // Skip if this transform belongs to another exclusion + if (current != target && current.GetComponent() != null) + continue; + + _exclusionControlledBones[target].Add(current); + + // Add renderers that will need their clone visibility toggled + foreach (var renderer in current.GetComponents()) + { + // Find corresponding clone renderer + if (renderer is MeshRenderer meshRenderer) + { + int index = _standardRenderers.IndexOf(meshRenderer); + if (index != -1) + _exclusionDirectRenderers[target].Add(_standardClones[index]); + } + else if (renderer is SkinnedMeshRenderer skinnedRenderer) + { + int index = _skinnedRenderers.IndexOf(skinnedRenderer); + if (index != -1) + _exclusionDirectRenderers[target].Add(_skinnedClones[index]); + } + } + + // Add children to stack + foreach (Transform child in current) + { + stack.Push(child); + } + } + } + + public void HandleExclusionUpdate(Transform target, Transform shrinkBone, bool isShown) + { + if (!_exclusionDirectRenderers.TryGetValue(target, out var directCloneRenderers) || + !_exclusionControlledBones.TryGetValue(target, out var controlledBones)) + return; + + // Handle direct clone renderers + foreach (var cloneRenderer in directCloneRenderers) + { + cloneRenderer.enabled = isShown; + } + + // Update bone references in clone renderers + int cloneCount = _skinnedClones.Count; + var cloneRenderers = _skinnedClones; + var sourceRenderers = _skinnedRenderers; + + for (int i = 0; i < cloneCount; i++) + { + var clone = cloneRenderers[i]; + var source = sourceRenderers[i]; + var sourceBones = source.bones; + var cloneBones = clone.bones; + int boneCount = cloneBones.Length; + bool needsUpdate = false; + + for (int j = 0; j < boneCount; j++) + { + // Check if this bone is in our controlled set + if (controlledBones.Contains(sourceBones[j])) + { + cloneBones[j] = isShown ? sourceBones[j] : shrinkBone; + needsUpdate = true; + } + } + + if (needsUpdate) + { + clone.bones = cloneBones; + } + } + } +} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Fields.cs b/AvatarCloneTest/AvatarClone/AvatarClone.Fields.cs new file mode 100644 index 0000000..0ba69b0 --- /dev/null +++ b/AvatarCloneTest/AvatarClone/AvatarClone.Fields.cs @@ -0,0 +1,67 @@ +using UnityEngine; + +namespace NAK.AvatarCloneTest; + +public partial class AvatarClone +{ + #region Profile Markers +//#if UNITY_EDITOR + private static readonly UnityEngine.Profiling.CustomSampler s_CopyMaterials = + UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.CopyMaterials"); + private static readonly UnityEngine.Profiling.CustomSampler s_CopyBlendShapes = + UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.CopyBlendShapes"); + private static readonly UnityEngine.Profiling.CustomSampler s_CopyMeshes = + UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.CopyMeshes"); + + private static readonly UnityEngine.Profiling.CustomSampler s_MyOnPreRender = + UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.MyOnPreRender"); + private static readonly UnityEngine.Profiling.CustomSampler s_SetShadowsOnly = + UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.SetShadowsOnly"); + private static readonly UnityEngine.Profiling.CustomSampler s_UndoShadowsOnly = + UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.UndoShadowsOnly"); + private static readonly UnityEngine.Profiling.CustomSampler s_SetUiCulling = + UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.SetUiCulling"); + private static readonly UnityEngine.Profiling.CustomSampler s_UndoUiCulling = + UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.UndoUiCulling"); + +//#endif + #endregion Profile Markers + + #region Source Renderers + private List _standardRenderers; + private List _standardFilters; + private List _skinnedRenderers; + private List _allSourceRenderers; // For shadow casting only + #endregion Source Renderers + + #region Clone Renderers + private List _standardClones; + private List _standardCloneFilters; + private List _skinnedClones; + #endregion Clone Renderers + + #region Dynamic Check Lists + private List _standardRenderersNeedingChecks; // Stores indices into _standardRenderers + private List _skinnedRenderersNeedingChecks; // Stores indices into _skinnedRenderers + private List _cachedSkinnedBoneCounts; // So we don't copy the bones unless they've changed + private List _cachedSharedMeshes; // So we don't copy the mesh unless it's changed + #endregion Dynamic Check Lists + + #region Material Data + private List _localMaterials; + private List _cullingMaterials; + private List _mainMaterials; + private MaterialPropertyBlock _propertyBlock; + #endregion Material Data + + #region Blend Shape Data + private List> _blendShapeWeights; + #endregion Blend Shape Data + + #region Shadow and UI Culling Settings + private bool _uiCullingActive; + private bool _shadowsOnlyActive; + private bool[] _originallyHadShadows; + private bool[] _originallyWasEnabled; + #endregion Shadow and UI Culling Settings +} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Init.cs b/AvatarCloneTest/AvatarClone/AvatarClone.Init.cs new file mode 100644 index 0000000..41bd84b --- /dev/null +++ b/AvatarCloneTest/AvatarClone/AvatarClone.Init.cs @@ -0,0 +1,128 @@ +using ABI_RC.Core.Player.ShadowClone; +using UnityEngine; + +namespace NAK.AvatarCloneTest; + +public partial class AvatarClone +{ + #region Initialization + + private void InitializeCollections() + { + _standardRenderers = new List(); + _standardFilters = new List(); + _skinnedRenderers = new List(); + _allSourceRenderers = new List(); + + _standardClones = new List(); + _standardCloneFilters = new List(); + _skinnedClones = new List(); + + _standardRenderersNeedingChecks = new List(); + _skinnedRenderersNeedingChecks = new List(); + _cachedSkinnedBoneCounts = new List(); + _cachedSharedMeshes = new List(); + + _localMaterials = new List(); + _cullingMaterials = new List(); + _mainMaterials = new List(); + _propertyBlock = new MaterialPropertyBlock(); + + _blendShapeWeights = new List>(); + } + + private void InitializeRenderers() + { + var renderers = GetComponentsInChildren(true); + + // Pre-size lists based on found renderers + // _standardRenderers.Capacity = renderers.Length; + // _standardFilters.Capacity = renderers.Length; + // _skinnedRenderers.Capacity = renderers.Length; + // _allSourceRenderers.Capacity = renderers.Length; + + // Sort renderers into their respective lists + foreach (Renderer render in renderers) + { + _allSourceRenderers.Add(render); + + switch (render) + { + case MeshRenderer meshRenderer: + { + MeshFilter filter = meshRenderer.GetComponent(); + if (filter != null && filter.sharedMesh != null) + { + _standardRenderers.Add(meshRenderer); + _standardFilters.Add(filter); + } + break; + } + case SkinnedMeshRenderer skinnedRenderer: + { + if (skinnedRenderer.sharedMesh != null) _skinnedRenderers.Add(skinnedRenderer); + break; + } + } + } + } + + private void SetupMaterialsAndBlendShapes() + { + // Cache counts + int standardCount = _standardRenderers.Count; + int skinnedCount = _skinnedRenderers.Count; + var standardRenderers = _standardRenderers; + var skinnedRenderers = _skinnedRenderers; + var localMats = _localMaterials; + var cullingMats = _cullingMaterials; + var blendWeights = _blendShapeWeights; + + // Setup standard renderer materials + for (int i = 0; i < standardCount; i++) + { + MeshRenderer render = standardRenderers[i]; + int matCount = render.sharedMaterials.Length; + + // Local materials array + var localMatArray = new Material[matCount]; + for (int j = 0; j < matCount; j++) localMatArray[j] = render.sharedMaterials[j]; + localMats.Add(localMatArray); + + // Culling materials array + var cullingMatArray = new Material[matCount]; + for (int j = 0; j < matCount; j++) cullingMatArray[j] = ShadowCloneUtils.cullingMaterial; + cullingMats.Add(cullingMatArray); + } + + // Setup skinned renderer materials and blend shapes + for (int i = 0; i < skinnedCount; i++) + { + SkinnedMeshRenderer render = skinnedRenderers[i]; + int matCount = render.sharedMaterials.Length; + + // Local materials array + var localMatArray = new Material[matCount]; + for (int j = 0; j < matCount; j++) localMatArray[j] = render.sharedMaterials[j]; + localMats.Add(localMatArray); + + // Culling materials array + var cullingMatArray = new Material[matCount]; + for (int j = 0; j < matCount; j++) cullingMatArray[j] = ShadowCloneUtils.cullingMaterial; + cullingMats.Add(cullingMatArray); + + // Blend shape weights + int blendShapeCount = render.sharedMesh.blendShapeCount; + var weights = new List(blendShapeCount); + for (int j = 0; j < blendShapeCount; j++) weights.Add(0f); + blendWeights.Add(weights); + } + + // Initialize renderer state arrays + int totalRenderers = _allSourceRenderers.Count; + _originallyHadShadows = new bool[totalRenderers]; + _originallyWasEnabled = new bool[totalRenderers]; + } + + #endregion Initialization +} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.MagicaSupport.cs b/AvatarCloneTest/AvatarClone/AvatarClone.MagicaSupport.cs new file mode 100644 index 0000000..7ae5855 --- /dev/null +++ b/AvatarCloneTest/AvatarClone/AvatarClone.MagicaSupport.cs @@ -0,0 +1,34 @@ +using MagicaCloth; +using MagicaCloth2; +using UnityEngine; + +namespace NAK.AvatarCloneTest; + +public partial class AvatarClone +{ + #region Magica Cloth Support + + private void SetupMagicaClothSupport() + { + var magicaCloths1 = GetComponentsInChildren(true); + foreach (MagicaRenderDeformer magicaCloth in magicaCloths1) + { + // Get the renderer on the same object + Renderer renderer = magicaCloth.gameObject.GetComponent(); + SetRendererNeedsAdditionalChecks(renderer, true); + } + + var magicaCloths2 = GetComponentsInChildren(true); + foreach (MagicaCloth2.MagicaCloth magicaCloth in magicaCloths2) + { + if (magicaCloth.serializeData.clothType != ClothProcess.ClothType.MeshCloth) + continue; // Only matters for cloth physics + + // Set the affected renderers as requiring extra checks + var renderers = magicaCloth.serializeData.sourceRenderers; + foreach (Renderer renderer in renderers) SetRendererNeedsAdditionalChecks(renderer, true); + } + } + + #endregion Magica Cloth Support +} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Update.cs b/AvatarCloneTest/AvatarClone/AvatarClone.Update.cs new file mode 100644 index 0000000..42cef73 --- /dev/null +++ b/AvatarCloneTest/AvatarClone/AvatarClone.Update.cs @@ -0,0 +1,181 @@ +using UnityEngine; + +namespace NAK.AvatarCloneTest; + +public partial class AvatarClone +{ + #region Update Methods + + private void UpdateStandardRenderers() + { + int count = _standardRenderers.Count; + var sourceRenderers = _standardRenderers; + var cloneRenderers = _standardClones; + var localMats = _localMaterials; + + for (int i = 0; i < count; i++) + { + if (!IsRendererValid(sourceRenderers[i])) continue; + CopyMaterialsAndProperties( + sourceRenderers[i], + cloneRenderers[i], + _propertyBlock, + _mainMaterials, + localMats[i]); + } + } + + private void UpdateSkinnedRenderers() + { + int standardCount = _standardRenderers.Count; + int count = _skinnedRenderers.Count; + var sourceRenderers = _skinnedRenderers; + var cloneRenderers = _skinnedClones; + var localMats = _localMaterials; + var blendWeights = _blendShapeWeights; + + for (int i = 0; i < count; i++) + { + SkinnedMeshRenderer source = sourceRenderers[i]; + if (!IsRendererValid(source)) continue; + + SkinnedMeshRenderer clone = cloneRenderers[i]; + CopyMaterialsAndProperties( + source, + clone, + _propertyBlock, + _mainMaterials, + localMats[i + standardCount]); + + CopyBlendShapes(source, clone, blendWeights[i]); + } + } + + private void UpdateStandardRenderersWithChecks() + { + s_CopyMeshes.Begin(); + + var cloneFilters = _standardCloneFilters; + var sourceFilters = _standardFilters; + var cachedMeshes = _cachedSharedMeshes; + var checkIndices = _standardRenderersNeedingChecks; + int checkCount = checkIndices.Count; + + while (cachedMeshes.Count < checkCount) cachedMeshes.Add(null); + + for (int i = 0; i < checkCount; i++) + { + int rendererIndex = checkIndices[i]; + Mesh newMesh = sourceFilters[rendererIndex].sharedMesh; + if (ReferenceEquals(newMesh, cachedMeshes[i])) continue; + cloneFilters[rendererIndex].sharedMesh = newMesh; // expensive & allocates + cachedMeshes[i] = newMesh; + } + + s_CopyMeshes.End(); + } + + private void UpdateSkinnedRenderersWithChecks() + { + s_CopyMeshes.Begin(); + + var sourceRenderers = _skinnedRenderers; + var cloneRenderers = _skinnedClones; + var cachedMeshes = _cachedSharedMeshes; + var cachedBoneCounts = _cachedSkinnedBoneCounts; + var checkIndices = _skinnedRenderersNeedingChecks; + int checkCount = checkIndices.Count; + int meshOffset = _standardRenderersNeedingChecks.Count; + + // Ensure cache lists are properly sized + while (cachedMeshes.Count < meshOffset + checkCount) cachedMeshes.Add(null); + while (cachedBoneCounts.Count < checkCount) cachedBoneCounts.Add(0); + + for (int i = 0; i < checkCount; i++) + { + int rendererIndex = checkIndices[i]; + SkinnedMeshRenderer source = sourceRenderers[rendererIndex]; + SkinnedMeshRenderer clone = cloneRenderers[rendererIndex]; + + // Check mesh changes + Mesh newMesh = source.sharedMesh; // expensive & allocates + if (!ReferenceEquals(newMesh, cachedMeshes[meshOffset + i])) + { + clone.sharedMesh = newMesh; + cachedMeshes[meshOffset + i] = newMesh; + } + + // Check bone changes + var sourceBones = source.bones; + int newBoneCount = sourceBones.Length; + int oldBoneCount = cachedBoneCounts[i]; + if (newBoneCount == oldBoneCount) + continue; + + var cloneBones = clone.bones; // expensive & allocates + if (newBoneCount > oldBoneCount) + { + // Resize array and copy only the new bones (Magica Cloth appends bones when enabling Mesh Cloth) + Array.Resize(ref cloneBones, newBoneCount); + for (int boneIndex = oldBoneCount; boneIndex < newBoneCount; boneIndex++) + cloneBones[boneIndex] = sourceBones[boneIndex]; + clone.bones = cloneBones; + } + else + { + // If shrinking, just set the whole array + clone.bones = sourceBones; + } + + cachedBoneCounts[i] = newBoneCount; + } + + s_CopyMeshes.End(); + } + + private static void CopyMaterialsAndProperties( + Renderer source, Renderer clone, + MaterialPropertyBlock propertyBlock, + List mainMaterials, + Material[] localMaterials) + { + s_CopyMaterials.Begin(); + + source.GetSharedMaterials(mainMaterials); + + int matCount = mainMaterials.Count; + bool hasChanged = false; + for (var i = 0; i < matCount; i++) + { + if (ReferenceEquals(mainMaterials[i], localMaterials[i])) continue; + localMaterials[i] = mainMaterials[i]; + hasChanged = true; + } + if (hasChanged) clone.sharedMaterials = localMaterials; + + source.GetPropertyBlock(propertyBlock); + clone.SetPropertyBlock(propertyBlock); + + s_CopyMaterials.End(); + } + + private static void CopyBlendShapes( + SkinnedMeshRenderer source, + SkinnedMeshRenderer target, + List blendShapeWeights) + { + s_CopyBlendShapes.Begin(); + + int weightCount = blendShapeWeights.Count; + for (var i = 0; i < weightCount; i++) + { + var weight = source.GetBlendShapeWeight(i); + // ReSharper disable once CompareOfFloatsByEqualityOperator + if (weight == blendShapeWeights[i]) continue; // Halves the work + target.SetBlendShapeWeight(i, blendShapeWeights[i] = weight); + } + + s_CopyBlendShapes.End(); + } + #endregion Update Methods +} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Util.cs b/AvatarCloneTest/AvatarClone/AvatarClone.Util.cs new file mode 100644 index 0000000..c6fb033 --- /dev/null +++ b/AvatarCloneTest/AvatarClone/AvatarClone.Util.cs @@ -0,0 +1,20 @@ +using ABI_RC.Core; +using ABI_RC.Core.Player; +using UnityEngine; + +namespace NAK.AvatarCloneTest; + +public partial class AvatarClone +{ + private static bool CameraRendersPlayerLocalLayer(Camera cam) + => (cam.cullingMask & (1 << CVRLayers.PlayerLocal)) != 0; + + private static bool CameraRendersPlayerCloneLayer(Camera cam) + => (cam.cullingMask & (1 << CVRLayers.PlayerClone)) != 0; + + private static bool IsUIInternalCamera(Camera cam) + => cam == PlayerSetup.Instance.activeUiCam; + + private static bool IsRendererValid(Renderer renderer) + => renderer && renderer.gameObject.activeInHierarchy; +} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.cs b/AvatarCloneTest/AvatarClone/AvatarClone.cs new file mode 100644 index 0000000..88c8112 --- /dev/null +++ b/AvatarCloneTest/AvatarClone/AvatarClone.cs @@ -0,0 +1,134 @@ +using UnityEngine; +using UnityEngine.Rendering; + +namespace NAK.AvatarCloneTest; + +public partial class AvatarClone : MonoBehaviour +{ + #region Unity Events + + private void Start() + { + InitializeCollections(); + InitializeRenderers(); + SetupMaterialsAndBlendShapes(); + CreateClones(); + + InitializeExclusions(); + SetupMagicaClothSupport(); + + Camera.onPreCull += MyOnPreRender; + } + + private void OnDestroy() + { + Camera.onPreCull -= MyOnPreRender; + } + + private void LateUpdate() + { + // Update all renderers with basic properties (Materials & BlendShapes) + UpdateStandardRenderers(); + UpdateSkinnedRenderers(); + + // Additional pass for renderers needing extra checks (Shared Mesh & Bone Changes) + UpdateStandardRenderersWithChecks(); + UpdateSkinnedRenderersWithChecks(); + } + + private void MyOnPreRender(Camera cam) + { + s_MyOnPreRender.Begin(); + + bool isOurUiCamera = IsUIInternalCamera(cam); + bool rendersOurPlayerLayer = CameraRendersPlayerLocalLayer(cam); + bool rendersOurCloneLayer = CameraRendersPlayerCloneLayer(cam); + + // Renders both player layers. + // PlayerLocal will now act as a shadow caster, while PlayerClone will act as the actual head-hidden renderer. + bool rendersBothPlayerLayers = rendersOurPlayerLayer && rendersOurCloneLayer; + if (!_shadowsOnlyActive && rendersBothPlayerLayers) + { + s_SetShadowsOnly.Begin(); + + int sourceCount = _allSourceRenderers.Count; + var sourceRenderers = _allSourceRenderers; + for (int i = 0; i < sourceCount; i++) + { + Renderer renderer = sourceRenderers[i]; + if (!IsRendererValid(renderer)) continue; + + bool shouldRender = renderer.shadowCastingMode != ShadowCastingMode.Off; + _originallyWasEnabled[i] = renderer.enabled; + _originallyHadShadows[i] = shouldRender; + renderer.shadowCastingMode = ShadowCastingMode.ShadowsOnly; + if (renderer.forceRenderingOff == shouldRender) renderer.forceRenderingOff = !shouldRender; // TODO: Eval if check is needed + } + _shadowsOnlyActive = true; + + s_SetShadowsOnly.End(); + } + else if (_shadowsOnlyActive && !rendersBothPlayerLayers) + { + s_UndoShadowsOnly.Begin(); + + int sourceCount = _allSourceRenderers.Count; + var sourceRenderers = _allSourceRenderers; + for (int i = 0; i < sourceCount; i++) + { + Renderer renderer = sourceRenderers[i]; + if (!IsRendererValid(renderer)) continue; + + renderer.shadowCastingMode = _originallyHadShadows[i] ? ShadowCastingMode.On : ShadowCastingMode.Off; + if (renderer.forceRenderingOff == _originallyWasEnabled[i]) renderer.forceRenderingOff = !_originallyWasEnabled[i]; // TODO: Eval if check is needed + } + _shadowsOnlyActive = false; + + s_UndoShadowsOnly.End(); + } + + // Handle UI culling material changes + if (isOurUiCamera && !_uiCullingActive && rendersOurCloneLayer) + { + s_SetUiCulling.Begin(); + + int standardCount = _standardRenderers.Count; + var standardClones = _standardClones; + var cullingMaterials = _cullingMaterials; + for (int i = 0; i < standardCount; i++) + standardClones[i].sharedMaterials = cullingMaterials[i]; + + int skinnedCount = _skinnedRenderers.Count; + var skinnedClones = _skinnedClones; + for (int i = 0; i < skinnedCount; i++) + skinnedClones[i].sharedMaterials = cullingMaterials[i + standardCount]; + + _uiCullingActive = true; + + s_SetUiCulling.End(); + } + else if (!isOurUiCamera && _uiCullingActive) + { + s_UndoUiCulling.Begin(); + + int standardCount = _standardRenderers.Count; + var standardClones = _standardClones; + var localMaterials = _localMaterials; + for (int i = 0; i < standardCount; i++) + standardClones[i].sharedMaterials = localMaterials[i]; + + int skinnedCount = _skinnedRenderers.Count; + var skinnedClones = _skinnedClones; + for (int i = 0; i < skinnedCount; i++) + skinnedClones[i].sharedMaterials = localMaterials[i + standardCount]; + + _uiCullingActive = false; + + s_UndoUiCulling.End(); + } + + s_MyOnPreRender.End(); + } + + #endregion Unity Events +} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/FPRExclusion/AvatarCloneExclusion.cs b/AvatarCloneTest/AvatarClone/FPRExclusion/AvatarCloneExclusion.cs new file mode 100644 index 0000000..5681761 --- /dev/null +++ b/AvatarCloneTest/AvatarClone/FPRExclusion/AvatarCloneExclusion.cs @@ -0,0 +1,38 @@ +using ABI.CCK.Components; +using UnityEngine; + +namespace NAK.AvatarCloneTest; + +public class AvatarCloneExclusion : IExclusionBehaviour +{ + private readonly AvatarClone _cloneSystem; + private readonly Transform _target; + private Transform _shrinkBone; + + public bool isImmuneToGlobalState { get; set; } + + public AvatarCloneExclusion(AvatarClone cloneSystem, Transform target) + { + _cloneSystem = cloneSystem; + _target = target; + } + + public void UpdateExclusions(bool isShown, bool shrinkToZero) + { + Debug.Log($"[AvatarClone2] Updating exclusion for {_target.name}: isShown={isShown}, shrinkToZero={shrinkToZero}"); + + if (_shrinkBone == null) + { + // Create shrink bone parented directly to target + _shrinkBone = new GameObject($"{_target.name}_Shrink").transform; + _shrinkBone.SetParent(_target, false); + Debug.Log($"[AvatarClone2] Created shrink bone for {_target.name}"); + } + + // Set scale based on shrink mode + _shrinkBone.localScale = shrinkToZero ? Vector3.zero : Vector3.positiveInfinity; + + // Let the clone system handle the update + _cloneSystem.HandleExclusionUpdate(_target, _shrinkBone, isShown); + } +} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarCloneTest.csproj b/AvatarCloneTest/AvatarCloneTest.csproj new file mode 100644 index 0000000..2e58669 --- /dev/null +++ b/AvatarCloneTest/AvatarCloneTest.csproj @@ -0,0 +1,9 @@ + + + + LocalCloneFix + + + TRACE;TRACE; + + diff --git a/AvatarCloneTest/Main.cs b/AvatarCloneTest/Main.cs new file mode 100644 index 0000000..21a34bf --- /dev/null +++ b/AvatarCloneTest/Main.cs @@ -0,0 +1,72 @@ +using ABI_RC.Core; +using MelonLoader; +using UnityEngine; + +namespace NAK.AvatarCloneTest; + +public class AvatarCloneTestMod : MelonMod +{ + #region Melon Preferences + + private static readonly MelonPreferences_Category Category = + MelonPreferences.CreateCategory(nameof(AvatarCloneTest)); + + internal static readonly MelonPreferences_Entry EntryUseAvatarCloneTest = + Category.CreateEntry("use_avatar_clone_test", true, + "Use Avatar Clone", description: "Uses the Avatar Clone setup for the local avatar."); + + // internal static readonly MelonPreferences_Entry EntryCopyBlendShapes = + // Category.CreateEntry("copy_blend_shapes", true, + // "Copy Blend Shapes", description: "Copies the blend shapes from the original avatar to the clone."); + // + // internal static readonly MelonPreferences_Entry EntryCopyMaterials = + // Category.CreateEntry("copy_materials", true, + // "Copy Materials", description: "Copies the materials from the original avatar to the clone."); + // + // internal static readonly MelonPreferences_Entry EntryCopyMeshes = + // Category.CreateEntry("copy_meshes", true, + // "Copy Meshes", description: "Copies the meshes from the original avatar to the clone."); + + #endregion Melon Preferences + + #region Melon Events + + public override void OnInitializeMelon() + { + ApplyPatches(typeof(Patches)); // slapped together a fix cause HarmonyInstance.Patch was null ref for no reason? + } + + public override void OnUpdate() + { + // press f1 to find all cameras that arent tagged main and set them tno not render CVRLayers.PlayerClone + if (Input.GetKeyDown(KeyCode.F1)) + { + foreach (var camera in UnityEngine.Object.FindObjectsOfType()) + { + if (camera.tag != "MainCamera") + { + camera.cullingMask &= ~(1 << CVRLayers.PlayerClone); + } + } + } + } + + #endregion Melon Events + + #region Melon Mod Utilities + + private void ApplyPatches(Type type) + { + try + { + HarmonyInstance.PatchAll(type); + } + catch (Exception e) + { + LoggerInstance.Msg($"Failed while patching {type.Name}!"); + LoggerInstance.Error(e); + } + } + + #endregion Melon Mod Utilities +} \ No newline at end of file diff --git a/AvatarCloneTest/Patches.cs b/AvatarCloneTest/Patches.cs new file mode 100644 index 0000000..b4cec17 --- /dev/null +++ b/AvatarCloneTest/Patches.cs @@ -0,0 +1,87 @@ +using ABI_RC.Core; +using ABI_RC.Core.Player; +using ABI_RC.Core.Player.TransformHider; +using ABI_RC.Core.Savior; +using ABI_RC.Systems.Camera; +using HarmonyLib; +using UnityEngine; + +namespace NAK.AvatarCloneTest; + +public static class Patches +{ + [HarmonyPrefix] + [HarmonyPatch(typeof(TransformHiderUtils), nameof(TransformHiderUtils.SetupAvatar))] + private static bool OnSetupAvatar(GameObject avatar) + { + if (!AvatarCloneTestMod.EntryUseAvatarCloneTest.Value) return true; + avatar.AddComponent(); + return false; + } + + // [HarmonyPostfix] + // [HarmonyPatch(typeof(FPRExclusion), nameof(FPRExclusion.UpdateExclusions))] + // private static void OnUpdateExclusions(ref FPRExclusion __instance) + // { + // AvatarClone clone = PlayerSetup.Instance._avatar.GetComponent(); + // if (clone == null) return; + // clone.SetBoneChainVisibility(__instance.target, !__instance.isShown, !__instance.shrinkToZero); + // } + + [HarmonyPostfix] + [HarmonyPatch(typeof(CVRMirror), nameof(CVRMirror.Start))] + private static void OnMirrorStart(CVRMirror __instance) + { + if (!AvatarCloneTestMod.EntryUseAvatarCloneTest.Value) + return; + + // Don't reflect the player clone layer + __instance.m_ReflectLayers &= ~(1 << CVRLayers.PlayerClone); + } + + [HarmonyPostfix] + [HarmonyPatch(typeof(PlayerSetup), nameof(PlayerSetup.Update))] + private static void OnTransformHiderManagerUpdate(PlayerSetup __instance) + { + if (!AvatarCloneTestMod.EntryUseAvatarCloneTest.Value) + return; + + if (MetaPort.Instance.settings.GetSettingsBool("ExperimentalAvatarOverrenderUI")) + __instance.activeUiCam.cullingMask |= 1 << CVRLayers.PlayerClone; + else + __instance.activeUiCam.cullingMask &= ~(1 << CVRLayers.PlayerClone); + } + + private static bool _wasDebugInPortableCamera; + + [HarmonyPostfix] + [HarmonyPatch(typeof(PortableCamera), nameof(PortableCamera.Update))] + private static void OnPortableCameraUpdate(ref PortableCamera __instance) + { + if (!AvatarCloneTestMod.EntryUseAvatarCloneTest.Value) + { + // Show both PlayerLocal and PlayerClone + __instance.cameraComponent.cullingMask |= 1 << CVRLayers.PlayerLocal; + __instance.cameraComponent.cullingMask |= 1 << CVRLayers.PlayerClone; + return; + } + + if (TransformHiderManager.s_DebugInPortableCamera == _wasDebugInPortableCamera) + return; + + if (TransformHiderManager.s_DebugInPortableCamera) + { + // Hide PlayerLocal, show PlayerClone + __instance.cameraComponent.cullingMask &= ~(1 << CVRLayers.PlayerLocal); + __instance.cameraComponent.cullingMask |= 1 << CVRLayers.PlayerClone; + } + else + { + // Show PlayerLocal, hide PlayerClone + __instance.cameraComponent.cullingMask |= 1 << CVRLayers.PlayerLocal; + __instance.cameraComponent.cullingMask &= ~(1 << CVRLayers.PlayerClone); + } + + _wasDebugInPortableCamera = TransformHiderManager.s_DebugInPortableCamera; + } +} \ No newline at end of file diff --git a/AvatarCloneTest/Properties/AssemblyInfo.cs b/AvatarCloneTest/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..3334b28 --- /dev/null +++ b/AvatarCloneTest/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using MelonLoader; +using NAK.AvatarCloneTest.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.AvatarCloneTest))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.AvatarCloneTest))] + +[assembly: MelonInfo( + typeof(NAK.AvatarCloneTest.AvatarCloneTestMod), + nameof(NAK.AvatarCloneTest), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/AvatarCloneTest" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red +[assembly: HarmonyDontPatchAll] + +namespace NAK.AvatarCloneTest.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/AvatarCloneTest/README.md b/AvatarCloneTest/README.md new file mode 100644 index 0000000..cc12a9c --- /dev/null +++ b/AvatarCloneTest/README.md @@ -0,0 +1,18 @@ +# VisualCloneFix + +Fixes the Visual Clone system and allows you to use it again. + +Using the Visual Clone should be faster than the default Head Hiding & Shadow Clones, but will add a longer hitch on initial avatar load. + +**NOTE:** The Visual Clone is still an experimental feature that was temporarily removed in [ChilloutVR 2024r175 Hotfix 1](https://abinteractive.net/blog/chilloutvr_2024r175_hotfix_1), so there may be bugs or issues with it. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation 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/AvatarCloneTest/format.json b/AvatarCloneTest/format.json new file mode 100644 index 0000000..6634e9f --- /dev/null +++ b/AvatarCloneTest/format.json @@ -0,0 +1,23 @@ +{ + "_id": 221, + "name": "VisualCloneFix", + "modversion": "1.0.1", + "gameversion": "2024r175", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Fixes the Visual Clone system and allows you to use it again.\n\nUsing the Visual Clone should be faster than the default Head Hiding & Shadow Clones, but will add a longer hitch on initial avatar load.\n\n**NOTE:** The Visual Clone is still an experimental feature that was temporarily removed in [ChilloutVR 2024r175 Hotfix 1](https://abinteractive.net/blog/chilloutvr_2024r175_hotfix_1), so there may be bugs or issues with it.", + "searchtags": [ + "visual", + "clone", + "head", + "hiding" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r36/VisualCloneFix.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/VisualCloneFix/", + "changelog": "- Fixed FPRExclusions IsShown state being inverted when toggled.\n- Fixed head FPRExclusion generation not checking for existing exclusion.\n- Sped up FindExclusionVertList by 100x by not being an idiot. This heavily reduces avatar hitch with Visual Clone active.", + "embedcolor": "#f61963" +} \ No newline at end of file From 0042590aa6b47da9b3656d016c8ff39df2c253d2 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 02:57:35 -0500 Subject: [PATCH 008/119] Move many mods to Deprecated folder, fix spelling --- .../AASBufferFix/AASBufferFix.csproj | 0 .../AASBufferFix/AASBufferHelper.cs | 0 .../AASBufferFix/HarmonyPatches.cs | 0 .../AASBufferFix/Main.cs | 0 .../AASBufferFix/Properties/AssemblyInfo.cs | 0 .../AASBufferFix/README.md | 0 .../AASBufferFix/Utils.cs | 0 .../AASBufferFix/format.json | 0 .../AASDefaultProfileFix.csproj | 0 .../AASDefaultProfileFix}/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../AASDefaultProfileFix}/README.md | 0 .../AASDefaultProfileFix}/format.json | 0 .../AlternateIKSystem.csproj | 0 .../AlternateIKSystem/HarmonyPatches.cs | 0 .../AlternateIKSystem/IK/BodyControl.cs | 0 .../AlternateIKSystem/IK/IKCalibrator.cs | 0 .../IK/IKHandlers/IKHandler.cs | 0 .../IK/IKHandlers/IKHandlerDesktop.cs | 0 .../IK/IKHandlers/IKHandlerHalfBody.cs | 0 .../AlternateIKSystem/IK/IKManager.cs | 0 .../AlternateIKSystem/IK/MusclePoses.cs | 0 .../IK/Tracking/SteamVRTrackerManager.cs | 0 .../IK/VRIKHelpers/VRIKLocomotionData.cs | 0 .../IK/VRIKHelpers/VRIKUtils.cs | 0 .../WeightManipulators/BodyParts/BodyPart.cs | 0 .../DeviceControlManipulator.cs | 0 .../Interface/IWeightManipulator.cs | 0 .../TrackingControlManipulator.cs | 0 .../WeightManipulatorManager.cs | 0 .../Integrations/BTKUIAddon.cs | 0 .../AlternateIKSystem/LICENSE.txt | 0 .../AlternateIKSystem/Main.cs | 0 .../AlternateIKSystem/ModSettings.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../AlternateIKSystem/README.md | 0 .../AlternateIKSystem/format.json | 0 .../AutoSyncTransforms}/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../AutoSyncTransforms}/README.md | 0 .../WhereAmIPointing.csproj | 0 .../AutoSyncTransforms}/format.json | 0 .../AvatarScaleMod}/AvatarScaleMod.csproj | 0 .../AvatarScaling/AvatarScaleManager.cs | 4 +- .../AvatarScaling/Components/BaseScaler.cs | 0 .../AvatarScaling/Components/LocalScaler.cs | 5 +- .../AvatarScaling/Components/NetworkScaler.cs | 0 .../AvatarScaling/Events/AvatarScaleEvents.cs | 0 .../AvatarScaling/ScaledComponents.cs | 0 .../AvatarScaleMod}/HarmonyPatches.cs | 0 .../AvatarScaleMod}/Input/DebugKeybinds.cs | 0 .../AvatarScaleMod}/Input/ScaleReconizer.cs | 0 .../Integrations/BTKUI/BtkUiAddon.cs | 55 +- .../BTKUI/BtkUiAddon_CAT_AvatarScaleMod.cs | 9 +- .../BTKUI/BtkUiAddon_CAT_AvatarScaleTool.cs | 9 +- .../BTKUI/BtkUiAddon_CAT_DebugOptions.cs | 9 +- ...BtkUiAddon_CAT_UniversalScalingSettings.cs | 31 +- .../BTKUI/BtkUiAddon_PSP_AvatarScaleMod.cs | 35 +- .../Integrations/BTKUI/BtkUiAddon_Utils.cs | 77 +++ .../AvatarScaleMod}/Main.cs | 0 .../AvatarScaleMod}/ModSettings.cs | 0 .../AvatarScaleMod}/Networking/ModNetwork.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../AvatarScaleMod}/README.md | 0 .../AvatarScaleMod}/Scripts.cs | 9 +- .../AvatarScaleMod}/format.json | 0 .../resources/ASM_Icon_AvatarHeightConfig.png | Bin .../resources/ASM_Icon_AvatarHeightCopy.png | Bin .../AvatarScaleMod}/resources/menu.js | 0 .../BadAnimatorFix/BadAnimatorFix.csproj | 0 .../BadAnimatorFix/BadAnimatorFixManager.cs | 0 .../BadAnimatorFix/BadAnimatorFixer.cs | 0 .../BadAnimatorFix/HarmonyPatches.cs | 0 .../BadAnimatorFix/Main.cs | 0 .../BadAnimatorFix/Properties/AssemblyInfo.cs | 0 .../BadAnimatorFix/format.json | 0 .../Blackout/AssetHandler.cs | 0 .../Blackout/Blackout.csproj | 0 .../Blackout/BlackoutController.cs | 0 .../Blackout/HarmonyPatches.cs | 0 .../Blackout/Integrations/BTKUIAddon.cs | 0 .../Integrations/UIExpansionKitAddon.cs | 0 .../Blackout/Main.cs | 0 .../Blackout/Properties/AssemblyInfo.cs | 0 .../Blackout/Resource1.Designer.cs | 0 .../Blackout/Resource1.resx | 0 .../Blackout/format.json | 0 .../resources/blackout_controller.asset | Bin .../BullshitWatcher}/BullshitWatcher.csproj | 0 .../BullshitWatcher}/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../CVRGizmos}/CVRGizmoManager.cs | 29 +- .../CVRGizmos}/CVRGizmos.csproj | 0 .../CVRAdvancedAvatarSettingsPointer.cs | 0 .../CVRAdvancedAvatarSettingsTrigger.cs | 0 .../CVRGizmos}/GizmoTypes/CVRAvatar.cs | 0 .../GizmoTypes/CVRAvatarPickupMarker.cs | 0 .../GizmoTypes/CVRDistanceConstrain.cs | 0 .../CVRGizmos}/GizmoTypes/CVRDistanceLod.cs | 0 .../CVRGizmos}/GizmoTypes/CVRGizmoBase.cs | 0 .../GizmoTypes/CVRHapticAreaChest.cs | 0 .../CVRGizmos}/GizmoTypes/CVRHapticZone.cs | 0 .../CVRGizmos}/GizmoTypes/CVRPointer.cs | 0 .../GizmoTypes/CVRSpawnableTrigger.cs | 0 .../GizmoTypes/CVRToggleStateTrigger.cs | 0 .../GizmoTypes/Unity_BoxCollider.cs | 0 .../GizmoTypes/Unity_CapsuleCollider.cs | 0 .../GizmoTypes/Unity_SphereCollider.cs | 0 {CVRGizmos => .Deprecated/CVRGizmos}/Main.cs | 0 .../CVRGizmos/Popcron.Gizmos/Constants.cs | 7 + .../CVRGizmos}/Popcron.Gizmos/Drawer.cs | 23 +- .../Popcron.Gizmos/Drawers/CubeDrawer.cs | 15 +- .../Popcron.Gizmos/Drawers/LineDrawer.cs | 18 + .../Popcron.Gizmos/Drawers/PolygonDrawer.cs | 15 +- .../Popcron.Gizmos/Drawers/SquareDrawer.cs | 15 +- .../CVRGizmos/Popcron.Gizmos/Element.cs | 11 + .../CVRGizmos}/Popcron.Gizmos/Gizmos.cs | 363 ++++++----- .../Popcron.Gizmos/GizmosInstance.cs | 0 .../CVRGizmos}/Popcron.Gizmos/LICENSE.md | 0 .../CVRGizmos}/Properties/AssemblyInfo.cs | 0 .../CVRGizmos}/format.json | 0 .../CameraExperiments.csproj | 0 .Deprecated/CameraExperiments/Main.cs | 170 ++++++ .../Properties/AssemblyInfo.cs | 32 + .Deprecated/CameraExperiments/README.md | 14 + .Deprecated/CameraExperiments/format.json | 23 + .../CameraFixes/CameraFixes.csproj | 0 .../CameraFixes/HarmonyPatches.cs | 0 .../CameraFixes/Main.cs | 0 .../CameraFixes/Properties/AssemblyInfo.cs | 0 .../CameraFixes/format.json | 0 .../ClearHudNotifications.csproj | 0 .../ClearHudNotifications/HarmonyPatches.cs | 0 .../ClearHudNotifications/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../ClearHudNotifications/format.json | 0 .../ControlToUnlockMouse.csproj | 6 + .Deprecated/ControlToUnlockMouse/Main.cs | 308 ++++++++++ .../Properties/AssemblyInfo.cs | 32 + .../ControlToUnlockMouse}/README.md | 0 .../ControlToUnlockMouse}/format.json | 0 .../ControllerFreeze/ControllerFreeze.csproj | 0 .../ControllerFreeze/HarmonyPatches.cs | 0 .../ControllerFreeze/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../ControllerFreeze/README.md | 0 .../ControllerFreeze/format.json | 0 .../DesktopVRIK/DesktopVRIK.csproj | 0 .../DesktopVRIK/HarmonyPatches.cs | 0 .../DesktopVRIK/IK/IKCalibrator.cs | 0 .../DesktopVRIK/IK/IKHandlers/IKHandler.cs | 0 .../IK/IKHandlers/IKHandlerDesktop.cs | 0 .../DesktopVRIK/IK/IKManager.cs | 0 .../DesktopVRIK/IK/MusclePoses.cs | 0 .../IK/VRIKHelpers/VRIKLocomotionData.cs | 0 .../DesktopVRIK/IK/VRIKHelpers/VRIKUtils.cs | 0 .../DesktopVRIK/Integrations/AMTAddon.cs | 0 .../DesktopVRIK/Integrations/BTKUIAddon.cs | 0 .../DesktopVRIK/Main.cs | 0 .../DesktopVRIK/ModSettings.cs | 0 .../DesktopVRIK/Properties/AssemblyInfo.cs | 0 .../DesktopVRIK/README.md | 0 .../DesktopVRIK/format.json | 0 .../DesktopVRSwitch/DesktopVRSwitch.csproj | 0 .../DesktopVRSwitch/HarmonyPatches.cs | 0 .../Integrations/BTKUIAddon.cs | 0 .../DesktopVRSwitch/Main.cs | 0 .../DesktopVRSwitch/ModSettings.cs | 0 .../DestroySteamVRInstancesImmediate.cs | 0 .../Patches/ReferenceCameraPatch.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../DesktopVRSwitch/README.md | 0 .../DesktopVRSwitch/Utils.cs | 0 .../DesktopVRSwitch/VRModeSwitchDebugger.cs | 0 .../DesktopVRSwitch/VRModeSwitchManager.cs | 0 .../CVRGestureRecognizerTracker.cs | 0 .../VRModeTrackers/CVRInputManagerTracker.cs | 0 .../VRModeTrackers/CVRPickupObjectTracker.cs | 0 .../VRModeTrackers/CVRWorldTracker.cs | 0 .../CVR_InteractableManagerTracker.cs | 0 .../VRModeTrackers/CVR_MenuManagerTracker.cs | 0 .../CameraFacingObjectTracker.cs | 0 .../VRModeTrackers/CheckVRTracker.cs | 0 .../VRModeTrackers/CohtmlHudTracker.cs | 0 .../VRModeTrackers/HudOperationsTracker.cs | 0 .../VRModeTrackers/IKSystemTracker.cs | 0 .../VRModeTrackers/MetaPortTracker.cs | 0 .../VRModeTrackers/MovementSystemTracker.cs | 0 .../VRModeTrackers/PlayerSetupTracker.cs | 0 .../VRModeTrackers/PortableCameraTracker.cs | 0 .../VRModeTrackers/VRModeTracker.cs | 0 .../VRModeTrackers/ViewManagerTracker.cs | 0 .../DesktopVRSwitch/XRHandler.cs | 0 .../DesktopVRSwitch/format.json | 0 .../DropPropTweak}/DropPropTweak.csproj | 0 .../DropPropTweak}/Main.cs | 2 - .../DropPropTweak}/Properties/AssemblyInfo.cs | 0 .../DropPropTweak}/README.md | 0 .../DropPropTweak}/format.json | 0 .../EzCurls/EzCurls.csproj | 0 .../InputModules/InputModuleCurlAdjuster.cs | 0 .../EzCurls/Main.cs | 0 .../EzCurls/ModSettings.cs | 0 .../EzCurls/Properties/AssemblyInfo.cs | 0 .../EzCurls/README.md | 0 .../EzCurls/format.json | 0 .../EzGrab/EzGrab.csproj | 0 .../EzGrab/Main.cs | 0 .../EzGrab/Properties/AssemblyInfo.cs | 0 .../EzGrab/format.json | 0 .../FOVAdjustment}/FOVAdjustment.csproj | 0 .../FOVAdjustment}/Main.cs | 6 +- .../FOVAdjustment}/Properties/AssemblyInfo.cs | 0 .../FOVAdjustment}/README.md | 0 .../FOVAdjustment}/format.json | 0 .../FuckCohtmlResourceHandler.csproj | 0 .../HarmonyPatches.cs | 0 .../FuckCohtmlResourceHandler/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../FuckCohtmlResourceHandler/README.md | 0 .../FuckCohtmlResourceHandler/format.json | 0 .../FuckMLA/FuckMLA.csproj | 0 .../FuckMLA/HarmonyPatches.cs | 0 .../FuckMLA/Main.cs | 0 .../FuckMLA/Properties/AssemblyInfo.cs | 0 .../FuckMLA/format.json | 0 .../FuckMagicaCloth2/FuckMagicaCloth2.csproj | 0 .Deprecated/FuckMagicaCloth2/Main.cs | 49 ++ .../Properties/AssemblyInfo.cs | 30 + .../FuckMagicaCloth2}/README.md | 0 .Deprecated/FuckMagicaCloth2/format.json | 24 + .../FuckMetrics/FuckMetrics.csproj | 0 .../FuckMetrics/HarmonyPatches.cs | 0 .../FuckMetrics/Main.cs | 0 .../FuckMetrics/ManagedLibs/.keep | 0 .../FuckMetrics/Properties/AssemblyInfo.cs | 0 .../FuckMetrics/format.json | 0 .../FuckOffUICamera/CohtmlRenderForwarder.cs | 35 ++ .../FuckOffUICamera/CommandBufferManager.cs | 144 +++++ .../FuckOffUICamera/FuckOffUICamera.csproj | 0 .Deprecated/FuckOffUICamera/Main.cs | 73 +++ .../Properties/AssemblyInfo.cs | 18 +- .Deprecated/FuckOffUICamera/README.md | 14 + .Deprecated/FuckOffUICamera/format.json | 23 + .../FuckVivox/FuckVivox.csproj | 0 .../FuckVivox/HarmonyPatches.cs | 0 .../FuckVivox/Main.cs | 0 .../FuckVivox/Properties/AssemblyInfo.cs | 0 .../FuckVivox/VivoxHelpers.cs | 0 .../FuckVivox/WindowFocusManager.cs | 0 .../FuckVivox/format.json | 0 .../GestureLock}/GestureLock.csproj | 0 .../GestureLock}/HarmonyPatches.cs | 0 .../GestureLock}/Main.cs | 0 .../GestureLock}/Properties/AssemblyInfo.cs | 0 .../GestureLock}/README.md | 0 .../GestureLock}/format.json | 0 .../HeadBobbingFix/HarmonyPatches.cs | 0 .../HeadBobbingFix/HeadBobbingFix.csproj | 0 .../HeadBobbingFix/Main.cs | 0 .../HeadBobbingFix/Properties/AssemblyInfo.cs | 0 .../HeadBobbingFix/README.md | 0 .../HeadBobbingFix/format.json | 0 .../HeadLookLockingInputFix.csproj | 0 .../HeadLookLockingInputFix/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../HeadLookLockingInputFix/README.md | 0 .../HeadLookLockingInputFix/format.json | 0 .../IKAdjustments/HarmonyPatches.cs | 0 .../IKAdjustments/IKAdjuster.cs | 0 .../IKAdjustments/IKAdjustments.csproj | 0 .../IKAdjustments/Integrations/BTKUIAddon.cs | 0 .../IKAdjustments/Main.cs | 0 .../IKAdjustments/Properties/AssemblyInfo.cs | 0 .../IKFixes/HarmonyPatches.cs | 0 .../IKFixes/IKFixes.csproj | 0 .../IKFixes/Integrations/UIExKitAddon.cs | 0 .../IKFixes/Main.cs | 0 .../IKFixes/Properties/AssemblyInfo.cs | 0 .../IKFixes/README.md | 0 .../IKFixes/format.json | 0 .../IKSimulatedRootAngleFix.csproj | 0 .../IKSimulatedRootAngleFix}/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .Deprecated/IKSimulatedRootAngleFix/README.md | 14 + .../IKSimulatedRootAngleFix}/format.json | 0 .../InteractionTest/AutoArmIK.cs | 0 .../ColliderTest/AvatarColliderStruct.cs | 0 .../ColliderTest/AvatarColliders.cs | 0 .../ColliderTest/LineColliderTest.cs | 0 .../InteractionTest/GrabbableAvatar.cs | 0 .../InteractionTest/GrabbingAvatar.cs | 0 .../InteractionTest/HarmonyPatches.cs | 0 .../InteractionTest/InteractionTest.csproj | 0 .../InteractionTest/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../InteractionTest/README.md | 0 .../InteractionTest}/format.json | 0 .../JumpPatch/HarmonyPatches.cs | 0 .../JumpPatch/JumpPatch.csproj | 0 .../JumpPatch/Main.cs | 0 .../JumpPatch/Properties/AssemblyInfo.cs | 0 .../JumpPatch/format.json | 0 .../LateInitComponentHelperHack.csproj | 0 .../LateInitComponentHelperHack/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../LateInitComponentHelperHack/format.json | 0 .../Components/CameraCallbackLogger.cs | 0 .../Components/FaceMirror.cs | 100 +++ .../Components/FakeMultiPassHack.cs | 0 .../Integrations/BtkUiAddon.cs | 0 .../LegacyContentMitigation.csproj | 0 .../LegacyContentMitigation}/Main.cs | 0 .../LegacyContentMitigation/ModSettings.cs | 52 ++ .../LegacyContentMitigation}/Patches.cs | 4 + .../Properties/AssemblyInfo.cs | 0 .../LegacyContentMitigation}/README.md | 0 .../LegacyContentMitigation}/format.json | 4 +- .../MenuScalePatch/HarmonyPatches.cs | 0 .../MenuScalePatch/Helpers/MainMenuHelper.cs | 0 .../MenuScalePatch/Helpers/QuickMenuHelper.cs | 0 .../MenuScalePatch/MSP_Menus.cs | 0 .../MenuScalePatch/Main.cs | 0 .../MenuScalePatch/MenuScalePatch.csproj | 0 .../MenuScalePatch/Properties/AssemblyInfo.cs | 0 .../MenuScalePatch/README.md | 0 .../MenuScalePatch/format.json | 0 .../MoreMenuOptions/Main.cs | 0 .../MoreMenuOptions/ModSettings.cs | 0 .../MoreMenuOptions/MoreMenuOptions.csproj | 0 .../Properties/AssemblyInfo.cs | 0 .../MoreMenuOptions/README.md | 0 .../MoreMenuOptions/format.json | 0 .../Components/NAKPointerTracker.cs | 0 .../CustomComponents.csproj | 0 .../NAK.CustomComponents/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../NAK.CustomComponents/format.json | 0 {Nevermind => .Deprecated/Nevermind}/Main.cs | 0 .../Nevermind}/Nevermind.csproj | 0 .../Nevermind}/Properties/AssemblyInfo.cs | 0 .../Nevermind}/README.md | 0 .../Nevermind}/format.json | 0 .../NoDepthOnlyFlat/Main.cs | 0 .../NoDepthOnlyFlat/NoDepthOnlyFlat.csproj | 0 .../Properties/AssemblyInfo.cs | 0 .../NoDepthOnlyFlat/README.md | 0 .../NoDepthOnlyFlat/format.json | 0 .../PickupPushPull/HarmonyPatches.cs | 0 .../InputModules/PickupPushPull_Module.cs | 0 .../PickupPushPull/Main.cs | 0 .../PickupPushPull/PickupPushPull.csproj | 0 .../PickupPushPull/Properties/AssemblyInfo.cs | 0 .../PickupPushPull/format.json | 0 .../PlaySpaceScaleFix/HarmonyPatches.cs | 0 .../PlaySpaceScaleFix/Main.cs | 0 .../PlaySpaceScaleFix.csproj | 0 .../Properties/AssemblyInfo.cs | 0 .../PlaySpaceScaleFix/README.md | 0 .../PlaySpaceScaleFix/format.json | 0 .../ReconnectionSystemFix}/Main.cs | 0 .../ReconnectionSystemFix}/Patches.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../ReconnectionSystemFix}/README.md | 0 .../ReconnectionSystemFix.csproj | 6 + .../ReconnectionSystemFix}/format.json | 0 .../Main.cs | 43 ++ .../Properties/AssemblyInfo.cs | 30 + .../README.md | 14 + ...vatarDisablingCameraOnFirstFrameFix.csproj | 6 + .../format.json | 24 + .../SearchWithSpacesFix}/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .Deprecated/SearchWithSpacesFix/README.md | 14 + .../SearchWithSpacesFix.csproj | 2 + .Deprecated/SearchWithSpacesFix/format.json | 23 + .../ShadowCloneFallback}/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../ShadowCloneFallback}/README.md | 0 .../ShadowCloneFallback.csproj | 0 .../ShadowCloneFallback}/format.json | 0 .../SmartReticle}/Main.cs | 0 .../SmartReticle}/Properties/AssemblyInfo.cs | 0 .../SmartReticle}/README.md | 0 .Deprecated/SmartReticle/SmartReticle.csproj | 6 + .../SmartReticle}/format.json | 0 .../StopClosingMyMenuOnWorldLoad}/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../StopClosingMyMenuOnWorldLoad}/README.md | 0 .../StopClosingMyMenuOnWorldLoad.csproj | 0 .../StopClosingMyMenuOnWorldLoad}/format.json | 0 .../Interaction/CVRPlayerHand.cs | 42 ++ .../CVRPlayerInteractionManager.cs | 214 +++++++ .../Components/CVRCanvasWrapper.cs | 121 ++++ .../RaycastImpl/CVRPlayerRaycaster.cs | 385 ++++++++++++ .../RaycastImpl/CVRPlayerRaycasterMouse.cs | 13 + .../CVRPlayerRaycasterTransform.cs | 10 + .../RaycastImpl/CVRRaycastResult.cs | 38 ++ .../Interaction/RaycastImpl/RaycastDebug.cs | 312 ++++++++++ .Deprecated/SuperAwesomeMod/Main.cs | 81 +++ .../Properties/AssemblyInfo.cs | 32 + .Deprecated/SuperAwesomeMod/README.md | 54 ++ .../SuperAwesomeMod/SuperAwesomeMod.csproj | 9 +- .Deprecated/SuperAwesomeMod/format.json | 24 + .../SwitchToDesktopOnSteamVRExit/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../SwitchToDesktopOnSteamVRExit/README.md | 0 .../SwitchToDesktopOnSteamVRExit.csproj | 0 .../SwitchToDesktopOnSteamVRExit/format.json | 0 .../TrackedControllerFix/HarmonyPatches.cs | 0 .../TrackedControllerFix/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../TrackedControllerFix/README.md | 0 .../TrackedControllerFix.csproj | 0 .../TrackedControllerFixer.cs | 0 .../TrackedControllerFix/format.json | 0 .../TrackedPointFix/HarmonyPatches.cs | 0 .../TrackedPointFix/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../TrackedPointFix/README.md | 0 .../TrackedPointFix/TrackedPointFix.csproj | 0 .../TrackedPointFix/format.json | 0 .../VisualCloneFix}/Main.cs | 0 .Deprecated/VisualCloneFix/Patches.cs | 157 +++++ .../Properties/AssemblyInfo.cs | 0 .../VisualCloneFix}/README.md | 0 .../VisualCloneFix}/VisualCloneFix.csproj | 0 .../VisualCloneFix}/format.json | 0 .Deprecated/WhereAmIPointing/Main.cs | 106 ++++ .../Properties/AssemblyInfo.cs | 32 + .Deprecated/WhereAmIPointing/README.md | 14 + .../WhereAmIPointing/WhereAmIPointing.csproj | 6 + .Deprecated/WhereAmIPointing/format.json | 23 + .gitignore | 3 + ASTExtension/Integrations/BTKUI/BtkUiAddon.cs | 63 +- .../AvatarClone/AvatarClone.API.cs | 68 --- .../AvatarClone/AvatarClone.Clones.cs | 103 ---- .../AvatarClone/AvatarClone.Exclusion.cs | 141 ----- .../AvatarClone/AvatarClone.Exclusions.cs | 229 +++++++ .../AvatarClone/AvatarClone.Fields.cs | 67 -- .../AvatarClone/AvatarClone.Init.cs | 360 ++++++++--- .../AvatarClone/AvatarClone.MagicaSupport.cs | 34 -- .../AvatarClone/AvatarClone.RenderState.cs | 212 +++++++ .../AvatarClone/AvatarClone.StateSync.cs | 156 +++++ .../AvatarClone/AvatarClone.Update.cs | 181 ------ .../AvatarClone/AvatarClone.Util.cs | 75 ++- AvatarCloneTest/AvatarClone/AvatarClone.cs | 233 +++---- .../FPRExclusion/AvatarCloneExclusion.cs | 15 +- AvatarCloneTest/Main.cs | 31 +- AvatarCloneTest/Patches.cs | 69 +-- AvatarCloneTest/Properties/AssemblyInfo.cs | 2 +- .../Integrations/BTKUI/BtkUiAddon_Utils.cs | 78 --- .../BetterContentLoading.csproj | 15 + .../BetterDownloadManager.cs | 210 +++++++ .../BetterContentLoading/DownloadInfo.cs | 63 ++ .../BetterContentLoading/DownloadProcessor.cs | 152 +++++ .../DownloadQueue/AvatarDownloadQueue.cs | 83 +++ .../DownloadQueue/ContentDownloadQueueBase.cs | 177 ++++++ .../DownloadQueue/PropDownloadQueue.cs | 81 +++ .../DownloadQueue/WorldDownloadQueue.cs | 66 ++ .../BetterContentLoading/DownloadState.cs | 26 + .../Util/ThreadingHelper.cs | 109 ++++ .../DownloadManager/DownloadManager.Core.cs | 237 ++++++++ .../DownloadManager.Helpers.cs | 58 ++ .../DownloadManager.Priority.cs | 38 ++ .../DownloadManager/DownloadTask.Main.cs | 33 + .../DownloadManager/DownloadTask.Priority.cs | 6 + .../ConcurrentPriorityQueue.cs | 43 ++ .../DownloadManager.Bandwidth.cs | 24 + .../DownloadManager2/DownloadManager.Core.cs | 126 ++++ .../DownloadManager.Helpers.cs | 58 ++ .../DownloadManager.Priority.cs | 47 ++ .../DownloadManager.Processing.cs | 144 +++++ .../DownloadManager2/DownloadManager.Queue.cs | 80 +++ .../DownloadManager2/DownloadTask2.cs | 62 ++ .../Main.cs | 17 +- BetterContentLoading/ModSettings.cs | 31 + BetterContentLoading/Patches.cs | 71 +++ .../Properties/AssemblyInfo.cs | 33 + BetterContentLoading/README.md | 14 + BetterContentLoading/format.json | 23 + CVRGizmos/Popcron.Gizmos/Constants.cs | 8 - .../Popcron.Gizmos/Drawers/LineDrawer.cs | 19 - CVRGizmos/Popcron.Gizmos/Element.cs | 12 - .../CVRLuaClientBehaviourExtensions.cs | 6 +- CustomRichPresence/CustomRichPresence.csproj | 11 + CustomRichPresence/Main.cs | 123 ++++ .../Properties/AssemblyInfo.cs | 18 +- CustomRichPresence/README.md | 14 + CustomRichPresence/format.json | 23 + CustomSpawnPoint/SpawnPointManager.cs | 127 ++-- .../Components/InteractionTracker.cs | 213 ------- InteractionTest/ModSettings.cs | 7 - InteractionTest/Patches.cs | 17 - InteractionTest/README.md | 52 -- InteractionTest/format.json | 23 - LegacyContentMitigation/ModSettings.cs | 24 - .../SyncedBehaviour/PickupableBehaviour.cs | 161 ----- .../SyncedBehaviour/PickupableObject.cs | 72 --- LuaTTS/Main.cs | 31 +- LuaTTS/Patches.cs | 10 +- NAK_CVR_Mods.sln | 84 +++ .../BTKUI/BtkUiAddon_CAT_OriginShiftMod.cs | 67 +- OriginShift/Integrations/BTKUI/BtkuiAddon.cs | 43 +- .../Integrations/BTKUI/BtkuiAddon_Utils.cs | 41 +- .../Components/OriginShiftController.cs | 75 ++- .../Receivers/OriginShiftEventReceiver.cs | 62 +- .../OriginShiftParticleSystemReceiver.cs | 41 +- .../Receivers/OriginShiftRigidbodyReceiver.cs | 33 +- .../OriginShiftTrailRendererReceiver.cs | 41 +- .../Receivers/OriginShiftTransformReceiver.cs | 27 +- .../OriginShiftOcclusionCullingDisabler.cs | 39 +- .../OriginShift/Player/OriginShiftMonitor.cs | 51 +- OriginShift/Patches.cs | 1 + PhysicsGunMod/Components/ObjectSyncBridge.cs | 92 --- .../PhysicsGunInteractionBehavior.cs | 572 ------------------ PhysicsGunMod/HarmonyPatches.cs | 20 - PhysicsGunMod/Main.cs | 43 -- PhysicsGunMod/ModSettings.cs | 12 - PhysicsGunMod/PhysicsGunMod.csproj | 37 -- PhysicsGunMod/README.md | 28 - PhysicsGunMod/format.json | 23 - PlayerColorsAPI/Main.cs | 44 ++ .../Patches.cs | 0 PlayerColorsAPI/PlayerColorsAPI.csproj | 6 + PlayerColorsAPI/Properties/AssemblyInfo.cs | 32 + PlayerColorsAPI/README.md | 18 + PlayerColorsAPI/format.json | 23 + Portals/format.json | 1 - References.Items.props | 28 +- SmootherRay/Main.cs | 4 + SmootherRay/Properties/AssemblyInfo.cs | 2 +- SmootherRay/SmootherRayer.cs | 4 + .../Stickers/Networking/ModNetwork.Inbound.cs | 9 +- .../Stickers/StickerSystem.PlayerCallbacks.cs | 4 +- .../StickerSystem.StickerLifecycle.cs | 2 +- ThirdPerson/CameraLogic.cs | 4 +- ThirdPerson/Patches.cs | 5 - ThirdPerson/Properties/AssemblyInfo.cs | 2 +- 539 files changed, 7475 insertions(+), 3120 deletions(-) rename {.DepricatedMods => .Deprecated}/AASBufferFix/AASBufferFix.csproj (100%) rename {.DepricatedMods => .Deprecated}/AASBufferFix/AASBufferHelper.cs (100%) rename {.DepricatedMods => .Deprecated}/AASBufferFix/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/AASBufferFix/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/AASBufferFix/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/AASBufferFix/README.md (100%) rename {.DepricatedMods => .Deprecated}/AASBufferFix/Utils.cs (100%) rename {.DepricatedMods => .Deprecated}/AASBufferFix/format.json (100%) rename {AASDefaultProfileFix => .Deprecated/AASDefaultProfileFix}/AASDefaultProfileFix.csproj (100%) rename {AASDefaultProfileFix => .Deprecated/AASDefaultProfileFix}/Main.cs (100%) rename {AASDefaultProfileFix => .Deprecated/AASDefaultProfileFix}/Properties/AssemblyInfo.cs (100%) rename {AASDefaultProfileFix => .Deprecated/AASDefaultProfileFix}/README.md (100%) rename {AASDefaultProfileFix => .Deprecated/AASDefaultProfileFix}/format.json (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/AlternateIKSystem.csproj (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/BodyControl.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/IKCalibrator.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/IKHandlers/IKHandler.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/IKHandlers/IKHandlerDesktop.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/IKHandlers/IKHandlerHalfBody.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/IKManager.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/MusclePoses.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/Tracking/SteamVRTrackerManager.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/VRIKHelpers/VRIKLocomotionData.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/VRIKHelpers/VRIKUtils.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/WeightManipulators/BodyParts/BodyPart.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/WeightManipulators/DeviceControlManipulator.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/WeightManipulators/Interface/IWeightManipulator.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/WeightManipulators/TrackingControlManipulator.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/IK/WeightManipulators/WeightManipulatorManager.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/Integrations/BTKUIAddon.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/LICENSE.txt (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/ModSettings.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/README.md (100%) rename {.DepricatedMods => .Deprecated}/AlternateIKSystem/format.json (100%) rename {WhereAmIPointing => .Deprecated/AutoSyncTransforms}/Main.cs (100%) rename {WhereAmIPointing => .Deprecated/AutoSyncTransforms}/Properties/AssemblyInfo.cs (100%) rename {WhereAmIPointing => .Deprecated/AutoSyncTransforms}/README.md (100%) rename {WhereAmIPointing => .Deprecated/AutoSyncTransforms}/WhereAmIPointing.csproj (100%) rename {WhereAmIPointing => .Deprecated/AutoSyncTransforms}/format.json (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/AvatarScaleMod.csproj (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/AvatarScaling/AvatarScaleManager.cs (99%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/AvatarScaling/Components/BaseScaler.cs (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/AvatarScaling/Components/LocalScaler.cs (94%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/AvatarScaling/Components/NetworkScaler.cs (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/AvatarScaling/Events/AvatarScaleEvents.cs (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/AvatarScaling/ScaledComponents.cs (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/HarmonyPatches.cs (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Input/DebugKeybinds.cs (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Input/ScaleReconizer.cs (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Integrations/BTKUI/BtkUiAddon.cs (71%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleMod.cs (76%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleTool.cs (83%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Integrations/BTKUI/BtkUiAddon_CAT_DebugOptions.cs (71%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Integrations/BTKUI/BtkUiAddon_CAT_UniversalScalingSettings.cs (83%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Integrations/BTKUI/BtkUiAddon_PSP_AvatarScaleMod.cs (76%) create mode 100644 .Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_Utils.cs rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Main.cs (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/ModSettings.cs (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Networking/ModNetwork.cs (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Properties/AssemblyInfo.cs (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/README.md (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/Scripts.cs (83%) rename {.DepricatedMods/InteractionTest => .Deprecated/AvatarScaleMod}/format.json (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/resources/ASM_Icon_AvatarHeightConfig.png (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/resources/ASM_Icon_AvatarHeightCopy.png (100%) rename {AvatarScaleMod => .Deprecated/AvatarScaleMod}/resources/menu.js (100%) rename {.DepricatedMods => .Deprecated}/BadAnimatorFix/BadAnimatorFix.csproj (100%) rename {.DepricatedMods => .Deprecated}/BadAnimatorFix/BadAnimatorFixManager.cs (100%) rename {.DepricatedMods => .Deprecated}/BadAnimatorFix/BadAnimatorFixer.cs (100%) rename {.DepricatedMods => .Deprecated}/BadAnimatorFix/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/BadAnimatorFix/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/BadAnimatorFix/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/BadAnimatorFix/format.json (100%) rename {.DepricatedMods => .Deprecated}/Blackout/AssetHandler.cs (100%) rename {.DepricatedMods => .Deprecated}/Blackout/Blackout.csproj (100%) rename {.DepricatedMods => .Deprecated}/Blackout/BlackoutController.cs (100%) rename {.DepricatedMods => .Deprecated}/Blackout/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/Blackout/Integrations/BTKUIAddon.cs (100%) rename {.DepricatedMods => .Deprecated}/Blackout/Integrations/UIExpansionKitAddon.cs (100%) rename {.DepricatedMods => .Deprecated}/Blackout/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/Blackout/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/Blackout/Resource1.Designer.cs (100%) rename {.DepricatedMods => .Deprecated}/Blackout/Resource1.resx (100%) rename {.DepricatedMods => .Deprecated}/Blackout/format.json (100%) rename {.DepricatedMods => .Deprecated}/Blackout/resources/blackout_controller.asset (100%) rename {BullshitWatcher => .Deprecated/BullshitWatcher}/BullshitWatcher.csproj (100%) rename {BullshitWatcher => .Deprecated/BullshitWatcher}/Main.cs (100%) rename {BullshitWatcher => .Deprecated/BullshitWatcher}/Properties/AssemblyInfo.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/CVRGizmoManager.cs (76%) rename {CVRGizmos => .Deprecated/CVRGizmos}/CVRGizmos.csproj (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRAdvancedAvatarSettingsPointer.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRAdvancedAvatarSettingsTrigger.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRAvatar.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRAvatarPickupMarker.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRDistanceConstrain.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRDistanceLod.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRGizmoBase.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRHapticAreaChest.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRHapticZone.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRPointer.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRSpawnableTrigger.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/CVRToggleStateTrigger.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/Unity_BoxCollider.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/Unity_CapsuleCollider.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/GizmoTypes/Unity_SphereCollider.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/Main.cs (100%) create mode 100644 .Deprecated/CVRGizmos/Popcron.Gizmos/Constants.cs rename {CVRGizmos => .Deprecated/CVRGizmos}/Popcron.Gizmos/Drawer.cs (86%) rename {CVRGizmos => .Deprecated/CVRGizmos}/Popcron.Gizmos/Drawers/CubeDrawer.cs (93%) create mode 100644 .Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/LineDrawer.cs rename {CVRGizmos => .Deprecated/CVRGizmos}/Popcron.Gizmos/Drawers/PolygonDrawer.cs (84%) rename {CVRGizmos => .Deprecated/CVRGizmos}/Popcron.Gizmos/Drawers/SquareDrawer.cs (89%) create mode 100644 .Deprecated/CVRGizmos/Popcron.Gizmos/Element.cs rename {CVRGizmos => .Deprecated/CVRGizmos}/Popcron.Gizmos/Gizmos.cs (52%) rename {CVRGizmos => .Deprecated/CVRGizmos}/Popcron.Gizmos/GizmosInstance.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/Popcron.Gizmos/LICENSE.md (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/Properties/AssemblyInfo.cs (100%) rename {CVRGizmos => .Deprecated/CVRGizmos}/format.json (100%) rename SmartReticle/SmartReticle.csproj => .Deprecated/CameraExperiments/CameraExperiments.csproj (100%) create mode 100644 .Deprecated/CameraExperiments/Main.cs create mode 100644 .Deprecated/CameraExperiments/Properties/AssemblyInfo.cs create mode 100644 .Deprecated/CameraExperiments/README.md create mode 100644 .Deprecated/CameraExperiments/format.json rename {.DepricatedMods => .Deprecated}/CameraFixes/CameraFixes.csproj (100%) rename {.DepricatedMods => .Deprecated}/CameraFixes/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/CameraFixes/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/CameraFixes/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/CameraFixes/format.json (100%) rename {.DepricatedMods => .Deprecated}/ClearHudNotifications/ClearHudNotifications.csproj (100%) rename {.DepricatedMods => .Deprecated}/ClearHudNotifications/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/ClearHudNotifications/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/ClearHudNotifications/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/ClearHudNotifications/format.json (100%) create mode 100644 .Deprecated/ControlToUnlockMouse/ControlToUnlockMouse.csproj create mode 100644 .Deprecated/ControlToUnlockMouse/Main.cs create mode 100644 .Deprecated/ControlToUnlockMouse/Properties/AssemblyInfo.cs rename {SearchWithSpacesFix => .Deprecated/ControlToUnlockMouse}/README.md (100%) rename {SearchWithSpacesFix => .Deprecated/ControlToUnlockMouse}/format.json (100%) rename {.DepricatedMods => .Deprecated}/ControllerFreeze/ControllerFreeze.csproj (100%) rename {.DepricatedMods => .Deprecated}/ControllerFreeze/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/ControllerFreeze/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/ControllerFreeze/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/ControllerFreeze/README.md (100%) rename {.DepricatedMods => .Deprecated}/ControllerFreeze/format.json (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/DesktopVRIK.csproj (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/IK/IKCalibrator.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/IK/IKHandlers/IKHandler.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/IK/IKHandlers/IKHandlerDesktop.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/IK/IKManager.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/IK/MusclePoses.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/IK/VRIKHelpers/VRIKLocomotionData.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/IK/VRIKHelpers/VRIKUtils.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/Integrations/AMTAddon.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/Integrations/BTKUIAddon.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/ModSettings.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/README.md (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRIK/format.json (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/DesktopVRSwitch.csproj (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/Integrations/BTKUIAddon.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/ModSettings.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/Patches/DestroySteamVRInstancesImmediate.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/Patches/ReferenceCameraPatch.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/README.md (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/Utils.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeSwitchDebugger.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeSwitchManager.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/CVRGestureRecognizerTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/CVRInputManagerTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/CVRPickupObjectTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/CVRWorldTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/CVR_InteractableManagerTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/CVR_MenuManagerTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/CameraFacingObjectTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/CheckVRTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/CohtmlHudTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/HudOperationsTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/IKSystemTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/MetaPortTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/MovementSystemTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/PlayerSetupTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/PortableCameraTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/VRModeTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/VRModeTrackers/ViewManagerTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/XRHandler.cs (100%) rename {.DepricatedMods => .Deprecated}/DesktopVRSwitch/format.json (100%) rename {DropPropTweak => .Deprecated/DropPropTweak}/DropPropTweak.csproj (100%) rename {DropPropTweak => .Deprecated/DropPropTweak}/Main.cs (99%) rename {DropPropTweak => .Deprecated/DropPropTweak}/Properties/AssemblyInfo.cs (100%) rename {DropPropTweak => .Deprecated/DropPropTweak}/README.md (100%) rename {DropPropTweak => .Deprecated/DropPropTweak}/format.json (100%) rename {.DepricatedMods => .Deprecated}/EzCurls/EzCurls.csproj (100%) rename {.DepricatedMods => .Deprecated}/EzCurls/InputModules/InputModuleCurlAdjuster.cs (100%) rename {.DepricatedMods => .Deprecated}/EzCurls/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/EzCurls/ModSettings.cs (100%) rename {.DepricatedMods => .Deprecated}/EzCurls/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/EzCurls/README.md (100%) rename {.DepricatedMods => .Deprecated}/EzCurls/format.json (100%) rename {.DepricatedMods => .Deprecated}/EzGrab/EzGrab.csproj (100%) rename {.DepricatedMods => .Deprecated}/EzGrab/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/EzGrab/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/EzGrab/format.json (100%) rename {FOVAdjustment => .Deprecated/FOVAdjustment}/FOVAdjustment.csproj (100%) rename {FOVAdjustment => .Deprecated/FOVAdjustment}/Main.cs (94%) rename {FOVAdjustment => .Deprecated/FOVAdjustment}/Properties/AssemblyInfo.cs (100%) rename {FOVAdjustment => .Deprecated/FOVAdjustment}/README.md (100%) rename {FOVAdjustment => .Deprecated/FOVAdjustment}/format.json (100%) rename {.DepricatedMods => .Deprecated}/FuckCohtmlResourceHandler/FuckCohtmlResourceHandler.csproj (100%) rename {.DepricatedMods => .Deprecated}/FuckCohtmlResourceHandler/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckCohtmlResourceHandler/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckCohtmlResourceHandler/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckCohtmlResourceHandler/README.md (100%) rename {.DepricatedMods => .Deprecated}/FuckCohtmlResourceHandler/format.json (100%) rename {.DepricatedMods => .Deprecated}/FuckMLA/FuckMLA.csproj (100%) rename {.DepricatedMods => .Deprecated}/FuckMLA/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckMLA/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckMLA/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckMLA/format.json (100%) rename .DepricatedMods/HeadLookLockingInputFix/HeadLookLockingInputFix.csproj => .Deprecated/FuckMagicaCloth2/FuckMagicaCloth2.csproj (100%) create mode 100644 .Deprecated/FuckMagicaCloth2/Main.cs create mode 100644 .Deprecated/FuckMagicaCloth2/Properties/AssemblyInfo.cs rename {IKSimulatedRootAngleFix => .Deprecated/FuckMagicaCloth2}/README.md (100%) create mode 100644 .Deprecated/FuckMagicaCloth2/format.json rename {.DepricatedMods => .Deprecated}/FuckMetrics/FuckMetrics.csproj (100%) rename {.DepricatedMods => .Deprecated}/FuckMetrics/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckMetrics/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckMetrics/ManagedLibs/.keep (100%) rename {.DepricatedMods => .Deprecated}/FuckMetrics/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckMetrics/format.json (100%) create mode 100644 .Deprecated/FuckOffUICamera/CohtmlRenderForwarder.cs create mode 100644 .Deprecated/FuckOffUICamera/CommandBufferManager.cs rename .DepricatedMods/NoDepthOnlyFlat/NoDepthOnlyFlat.csproj => .Deprecated/FuckOffUICamera/FuckOffUICamera.csproj (100%) create mode 100644 .Deprecated/FuckOffUICamera/Main.cs rename {PhysicsGunMod => .Deprecated/FuckOffUICamera}/Properties/AssemblyInfo.cs (67%) create mode 100644 .Deprecated/FuckOffUICamera/README.md create mode 100644 .Deprecated/FuckOffUICamera/format.json rename {.DepricatedMods => .Deprecated}/FuckVivox/FuckVivox.csproj (100%) rename {.DepricatedMods => .Deprecated}/FuckVivox/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckVivox/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckVivox/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckVivox/VivoxHelpers.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckVivox/WindowFocusManager.cs (100%) rename {.DepricatedMods => .Deprecated}/FuckVivox/format.json (100%) rename {GestureLock => .Deprecated/GestureLock}/GestureLock.csproj (100%) rename {GestureLock => .Deprecated/GestureLock}/HarmonyPatches.cs (100%) rename {GestureLock => .Deprecated/GestureLock}/Main.cs (100%) rename {GestureLock => .Deprecated/GestureLock}/Properties/AssemblyInfo.cs (100%) rename {GestureLock => .Deprecated/GestureLock}/README.md (100%) rename {GestureLock => .Deprecated/GestureLock}/format.json (100%) rename {.DepricatedMods => .Deprecated}/HeadBobbingFix/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/HeadBobbingFix/HeadBobbingFix.csproj (100%) rename {.DepricatedMods => .Deprecated}/HeadBobbingFix/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/HeadBobbingFix/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/HeadBobbingFix/README.md (100%) rename {.DepricatedMods => .Deprecated}/HeadBobbingFix/format.json (100%) rename ReconnectionSystemFix/ReconnectionSystemFix.csproj => .Deprecated/HeadLookLockingInputFix/HeadLookLockingInputFix.csproj (100%) rename {.DepricatedMods => .Deprecated}/HeadLookLockingInputFix/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/HeadLookLockingInputFix/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/HeadLookLockingInputFix/README.md (100%) rename {.DepricatedMods => .Deprecated}/HeadLookLockingInputFix/format.json (100%) rename {.DepricatedMods => .Deprecated}/IKAdjustments/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/IKAdjustments/IKAdjuster.cs (100%) rename {.DepricatedMods => .Deprecated}/IKAdjustments/IKAdjustments.csproj (100%) rename {.DepricatedMods => .Deprecated}/IKAdjustments/Integrations/BTKUIAddon.cs (100%) rename {.DepricatedMods => .Deprecated}/IKAdjustments/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/IKAdjustments/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/IKFixes/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/IKFixes/IKFixes.csproj (100%) rename {.DepricatedMods => .Deprecated}/IKFixes/Integrations/UIExKitAddon.cs (100%) rename {.DepricatedMods => .Deprecated}/IKFixes/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/IKFixes/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/IKFixes/README.md (100%) rename {.DepricatedMods => .Deprecated}/IKFixes/format.json (100%) rename {IKSimulatedRootAngleFix => .Deprecated/IKSimulatedRootAngleFix}/IKSimulatedRootAngleFix.csproj (100%) rename {IKSimulatedRootAngleFix => .Deprecated/IKSimulatedRootAngleFix}/Main.cs (100%) rename {IKSimulatedRootAngleFix => .Deprecated/IKSimulatedRootAngleFix}/Properties/AssemblyInfo.cs (100%) create mode 100644 .Deprecated/IKSimulatedRootAngleFix/README.md rename {IKSimulatedRootAngleFix => .Deprecated/IKSimulatedRootAngleFix}/format.json (100%) rename {.DepricatedMods => .Deprecated}/InteractionTest/AutoArmIK.cs (100%) rename {.DepricatedMods => .Deprecated}/InteractionTest/ColliderTest/AvatarColliderStruct.cs (100%) rename {.DepricatedMods => .Deprecated}/InteractionTest/ColliderTest/AvatarColliders.cs (100%) rename {.DepricatedMods => .Deprecated}/InteractionTest/ColliderTest/LineColliderTest.cs (100%) rename {.DepricatedMods => .Deprecated}/InteractionTest/GrabbableAvatar.cs (100%) rename {.DepricatedMods => .Deprecated}/InteractionTest/GrabbingAvatar.cs (100%) rename {.DepricatedMods => .Deprecated}/InteractionTest/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/InteractionTest/InteractionTest.csproj (100%) rename {.DepricatedMods => .Deprecated}/InteractionTest/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/InteractionTest/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/InteractionTest/README.md (100%) rename {AvatarScaleMod => .Deprecated/InteractionTest}/format.json (100%) rename {.DepricatedMods => .Deprecated}/JumpPatch/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/JumpPatch/JumpPatch.csproj (100%) rename {.DepricatedMods => .Deprecated}/JumpPatch/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/JumpPatch/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/JumpPatch/format.json (100%) rename {.DepricatedMods => .Deprecated}/LateInitComponentHelperHack/LateInitComponentHelperHack.csproj (100%) rename {.DepricatedMods => .Deprecated}/LateInitComponentHelperHack/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/LateInitComponentHelperHack/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/LateInitComponentHelperHack/format.json (100%) rename {LegacyContentMitigation => .Deprecated/LegacyContentMitigation}/Components/CameraCallbackLogger.cs (100%) create mode 100644 .Deprecated/LegacyContentMitigation/Components/FaceMirror.cs rename {LegacyContentMitigation => .Deprecated/LegacyContentMitigation}/Components/FakeMultiPassHack.cs (100%) rename {LegacyContentMitigation => .Deprecated/LegacyContentMitigation}/Integrations/BtkUiAddon.cs (100%) rename {LegacyContentMitigation => .Deprecated/LegacyContentMitigation}/LegacyContentMitigation.csproj (100%) rename {LegacyContentMitigation => .Deprecated/LegacyContentMitigation}/Main.cs (100%) create mode 100644 .Deprecated/LegacyContentMitigation/ModSettings.cs rename {LegacyContentMitigation => .Deprecated/LegacyContentMitigation}/Patches.cs (97%) rename {LegacyContentMitigation => .Deprecated/LegacyContentMitigation}/Properties/AssemblyInfo.cs (100%) rename {LegacyContentMitigation => .Deprecated/LegacyContentMitigation}/README.md (100%) rename {LegacyContentMitigation => .Deprecated/LegacyContentMitigation}/format.json (96%) rename {.DepricatedMods => .Deprecated}/MenuScalePatch/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/MenuScalePatch/Helpers/MainMenuHelper.cs (100%) rename {.DepricatedMods => .Deprecated}/MenuScalePatch/Helpers/QuickMenuHelper.cs (100%) rename {.DepricatedMods => .Deprecated}/MenuScalePatch/MSP_Menus.cs (100%) rename {.DepricatedMods => .Deprecated}/MenuScalePatch/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/MenuScalePatch/MenuScalePatch.csproj (100%) rename {.DepricatedMods => .Deprecated}/MenuScalePatch/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/MenuScalePatch/README.md (100%) rename {.DepricatedMods => .Deprecated}/MenuScalePatch/format.json (100%) rename {.DepricatedMods => .Deprecated}/MoreMenuOptions/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/MoreMenuOptions/ModSettings.cs (100%) rename {.DepricatedMods => .Deprecated}/MoreMenuOptions/MoreMenuOptions.csproj (100%) rename {.DepricatedMods => .Deprecated}/MoreMenuOptions/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/MoreMenuOptions/README.md (100%) rename {.DepricatedMods => .Deprecated}/MoreMenuOptions/format.json (100%) rename {.DepricatedMods => .Deprecated}/NAK.CustomComponents/Components/NAKPointerTracker.cs (100%) rename {.DepricatedMods => .Deprecated}/NAK.CustomComponents/CustomComponents.csproj (100%) rename {.DepricatedMods => .Deprecated}/NAK.CustomComponents/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/NAK.CustomComponents/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/NAK.CustomComponents/format.json (100%) rename {Nevermind => .Deprecated/Nevermind}/Main.cs (100%) rename {Nevermind => .Deprecated/Nevermind}/Nevermind.csproj (100%) rename {Nevermind => .Deprecated/Nevermind}/Properties/AssemblyInfo.cs (100%) rename {Nevermind => .Deprecated/Nevermind}/README.md (100%) rename {Nevermind => .Deprecated/Nevermind}/format.json (100%) rename {.DepricatedMods => .Deprecated}/NoDepthOnlyFlat/Main.cs (100%) rename SearchWithSpacesFix/SearchWithSpacesFix.csproj => .Deprecated/NoDepthOnlyFlat/NoDepthOnlyFlat.csproj (100%) rename {.DepricatedMods => .Deprecated}/NoDepthOnlyFlat/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/NoDepthOnlyFlat/README.md (100%) rename {.DepricatedMods => .Deprecated}/NoDepthOnlyFlat/format.json (100%) rename {.DepricatedMods => .Deprecated}/PickupPushPull/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/PickupPushPull/InputModules/PickupPushPull_Module.cs (100%) rename {.DepricatedMods => .Deprecated}/PickupPushPull/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/PickupPushPull/PickupPushPull.csproj (100%) rename {.DepricatedMods => .Deprecated}/PickupPushPull/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/PickupPushPull/format.json (100%) rename {.DepricatedMods => .Deprecated}/PlaySpaceScaleFix/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/PlaySpaceScaleFix/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/PlaySpaceScaleFix/PlaySpaceScaleFix.csproj (100%) rename {.DepricatedMods => .Deprecated}/PlaySpaceScaleFix/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/PlaySpaceScaleFix/README.md (100%) rename {.DepricatedMods => .Deprecated}/PlaySpaceScaleFix/format.json (100%) rename {ReconnectionSystemFix => .Deprecated/ReconnectionSystemFix}/Main.cs (100%) rename {ReconnectionSystemFix => .Deprecated/ReconnectionSystemFix}/Patches.cs (100%) rename {ReconnectionSystemFix => .Deprecated/ReconnectionSystemFix}/Properties/AssemblyInfo.cs (100%) rename {ReconnectionSystemFix => .Deprecated/ReconnectionSystemFix}/README.md (100%) create mode 100644 .Deprecated/ReconnectionSystemFix/ReconnectionSystemFix.csproj rename {ReconnectionSystemFix => .Deprecated/ReconnectionSystemFix}/format.json (100%) create mode 100644 .Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/Main.cs create mode 100644 .Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/Properties/AssemblyInfo.cs create mode 100644 .Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/README.md create mode 100644 .Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/RemoteAvatarDisablingCameraOnFirstFrameFix.csproj create mode 100644 .Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/format.json rename {SearchWithSpacesFix => .Deprecated/SearchWithSpacesFix}/Main.cs (100%) rename {SearchWithSpacesFix => .Deprecated/SearchWithSpacesFix}/Properties/AssemblyInfo.cs (100%) create mode 100644 .Deprecated/SearchWithSpacesFix/README.md create mode 100644 .Deprecated/SearchWithSpacesFix/SearchWithSpacesFix.csproj create mode 100644 .Deprecated/SearchWithSpacesFix/format.json rename {ShadowCloneFallback => .Deprecated/ShadowCloneFallback}/Main.cs (100%) rename {ShadowCloneFallback => .Deprecated/ShadowCloneFallback}/Properties/AssemblyInfo.cs (100%) rename {ShadowCloneFallback => .Deprecated/ShadowCloneFallback}/README.md (100%) rename {ShadowCloneFallback => .Deprecated/ShadowCloneFallback}/ShadowCloneFallback.csproj (100%) rename {ShadowCloneFallback => .Deprecated/ShadowCloneFallback}/format.json (100%) rename {SmartReticle => .Deprecated/SmartReticle}/Main.cs (100%) rename {SmartReticle => .Deprecated/SmartReticle}/Properties/AssemblyInfo.cs (100%) rename {SmartReticle => .Deprecated/SmartReticle}/README.md (100%) create mode 100644 .Deprecated/SmartReticle/SmartReticle.csproj rename {SmartReticle => .Deprecated/SmartReticle}/format.json (100%) rename {StopClosingMyMenuOnWorldLoad => .Deprecated/StopClosingMyMenuOnWorldLoad}/Main.cs (100%) rename {StopClosingMyMenuOnWorldLoad => .Deprecated/StopClosingMyMenuOnWorldLoad}/Properties/AssemblyInfo.cs (100%) rename {StopClosingMyMenuOnWorldLoad => .Deprecated/StopClosingMyMenuOnWorldLoad}/README.md (100%) rename {StopClosingMyMenuOnWorldLoad => .Deprecated/StopClosingMyMenuOnWorldLoad}/StopClosingMyMenuOnWorldLoad.csproj (100%) rename {StopClosingMyMenuOnWorldLoad => .Deprecated/StopClosingMyMenuOnWorldLoad}/format.json (100%) create mode 100644 .Deprecated/SuperAwesomeMod/Interaction/CVRPlayerHand.cs create mode 100644 .Deprecated/SuperAwesomeMod/Interaction/CVRPlayerInteractionManager.cs create mode 100644 .Deprecated/SuperAwesomeMod/Interaction/Components/CVRCanvasWrapper.cs create mode 100644 .Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycaster.cs create mode 100644 .Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterMouse.cs create mode 100644 .Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterTransform.cs create mode 100644 .Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRRaycastResult.cs create mode 100644 .Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/RaycastDebug.cs create mode 100644 .Deprecated/SuperAwesomeMod/Main.cs create mode 100644 .Deprecated/SuperAwesomeMod/Properties/AssemblyInfo.cs create mode 100644 .Deprecated/SuperAwesomeMod/README.md rename InteractionTest/InteractionTest.csproj => .Deprecated/SuperAwesomeMod/SuperAwesomeMod.csproj (52%) create mode 100644 .Deprecated/SuperAwesomeMod/format.json rename {.DepricatedMods => .Deprecated}/SwitchToDesktopOnSteamVRExit/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/SwitchToDesktopOnSteamVRExit/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/SwitchToDesktopOnSteamVRExit/README.md (100%) rename {.DepricatedMods => .Deprecated}/SwitchToDesktopOnSteamVRExit/SwitchToDesktopOnSteamVRExit.csproj (100%) rename {.DepricatedMods => .Deprecated}/SwitchToDesktopOnSteamVRExit/format.json (100%) rename {.DepricatedMods => .Deprecated}/TrackedControllerFix/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/TrackedControllerFix/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/TrackedControllerFix/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/TrackedControllerFix/README.md (100%) rename {.DepricatedMods => .Deprecated}/TrackedControllerFix/TrackedControllerFix.csproj (100%) rename {.DepricatedMods => .Deprecated}/TrackedControllerFix/TrackedControllerFixer.cs (100%) rename {.DepricatedMods => .Deprecated}/TrackedControllerFix/format.json (100%) rename {.DepricatedMods => .Deprecated}/TrackedPointFix/HarmonyPatches.cs (100%) rename {.DepricatedMods => .Deprecated}/TrackedPointFix/Main.cs (100%) rename {.DepricatedMods => .Deprecated}/TrackedPointFix/Properties/AssemblyInfo.cs (100%) rename {.DepricatedMods => .Deprecated}/TrackedPointFix/README.md (100%) rename {.DepricatedMods => .Deprecated}/TrackedPointFix/TrackedPointFix.csproj (100%) rename {.DepricatedMods => .Deprecated}/TrackedPointFix/format.json (100%) rename {VisualCloneFix => .Deprecated/VisualCloneFix}/Main.cs (100%) create mode 100644 .Deprecated/VisualCloneFix/Patches.cs rename {VisualCloneFix => .Deprecated/VisualCloneFix}/Properties/AssemblyInfo.cs (100%) rename {VisualCloneFix => .Deprecated/VisualCloneFix}/README.md (100%) rename {VisualCloneFix => .Deprecated/VisualCloneFix}/VisualCloneFix.csproj (100%) rename {VisualCloneFix => .Deprecated/VisualCloneFix}/format.json (100%) create mode 100644 .Deprecated/WhereAmIPointing/Main.cs create mode 100644 .Deprecated/WhereAmIPointing/Properties/AssemblyInfo.cs create mode 100644 .Deprecated/WhereAmIPointing/README.md create mode 100644 .Deprecated/WhereAmIPointing/WhereAmIPointing.csproj create mode 100644 .Deprecated/WhereAmIPointing/format.json delete mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.API.cs delete mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.Clones.cs delete mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.Exclusion.cs create mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.Exclusions.cs delete mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.Fields.cs delete mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.MagicaSupport.cs create mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.RenderState.cs create mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.StateSync.cs delete mode 100644 AvatarCloneTest/AvatarClone/AvatarClone.Update.cs delete mode 100644 AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_Utils.cs create mode 100644 BetterContentLoading/BetterContentLoading.csproj create mode 100644 BetterContentLoading/BetterContentLoading/BetterDownloadManager.cs create mode 100644 BetterContentLoading/BetterContentLoading/DownloadInfo.cs create mode 100644 BetterContentLoading/BetterContentLoading/DownloadProcessor.cs create mode 100644 BetterContentLoading/BetterContentLoading/DownloadQueue/AvatarDownloadQueue.cs create mode 100644 BetterContentLoading/BetterContentLoading/DownloadQueue/ContentDownloadQueueBase.cs create mode 100644 BetterContentLoading/BetterContentLoading/DownloadQueue/PropDownloadQueue.cs create mode 100644 BetterContentLoading/BetterContentLoading/DownloadQueue/WorldDownloadQueue.cs create mode 100644 BetterContentLoading/BetterContentLoading/DownloadState.cs create mode 100644 BetterContentLoading/BetterContentLoading/Util/ThreadingHelper.cs create mode 100644 BetterContentLoading/DownloadManager/DownloadManager.Core.cs create mode 100644 BetterContentLoading/DownloadManager/DownloadManager.Helpers.cs create mode 100644 BetterContentLoading/DownloadManager/DownloadManager.Priority.cs create mode 100644 BetterContentLoading/DownloadManager/DownloadTask.Main.cs create mode 100644 BetterContentLoading/DownloadManager/DownloadTask.Priority.cs create mode 100644 BetterContentLoading/DownloadManager2/ConcurrentPriorityQueue.cs create mode 100644 BetterContentLoading/DownloadManager2/DownloadManager.Bandwidth.cs create mode 100644 BetterContentLoading/DownloadManager2/DownloadManager.Core.cs create mode 100644 BetterContentLoading/DownloadManager2/DownloadManager.Helpers.cs create mode 100644 BetterContentLoading/DownloadManager2/DownloadManager.Priority.cs create mode 100644 BetterContentLoading/DownloadManager2/DownloadManager.Processing.cs create mode 100644 BetterContentLoading/DownloadManager2/DownloadManager.Queue.cs create mode 100644 BetterContentLoading/DownloadManager2/DownloadTask2.cs rename {InteractionTest => BetterContentLoading}/Main.cs (68%) create mode 100644 BetterContentLoading/ModSettings.cs create mode 100644 BetterContentLoading/Patches.cs create mode 100644 BetterContentLoading/Properties/AssemblyInfo.cs create mode 100644 BetterContentLoading/README.md create mode 100644 BetterContentLoading/format.json delete mode 100644 CVRGizmos/Popcron.Gizmos/Constants.cs delete mode 100644 CVRGizmos/Popcron.Gizmos/Drawers/LineDrawer.cs delete mode 100644 CVRGizmos/Popcron.Gizmos/Element.cs create mode 100644 CustomRichPresence/CustomRichPresence.csproj create mode 100644 CustomRichPresence/Main.cs rename {InteractionTest => CustomRichPresence}/Properties/AssemblyInfo.cs (65%) create mode 100644 CustomRichPresence/README.md create mode 100644 CustomRichPresence/format.json delete mode 100644 InteractionTest/Components/InteractionTracker.cs delete mode 100644 InteractionTest/ModSettings.cs delete mode 100644 InteractionTest/Patches.cs delete mode 100644 InteractionTest/README.md delete mode 100644 InteractionTest/format.json delete mode 100644 LegacyContentMitigation/ModSettings.cs delete mode 100644 LuaNetworkVariables/SyncedBehaviour/PickupableBehaviour.cs delete mode 100644 LuaNetworkVariables/SyncedBehaviour/PickupableObject.cs delete mode 100644 PhysicsGunMod/Components/ObjectSyncBridge.cs delete mode 100644 PhysicsGunMod/Components/PhysicsGunInteractionBehavior.cs delete mode 100644 PhysicsGunMod/HarmonyPatches.cs delete mode 100644 PhysicsGunMod/Main.cs delete mode 100644 PhysicsGunMod/ModSettings.cs delete mode 100644 PhysicsGunMod/PhysicsGunMod.csproj delete mode 100644 PhysicsGunMod/README.md delete mode 100644 PhysicsGunMod/format.json create mode 100644 PlayerColorsAPI/Main.cs rename {VisualCloneFix => PlayerColorsAPI}/Patches.cs (100%) create mode 100644 PlayerColorsAPI/PlayerColorsAPI.csproj create mode 100644 PlayerColorsAPI/Properties/AssemblyInfo.cs create mode 100644 PlayerColorsAPI/README.md create mode 100644 PlayerColorsAPI/format.json delete mode 100644 Portals/format.json diff --git a/.DepricatedMods/AASBufferFix/AASBufferFix.csproj b/.Deprecated/AASBufferFix/AASBufferFix.csproj similarity index 100% rename from .DepricatedMods/AASBufferFix/AASBufferFix.csproj rename to .Deprecated/AASBufferFix/AASBufferFix.csproj diff --git a/.DepricatedMods/AASBufferFix/AASBufferHelper.cs b/.Deprecated/AASBufferFix/AASBufferHelper.cs similarity index 100% rename from .DepricatedMods/AASBufferFix/AASBufferHelper.cs rename to .Deprecated/AASBufferFix/AASBufferHelper.cs diff --git a/.DepricatedMods/AASBufferFix/HarmonyPatches.cs b/.Deprecated/AASBufferFix/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/AASBufferFix/HarmonyPatches.cs rename to .Deprecated/AASBufferFix/HarmonyPatches.cs diff --git a/.DepricatedMods/AASBufferFix/Main.cs b/.Deprecated/AASBufferFix/Main.cs similarity index 100% rename from .DepricatedMods/AASBufferFix/Main.cs rename to .Deprecated/AASBufferFix/Main.cs diff --git a/.DepricatedMods/AASBufferFix/Properties/AssemblyInfo.cs b/.Deprecated/AASBufferFix/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/AASBufferFix/Properties/AssemblyInfo.cs rename to .Deprecated/AASBufferFix/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/AASBufferFix/README.md b/.Deprecated/AASBufferFix/README.md similarity index 100% rename from .DepricatedMods/AASBufferFix/README.md rename to .Deprecated/AASBufferFix/README.md diff --git a/.DepricatedMods/AASBufferFix/Utils.cs b/.Deprecated/AASBufferFix/Utils.cs similarity index 100% rename from .DepricatedMods/AASBufferFix/Utils.cs rename to .Deprecated/AASBufferFix/Utils.cs diff --git a/.DepricatedMods/AASBufferFix/format.json b/.Deprecated/AASBufferFix/format.json similarity index 100% rename from .DepricatedMods/AASBufferFix/format.json rename to .Deprecated/AASBufferFix/format.json diff --git a/AASDefaultProfileFix/AASDefaultProfileFix.csproj b/.Deprecated/AASDefaultProfileFix/AASDefaultProfileFix.csproj similarity index 100% rename from AASDefaultProfileFix/AASDefaultProfileFix.csproj rename to .Deprecated/AASDefaultProfileFix/AASDefaultProfileFix.csproj diff --git a/AASDefaultProfileFix/Main.cs b/.Deprecated/AASDefaultProfileFix/Main.cs similarity index 100% rename from AASDefaultProfileFix/Main.cs rename to .Deprecated/AASDefaultProfileFix/Main.cs diff --git a/AASDefaultProfileFix/Properties/AssemblyInfo.cs b/.Deprecated/AASDefaultProfileFix/Properties/AssemblyInfo.cs similarity index 100% rename from AASDefaultProfileFix/Properties/AssemblyInfo.cs rename to .Deprecated/AASDefaultProfileFix/Properties/AssemblyInfo.cs diff --git a/AASDefaultProfileFix/README.md b/.Deprecated/AASDefaultProfileFix/README.md similarity index 100% rename from AASDefaultProfileFix/README.md rename to .Deprecated/AASDefaultProfileFix/README.md diff --git a/AASDefaultProfileFix/format.json b/.Deprecated/AASDefaultProfileFix/format.json similarity index 100% rename from AASDefaultProfileFix/format.json rename to .Deprecated/AASDefaultProfileFix/format.json diff --git a/.DepricatedMods/AlternateIKSystem/AlternateIKSystem.csproj b/.Deprecated/AlternateIKSystem/AlternateIKSystem.csproj similarity index 100% rename from .DepricatedMods/AlternateIKSystem/AlternateIKSystem.csproj rename to .Deprecated/AlternateIKSystem/AlternateIKSystem.csproj diff --git a/.DepricatedMods/AlternateIKSystem/HarmonyPatches.cs b/.Deprecated/AlternateIKSystem/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/HarmonyPatches.cs rename to .Deprecated/AlternateIKSystem/HarmonyPatches.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/BodyControl.cs b/.Deprecated/AlternateIKSystem/IK/BodyControl.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/BodyControl.cs rename to .Deprecated/AlternateIKSystem/IK/BodyControl.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/IKCalibrator.cs b/.Deprecated/AlternateIKSystem/IK/IKCalibrator.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/IKCalibrator.cs rename to .Deprecated/AlternateIKSystem/IK/IKCalibrator.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/IKHandlers/IKHandler.cs b/.Deprecated/AlternateIKSystem/IK/IKHandlers/IKHandler.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/IKHandlers/IKHandler.cs rename to .Deprecated/AlternateIKSystem/IK/IKHandlers/IKHandler.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/IKHandlers/IKHandlerDesktop.cs b/.Deprecated/AlternateIKSystem/IK/IKHandlers/IKHandlerDesktop.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/IKHandlers/IKHandlerDesktop.cs rename to .Deprecated/AlternateIKSystem/IK/IKHandlers/IKHandlerDesktop.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/IKHandlers/IKHandlerHalfBody.cs b/.Deprecated/AlternateIKSystem/IK/IKHandlers/IKHandlerHalfBody.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/IKHandlers/IKHandlerHalfBody.cs rename to .Deprecated/AlternateIKSystem/IK/IKHandlers/IKHandlerHalfBody.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/IKManager.cs b/.Deprecated/AlternateIKSystem/IK/IKManager.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/IKManager.cs rename to .Deprecated/AlternateIKSystem/IK/IKManager.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/MusclePoses.cs b/.Deprecated/AlternateIKSystem/IK/MusclePoses.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/MusclePoses.cs rename to .Deprecated/AlternateIKSystem/IK/MusclePoses.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/Tracking/SteamVRTrackerManager.cs b/.Deprecated/AlternateIKSystem/IK/Tracking/SteamVRTrackerManager.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/Tracking/SteamVRTrackerManager.cs rename to .Deprecated/AlternateIKSystem/IK/Tracking/SteamVRTrackerManager.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/VRIKHelpers/VRIKLocomotionData.cs b/.Deprecated/AlternateIKSystem/IK/VRIKHelpers/VRIKLocomotionData.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/VRIKHelpers/VRIKLocomotionData.cs rename to .Deprecated/AlternateIKSystem/IK/VRIKHelpers/VRIKLocomotionData.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/VRIKHelpers/VRIKUtils.cs b/.Deprecated/AlternateIKSystem/IK/VRIKHelpers/VRIKUtils.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/VRIKHelpers/VRIKUtils.cs rename to .Deprecated/AlternateIKSystem/IK/VRIKHelpers/VRIKUtils.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/WeightManipulators/BodyParts/BodyPart.cs b/.Deprecated/AlternateIKSystem/IK/WeightManipulators/BodyParts/BodyPart.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/WeightManipulators/BodyParts/BodyPart.cs rename to .Deprecated/AlternateIKSystem/IK/WeightManipulators/BodyParts/BodyPart.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/WeightManipulators/DeviceControlManipulator.cs b/.Deprecated/AlternateIKSystem/IK/WeightManipulators/DeviceControlManipulator.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/WeightManipulators/DeviceControlManipulator.cs rename to .Deprecated/AlternateIKSystem/IK/WeightManipulators/DeviceControlManipulator.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/WeightManipulators/Interface/IWeightManipulator.cs b/.Deprecated/AlternateIKSystem/IK/WeightManipulators/Interface/IWeightManipulator.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/WeightManipulators/Interface/IWeightManipulator.cs rename to .Deprecated/AlternateIKSystem/IK/WeightManipulators/Interface/IWeightManipulator.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/WeightManipulators/TrackingControlManipulator.cs b/.Deprecated/AlternateIKSystem/IK/WeightManipulators/TrackingControlManipulator.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/WeightManipulators/TrackingControlManipulator.cs rename to .Deprecated/AlternateIKSystem/IK/WeightManipulators/TrackingControlManipulator.cs diff --git a/.DepricatedMods/AlternateIKSystem/IK/WeightManipulators/WeightManipulatorManager.cs b/.Deprecated/AlternateIKSystem/IK/WeightManipulators/WeightManipulatorManager.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/IK/WeightManipulators/WeightManipulatorManager.cs rename to .Deprecated/AlternateIKSystem/IK/WeightManipulators/WeightManipulatorManager.cs diff --git a/.DepricatedMods/AlternateIKSystem/Integrations/BTKUIAddon.cs b/.Deprecated/AlternateIKSystem/Integrations/BTKUIAddon.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/Integrations/BTKUIAddon.cs rename to .Deprecated/AlternateIKSystem/Integrations/BTKUIAddon.cs diff --git a/.DepricatedMods/AlternateIKSystem/LICENSE.txt b/.Deprecated/AlternateIKSystem/LICENSE.txt similarity index 100% rename from .DepricatedMods/AlternateIKSystem/LICENSE.txt rename to .Deprecated/AlternateIKSystem/LICENSE.txt diff --git a/.DepricatedMods/AlternateIKSystem/Main.cs b/.Deprecated/AlternateIKSystem/Main.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/Main.cs rename to .Deprecated/AlternateIKSystem/Main.cs diff --git a/.DepricatedMods/AlternateIKSystem/ModSettings.cs b/.Deprecated/AlternateIKSystem/ModSettings.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/ModSettings.cs rename to .Deprecated/AlternateIKSystem/ModSettings.cs diff --git a/.DepricatedMods/AlternateIKSystem/Properties/AssemblyInfo.cs b/.Deprecated/AlternateIKSystem/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/AlternateIKSystem/Properties/AssemblyInfo.cs rename to .Deprecated/AlternateIKSystem/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/AlternateIKSystem/README.md b/.Deprecated/AlternateIKSystem/README.md similarity index 100% rename from .DepricatedMods/AlternateIKSystem/README.md rename to .Deprecated/AlternateIKSystem/README.md diff --git a/.DepricatedMods/AlternateIKSystem/format.json b/.Deprecated/AlternateIKSystem/format.json similarity index 100% rename from .DepricatedMods/AlternateIKSystem/format.json rename to .Deprecated/AlternateIKSystem/format.json diff --git a/WhereAmIPointing/Main.cs b/.Deprecated/AutoSyncTransforms/Main.cs similarity index 100% rename from WhereAmIPointing/Main.cs rename to .Deprecated/AutoSyncTransforms/Main.cs diff --git a/WhereAmIPointing/Properties/AssemblyInfo.cs b/.Deprecated/AutoSyncTransforms/Properties/AssemblyInfo.cs similarity index 100% rename from WhereAmIPointing/Properties/AssemblyInfo.cs rename to .Deprecated/AutoSyncTransforms/Properties/AssemblyInfo.cs diff --git a/WhereAmIPointing/README.md b/.Deprecated/AutoSyncTransforms/README.md similarity index 100% rename from WhereAmIPointing/README.md rename to .Deprecated/AutoSyncTransforms/README.md diff --git a/WhereAmIPointing/WhereAmIPointing.csproj b/.Deprecated/AutoSyncTransforms/WhereAmIPointing.csproj similarity index 100% rename from WhereAmIPointing/WhereAmIPointing.csproj rename to .Deprecated/AutoSyncTransforms/WhereAmIPointing.csproj diff --git a/WhereAmIPointing/format.json b/.Deprecated/AutoSyncTransforms/format.json similarity index 100% rename from WhereAmIPointing/format.json rename to .Deprecated/AutoSyncTransforms/format.json diff --git a/AvatarScaleMod/AvatarScaleMod.csproj b/.Deprecated/AvatarScaleMod/AvatarScaleMod.csproj similarity index 100% rename from AvatarScaleMod/AvatarScaleMod.csproj rename to .Deprecated/AvatarScaleMod/AvatarScaleMod.csproj diff --git a/AvatarScaleMod/AvatarScaling/AvatarScaleManager.cs b/.Deprecated/AvatarScaleMod/AvatarScaling/AvatarScaleManager.cs similarity index 99% rename from AvatarScaleMod/AvatarScaling/AvatarScaleManager.cs rename to .Deprecated/AvatarScaleMod/AvatarScaling/AvatarScaleManager.cs index 38d6a9a..f3c1da4 100644 --- a/AvatarScaleMod/AvatarScaling/AvatarScaleManager.cs +++ b/.Deprecated/AvatarScaleMod/AvatarScaling/AvatarScaleManager.cs @@ -211,7 +211,7 @@ public class AvatarScaleManager : MonoBehaviour public float GetHeight() { if (_localAvatarScaler == null) - return PlayerAvatarPoint.defaultAvatarHeight; + return PlayerAvatarPoint.DefaultAvatarHeight; if (!_localAvatarScaler.IsForcingHeight()) return PlayerSetup.Instance.GetAvatarHeight(); @@ -222,7 +222,7 @@ public class AvatarScaleManager : MonoBehaviour public float GetAnimationClipHeight() { if (_localAvatarScaler == null) - return PlayerAvatarPoint.defaultAvatarHeight; + return PlayerAvatarPoint.DefaultAvatarHeight; if (!_localAvatarScaler.IsForcingHeight()) return PlayerSetup.Instance.GetAvatarHeight(); diff --git a/AvatarScaleMod/AvatarScaling/Components/BaseScaler.cs b/.Deprecated/AvatarScaleMod/AvatarScaling/Components/BaseScaler.cs similarity index 100% rename from AvatarScaleMod/AvatarScaling/Components/BaseScaler.cs rename to .Deprecated/AvatarScaleMod/AvatarScaling/Components/BaseScaler.cs diff --git a/AvatarScaleMod/AvatarScaling/Components/LocalScaler.cs b/.Deprecated/AvatarScaleMod/AvatarScaling/Components/LocalScaler.cs similarity index 94% rename from AvatarScaleMod/AvatarScaling/Components/LocalScaler.cs rename to .Deprecated/AvatarScaleMod/AvatarScaling/Components/LocalScaler.cs index e6d79f4..7a076d8 100644 --- a/AvatarScaleMod/AvatarScaling/Components/LocalScaler.cs +++ b/.Deprecated/AvatarScaleMod/AvatarScaling/Components/LocalScaler.cs @@ -1,4 +1,5 @@ -using ABI_RC.Core.Player; +using ABI_RC.Core; +using ABI_RC.Core.Player; using ABI_RC.Core.UI; using NAK.AvatarScaleMod.AvatarScaling; using UnityEngine; @@ -72,7 +73,7 @@ public class LocalScaler : BaseScaler } // animation scale changed, record it! - Vector3 scaleDifference = PlayerSetup.DivideVectors(localScale - _initialScale, _initialScale); + Vector3 scaleDifference = CVRTools.DivideVectors(localScale - _initialScale, _initialScale); _animatedScaleFactor = scaleDifference.y; _animatedHeight = (_initialHeight * _animatedScaleFactor) + _initialHeight; _animatedScale = localScale; diff --git a/AvatarScaleMod/AvatarScaling/Components/NetworkScaler.cs b/.Deprecated/AvatarScaleMod/AvatarScaling/Components/NetworkScaler.cs similarity index 100% rename from AvatarScaleMod/AvatarScaling/Components/NetworkScaler.cs rename to .Deprecated/AvatarScaleMod/AvatarScaling/Components/NetworkScaler.cs diff --git a/AvatarScaleMod/AvatarScaling/Events/AvatarScaleEvents.cs b/.Deprecated/AvatarScaleMod/AvatarScaling/Events/AvatarScaleEvents.cs similarity index 100% rename from AvatarScaleMod/AvatarScaling/Events/AvatarScaleEvents.cs rename to .Deprecated/AvatarScaleMod/AvatarScaling/Events/AvatarScaleEvents.cs diff --git a/AvatarScaleMod/AvatarScaling/ScaledComponents.cs b/.Deprecated/AvatarScaleMod/AvatarScaling/ScaledComponents.cs similarity index 100% rename from AvatarScaleMod/AvatarScaling/ScaledComponents.cs rename to .Deprecated/AvatarScaleMod/AvatarScaling/ScaledComponents.cs diff --git a/AvatarScaleMod/HarmonyPatches.cs b/.Deprecated/AvatarScaleMod/HarmonyPatches.cs similarity index 100% rename from AvatarScaleMod/HarmonyPatches.cs rename to .Deprecated/AvatarScaleMod/HarmonyPatches.cs diff --git a/AvatarScaleMod/Input/DebugKeybinds.cs b/.Deprecated/AvatarScaleMod/Input/DebugKeybinds.cs similarity index 100% rename from AvatarScaleMod/Input/DebugKeybinds.cs rename to .Deprecated/AvatarScaleMod/Input/DebugKeybinds.cs diff --git a/AvatarScaleMod/Input/ScaleReconizer.cs b/.Deprecated/AvatarScaleMod/Input/ScaleReconizer.cs similarity index 100% rename from AvatarScaleMod/Input/ScaleReconizer.cs rename to .Deprecated/AvatarScaleMod/Input/ScaleReconizer.cs diff --git a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon.cs b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon.cs similarity index 71% rename from AvatarScaleMod/Integrations/BTKUI/BtkUiAddon.cs rename to .Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon.cs index 09a5ff4..acf9fab 100644 --- a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon.cs +++ b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon.cs @@ -3,32 +3,32 @@ using BTKUILib; using BTKUILib.UIObjects; using NAK.AvatarScaleMod.AvatarScaling; -namespace NAK.AvatarScaleMod.Integrations -{ - public static partial class BtkUiAddon - { - private static Page _asmRootPage; - private static string _rootPageElementID; +namespace NAK.AvatarScaleMod.Integrations; - public static void Initialize() - { +public static partial class BtkUiAddon +{ + private static Page _asmRootPage; + private static string _rootPageElementID; + + public static void Initialize() + { Prepare_Icons(); Setup_AvatarScaleModTab(); Setup_PlayerSelectPage(); } - #region Initialization + #region Initialization - private static void Prepare_Icons() - { + private static void Prepare_Icons() + { QuickMenuAPI.PrepareIcon(ModSettings.ModName, "ASM_Icon_AvatarHeightConfig", GetIconStream("ASM_Icon_AvatarHeightConfig.png")); QuickMenuAPI.PrepareIcon(ModSettings.ModName, "ASM_Icon_AvatarHeightCopy", GetIconStream("ASM_Icon_AvatarHeightCopy.png")); } - private static void Setup_AvatarScaleModTab() - { + private static void Setup_AvatarScaleModTab() + { _asmRootPage = new Page(ModSettings.ModName, ModSettings.ASM_SettingsCategory, true, "ASM_Icon_AvatarHeightConfig") { MenuTitle = ModSettings.ASM_SettingsCategory, @@ -54,18 +54,18 @@ namespace NAK.AvatarScaleMod.Integrations Setup_DebugOptionsCategory(_asmRootPage); } - #endregion + #endregion - #region Player Count Display + #region Player Count Display - private static void OnWorldLeave() - => UpdatePlayerCountDisplay(); + private static void OnWorldLeave() + => UpdatePlayerCountDisplay(); - private static void OnUserJoinLeave(CVRPlayerEntity _) - => UpdatePlayerCountDisplay(); + private static void OnUserJoinLeave(CVRPlayerEntity _) + => UpdatePlayerCountDisplay(); - private static void UpdatePlayerCountDisplay() - { + private static void UpdatePlayerCountDisplay() + { if (_asmRootPage == null) return; @@ -74,14 +74,14 @@ namespace NAK.AvatarScaleMod.Integrations _asmRootPage.MenuSubtitle = $"Everything Avatar Scaling! :: ({modUserCount}/{playerCount} players using ASM)"; } - #endregion + #endregion - #region Double-Click Reset Height + #region Double-Click Reset Height - private static DateTime lastTime = DateTime.Now; + private static DateTime lastTime = DateTime.Now; - private static void OnTabChange(string newTab, string previousTab) - { + private static void OnTabChange(string newTab, string previousTab) + { if (newTab == _rootPageElementID) { UpdatePlayerCountDisplay(); @@ -95,6 +95,5 @@ namespace NAK.AvatarScaleMod.Integrations lastTime = DateTime.Now; } - #endregion - } + #endregion } \ No newline at end of file diff --git a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleMod.cs b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleMod.cs similarity index 76% rename from AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleMod.cs rename to .Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleMod.cs index 875668c..9ddc1c2 100644 --- a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleMod.cs +++ b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleMod.cs @@ -1,11 +1,11 @@ using BTKUILib.UIObjects; -namespace NAK.AvatarScaleMod.Integrations +namespace NAK.AvatarScaleMod.Integrations; + +public static partial class BtkUiAddon { - public static partial class BtkUiAddon + private static void Setup_AvatarScaleModCategory(Page page) { - private static void Setup_AvatarScaleModCategory(Page page) - { Category avScaleModCategory = AddMelonCategory(ref page, ModSettings.Hidden_Foldout_ASM_SettingsCategory); AddMelonToggle(ref avScaleModCategory, ModSettings.EntryScaleGestureEnabled); @@ -13,5 +13,4 @@ namespace NAK.AvatarScaleMod.Integrations AddMelonToggle(ref avScaleModCategory, ModSettings.EntryPersistentHeight); AddMelonToggle(ref avScaleModCategory, ModSettings.EntryPersistThroughRestart); } - } } \ No newline at end of file diff --git a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleTool.cs b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleTool.cs similarity index 83% rename from AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleTool.cs rename to .Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleTool.cs index 2eb6c57..d3820df 100644 --- a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleTool.cs +++ b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_AvatarScaleTool.cs @@ -1,12 +1,12 @@ using BTKUILib.UIObjects; using BTKUILib.UIObjects.Components; -namespace NAK.AvatarScaleMod.Integrations +namespace NAK.AvatarScaleMod.Integrations; + +public static partial class BtkUiAddon { - public static partial class BtkUiAddon + private static void Setup_AvatarScaleToolCategory(Page page) { - private static void Setup_AvatarScaleToolCategory(Page page) - { Category avScaleToolCategory = AddMelonCategory(ref page, ModSettings.Hidden_Foldout_AST_SettingsCategory); AddMelonStringInput(ref avScaleToolCategory, ModSettings.EntryASTScaleParameter, "icon"); @@ -19,5 +19,4 @@ namespace NAK.AvatarScaleMod.Integrations ModSettings.EntryASTMaxHeight.ResetToDefault(); }; } - } } \ No newline at end of file diff --git a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_DebugOptions.cs b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_DebugOptions.cs similarity index 71% rename from AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_DebugOptions.cs rename to .Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_DebugOptions.cs index b05dd94..088aafd 100644 --- a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_DebugOptions.cs +++ b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_DebugOptions.cs @@ -1,16 +1,15 @@ using BTKUILib.UIObjects; -namespace NAK.AvatarScaleMod.Integrations +namespace NAK.AvatarScaleMod.Integrations; + +public static partial class BtkUiAddon { - public static partial class BtkUiAddon + private static void Setup_DebugOptionsCategory(Page page) { - private static void Setup_DebugOptionsCategory(Page page) - { Category debugCategory = AddMelonCategory(ref page, ModSettings.Hidden_Foldout_DEBUG_SettingsCategory); AddMelonToggle(ref debugCategory, ModSettings.Debug_NetworkInbound); AddMelonToggle(ref debugCategory, ModSettings.Debug_NetworkOutbound); AddMelonToggle(ref debugCategory, ModSettings.Debug_ComponentSearchTime); } - } } \ No newline at end of file diff --git a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_UniversalScalingSettings.cs b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_UniversalScalingSettings.cs similarity index 83% rename from AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_UniversalScalingSettings.cs rename to .Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_UniversalScalingSettings.cs index 216fa48..1437582 100644 --- a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_UniversalScalingSettings.cs +++ b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_CAT_UniversalScalingSettings.cs @@ -4,14 +4,14 @@ using BTKUILib.UIObjects.Components; using NAK.AvatarScaleMod.AvatarScaling; using System.Collections.Generic; // Added for list support -namespace NAK.AvatarScaleMod.Integrations -{ - public static partial class BtkUiAddon - { - private static readonly List USM_QmUiElements = new(); +namespace NAK.AvatarScaleMod.Integrations; - private static void Setup_UniversalScalingSettings(Page page) - { +public static partial class BtkUiAddon +{ + private static readonly List USM_QmUiElements = new(); + + private static void Setup_UniversalScalingSettings(Page page) + { Category uniScalingCategory = AddMelonCategory(ref page, ModSettings.Hidden_Foldout_USM_SettingsCategory); SliderFloat scaleSlider = AddMelonSlider(ref uniScalingCategory, ModSettings.EntryHiddenAvatarHeight, AvatarScaleManager.DefaultMinHeight, AvatarScaleManager.DefaultMaxHeight); @@ -52,24 +52,23 @@ namespace NAK.AvatarScaleMod.Integrations ModSettings.EntryUseUniversalScaling.OnEntryValueChanged.Subscribe((_, newValue) => OnUniversalScalingChanged(newValue)); } - private static void OnUniversalScalingChanged(bool value) - { + private static void OnUniversalScalingChanged(bool value) + { foreach (QMUIElement uiElement in USM_QmUiElements) uiElement.Disabled = !value; } - #region Slider Events + #region Slider Events - private static void OnAvatarHeightSliderChanged(float height) - { + private static void OnAvatarHeightSliderChanged(float height) + { AvatarScaleManager.Instance.SetTargetHeight(height); } - private static void OnAvatarHeightSliderReset() - { + private static void OnAvatarHeightSliderReset() + { AvatarScaleManager.Instance.Setting_UniversalScaling = false; } - #endregion - } + #endregion } \ No newline at end of file diff --git a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_PSP_AvatarScaleMod.cs b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_PSP_AvatarScaleMod.cs similarity index 76% rename from AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_PSP_AvatarScaleMod.cs rename to .Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_PSP_AvatarScaleMod.cs index c83796d..ab54a69 100644 --- a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_PSP_AvatarScaleMod.cs +++ b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_PSP_AvatarScaleMod.cs @@ -3,15 +3,15 @@ using BTKUILib.UIObjects; using BTKUILib.UIObjects.Components; using NAK.AvatarScaleMod.AvatarScaling; -namespace NAK.AvatarScaleMod.Integrations +namespace NAK.AvatarScaleMod.Integrations; + +public static partial class BtkUiAddon { - public static partial class BtkUiAddon - { - private static Button _playerHasModElement; - private static string _selectedPlayer; + private static Button _playerHasModElement; + private static string _selectedPlayer; - private static void Setup_PlayerSelectPage() - { + private static void Setup_PlayerSelectPage() + { QuickMenuAPI.OnPlayerSelected += OnPlayerSelected; Category category = QuickMenuAPI.PlayerSelectPage.AddCategory(ModSettings.ASM_SettingsCategory, ModSettings.ModName); @@ -22,27 +22,27 @@ namespace NAK.AvatarScaleMod.Integrations button.OnPress += OnCopyPlayerHeight; } - #region QM Events + #region QM Events - private static void OnPlayerSelected(string _, string id) - { + private static void OnPlayerSelected(string _, string id) + { _selectedPlayer = id; UpdatePlayerHasModIcon(); } - private static void OnCopyPlayerHeight() - { + private static void OnCopyPlayerHeight() + { float networkHeight = AvatarScaleManager.Instance.GetNetworkHeight(_selectedPlayer); if (networkHeight < 0) return; AvatarScaleManager.Instance.SetTargetHeight(networkHeight); } - #endregion + #endregion - #region Private Methods + #region Private Methods - private static void UpdatePlayerHasModIcon() - { + private static void UpdatePlayerHasModIcon() + { if (_playerHasModElement == null) return; @@ -60,6 +60,5 @@ namespace NAK.AvatarScaleMod.Integrations } } - #endregion - } + #endregion } \ No newline at end of file diff --git a/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_Utils.cs b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_Utils.cs new file mode 100644 index 0000000..9c9eb20 --- /dev/null +++ b/.Deprecated/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_Utils.cs @@ -0,0 +1,77 @@ +using System.Reflection; +using BTKUILib; +using BTKUILib.UIObjects; +using BTKUILib.UIObjects.Components; +using MelonLoader; +using UnityEngine; + +namespace NAK.AvatarScaleMod.Integrations; + +public static partial class BtkUiAddon +{ + #region Melon Preference Helpers + + private static ToggleButton AddMelonToggle(ref Category category, MelonPreferences_Entry entry) + { + ToggleButton toggle = category.AddToggle(entry.DisplayName, entry.Description, entry.Value); + toggle.OnValueUpdated += b => entry.Value = b; + return toggle; + } + + private static SliderFloat AddMelonSlider(ref Category category, MelonPreferences_Entry entry, float min, + float max, int decimalPlaces = 2, bool allowReset = true) + { + SliderFloat slider = category.AddSlider(entry.DisplayName, entry.Description, + Mathf.Clamp(entry.Value, min, max), min, max, decimalPlaces, entry.DefaultValue, allowReset); + slider.OnValueUpdated += f => entry.Value = f; + return slider; + } + + private static Button AddMelonStringInput(ref Category category, MelonPreferences_Entry entry, string buttonIcon = "", ButtonStyle buttonStyle = ButtonStyle.TextOnly) + { + Button button = category.AddButton(entry.DisplayName, buttonIcon, entry.Description, buttonStyle); + button.OnPress += () => QuickMenuAPI.OpenKeyboard(entry.Value, s => entry.Value = s); + return button; + } + + private static Button AddMelonNumberInput(ref Category category, MelonPreferences_Entry entry, string buttonIcon = "", ButtonStyle buttonStyle = ButtonStyle.TextOnly) + { + Button button = category.AddButton(entry.DisplayName, buttonIcon, entry.Description, buttonStyle); + button.OnPress += () => QuickMenuAPI.OpenNumberInput(entry.DisplayName, entry.Value, f => entry.Value = f); + return button; + } + + // private static SliderFloat AddMelonSlider(ref Page page, MelonPreferences_Entry entry, float min, float max, int decimalPlaces = 2, bool allowReset = true) + // { + // SliderFloat slider = page.AddSlider(entry.DisplayName, entry.Description, Mathf.Clamp(entry.Value, min, max), min, max, decimalPlaces, entry.DefaultValue, allowReset); + // slider.OnValueUpdated += f => entry.Value = f; + // return slider; + // } + + /// + /// Helper method to create a category that saves its collapsed state to a MelonPreferences entry. + /// + /// + /// + /// + /// + private static Category AddMelonCategory(ref Page page, MelonPreferences_Entry entry, bool showHeader = true) + { + Category category = page.AddCategory(entry.DisplayName, showHeader, true, entry.Value); + category.OnCollapse += b => entry.Value = b; + return category; + } + + #endregion + + #region Icon Utils + + private static Stream GetIconStream(string iconName) + { + Assembly assembly = Assembly.GetExecutingAssembly(); + string assemblyName = assembly.GetName().Name; + return assembly.GetManifestResourceStream($"{assemblyName}.resources.{iconName}"); + } + + #endregion +} \ No newline at end of file diff --git a/AvatarScaleMod/Main.cs b/.Deprecated/AvatarScaleMod/Main.cs similarity index 100% rename from AvatarScaleMod/Main.cs rename to .Deprecated/AvatarScaleMod/Main.cs diff --git a/AvatarScaleMod/ModSettings.cs b/.Deprecated/AvatarScaleMod/ModSettings.cs similarity index 100% rename from AvatarScaleMod/ModSettings.cs rename to .Deprecated/AvatarScaleMod/ModSettings.cs diff --git a/AvatarScaleMod/Networking/ModNetwork.cs b/.Deprecated/AvatarScaleMod/Networking/ModNetwork.cs similarity index 100% rename from AvatarScaleMod/Networking/ModNetwork.cs rename to .Deprecated/AvatarScaleMod/Networking/ModNetwork.cs diff --git a/AvatarScaleMod/Properties/AssemblyInfo.cs b/.Deprecated/AvatarScaleMod/Properties/AssemblyInfo.cs similarity index 100% rename from AvatarScaleMod/Properties/AssemblyInfo.cs rename to .Deprecated/AvatarScaleMod/Properties/AssemblyInfo.cs diff --git a/AvatarScaleMod/README.md b/.Deprecated/AvatarScaleMod/README.md similarity index 100% rename from AvatarScaleMod/README.md rename to .Deprecated/AvatarScaleMod/README.md diff --git a/AvatarScaleMod/Scripts.cs b/.Deprecated/AvatarScaleMod/Scripts.cs similarity index 83% rename from AvatarScaleMod/Scripts.cs rename to .Deprecated/AvatarScaleMod/Scripts.cs index 5980b65..16d7319 100644 --- a/AvatarScaleMod/Scripts.cs +++ b/.Deprecated/AvatarScaleMod/Scripts.cs @@ -3,12 +3,12 @@ using System.IO; using System.Reflection; // https://github.com/SDraw/ml_mods_cvr/blob/master/ml_amt/Scripts.cs -namespace NAK.AvatarScaleMod +namespace NAK.AvatarScaleMod; + +static class Scripts { - static class Scripts + public static string GetEmbeddedScript(string p_name) { - public static string GetEmbeddedScript(string p_name) - { string l_result = ""; Assembly l_assembly = Assembly.GetExecutingAssembly(); string l_assemblyName = l_assembly.GetName().Name; @@ -23,5 +23,4 @@ namespace NAK.AvatarScaleMod return l_result; } - } } \ No newline at end of file diff --git a/.DepricatedMods/InteractionTest/format.json b/.Deprecated/AvatarScaleMod/format.json similarity index 100% rename from .DepricatedMods/InteractionTest/format.json rename to .Deprecated/AvatarScaleMod/format.json diff --git a/AvatarScaleMod/resources/ASM_Icon_AvatarHeightConfig.png b/.Deprecated/AvatarScaleMod/resources/ASM_Icon_AvatarHeightConfig.png similarity index 100% rename from AvatarScaleMod/resources/ASM_Icon_AvatarHeightConfig.png rename to .Deprecated/AvatarScaleMod/resources/ASM_Icon_AvatarHeightConfig.png diff --git a/AvatarScaleMod/resources/ASM_Icon_AvatarHeightCopy.png b/.Deprecated/AvatarScaleMod/resources/ASM_Icon_AvatarHeightCopy.png similarity index 100% rename from AvatarScaleMod/resources/ASM_Icon_AvatarHeightCopy.png rename to .Deprecated/AvatarScaleMod/resources/ASM_Icon_AvatarHeightCopy.png diff --git a/AvatarScaleMod/resources/menu.js b/.Deprecated/AvatarScaleMod/resources/menu.js similarity index 100% rename from AvatarScaleMod/resources/menu.js rename to .Deprecated/AvatarScaleMod/resources/menu.js diff --git a/.DepricatedMods/BadAnimatorFix/BadAnimatorFix.csproj b/.Deprecated/BadAnimatorFix/BadAnimatorFix.csproj similarity index 100% rename from .DepricatedMods/BadAnimatorFix/BadAnimatorFix.csproj rename to .Deprecated/BadAnimatorFix/BadAnimatorFix.csproj diff --git a/.DepricatedMods/BadAnimatorFix/BadAnimatorFixManager.cs b/.Deprecated/BadAnimatorFix/BadAnimatorFixManager.cs similarity index 100% rename from .DepricatedMods/BadAnimatorFix/BadAnimatorFixManager.cs rename to .Deprecated/BadAnimatorFix/BadAnimatorFixManager.cs diff --git a/.DepricatedMods/BadAnimatorFix/BadAnimatorFixer.cs b/.Deprecated/BadAnimatorFix/BadAnimatorFixer.cs similarity index 100% rename from .DepricatedMods/BadAnimatorFix/BadAnimatorFixer.cs rename to .Deprecated/BadAnimatorFix/BadAnimatorFixer.cs diff --git a/.DepricatedMods/BadAnimatorFix/HarmonyPatches.cs b/.Deprecated/BadAnimatorFix/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/BadAnimatorFix/HarmonyPatches.cs rename to .Deprecated/BadAnimatorFix/HarmonyPatches.cs diff --git a/.DepricatedMods/BadAnimatorFix/Main.cs b/.Deprecated/BadAnimatorFix/Main.cs similarity index 100% rename from .DepricatedMods/BadAnimatorFix/Main.cs rename to .Deprecated/BadAnimatorFix/Main.cs diff --git a/.DepricatedMods/BadAnimatorFix/Properties/AssemblyInfo.cs b/.Deprecated/BadAnimatorFix/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/BadAnimatorFix/Properties/AssemblyInfo.cs rename to .Deprecated/BadAnimatorFix/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/BadAnimatorFix/format.json b/.Deprecated/BadAnimatorFix/format.json similarity index 100% rename from .DepricatedMods/BadAnimatorFix/format.json rename to .Deprecated/BadAnimatorFix/format.json diff --git a/.DepricatedMods/Blackout/AssetHandler.cs b/.Deprecated/Blackout/AssetHandler.cs similarity index 100% rename from .DepricatedMods/Blackout/AssetHandler.cs rename to .Deprecated/Blackout/AssetHandler.cs diff --git a/.DepricatedMods/Blackout/Blackout.csproj b/.Deprecated/Blackout/Blackout.csproj similarity index 100% rename from .DepricatedMods/Blackout/Blackout.csproj rename to .Deprecated/Blackout/Blackout.csproj diff --git a/.DepricatedMods/Blackout/BlackoutController.cs b/.Deprecated/Blackout/BlackoutController.cs similarity index 100% rename from .DepricatedMods/Blackout/BlackoutController.cs rename to .Deprecated/Blackout/BlackoutController.cs diff --git a/.DepricatedMods/Blackout/HarmonyPatches.cs b/.Deprecated/Blackout/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/Blackout/HarmonyPatches.cs rename to .Deprecated/Blackout/HarmonyPatches.cs diff --git a/.DepricatedMods/Blackout/Integrations/BTKUIAddon.cs b/.Deprecated/Blackout/Integrations/BTKUIAddon.cs similarity index 100% rename from .DepricatedMods/Blackout/Integrations/BTKUIAddon.cs rename to .Deprecated/Blackout/Integrations/BTKUIAddon.cs diff --git a/.DepricatedMods/Blackout/Integrations/UIExpansionKitAddon.cs b/.Deprecated/Blackout/Integrations/UIExpansionKitAddon.cs similarity index 100% rename from .DepricatedMods/Blackout/Integrations/UIExpansionKitAddon.cs rename to .Deprecated/Blackout/Integrations/UIExpansionKitAddon.cs diff --git a/.DepricatedMods/Blackout/Main.cs b/.Deprecated/Blackout/Main.cs similarity index 100% rename from .DepricatedMods/Blackout/Main.cs rename to .Deprecated/Blackout/Main.cs diff --git a/.DepricatedMods/Blackout/Properties/AssemblyInfo.cs b/.Deprecated/Blackout/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/Blackout/Properties/AssemblyInfo.cs rename to .Deprecated/Blackout/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/Blackout/Resource1.Designer.cs b/.Deprecated/Blackout/Resource1.Designer.cs similarity index 100% rename from .DepricatedMods/Blackout/Resource1.Designer.cs rename to .Deprecated/Blackout/Resource1.Designer.cs diff --git a/.DepricatedMods/Blackout/Resource1.resx b/.Deprecated/Blackout/Resource1.resx similarity index 100% rename from .DepricatedMods/Blackout/Resource1.resx rename to .Deprecated/Blackout/Resource1.resx diff --git a/.DepricatedMods/Blackout/format.json b/.Deprecated/Blackout/format.json similarity index 100% rename from .DepricatedMods/Blackout/format.json rename to .Deprecated/Blackout/format.json diff --git a/.DepricatedMods/Blackout/resources/blackout_controller.asset b/.Deprecated/Blackout/resources/blackout_controller.asset similarity index 100% rename from .DepricatedMods/Blackout/resources/blackout_controller.asset rename to .Deprecated/Blackout/resources/blackout_controller.asset diff --git a/BullshitWatcher/BullshitWatcher.csproj b/.Deprecated/BullshitWatcher/BullshitWatcher.csproj similarity index 100% rename from BullshitWatcher/BullshitWatcher.csproj rename to .Deprecated/BullshitWatcher/BullshitWatcher.csproj diff --git a/BullshitWatcher/Main.cs b/.Deprecated/BullshitWatcher/Main.cs similarity index 100% rename from BullshitWatcher/Main.cs rename to .Deprecated/BullshitWatcher/Main.cs diff --git a/BullshitWatcher/Properties/AssemblyInfo.cs b/.Deprecated/BullshitWatcher/Properties/AssemblyInfo.cs similarity index 100% rename from BullshitWatcher/Properties/AssemblyInfo.cs rename to .Deprecated/BullshitWatcher/Properties/AssemblyInfo.cs diff --git a/CVRGizmos/CVRGizmoManager.cs b/.Deprecated/CVRGizmos/CVRGizmoManager.cs similarity index 76% rename from CVRGizmos/CVRGizmoManager.cs rename to .Deprecated/CVRGizmos/CVRGizmoManager.cs index fd03eb0..b1d55b5 100644 --- a/CVRGizmos/CVRGizmoManager.cs +++ b/.Deprecated/CVRGizmos/CVRGizmoManager.cs @@ -2,18 +2,18 @@ using UnityEngine; using Gizmos = Popcron.Gizmos; -namespace NAK.CVRGizmos +namespace NAK.CVRGizmos; + +public class CVRGizmoManager : MonoBehaviour { - public class CVRGizmoManager : MonoBehaviour - { - public static CVRGizmoManager Instance; + public static CVRGizmoManager Instance; - public bool g_enabled = false; - public bool g_localOnly = false; + public bool g_enabled = false; + public bool g_localOnly = false; - public MonoBehaviour[] managed; + public MonoBehaviour[] managed; - public System.Type[] GizmoTypes = { + public System.Type[] GizmoTypes = { typeof(CVRGizmos_Pointer), typeof(CVRGizmos_AdvancedAvatarSettingsTrigger), typeof(CVRGizmos_SpawnableTrigger), @@ -30,8 +30,8 @@ namespace NAK.CVRGizmos typeof(CVRGizmos_CapsuleCollider), }; - private void Start() - { + private void Start() + { CVRGizmoManager.Instance = this; managed = new MonoBehaviour[GizmoTypes.Count()]; for (int i = 0; i < GizmoTypes.Count(); i++) @@ -40,8 +40,8 @@ namespace NAK.CVRGizmos } } - public void EnableGizmos(bool able) - { + public void EnableGizmos(bool able) + { for (int i = 0; i < GizmoTypes.Count(); i++) { managed[i].enabled = able; @@ -50,12 +50,11 @@ namespace NAK.CVRGizmos RefreshGizmos(); } - public void RefreshGizmos() - { + public void RefreshGizmos() + { for (int i = 0; i < GizmoTypes.Count(); i++) { managed[i].Invoke("CacheGizmos", 0f); } } - } } \ No newline at end of file diff --git a/CVRGizmos/CVRGizmos.csproj b/.Deprecated/CVRGizmos/CVRGizmos.csproj similarity index 100% rename from CVRGizmos/CVRGizmos.csproj rename to .Deprecated/CVRGizmos/CVRGizmos.csproj diff --git a/CVRGizmos/GizmoTypes/CVRAdvancedAvatarSettingsPointer.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRAdvancedAvatarSettingsPointer.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRAdvancedAvatarSettingsPointer.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRAdvancedAvatarSettingsPointer.cs diff --git a/CVRGizmos/GizmoTypes/CVRAdvancedAvatarSettingsTrigger.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRAdvancedAvatarSettingsTrigger.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRAdvancedAvatarSettingsTrigger.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRAdvancedAvatarSettingsTrigger.cs diff --git a/CVRGizmos/GizmoTypes/CVRAvatar.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRAvatar.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRAvatar.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRAvatar.cs diff --git a/CVRGizmos/GizmoTypes/CVRAvatarPickupMarker.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRAvatarPickupMarker.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRAvatarPickupMarker.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRAvatarPickupMarker.cs diff --git a/CVRGizmos/GizmoTypes/CVRDistanceConstrain.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRDistanceConstrain.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRDistanceConstrain.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRDistanceConstrain.cs diff --git a/CVRGizmos/GizmoTypes/CVRDistanceLod.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRDistanceLod.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRDistanceLod.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRDistanceLod.cs diff --git a/CVRGizmos/GizmoTypes/CVRGizmoBase.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRGizmoBase.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRGizmoBase.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRGizmoBase.cs diff --git a/CVRGizmos/GizmoTypes/CVRHapticAreaChest.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRHapticAreaChest.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRHapticAreaChest.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRHapticAreaChest.cs diff --git a/CVRGizmos/GizmoTypes/CVRHapticZone.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRHapticZone.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRHapticZone.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRHapticZone.cs diff --git a/CVRGizmos/GizmoTypes/CVRPointer.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRPointer.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRPointer.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRPointer.cs diff --git a/CVRGizmos/GizmoTypes/CVRSpawnableTrigger.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRSpawnableTrigger.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRSpawnableTrigger.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRSpawnableTrigger.cs diff --git a/CVRGizmos/GizmoTypes/CVRToggleStateTrigger.cs b/.Deprecated/CVRGizmos/GizmoTypes/CVRToggleStateTrigger.cs similarity index 100% rename from CVRGizmos/GizmoTypes/CVRToggleStateTrigger.cs rename to .Deprecated/CVRGizmos/GizmoTypes/CVRToggleStateTrigger.cs diff --git a/CVRGizmos/GizmoTypes/Unity_BoxCollider.cs b/.Deprecated/CVRGizmos/GizmoTypes/Unity_BoxCollider.cs similarity index 100% rename from CVRGizmos/GizmoTypes/Unity_BoxCollider.cs rename to .Deprecated/CVRGizmos/GizmoTypes/Unity_BoxCollider.cs diff --git a/CVRGizmos/GizmoTypes/Unity_CapsuleCollider.cs b/.Deprecated/CVRGizmos/GizmoTypes/Unity_CapsuleCollider.cs similarity index 100% rename from CVRGizmos/GizmoTypes/Unity_CapsuleCollider.cs rename to .Deprecated/CVRGizmos/GizmoTypes/Unity_CapsuleCollider.cs diff --git a/CVRGizmos/GizmoTypes/Unity_SphereCollider.cs b/.Deprecated/CVRGizmos/GizmoTypes/Unity_SphereCollider.cs similarity index 100% rename from CVRGizmos/GizmoTypes/Unity_SphereCollider.cs rename to .Deprecated/CVRGizmos/GizmoTypes/Unity_SphereCollider.cs diff --git a/CVRGizmos/Main.cs b/.Deprecated/CVRGizmos/Main.cs similarity index 100% rename from CVRGizmos/Main.cs rename to .Deprecated/CVRGizmos/Main.cs diff --git a/.Deprecated/CVRGizmos/Popcron.Gizmos/Constants.cs b/.Deprecated/CVRGizmos/Popcron.Gizmos/Constants.cs new file mode 100644 index 0000000..56f8ef4 --- /dev/null +++ b/.Deprecated/CVRGizmos/Popcron.Gizmos/Constants.cs @@ -0,0 +1,7 @@ +namespace Popcron; + +public class Constants +{ + public const string UniqueIdentifier = "Popcron.Gizmos"; + public const string EnabledKey = UniqueIdentifier + ".Enabled"; +} \ No newline at end of file diff --git a/CVRGizmos/Popcron.Gizmos/Drawer.cs b/.Deprecated/CVRGizmos/Popcron.Gizmos/Drawer.cs similarity index 86% rename from CVRGizmos/Popcron.Gizmos/Drawer.cs rename to .Deprecated/CVRGizmos/Popcron.Gizmos/Drawer.cs index 8e42ae8..729445f 100644 --- a/CVRGizmos/Popcron.Gizmos/Drawer.cs +++ b/.Deprecated/CVRGizmos/Popcron.Gizmos/Drawer.cs @@ -1,21 +1,21 @@ using System.Reflection; using UnityEngine; -namespace Popcron +namespace Popcron; + +public abstract class Drawer { - public abstract class Drawer + private static Dictionary typeToDrawer = null; + + public abstract int Draw(ref Vector3[] buffer, params object[] args); + + public Drawer() { - private static Dictionary typeToDrawer = null; - - public abstract int Draw(ref Vector3[] buffer, params object[] args); - - public Drawer() - { } - public static Drawer Get() where T : class - { + public static Drawer Get() where T : class + { //find all drawers if (typeToDrawer == null) { @@ -64,5 +64,4 @@ namespace Popcron return null; } } - } -} +} \ No newline at end of file diff --git a/CVRGizmos/Popcron.Gizmos/Drawers/CubeDrawer.cs b/.Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/CubeDrawer.cs similarity index 93% rename from CVRGizmos/Popcron.Gizmos/Drawers/CubeDrawer.cs rename to .Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/CubeDrawer.cs index 478a0b6..78ab2bf 100644 --- a/CVRGizmos/Popcron.Gizmos/Drawers/CubeDrawer.cs +++ b/.Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/CubeDrawer.cs @@ -1,16 +1,16 @@ using UnityEngine; -namespace Popcron +namespace Popcron; + +public class CubeDrawer : Drawer { - public class CubeDrawer : Drawer + public CubeDrawer() { - public CubeDrawer() - { } - public override int Draw(ref Vector3[] buffer, params object[] values) - { + public override int Draw(ref Vector3[] buffer, params object[] values) + { Vector3 position = (Vector3)values[0]; Quaternion rotation = (Quaternion)values[1]; Vector3 size = (Vector3)values[2]; @@ -92,5 +92,4 @@ namespace Popcron return 24; } - } -} +} \ No newline at end of file diff --git a/.Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/LineDrawer.cs b/.Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/LineDrawer.cs new file mode 100644 index 0000000..0f17498 --- /dev/null +++ b/.Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/LineDrawer.cs @@ -0,0 +1,18 @@ +using UnityEngine; + +namespace Popcron; + +public class LineDrawer : Drawer +{ + public LineDrawer() + { + + } + + public override int Draw(ref Vector3[] buffer, params object[] args) + { + buffer[0] = (Vector3)args[0]; + buffer[1] = (Vector3)args[1]; + return 2; + } +} \ No newline at end of file diff --git a/CVRGizmos/Popcron.Gizmos/Drawers/PolygonDrawer.cs b/.Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/PolygonDrawer.cs similarity index 84% rename from CVRGizmos/Popcron.Gizmos/Drawers/PolygonDrawer.cs rename to .Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/PolygonDrawer.cs index ad3b1b2..ab66d29 100644 --- a/CVRGizmos/Popcron.Gizmos/Drawers/PolygonDrawer.cs +++ b/.Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/PolygonDrawer.cs @@ -1,16 +1,16 @@ using UnityEngine; -namespace Popcron +namespace Popcron; + +public class PolygonDrawer : Drawer { - public class PolygonDrawer : Drawer + public PolygonDrawer() { - public PolygonDrawer() - { } - public override int Draw(ref Vector3[] buffer, params object[] values) - { + public override int Draw(ref Vector3[] buffer, params object[] values) + { Vector3 position = (Vector3)values[0]; int points = (int)values[1]; float radius = (float)values[2]; @@ -36,5 +36,4 @@ namespace Popcron return points * 2; } - } -} +} \ No newline at end of file diff --git a/CVRGizmos/Popcron.Gizmos/Drawers/SquareDrawer.cs b/.Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/SquareDrawer.cs similarity index 89% rename from CVRGizmos/Popcron.Gizmos/Drawers/SquareDrawer.cs rename to .Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/SquareDrawer.cs index c46160a..7b0643d 100644 --- a/CVRGizmos/Popcron.Gizmos/Drawers/SquareDrawer.cs +++ b/.Deprecated/CVRGizmos/Popcron.Gizmos/Drawers/SquareDrawer.cs @@ -1,16 +1,16 @@ using UnityEngine; -namespace Popcron +namespace Popcron; + +public class SquareDrawer : Drawer { - public class SquareDrawer : Drawer + public SquareDrawer() { - public SquareDrawer() - { } - public override int Draw(ref Vector3[] buffer, params object[] values) - { + public override int Draw(ref Vector3[] buffer, params object[] values) + { Vector2 position = default; if (values[0] is Vector2 p2) { @@ -68,5 +68,4 @@ namespace Popcron return 8; } - } -} +} \ No newline at end of file diff --git a/.Deprecated/CVRGizmos/Popcron.Gizmos/Element.cs b/.Deprecated/CVRGizmos/Popcron.Gizmos/Element.cs new file mode 100644 index 0000000..1ea97d5 --- /dev/null +++ b/.Deprecated/CVRGizmos/Popcron.Gizmos/Element.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +namespace Popcron; + +internal class Element +{ + public Vector3[] points = { }; + public Color color = Color.white; + public bool dashed = false; + public Matrix4x4 matrix = Matrix4x4.identity; +} \ No newline at end of file diff --git a/CVRGizmos/Popcron.Gizmos/Gizmos.cs b/.Deprecated/CVRGizmos/Popcron.Gizmos/Gizmos.cs similarity index 52% rename from CVRGizmos/Popcron.Gizmos/Gizmos.cs rename to .Deprecated/CVRGizmos/Popcron.Gizmos/Gizmos.cs index a897991..cf86940 100644 --- a/CVRGizmos/Popcron.Gizmos/Gizmos.cs +++ b/.Deprecated/CVRGizmos/Popcron.Gizmos/Gizmos.cs @@ -1,29 +1,29 @@ using UnityEngine; -namespace Popcron +namespace Popcron; + +public class Gizmos { - public class Gizmos + private static string _prefsKey = null; + private static int? _bufferSize = null; + private static bool? _enabled = null; + private static float? _dashGap = null; + private static bool? _cull = null; + private static int? _pass = null; + private static Vector3? _offset = null; + + private static Vector3[] buffer = new Vector3[BufferSize]; + + /// + /// By default, it will always render to scene view camera and the main camera. + /// Subscribing to this allows you to whitelist your custom cameras. + /// + public static Func CameraFilter = cam => false; + + private static string PrefsKey { - private static string _prefsKey = null; - private static int? _bufferSize = null; - private static bool? _enabled = null; - private static float? _dashGap = null; - private static bool? _cull = null; - private static int? _pass = null; - private static Vector3? _offset = null; - - private static Vector3[] buffer = new Vector3[BufferSize]; - - /// - /// By default, it will always render to scene view camera and the main camera. - /// Subscribing to this allows you to whitelist your custom cameras. - /// - public static Func CameraFilter = cam => false; - - private static string PrefsKey + get { - get - { if (string.IsNullOrEmpty(_prefsKey)) { _prefsKey = $"{SystemInfo.deviceUniqueIdentifier}.{Application.companyName}.{Application.productName}.{Constants.UniqueIdentifier}"; @@ -31,34 +31,34 @@ namespace Popcron return _prefsKey; } - } + } - /// - /// The matrix to use. - /// - public static Matrix4x4 Matrix - { - get => GizmosInstance.Matrix; - set => GizmosInstance.Matrix = value; - } + /// + /// The matrix to use. + /// + public static Matrix4x4 Matrix + { + get => GizmosInstance.Matrix; + set => GizmosInstance.Matrix = value; + } - /// - /// The matrix to use. - /// - public static Color Color - { - get => GizmosInstance.Color; - set => GizmosInstance.Color = value; - } + /// + /// The matrix to use. + /// + public static Color Color + { + get => GizmosInstance.Color; + set => GizmosInstance.Color = value; + } - /// - /// The size of the total gizmos buffer. - /// Default is 4096. - /// - public static int BufferSize + /// + /// The size of the total gizmos buffer. + /// Default is 4096. + /// + public static int BufferSize + { + get { - get - { if (_bufferSize == null) { _bufferSize = PlayerPrefs.GetInt($"{PrefsKey}.BufferSize", 4096); @@ -66,8 +66,8 @@ namespace Popcron return _bufferSize.Value; } - set - { + set + { value = Mathf.Clamp(value, 0, int.MaxValue); if (_bufferSize != value) { @@ -78,15 +78,15 @@ namespace Popcron buffer = new Vector3[value]; } } - } + } - /// - /// Toggles wether the gizmos could be drawn or not. - /// - public static bool Enabled + /// + /// Toggles wether the gizmos could be drawn or not. + /// + public static bool Enabled + { + get { - get - { if (_enabled == null) { _enabled = PlayerPrefs.GetInt($"{PrefsKey}.Enabled", 1) == 1; @@ -94,24 +94,24 @@ namespace Popcron return _enabled.Value; } - set - { + set + { if (_enabled != value) { _enabled = value; PlayerPrefs.SetInt($"{PrefsKey}.Enabled", value ? 1 : 0); } } - } + } - /// - /// The size of the gap when drawing dashed elements. - /// Default gap size is 0.1 - /// - public static float DashGap + /// + /// The size of the gap when drawing dashed elements. + /// Default gap size is 0.1 + /// + public static float DashGap + { + get { - get - { if (_dashGap == null) { _dashGap = PlayerPrefs.GetFloat($"{PrefsKey}.DashGap", 0.1f); @@ -119,46 +119,46 @@ namespace Popcron return _dashGap.Value; } - set - { + set + { if (_dashGap != value) { _dashGap = value; PlayerPrefs.SetFloat($"{PrefsKey}.DashGap", value); } } - } + } - [Obsolete("This property is obsolete. Use FrustumCulling instead.", false)] - public static bool Cull + [Obsolete("This property is obsolete. Use FrustumCulling instead.", false)] + public static bool Cull + { + get { - get - { return FrustumCulling; } - set - { + set + { FrustumCulling = value; } - } + } - [Obsolete("This property is obsolete. Subscribe to CameraFilter predicate instead and return true for your custom camera.", false)] - public static Camera Camera + [Obsolete("This property is obsolete. Subscribe to CameraFilter predicate instead and return true for your custom camera.", false)] + public static Camera Camera + { + get => null; + set { - get => null; - set - { } - } + } - /// - /// Should the camera not draw elements that are not visible? - /// - public static bool FrustumCulling + /// + /// Should the camera not draw elements that are not visible? + /// + public static bool FrustumCulling + { + get { - get - { if (_cull == null) { _cull = PlayerPrefs.GetInt($"{PrefsKey}.FrustumCulling", 1) == 1; @@ -166,32 +166,32 @@ namespace Popcron return _cull.Value; } - set - { + set + { if (_cull != value) { _cull = value; PlayerPrefs.SetInt($"{PrefsKey}.FrustumCulling", value ? 1 : 0); } } - } + } - /// - /// The material being used to render. - /// - public static Material Material - { - get => GizmosInstance.Material; - set => GizmosInstance.Material = value; - } + /// + /// The material being used to render. + /// + public static Material Material + { + get => GizmosInstance.Material; + set => GizmosInstance.Material = value; + } - /// - /// Rendering pass to activate. - /// - public static int Pass + /// + /// Rendering pass to activate. + /// + public static int Pass + { + get { - get - { if (_pass == null) { _pass = PlayerPrefs.GetInt($"{PrefsKey}.Pass", 0); @@ -199,23 +199,23 @@ namespace Popcron return _pass.Value; } - set - { + set + { if (_pass != value) { _pass = value; PlayerPrefs.SetInt($"{PrefsKey}.Pass", value); } } - } + } - /// - /// Global offset for all points. Default is (0, 0, 0). - /// - public static Vector3 Offset + /// + /// Global offset for all points. Default is (0, 0, 0). + /// + public static Vector3 Offset + { + get { - get - { const string Delim = ","; if (_offset == null) { @@ -235,8 +235,8 @@ namespace Popcron return _offset.Value; } - set - { + set + { const string Delim = ","; if (_offset != value) { @@ -244,13 +244,13 @@ namespace Popcron PlayerPrefs.SetString($"{PrefsKey}.Offset", value.x + Delim + value.y + Delim + value.y); } } - } + } - /// - /// Draws an element onto the screen. - /// - public static void Draw(Color? color, bool dashed, params object[] args) where T : Drawer - { + /// + /// Draws an element onto the screen. + /// + public static void Draw(Color? color, bool dashed, params object[] args) where T : Drawer + { if (!Enabled) { return; @@ -268,11 +268,11 @@ namespace Popcron } } - /// - /// Draws an array of lines. Useful for things like paths. - /// - public static void Lines(Vector3[] lines, Color? color = null, bool dashed = false) - { + /// + /// Draws an array of lines. Useful for things like paths. + /// + public static void Lines(Vector3[] lines, Color? color = null, bool dashed = false) + { if (!Enabled) { return; @@ -281,69 +281,69 @@ namespace Popcron GizmosInstance.Submit(lines, color, dashed); } - /// - /// Draw line in world space. - /// - public static void Line(Vector3 a, Vector3 b, Color? color = null, bool dashed = false) - { + /// + /// Draw line in world space. + /// + public static void Line(Vector3 a, Vector3 b, Color? color = null, bool dashed = false) + { Draw(color, dashed, a, b); } - /// - /// Draw square in world space. - /// - public static void Square(Vector2 position, Vector2 size, Color? color = null, bool dashed = false) - { + /// + /// Draw square in world space. + /// + public static void Square(Vector2 position, Vector2 size, Color? color = null, bool dashed = false) + { Square(position, Quaternion.identity, size, color, dashed); } - /// - /// Draw square in world space with float diameter parameter. - /// - public static void Square(Vector2 position, float diameter, Color? color = null, bool dashed = false) - { + /// + /// Draw square in world space with float diameter parameter. + /// + public static void Square(Vector2 position, float diameter, Color? color = null, bool dashed = false) + { Square(position, Quaternion.identity, Vector2.one * diameter, color, dashed); } - /// - /// Draw square in world space with a rotation parameter. - /// - public static void Square(Vector2 position, Quaternion rotation, Vector2 size, Color? color = null, bool dashed = false) - { + /// + /// Draw square in world space with a rotation parameter. + /// + public static void Square(Vector2 position, Quaternion rotation, Vector2 size, Color? color = null, bool dashed = false) + { Draw(color, dashed, position, rotation, size); } - /// - /// Draws a cube in world space. - /// - public static void Cube(Vector3 position, Quaternion rotation, Vector3 size, Color? color = null, bool dashed = false) - { + /// + /// Draws a cube in world space. + /// + public static void Cube(Vector3 position, Quaternion rotation, Vector3 size, Color? color = null, bool dashed = false) + { Draw(color, dashed, position, rotation, size); } - /// - /// Draws a rectangle in screen space. - /// - public static void Rect(Rect rect, Camera camera, Color? color = null, bool dashed = false) - { + /// + /// Draws a rectangle in screen space. + /// + public static void Rect(Rect rect, Camera camera, Color? color = null, bool dashed = false) + { rect.y = Screen.height - rect.y; Vector2 corner = camera.ScreenToWorldPoint(new Vector2(rect.x, rect.y - rect.height)); Draw(color, dashed, corner + rect.size * 0.5f, Quaternion.identity, rect.size); } - /// - /// Draws a representation of a bounding box. - /// - public static void Bounds(Bounds bounds, Color? color = null, bool dashed = false) - { + /// + /// Draws a representation of a bounding box. + /// + public static void Bounds(Bounds bounds, Color? color = null, bool dashed = false) + { Draw(color, dashed, bounds.center, Quaternion.identity, bounds.size); } - /// - /// Draws a cone similar to the one that spot lights draw. - /// - public static void Cone(Vector3 position, Quaternion rotation, float length, float angle, Color? color = null, bool dashed = false, int pointsCount = 16) - { + /// + /// Draws a cone similar to the one that spot lights draw. + /// + public static void Cone(Vector3 position, Quaternion rotation, float length, float angle, Color? color = null, bool dashed = false, int pointsCount = 16) + { //draw the end of the cone float endAngle = Mathf.Tan(angle * 0.5f * Mathf.Deg2Rad) * length; Vector3 forward = rotation * Vector3.forward; @@ -360,34 +360,33 @@ namespace Popcron } } - /// - /// Draws a sphere at position with specified radius. - /// - public static void Sphere(Vector3 position, float radius, Color? color = null, bool dashed = false, int pointsCount = 16) - { + /// + /// Draws a sphere at position with specified radius. + /// + public static void Sphere(Vector3 position, float radius, Color? color = null, bool dashed = false, int pointsCount = 16) + { float offset = 0f; Draw(color, dashed, position, pointsCount, radius, offset, Quaternion.Euler(0f, 0f, 0f)); Draw(color, dashed, position, pointsCount, radius, offset, Quaternion.Euler(90f, 0f, 0f)); Draw(color, dashed, position, pointsCount, radius, offset, Quaternion.Euler(0f, 90f, 90f)); } - /// - /// Draws a circle in world space and billboards towards the camera. - /// - public static void Circle(Vector3 position, float radius, Camera camera, Color? color = null, bool dashed = false, int pointsCount = 16) - { + /// + /// Draws a circle in world space and billboards towards the camera. + /// + public static void Circle(Vector3 position, float radius, Camera camera, Color? color = null, bool dashed = false, int pointsCount = 16) + { float offset = 0f; Quaternion rotation = Quaternion.LookRotation(position - camera.transform.position); Draw(color, dashed, position, pointsCount, radius, offset, rotation); } - /// - /// Draws a circle in world space with a specified rotation. - /// - public static void Circle(Vector3 position, float radius, Quaternion rotation, Color? color = null, bool dashed = false, int pointsCount = 16) - { + /// + /// Draws a circle in world space with a specified rotation. + /// + public static void Circle(Vector3 position, float radius, Quaternion rotation, Color? color = null, bool dashed = false, int pointsCount = 16) + { float offset = 0f; Draw(color, dashed, position, pointsCount, radius, offset, rotation); } - } -} +} \ No newline at end of file diff --git a/CVRGizmos/Popcron.Gizmos/GizmosInstance.cs b/.Deprecated/CVRGizmos/Popcron.Gizmos/GizmosInstance.cs similarity index 100% rename from CVRGizmos/Popcron.Gizmos/GizmosInstance.cs rename to .Deprecated/CVRGizmos/Popcron.Gizmos/GizmosInstance.cs diff --git a/CVRGizmos/Popcron.Gizmos/LICENSE.md b/.Deprecated/CVRGizmos/Popcron.Gizmos/LICENSE.md similarity index 100% rename from CVRGizmos/Popcron.Gizmos/LICENSE.md rename to .Deprecated/CVRGizmos/Popcron.Gizmos/LICENSE.md diff --git a/CVRGizmos/Properties/AssemblyInfo.cs b/.Deprecated/CVRGizmos/Properties/AssemblyInfo.cs similarity index 100% rename from CVRGizmos/Properties/AssemblyInfo.cs rename to .Deprecated/CVRGizmos/Properties/AssemblyInfo.cs diff --git a/CVRGizmos/format.json b/.Deprecated/CVRGizmos/format.json similarity index 100% rename from CVRGizmos/format.json rename to .Deprecated/CVRGizmos/format.json diff --git a/SmartReticle/SmartReticle.csproj b/.Deprecated/CameraExperiments/CameraExperiments.csproj similarity index 100% rename from SmartReticle/SmartReticle.csproj rename to .Deprecated/CameraExperiments/CameraExperiments.csproj diff --git a/.Deprecated/CameraExperiments/Main.cs b/.Deprecated/CameraExperiments/Main.cs new file mode 100644 index 0000000..51035fd --- /dev/null +++ b/.Deprecated/CameraExperiments/Main.cs @@ -0,0 +1,170 @@ +using ABI_RC.Core; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Player; +using HarmonyLib; +using MagicaCloth2; +using MelonLoader; +using Unity.Burst; +using Unity.Collections; +using Unity.Jobs; +using UnityEngine; + +namespace NAK.WhereAmIPointing; + +public class WhereAmIPointingMod : MelonMod +{ + #region Melon Preferences + + // cannot disable because then id need extra logic to reset the alpha :) + // private const string SettingsCategory = nameof(WhereAmIPointingMod); + // + // private static readonly MelonPreferences_Category Category = + // MelonPreferences.CreateCategory(SettingsCategory); + // + // private static readonly MelonPreferences_Entry Entry_Enabled = + // Category.CreateEntry("enabled", true, display_name: "Enabled",description: "Toggle WhereAmIPointingMod entirely."); + + #endregion Melon Preferences + + public override void OnInitializeMelon() + { + ApplyPatches(typeof(TransformManager_Patches)); + } + + private void ApplyPatches(Type type) + { + try + { + HarmonyInstance.PatchAll(type); + } + catch (Exception e) + { + LoggerInstance.Msg($"Failed while patching {type.Name}!"); + LoggerInstance.Error(e); + } + } + + internal static class TransformManager_Patches + { + // Patch for EnableTransform(DataChunk, bool) + [HarmonyPrefix] + [HarmonyPatch(typeof(TransformManager), nameof(TransformManager.EnableTransform), new[] { typeof(DataChunk), typeof(bool) })] + private static bool OnEnableTransformChunk(TransformManager __instance, DataChunk c, bool sw, ref NativeArray ___flagArray) + { + try + { + // Enhanced validation + if (!__instance.IsValid()) + return false; + + if (___flagArray == null || !___flagArray.IsCreated) + { + Debug.LogWarning("[MagicaCloth2] EnableTransform failed: Flag array is invalid or disposed"); + return false; + } + + if (!c.IsValid || c.startIndex < 0 || c.startIndex + c.dataLength > ___flagArray.Length) + { + Debug.LogWarning($"[MagicaCloth2] EnableTransform failed: Invalid chunk parameters. Start: {c.startIndex}, Length: {c.dataLength}, Array Length: {___flagArray.Length}"); + return false; + } + + // Create and run the job with additional safety + SafeEnableTransformJob job = new() + { + chunk = c, + sw = sw, + flagList = ___flagArray, + maxLength = ___flagArray.Length + }; + + try + { + job.Run(); + } + catch (Exception ex) + { + Debug.LogError($"[MagicaCloth2] Error in EnableTransform job execution: {ex.Message}"); + return false; + } + + return false; // Prevent original method execution + } + catch (Exception ex) + { + Debug.LogError($"[MagicaCloth2] Critical error in EnableTransform patch: {ex.Message}"); + return false; + } + } + + // Patch for EnableTransform(int, bool) + [HarmonyPrefix] + [HarmonyPatch(typeof(TransformManager), nameof(TransformManager.EnableTransform), new[] { typeof(int), typeof(bool) })] + private static bool OnEnableTransformIndex(TransformManager __instance, int index, bool sw, ref NativeArray ___flagArray) + { + try + { + // Enhanced validation + if (!__instance.IsValid()) + return false; + + if (___flagArray == null || !___flagArray.IsCreated) + { + Debug.LogWarning("[MagicaCloth2] EnableTransform failed: Flag array is invalid or disposed"); + return false; + } + + if (index < 0 || index >= ___flagArray.Length) + { + Debug.LogWarning($"[MagicaCloth2] EnableTransform failed: Index {index} out of range [0, {___flagArray.Length})"); + return false; + } + + // Safely modify the flag + var flag = ___flagArray[index]; + if (flag.Value == 0) + return false; + + flag.SetFlag(TransformManager.Flag_Enable, sw); + ___flagArray[index] = flag; + + return false; // Prevent original method execution + } + catch (Exception ex) + { + Debug.LogError($"[MagicaCloth2] Critical error in EnableTransform patch: {ex.Message}"); + return false; + } + } + + [BurstCompile] + private struct SafeEnableTransformJob : IJob + { + public DataChunk chunk; + public bool sw; + public NativeArray flagList; + [ReadOnly] public int maxLength; + + public void Execute() + { + // Additional bounds checking + if (chunk.startIndex < 0 || chunk.startIndex + chunk.dataLength > maxLength) + return; + + for (int i = 0; i < chunk.dataLength; i++) + { + int index = chunk.startIndex + i; + if (index >= maxLength) + break; + + ExBitFlag8 flag = flagList[index]; + if (flag.Value == 0) + continue; + + flag.SetFlag(TransformManager.Flag_Enable, sw); + flagList[index] = flag; + } + } + } + } +} \ No newline at end of file diff --git a/.Deprecated/CameraExperiments/Properties/AssemblyInfo.cs b/.Deprecated/CameraExperiments/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..48c359f --- /dev/null +++ b/.Deprecated/CameraExperiments/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using NAK.WhereAmIPointing.Properties; +using MelonLoader; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.WhereAmIPointing))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.WhereAmIPointing))] + +[assembly: MelonInfo( + typeof(NAK.WhereAmIPointing.WhereAmIPointingMod), + nameof(NAK.WhereAmIPointing), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/WhereAmIPointing" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red +[assembly: HarmonyDontPatchAll] + +namespace NAK.WhereAmIPointing.Properties; +internal static class AssemblyInfoParams +{ + public const string Version = "1.0.1"; + public const string Author = "NotAKidoS"; +} \ No newline at end of file diff --git a/.Deprecated/CameraExperiments/README.md b/.Deprecated/CameraExperiments/README.md new file mode 100644 index 0000000..c78a56a --- /dev/null +++ b/.Deprecated/CameraExperiments/README.md @@ -0,0 +1,14 @@ +# WhereAmIPointing + +Simple mod that makes your controller rays always visible when the menus are open. Useful for when you're trying to aim at something in the distance. Also visualizes which ray is being used for menu interaction. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation 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/.Deprecated/CameraExperiments/format.json b/.Deprecated/CameraExperiments/format.json new file mode 100644 index 0000000..654911a --- /dev/null +++ b/.Deprecated/CameraExperiments/format.json @@ -0,0 +1,23 @@ +{ + "_id": 234, + "name": "WhereAmIPointing", + "modversion": "1.0.1", + "gameversion": "2024r175", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Simple mod that makes your controller rays always visible when the menus are open. Useful for when you're trying to aim at something in the distance. Also visualizes which ray is being used for menu interaction.", + "searchtags": [ + "controller", + "ray", + "line", + "tomato" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r40/WhereAmIPointing.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/WhereAmIPointing/", + "changelog": "- Fixed line renderer alpha not being reset when the menu is closed.", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/.DepricatedMods/CameraFixes/CameraFixes.csproj b/.Deprecated/CameraFixes/CameraFixes.csproj similarity index 100% rename from .DepricatedMods/CameraFixes/CameraFixes.csproj rename to .Deprecated/CameraFixes/CameraFixes.csproj diff --git a/.DepricatedMods/CameraFixes/HarmonyPatches.cs b/.Deprecated/CameraFixes/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/CameraFixes/HarmonyPatches.cs rename to .Deprecated/CameraFixes/HarmonyPatches.cs diff --git a/.DepricatedMods/CameraFixes/Main.cs b/.Deprecated/CameraFixes/Main.cs similarity index 100% rename from .DepricatedMods/CameraFixes/Main.cs rename to .Deprecated/CameraFixes/Main.cs diff --git a/.DepricatedMods/CameraFixes/Properties/AssemblyInfo.cs b/.Deprecated/CameraFixes/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/CameraFixes/Properties/AssemblyInfo.cs rename to .Deprecated/CameraFixes/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/CameraFixes/format.json b/.Deprecated/CameraFixes/format.json similarity index 100% rename from .DepricatedMods/CameraFixes/format.json rename to .Deprecated/CameraFixes/format.json diff --git a/.DepricatedMods/ClearHudNotifications/ClearHudNotifications.csproj b/.Deprecated/ClearHudNotifications/ClearHudNotifications.csproj similarity index 100% rename from .DepricatedMods/ClearHudNotifications/ClearHudNotifications.csproj rename to .Deprecated/ClearHudNotifications/ClearHudNotifications.csproj diff --git a/.DepricatedMods/ClearHudNotifications/HarmonyPatches.cs b/.Deprecated/ClearHudNotifications/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/ClearHudNotifications/HarmonyPatches.cs rename to .Deprecated/ClearHudNotifications/HarmonyPatches.cs diff --git a/.DepricatedMods/ClearHudNotifications/Main.cs b/.Deprecated/ClearHudNotifications/Main.cs similarity index 100% rename from .DepricatedMods/ClearHudNotifications/Main.cs rename to .Deprecated/ClearHudNotifications/Main.cs diff --git a/.DepricatedMods/ClearHudNotifications/Properties/AssemblyInfo.cs b/.Deprecated/ClearHudNotifications/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/ClearHudNotifications/Properties/AssemblyInfo.cs rename to .Deprecated/ClearHudNotifications/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/ClearHudNotifications/format.json b/.Deprecated/ClearHudNotifications/format.json similarity index 100% rename from .DepricatedMods/ClearHudNotifications/format.json rename to .Deprecated/ClearHudNotifications/format.json diff --git a/.Deprecated/ControlToUnlockMouse/ControlToUnlockMouse.csproj b/.Deprecated/ControlToUnlockMouse/ControlToUnlockMouse.csproj new file mode 100644 index 0000000..0f08b56 --- /dev/null +++ b/.Deprecated/ControlToUnlockMouse/ControlToUnlockMouse.csproj @@ -0,0 +1,6 @@ + + + + SpawnableReceiveOwnChanges + + diff --git a/.Deprecated/ControlToUnlockMouse/Main.cs b/.Deprecated/ControlToUnlockMouse/Main.cs new file mode 100644 index 0000000..4ca9845 --- /dev/null +++ b/.Deprecated/ControlToUnlockMouse/Main.cs @@ -0,0 +1,308 @@ +using ABI_RC.Core; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.InteractionSystem.Base; +using ABI_RC.Core.Player; +using System.Reflection; +using cohtml.Net; +using HarmonyLib; +using UnityEngine; +using MelonLoader; +using Object = UnityEngine.Object; + +namespace NAK.ControlToUnlockMouse; + +public class ControlToUnlockMouseMod : MelonMod +{ + private static readonly MelonPreferences_Category Category = + MelonPreferences.CreateCategory(nameof(ControlToUnlockMouseMod)); + + internal static readonly MelonPreferences_Entry EntryOriginPivotPoint = + Category.CreateEntry("no_rotate_pivot_point", NoRotatePivotPoint.Pickupable, + "NoRotation Pickupable Pivot Point", "The pivot point to use when no rotation object is grabbed."); + + public enum NoRotatePivotPoint + { + Pickupable, + AvatarHead, + AvatarChest, + AvatarClosestShoulder, + } + + public override void OnInitializeMelon() + { + HarmonyInstance.Patch( + typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.Awake), + BindingFlags.NonPublic | BindingFlags.Instance), + postfix: new HarmonyMethod(typeof(ControlToUnlockMouseMod).GetMethod(nameof(OnPlayerSetupAwake), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + HarmonyInstance.Patch( + typeof(CVR_MenuManager).GetMethod(nameof(CVR_MenuManager.Start), + BindingFlags.NonPublic | BindingFlags.Instance), + postfix: new HarmonyMethod(typeof(ControlToUnlockMouseMod).GetMethod(nameof(OnMenuManagerStart), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + HarmonyInstance.Patch( + typeof(ControllerRay).GetMethod(nameof(ControllerRay.HandleUnityUI), + BindingFlags.NonPublic | BindingFlags.Instance), + prefix: new HarmonyMethod(typeof(ControlToUnlockMouseMod).GetMethod(nameof(OnControllerRayHandleUnityUIDirectAndIndirect), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + HarmonyInstance.Patch( + typeof(ControllerRay).GetMethod(nameof(ControllerRay.HandleIndirectUnityUI), + BindingFlags.NonPublic | BindingFlags.Instance), + prefix: new HarmonyMethod(typeof(ControlToUnlockMouseMod).GetMethod(nameof(OnControllerRayHandleUnityUIDirectAndIndirect), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + HarmonyInstance.Patch( + typeof(ControllerRay).GetMethod(nameof(ControllerRay.LateUpdate), + BindingFlags.NonPublic | BindingFlags.Instance), + prefix: new HarmonyMethod(typeof(ControlToUnlockMouseMod).GetMethod(nameof(OnPreControllerRayLateUpdate), + BindingFlags.NonPublic | BindingFlags.Static)), + postfix: new HarmonyMethod(typeof(ControlToUnlockMouseMod).GetMethod(nameof(OnPostControllerRayLateUpdate), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + } + + private static void OnPlayerSetupAwake(PlayerSetup __instance) + { + // Get original fields + LayerMask layerMask = __instance.desktopRay.generalMask; + + // Destroy the existing desktop ray + Object.Destroy(__instance.desktopRay); + + // Get the desktop camera + Camera desktopCam = __instance.desktopCam; + + // Create a new child object under the desktop camera for the ray + GameObject rayObject = new("DesktopRay") + { + transform = + { + parent = desktopCam.transform, + localPosition = Vector3.zero, + localRotation = Quaternion.identity + } + }; + + // Add ControllerRay component + ControllerRay newRay = rayObject.AddComponent(); + newRay.isDesktopRay = true; + newRay.isInteractionRay = true; + newRay.RayDirection = Vector3.forward; + newRay.generalMask = layerMask; + newRay.hand = CVRHand.Right; // Important to even work + newRay.attachmentDistance = 0f; + newRay.currentAttachmentDistance = 0f; + + // Assign new ray to desktopRay field + __instance.desktopRay = newRay; + + // Add our custom controller script + DesktopRayController rayController = rayObject.AddComponent(); + rayController.controllerRay = newRay; + rayController.desktopCamera = desktopCam; + } + + private static void OnMenuManagerStart(CVR_MenuManager __instance) + { + __instance.desktopControllerRay = PlayerSetup.Instance.desktopRay; + } + + private static bool OnControllerRayHandleUnityUIDirectAndIndirect(ControllerRay __instance) + { + return !__instance.isDesktopRay || Cursor.lockState == CursorLockMode.Locked; + } + + private static void OnPreControllerRayLateUpdate(ControllerRay __instance, ref bool __state) + { + if (!__instance.isDesktopRay) + return; + + ViewManager menu = ViewManager.Instance; + __state = menu._gameMenuOpen; + + if (!__state) menu._gameMenuOpen = Cursor.lockState != CursorLockMode.Locked; + } + + private static void OnPostControllerRayLateUpdate(ControllerRay __instance, ref bool __state) + { + if (!__instance.isDesktopRay) return; + ViewManager.Instance._gameMenuOpen = __state; + } +} + +public class DesktopRayController : MonoBehaviour +{ + internal ControllerRay controllerRay; + internal Camera desktopCamera; + + private void Update() + { + // Toggle desktop mouse mode based on Control key state + if (Input.GetKeyDown(KeyCode.LeftControl)) + { + if (!ViewManager.Instance.IsAnyMenuOpen) RootLogic.CursorLock(false); + } + + if (Input.GetKeyUp(KeyCode.LeftControl)) + { + if (!ViewManager.Instance.IsAnyMenuOpen) RootLogic.CursorLock(true); + } + + Transform rayRoot = controllerRay.transform; + Transform rayDirection = controllerRay.rayDirectionTransform; + Transform attachment = controllerRay.attachmentPoint; + Camera cam = desktopCamera; + + if (Cursor.lockState == CursorLockMode.Locked) + { + // Reset local position when unlocked + rayRoot.localPosition = Vector3.zero; + rayRoot.localRotation = Quaternion.identity; + + // Reset local position and rotation when locked + rayDirection.localPosition = new Vector3(0f, 0f, 0.001f); + rayDirection.localRotation = Quaternion.identity; + } + else + { + bool isAnyMenuOpen = ViewManager.Instance.IsAnyMenuOpen; + Pickupable grabbedObject = controllerRay.grabbedObject; + + // Only do when not holding an origin object + Vector3 screenPos = new(Input.mousePosition.x, Input.mousePosition.y); + + if (isAnyMenuOpen) + { + // Center the ray + rayRoot.localPosition = Vector3.zero; + } + else if (grabbedObject && !grabbedObject.IsObjectRotationAllowed) + { + // Specialized movement of ray around pickupable pivot + Vector3 pivotPoint = grabbedObject.transform.position; + Vector3 pivotPointCenter = grabbedObject.RootTransform.position; + + PlayerSetup playerSetup = PlayerSetup.Instance; + if (playerSetup != null && playerSetup._animator != null && playerSetup._animator.isHuman) + { + Animator animator = playerSetup._animator; + switch (ControlToUnlockMouseMod.EntryOriginPivotPoint.Value) + { + case ControlToUnlockMouseMod.NoRotatePivotPoint.AvatarHead: + { + Transform headBone = animator.GetBoneTransform(HumanBodyBones.Head); + if (headBone != null) pivotPoint = headBone.position; + break; + } + case ControlToUnlockMouseMod.NoRotatePivotPoint.AvatarChest: + { + if (playerSetup._avatar != null) + { + Transform chestBone = animator.GetBoneTransform(HumanBodyBones.Chest); + if (chestBone != null) pivotPoint = chestBone.position; + } + break; + } + case ControlToUnlockMouseMod.NoRotatePivotPoint.AvatarClosestShoulder: + { + if (playerSetup._avatar != null) + { + Transform leftShoulder = animator.GetBoneTransform(HumanBodyBones.LeftShoulder); + Transform rightShoulder = animator.GetBoneTransform(HumanBodyBones.RightShoulder); + if (leftShoulder != null || rightShoulder != null) + { + if (leftShoulder != null && rightShoulder != null) + { + pivotPoint = Vector3.Distance(leftShoulder.position, pivotPoint) < Vector3.Distance(rightShoulder.position, pivotPoint) + ? leftShoulder.position + : rightShoulder.position; + } + else if (leftShoulder != null) + { + pivotPoint = leftShoulder.position; + } + else + { + pivotPoint = rightShoulder.position; + } + } + } + break; + } + case ControlToUnlockMouseMod.NoRotatePivotPoint.Pickupable: + default: + break; + } + } + + // Get local position of pivotPoint relative to rayRoot + // This is shit but i cant wrap my head around the proper way to compute this lol + Vector3 localPivotPoint = rayRoot.InverseTransformPoint(pivotPoint); + Vector3 localPivotPointCenter = rayRoot.InverseTransformPoint(pivotPointCenter); + localPivotPoint.x = localPivotPointCenter.x; // Maintain local X + localPivotPoint.y = localPivotPointCenter.y; // Maintain local Y + + // Compute target world position based on the mouse and attachment distance. + screenPos.z = 10f; + Vector3 targetWorldPos = cam.ScreenToWorldPoint(screenPos); + + // Desired direction from the pivot point (grabbed object) to the target world position. + Vector3 directionToTarget = targetWorldPos - rayRoot.TransformPoint(localPivotPoint);; + + if (directionToTarget.sqrMagnitude < 1e-6f) + directionToTarget = rayRoot.forward; // Fallback if mouse is centered + + // Calculate the target rotation for rayRoot. + Quaternion targetRotation = Quaternion.LookRotation(directionToTarget, cam.transform.up); + + // Get the current local offset of the grabbed object relative to rayRoot. + Vector3 localPickupOffset = rayRoot.InverseTransformPoint(pivotPoint); + + // Compute the new rayRoot position to keep the grabbed object (child) at pivotPoint. + Vector3 newRayRootPos = pivotPoint - (targetRotation * localPickupOffset); + + // Apply the new rotation and position. + rayRoot.rotation = targetRotation; + rayRoot.position = newRayRootPos; + } + else + { + float distance; + if (grabbedObject) + { + // This position is calculated basically same way as below in BasePickupHandler, + // but not determined by ray hit + distance = attachment.localPosition.z; + } + else + { + // Compute distance forward from ray + Vector3 localOffset = rayRoot.InverseTransformPoint(controllerRay._hit.point); + distance = localOffset.z; + } + + screenPos.z = distance; + + // Compute world position from where mouse is on screen + Vector3 worldPos = cam.ScreenToWorldPoint(screenPos); + + // Normal movement of ray + Vector3 newLocalPos = rayRoot.parent.InverseTransformPoint(worldPos); + newLocalPos.z = rayRoot.localPosition.z; // Maintain local Z + rayRoot.localPosition = newLocalPos; + } + + // Compute mouse ray in world space + Ray mouseRay = cam.ScreenPointToRay(Input.mousePosition); + rayDirection.position = mouseRay.origin; + rayDirection.rotation = Quaternion.LookRotation(mouseRay.direction, cam.transform.up); + } + } +} \ No newline at end of file diff --git a/.Deprecated/ControlToUnlockMouse/Properties/AssemblyInfo.cs b/.Deprecated/ControlToUnlockMouse/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..9e54143 --- /dev/null +++ b/.Deprecated/ControlToUnlockMouse/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using MelonLoader; +using NAK.ControlToUnlockMouse.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.ControlToUnlockMouse))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.ControlToUnlockMouse))] + +[assembly: MelonInfo( + typeof(NAK.ControlToUnlockMouse.ControlToUnlockMouseMod), + nameof(NAK.ControlToUnlockMouse), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ControlToUnlockMouse" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red +[assembly: HarmonyDontPatchAll] + +namespace NAK.ControlToUnlockMouse.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/SearchWithSpacesFix/README.md b/.Deprecated/ControlToUnlockMouse/README.md similarity index 100% rename from SearchWithSpacesFix/README.md rename to .Deprecated/ControlToUnlockMouse/README.md diff --git a/SearchWithSpacesFix/format.json b/.Deprecated/ControlToUnlockMouse/format.json similarity index 100% rename from SearchWithSpacesFix/format.json rename to .Deprecated/ControlToUnlockMouse/format.json diff --git a/.DepricatedMods/ControllerFreeze/ControllerFreeze.csproj b/.Deprecated/ControllerFreeze/ControllerFreeze.csproj similarity index 100% rename from .DepricatedMods/ControllerFreeze/ControllerFreeze.csproj rename to .Deprecated/ControllerFreeze/ControllerFreeze.csproj diff --git a/.DepricatedMods/ControllerFreeze/HarmonyPatches.cs b/.Deprecated/ControllerFreeze/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/ControllerFreeze/HarmonyPatches.cs rename to .Deprecated/ControllerFreeze/HarmonyPatches.cs diff --git a/.DepricatedMods/ControllerFreeze/Main.cs b/.Deprecated/ControllerFreeze/Main.cs similarity index 100% rename from .DepricatedMods/ControllerFreeze/Main.cs rename to .Deprecated/ControllerFreeze/Main.cs diff --git a/.DepricatedMods/ControllerFreeze/Properties/AssemblyInfo.cs b/.Deprecated/ControllerFreeze/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/ControllerFreeze/Properties/AssemblyInfo.cs rename to .Deprecated/ControllerFreeze/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/ControllerFreeze/README.md b/.Deprecated/ControllerFreeze/README.md similarity index 100% rename from .DepricatedMods/ControllerFreeze/README.md rename to .Deprecated/ControllerFreeze/README.md diff --git a/.DepricatedMods/ControllerFreeze/format.json b/.Deprecated/ControllerFreeze/format.json similarity index 100% rename from .DepricatedMods/ControllerFreeze/format.json rename to .Deprecated/ControllerFreeze/format.json diff --git a/.DepricatedMods/DesktopVRIK/DesktopVRIK.csproj b/.Deprecated/DesktopVRIK/DesktopVRIK.csproj similarity index 100% rename from .DepricatedMods/DesktopVRIK/DesktopVRIK.csproj rename to .Deprecated/DesktopVRIK/DesktopVRIK.csproj diff --git a/.DepricatedMods/DesktopVRIK/HarmonyPatches.cs b/.Deprecated/DesktopVRIK/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/HarmonyPatches.cs rename to .Deprecated/DesktopVRIK/HarmonyPatches.cs diff --git a/.DepricatedMods/DesktopVRIK/IK/IKCalibrator.cs b/.Deprecated/DesktopVRIK/IK/IKCalibrator.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/IK/IKCalibrator.cs rename to .Deprecated/DesktopVRIK/IK/IKCalibrator.cs diff --git a/.DepricatedMods/DesktopVRIK/IK/IKHandlers/IKHandler.cs b/.Deprecated/DesktopVRIK/IK/IKHandlers/IKHandler.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/IK/IKHandlers/IKHandler.cs rename to .Deprecated/DesktopVRIK/IK/IKHandlers/IKHandler.cs diff --git a/.DepricatedMods/DesktopVRIK/IK/IKHandlers/IKHandlerDesktop.cs b/.Deprecated/DesktopVRIK/IK/IKHandlers/IKHandlerDesktop.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/IK/IKHandlers/IKHandlerDesktop.cs rename to .Deprecated/DesktopVRIK/IK/IKHandlers/IKHandlerDesktop.cs diff --git a/.DepricatedMods/DesktopVRIK/IK/IKManager.cs b/.Deprecated/DesktopVRIK/IK/IKManager.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/IK/IKManager.cs rename to .Deprecated/DesktopVRIK/IK/IKManager.cs diff --git a/.DepricatedMods/DesktopVRIK/IK/MusclePoses.cs b/.Deprecated/DesktopVRIK/IK/MusclePoses.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/IK/MusclePoses.cs rename to .Deprecated/DesktopVRIK/IK/MusclePoses.cs diff --git a/.DepricatedMods/DesktopVRIK/IK/VRIKHelpers/VRIKLocomotionData.cs b/.Deprecated/DesktopVRIK/IK/VRIKHelpers/VRIKLocomotionData.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/IK/VRIKHelpers/VRIKLocomotionData.cs rename to .Deprecated/DesktopVRIK/IK/VRIKHelpers/VRIKLocomotionData.cs diff --git a/.DepricatedMods/DesktopVRIK/IK/VRIKHelpers/VRIKUtils.cs b/.Deprecated/DesktopVRIK/IK/VRIKHelpers/VRIKUtils.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/IK/VRIKHelpers/VRIKUtils.cs rename to .Deprecated/DesktopVRIK/IK/VRIKHelpers/VRIKUtils.cs diff --git a/.DepricatedMods/DesktopVRIK/Integrations/AMTAddon.cs b/.Deprecated/DesktopVRIK/Integrations/AMTAddon.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/Integrations/AMTAddon.cs rename to .Deprecated/DesktopVRIK/Integrations/AMTAddon.cs diff --git a/.DepricatedMods/DesktopVRIK/Integrations/BTKUIAddon.cs b/.Deprecated/DesktopVRIK/Integrations/BTKUIAddon.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/Integrations/BTKUIAddon.cs rename to .Deprecated/DesktopVRIK/Integrations/BTKUIAddon.cs diff --git a/.DepricatedMods/DesktopVRIK/Main.cs b/.Deprecated/DesktopVRIK/Main.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/Main.cs rename to .Deprecated/DesktopVRIK/Main.cs diff --git a/.DepricatedMods/DesktopVRIK/ModSettings.cs b/.Deprecated/DesktopVRIK/ModSettings.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/ModSettings.cs rename to .Deprecated/DesktopVRIK/ModSettings.cs diff --git a/.DepricatedMods/DesktopVRIK/Properties/AssemblyInfo.cs b/.Deprecated/DesktopVRIK/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/DesktopVRIK/Properties/AssemblyInfo.cs rename to .Deprecated/DesktopVRIK/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/DesktopVRIK/README.md b/.Deprecated/DesktopVRIK/README.md similarity index 100% rename from .DepricatedMods/DesktopVRIK/README.md rename to .Deprecated/DesktopVRIK/README.md diff --git a/.DepricatedMods/DesktopVRIK/format.json b/.Deprecated/DesktopVRIK/format.json similarity index 100% rename from .DepricatedMods/DesktopVRIK/format.json rename to .Deprecated/DesktopVRIK/format.json diff --git a/.DepricatedMods/DesktopVRSwitch/DesktopVRSwitch.csproj b/.Deprecated/DesktopVRSwitch/DesktopVRSwitch.csproj similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/DesktopVRSwitch.csproj rename to .Deprecated/DesktopVRSwitch/DesktopVRSwitch.csproj diff --git a/.DepricatedMods/DesktopVRSwitch/HarmonyPatches.cs b/.Deprecated/DesktopVRSwitch/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/HarmonyPatches.cs rename to .Deprecated/DesktopVRSwitch/HarmonyPatches.cs diff --git a/.DepricatedMods/DesktopVRSwitch/Integrations/BTKUIAddon.cs b/.Deprecated/DesktopVRSwitch/Integrations/BTKUIAddon.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/Integrations/BTKUIAddon.cs rename to .Deprecated/DesktopVRSwitch/Integrations/BTKUIAddon.cs diff --git a/.DepricatedMods/DesktopVRSwitch/Main.cs b/.Deprecated/DesktopVRSwitch/Main.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/Main.cs rename to .Deprecated/DesktopVRSwitch/Main.cs diff --git a/.DepricatedMods/DesktopVRSwitch/ModSettings.cs b/.Deprecated/DesktopVRSwitch/ModSettings.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/ModSettings.cs rename to .Deprecated/DesktopVRSwitch/ModSettings.cs diff --git a/.DepricatedMods/DesktopVRSwitch/Patches/DestroySteamVRInstancesImmediate.cs b/.Deprecated/DesktopVRSwitch/Patches/DestroySteamVRInstancesImmediate.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/Patches/DestroySteamVRInstancesImmediate.cs rename to .Deprecated/DesktopVRSwitch/Patches/DestroySteamVRInstancesImmediate.cs diff --git a/.DepricatedMods/DesktopVRSwitch/Patches/ReferenceCameraPatch.cs b/.Deprecated/DesktopVRSwitch/Patches/ReferenceCameraPatch.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/Patches/ReferenceCameraPatch.cs rename to .Deprecated/DesktopVRSwitch/Patches/ReferenceCameraPatch.cs diff --git a/.DepricatedMods/DesktopVRSwitch/Properties/AssemblyInfo.cs b/.Deprecated/DesktopVRSwitch/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/Properties/AssemblyInfo.cs rename to .Deprecated/DesktopVRSwitch/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/DesktopVRSwitch/README.md b/.Deprecated/DesktopVRSwitch/README.md similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/README.md rename to .Deprecated/DesktopVRSwitch/README.md diff --git a/.DepricatedMods/DesktopVRSwitch/Utils.cs b/.Deprecated/DesktopVRSwitch/Utils.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/Utils.cs rename to .Deprecated/DesktopVRSwitch/Utils.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeSwitchDebugger.cs b/.Deprecated/DesktopVRSwitch/VRModeSwitchDebugger.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeSwitchDebugger.cs rename to .Deprecated/DesktopVRSwitch/VRModeSwitchDebugger.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeSwitchManager.cs b/.Deprecated/DesktopVRSwitch/VRModeSwitchManager.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeSwitchManager.cs rename to .Deprecated/DesktopVRSwitch/VRModeSwitchManager.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVRGestureRecognizerTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/CVRGestureRecognizerTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVRGestureRecognizerTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/CVRGestureRecognizerTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVRInputManagerTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/CVRInputManagerTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVRInputManagerTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/CVRInputManagerTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVRPickupObjectTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/CVRPickupObjectTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVRPickupObjectTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/CVRPickupObjectTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVRWorldTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/CVRWorldTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVRWorldTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/CVRWorldTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVR_InteractableManagerTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/CVR_InteractableManagerTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVR_InteractableManagerTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/CVR_InteractableManagerTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVR_MenuManagerTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/CVR_MenuManagerTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/CVR_MenuManagerTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/CVR_MenuManagerTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/CameraFacingObjectTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/CameraFacingObjectTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/CameraFacingObjectTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/CameraFacingObjectTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/CheckVRTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/CheckVRTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/CheckVRTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/CheckVRTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/CohtmlHudTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/CohtmlHudTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/CohtmlHudTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/CohtmlHudTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/HudOperationsTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/HudOperationsTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/HudOperationsTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/HudOperationsTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/IKSystemTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/IKSystemTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/IKSystemTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/IKSystemTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/MetaPortTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/MetaPortTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/MetaPortTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/MetaPortTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/MovementSystemTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/MovementSystemTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/MovementSystemTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/MovementSystemTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/PlayerSetupTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/PlayerSetupTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/PlayerSetupTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/PlayerSetupTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/PortableCameraTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/PortableCameraTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/PortableCameraTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/PortableCameraTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/VRModeTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/VRModeTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/VRModeTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/VRModeTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/VRModeTrackers/ViewManagerTracker.cs b/.Deprecated/DesktopVRSwitch/VRModeTrackers/ViewManagerTracker.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/VRModeTrackers/ViewManagerTracker.cs rename to .Deprecated/DesktopVRSwitch/VRModeTrackers/ViewManagerTracker.cs diff --git a/.DepricatedMods/DesktopVRSwitch/XRHandler.cs b/.Deprecated/DesktopVRSwitch/XRHandler.cs similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/XRHandler.cs rename to .Deprecated/DesktopVRSwitch/XRHandler.cs diff --git a/.DepricatedMods/DesktopVRSwitch/format.json b/.Deprecated/DesktopVRSwitch/format.json similarity index 100% rename from .DepricatedMods/DesktopVRSwitch/format.json rename to .Deprecated/DesktopVRSwitch/format.json diff --git a/DropPropTweak/DropPropTweak.csproj b/.Deprecated/DropPropTweak/DropPropTweak.csproj similarity index 100% rename from DropPropTweak/DropPropTweak.csproj rename to .Deprecated/DropPropTweak/DropPropTweak.csproj diff --git a/DropPropTweak/Main.cs b/.Deprecated/DropPropTweak/Main.cs similarity index 99% rename from DropPropTweak/Main.cs rename to .Deprecated/DropPropTweak/Main.cs index 023ce21..b72f652 100644 --- a/DropPropTweak/Main.cs +++ b/.Deprecated/DropPropTweak/Main.cs @@ -44,6 +44,4 @@ public class DropPropTweakMod : MelonMod __instance.CharacterController.gravity = ogGravity; // restore gravity return false; } - - } \ No newline at end of file diff --git a/DropPropTweak/Properties/AssemblyInfo.cs b/.Deprecated/DropPropTweak/Properties/AssemblyInfo.cs similarity index 100% rename from DropPropTweak/Properties/AssemblyInfo.cs rename to .Deprecated/DropPropTweak/Properties/AssemblyInfo.cs diff --git a/DropPropTweak/README.md b/.Deprecated/DropPropTweak/README.md similarity index 100% rename from DropPropTweak/README.md rename to .Deprecated/DropPropTweak/README.md diff --git a/DropPropTweak/format.json b/.Deprecated/DropPropTweak/format.json similarity index 100% rename from DropPropTweak/format.json rename to .Deprecated/DropPropTweak/format.json diff --git a/.DepricatedMods/EzCurls/EzCurls.csproj b/.Deprecated/EzCurls/EzCurls.csproj similarity index 100% rename from .DepricatedMods/EzCurls/EzCurls.csproj rename to .Deprecated/EzCurls/EzCurls.csproj diff --git a/.DepricatedMods/EzCurls/InputModules/InputModuleCurlAdjuster.cs b/.Deprecated/EzCurls/InputModules/InputModuleCurlAdjuster.cs similarity index 100% rename from .DepricatedMods/EzCurls/InputModules/InputModuleCurlAdjuster.cs rename to .Deprecated/EzCurls/InputModules/InputModuleCurlAdjuster.cs diff --git a/.DepricatedMods/EzCurls/Main.cs b/.Deprecated/EzCurls/Main.cs similarity index 100% rename from .DepricatedMods/EzCurls/Main.cs rename to .Deprecated/EzCurls/Main.cs diff --git a/.DepricatedMods/EzCurls/ModSettings.cs b/.Deprecated/EzCurls/ModSettings.cs similarity index 100% rename from .DepricatedMods/EzCurls/ModSettings.cs rename to .Deprecated/EzCurls/ModSettings.cs diff --git a/.DepricatedMods/EzCurls/Properties/AssemblyInfo.cs b/.Deprecated/EzCurls/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/EzCurls/Properties/AssemblyInfo.cs rename to .Deprecated/EzCurls/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/EzCurls/README.md b/.Deprecated/EzCurls/README.md similarity index 100% rename from .DepricatedMods/EzCurls/README.md rename to .Deprecated/EzCurls/README.md diff --git a/.DepricatedMods/EzCurls/format.json b/.Deprecated/EzCurls/format.json similarity index 100% rename from .DepricatedMods/EzCurls/format.json rename to .Deprecated/EzCurls/format.json diff --git a/.DepricatedMods/EzGrab/EzGrab.csproj b/.Deprecated/EzGrab/EzGrab.csproj similarity index 100% rename from .DepricatedMods/EzGrab/EzGrab.csproj rename to .Deprecated/EzGrab/EzGrab.csproj diff --git a/.DepricatedMods/EzGrab/Main.cs b/.Deprecated/EzGrab/Main.cs similarity index 100% rename from .DepricatedMods/EzGrab/Main.cs rename to .Deprecated/EzGrab/Main.cs diff --git a/.DepricatedMods/EzGrab/Properties/AssemblyInfo.cs b/.Deprecated/EzGrab/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/EzGrab/Properties/AssemblyInfo.cs rename to .Deprecated/EzGrab/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/EzGrab/format.json b/.Deprecated/EzGrab/format.json similarity index 100% rename from .DepricatedMods/EzGrab/format.json rename to .Deprecated/EzGrab/format.json diff --git a/FOVAdjustment/FOVAdjustment.csproj b/.Deprecated/FOVAdjustment/FOVAdjustment.csproj similarity index 100% rename from FOVAdjustment/FOVAdjustment.csproj rename to .Deprecated/FOVAdjustment/FOVAdjustment.csproj diff --git a/FOVAdjustment/Main.cs b/.Deprecated/FOVAdjustment/Main.cs similarity index 94% rename from FOVAdjustment/Main.cs rename to .Deprecated/FOVAdjustment/Main.cs index a593ab0..bafb6ae 100644 --- a/FOVAdjustment/Main.cs +++ b/.Deprecated/FOVAdjustment/Main.cs @@ -55,10 +55,10 @@ public class FOVAdjustment : MelonMod private static void UpdateDesktopCameraControllerFov(float value) { - if (CVRWorld.Instance != null && Mathf.Approximately(CVRWorld.Instance.fov, 60f)) - { + // if (CVRWorld.Instance != null && Mathf.Approximately(CVRWorld.Instance.fov, 60f)) + // { CVR_DesktopCameraController.defaultFov = Mathf.Clamp(value, 60f, 120f); CVR_DesktopCameraController.zoomFov = CVR_DesktopCameraController.defaultFov * 0.5f; - } + //} } } \ No newline at end of file diff --git a/FOVAdjustment/Properties/AssemblyInfo.cs b/.Deprecated/FOVAdjustment/Properties/AssemblyInfo.cs similarity index 100% rename from FOVAdjustment/Properties/AssemblyInfo.cs rename to .Deprecated/FOVAdjustment/Properties/AssemblyInfo.cs diff --git a/FOVAdjustment/README.md b/.Deprecated/FOVAdjustment/README.md similarity index 100% rename from FOVAdjustment/README.md rename to .Deprecated/FOVAdjustment/README.md diff --git a/FOVAdjustment/format.json b/.Deprecated/FOVAdjustment/format.json similarity index 100% rename from FOVAdjustment/format.json rename to .Deprecated/FOVAdjustment/format.json diff --git a/.DepricatedMods/FuckCohtmlResourceHandler/FuckCohtmlResourceHandler.csproj b/.Deprecated/FuckCohtmlResourceHandler/FuckCohtmlResourceHandler.csproj similarity index 100% rename from .DepricatedMods/FuckCohtmlResourceHandler/FuckCohtmlResourceHandler.csproj rename to .Deprecated/FuckCohtmlResourceHandler/FuckCohtmlResourceHandler.csproj diff --git a/.DepricatedMods/FuckCohtmlResourceHandler/HarmonyPatches.cs b/.Deprecated/FuckCohtmlResourceHandler/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/FuckCohtmlResourceHandler/HarmonyPatches.cs rename to .Deprecated/FuckCohtmlResourceHandler/HarmonyPatches.cs diff --git a/.DepricatedMods/FuckCohtmlResourceHandler/Main.cs b/.Deprecated/FuckCohtmlResourceHandler/Main.cs similarity index 100% rename from .DepricatedMods/FuckCohtmlResourceHandler/Main.cs rename to .Deprecated/FuckCohtmlResourceHandler/Main.cs diff --git a/.DepricatedMods/FuckCohtmlResourceHandler/Properties/AssemblyInfo.cs b/.Deprecated/FuckCohtmlResourceHandler/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/FuckCohtmlResourceHandler/Properties/AssemblyInfo.cs rename to .Deprecated/FuckCohtmlResourceHandler/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/FuckCohtmlResourceHandler/README.md b/.Deprecated/FuckCohtmlResourceHandler/README.md similarity index 100% rename from .DepricatedMods/FuckCohtmlResourceHandler/README.md rename to .Deprecated/FuckCohtmlResourceHandler/README.md diff --git a/.DepricatedMods/FuckCohtmlResourceHandler/format.json b/.Deprecated/FuckCohtmlResourceHandler/format.json similarity index 100% rename from .DepricatedMods/FuckCohtmlResourceHandler/format.json rename to .Deprecated/FuckCohtmlResourceHandler/format.json diff --git a/.DepricatedMods/FuckMLA/FuckMLA.csproj b/.Deprecated/FuckMLA/FuckMLA.csproj similarity index 100% rename from .DepricatedMods/FuckMLA/FuckMLA.csproj rename to .Deprecated/FuckMLA/FuckMLA.csproj diff --git a/.DepricatedMods/FuckMLA/HarmonyPatches.cs b/.Deprecated/FuckMLA/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/FuckMLA/HarmonyPatches.cs rename to .Deprecated/FuckMLA/HarmonyPatches.cs diff --git a/.DepricatedMods/FuckMLA/Main.cs b/.Deprecated/FuckMLA/Main.cs similarity index 100% rename from .DepricatedMods/FuckMLA/Main.cs rename to .Deprecated/FuckMLA/Main.cs diff --git a/.DepricatedMods/FuckMLA/Properties/AssemblyInfo.cs b/.Deprecated/FuckMLA/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/FuckMLA/Properties/AssemblyInfo.cs rename to .Deprecated/FuckMLA/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/FuckMLA/format.json b/.Deprecated/FuckMLA/format.json similarity index 100% rename from .DepricatedMods/FuckMLA/format.json rename to .Deprecated/FuckMLA/format.json diff --git a/.DepricatedMods/HeadLookLockingInputFix/HeadLookLockingInputFix.csproj b/.Deprecated/FuckMagicaCloth2/FuckMagicaCloth2.csproj similarity index 100% rename from .DepricatedMods/HeadLookLockingInputFix/HeadLookLockingInputFix.csproj rename to .Deprecated/FuckMagicaCloth2/FuckMagicaCloth2.csproj diff --git a/.Deprecated/FuckMagicaCloth2/Main.cs b/.Deprecated/FuckMagicaCloth2/Main.cs new file mode 100644 index 0000000..2b1421d --- /dev/null +++ b/.Deprecated/FuckMagicaCloth2/Main.cs @@ -0,0 +1,49 @@ +using ABI_RC.Core; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Player; +using HarmonyLib; +using MagicaCloth2; +using MelonLoader; +using Unity.Burst; +using Unity.Collections; +using Unity.Jobs; +using Unity.Mathematics; +using UnityEngine; +using UnityEngine.Jobs; + +namespace NAK.FuckOffMagicaCloth2; + +public class FuckOffMagicaCloth2Mod : MelonMod +{ + private static MelonLogger.Instance Logger; + + public override void OnInitializeMelon() + { + Logger = LoggerInstance; + ApplyPatches(typeof(MagicaCloth_Patches)); + } + + private void ApplyPatches(Type type) + { + try + { + HarmonyInstance.PatchAll(type); + } + catch (Exception e) + { + LoggerInstance.Msg($"Failed while patching {type.Name}!"); + LoggerInstance.Error(e); + } + } + + internal static class MagicaCloth_Patches + { + [HarmonyPrefix] + [HarmonyPatch(typeof(MagicaCloth2.MagicaCloth), nameof(MagicaCloth2.MagicaCloth.Awake))] + private static void MagicaCloth_Awake_Prefix(MagicaCloth2.MagicaCloth __instance) + { + __instance.SerializeData.selfCollisionConstraint.selfMode = SelfCollisionConstraint.SelfCollisionMode.None; + __instance.SerializeData.selfCollisionConstraint.syncMode = SelfCollisionConstraint.SelfCollisionMode.None; + } + } +} \ No newline at end of file diff --git a/.Deprecated/FuckMagicaCloth2/Properties/AssemblyInfo.cs b/.Deprecated/FuckMagicaCloth2/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..91ab089 --- /dev/null +++ b/.Deprecated/FuckMagicaCloth2/Properties/AssemblyInfo.cs @@ -0,0 +1,30 @@ +using MelonLoader; +using NAK.FuckOffMagicaCloth2.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.FuckOffMagicaCloth2))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.FuckOffMagicaCloth2))] + +[assembly: MelonInfo( + typeof(NAK.FuckOffMagicaCloth2.FuckOffMagicaCloth2Mod), + nameof(NAK.FuckOffMagicaCloth2), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/FuckOffMagicaCloth2" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: HarmonyDontPatchAll] + +namespace NAK.FuckOffMagicaCloth2.Properties; +internal static class AssemblyInfoParams +{ + public const string Version = "1.0.1"; + public const string Author = "NotAKidoS"; +} \ No newline at end of file diff --git a/IKSimulatedRootAngleFix/README.md b/.Deprecated/FuckMagicaCloth2/README.md similarity index 100% rename from IKSimulatedRootAngleFix/README.md rename to .Deprecated/FuckMagicaCloth2/README.md diff --git a/.Deprecated/FuckMagicaCloth2/format.json b/.Deprecated/FuckMagicaCloth2/format.json new file mode 100644 index 0000000..ddf506b --- /dev/null +++ b/.Deprecated/FuckMagicaCloth2/format.json @@ -0,0 +1,24 @@ +{ + "_id": -1, + "name": "AASDefaultProfileFix", + "modversion": "1.0.0", + "gameversion": "2024r175", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Fixes the Default AAS profile not being applied when loading into an avatar without a profile selected.\n\nBy default, the game will not apply anything and the avatar will default to the state found within the Controller parameters.", + "searchtags": [ + "aas", + "profile", + "default", + "fix", + "meow" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r33/AASDefaultProfileFix.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/AASDefaultProfileFix/", + "changelog": "- Initial release", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/.DepricatedMods/FuckMetrics/FuckMetrics.csproj b/.Deprecated/FuckMetrics/FuckMetrics.csproj similarity index 100% rename from .DepricatedMods/FuckMetrics/FuckMetrics.csproj rename to .Deprecated/FuckMetrics/FuckMetrics.csproj diff --git a/.DepricatedMods/FuckMetrics/HarmonyPatches.cs b/.Deprecated/FuckMetrics/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/FuckMetrics/HarmonyPatches.cs rename to .Deprecated/FuckMetrics/HarmonyPatches.cs diff --git a/.DepricatedMods/FuckMetrics/Main.cs b/.Deprecated/FuckMetrics/Main.cs similarity index 100% rename from .DepricatedMods/FuckMetrics/Main.cs rename to .Deprecated/FuckMetrics/Main.cs diff --git a/.DepricatedMods/FuckMetrics/ManagedLibs/.keep b/.Deprecated/FuckMetrics/ManagedLibs/.keep similarity index 100% rename from .DepricatedMods/FuckMetrics/ManagedLibs/.keep rename to .Deprecated/FuckMetrics/ManagedLibs/.keep diff --git a/.DepricatedMods/FuckMetrics/Properties/AssemblyInfo.cs b/.Deprecated/FuckMetrics/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/FuckMetrics/Properties/AssemblyInfo.cs rename to .Deprecated/FuckMetrics/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/FuckMetrics/format.json b/.Deprecated/FuckMetrics/format.json similarity index 100% rename from .DepricatedMods/FuckMetrics/format.json rename to .Deprecated/FuckMetrics/format.json diff --git a/.Deprecated/FuckOffUICamera/CohtmlRenderForwarder.cs b/.Deprecated/FuckOffUICamera/CohtmlRenderForwarder.cs new file mode 100644 index 0000000..5f5dd2a --- /dev/null +++ b/.Deprecated/FuckOffUICamera/CohtmlRenderForwarder.cs @@ -0,0 +1,35 @@ +using ABI_RC.Core.UI; +using UnityEngine; + +namespace NAK.FuckOffUICamera; + +[RequireComponent(typeof(Camera))] +public class CohtmlRenderForwarder : MonoBehaviour +{ + #region Private Variables + + private CohtmlControlledView[] controlledViews; + + #endregion Private Variables + + #region Unity Events + + private void OnPreRender() + { + if (controlledViews == null) return; + foreach (CohtmlControlledView view in controlledViews) + if (view) view.OnPreRender(); + } + + #endregion Unity Events + + #region Public Methods + + public static void Setup(Camera camera, params CohtmlControlledView[] views) + { + CohtmlRenderForwarder forwarder = camera.gameObject.AddComponent(); + forwarder.controlledViews = views; + } + + #endregion Public Methods +} \ No newline at end of file diff --git a/.Deprecated/FuckOffUICamera/CommandBufferManager.cs b/.Deprecated/FuckOffUICamera/CommandBufferManager.cs new file mode 100644 index 0000000..aa76f1f --- /dev/null +++ b/.Deprecated/FuckOffUICamera/CommandBufferManager.cs @@ -0,0 +1,144 @@ +using System.Collections; +using UnityEngine; +using UnityEngine.Rendering; + +namespace NAK.FuckOffUICamera; + +public class CommandBufferManager : MonoBehaviour +{ + #region Private Variables + + private CommandBuffer commandBuffer; + private Camera targetCamera; + private Renderer[] targetRenderers; + private bool[] rendererEnabledStates; + private const string CommandBufferName = "CustomRenderPass"; + private bool _didSetup; + + #endregion Private Variables + + #region Unity Events + + private IEnumerator Start() + { + yield return new WaitForSeconds(2f); // I have no idea why this needs to be delayed + _didSetup = true; + OnEnable(); + } + + private void OnEnable() + { + if (!_didSetup) return; + if (targetCamera == null || targetRenderers == null) + return; + + SetupEnabledStateCollection(); + SetupCommandBuffer(); + } + + private void OnDisable() + { + CleanupCommandBuffer(); + } + + private void LateUpdate() + { + if (targetRenderers == null + || rendererEnabledStates == null) + return; + + bool needsRebuild = false; + + // Check if any renderer enabled states have changed + int targetRenderersLength = targetRenderers.Length; + for (int i = 0; i < targetRenderersLength; i++) + { + if (targetRenderers[i] == null) continue; + + bool currentState = targetRenderers[i].enabled && targetRenderers[i].gameObject.activeInHierarchy; + if (currentState == rendererEnabledStates[i]) + continue; + + rendererEnabledStates[i] = currentState; + needsRebuild = true; + } + + if (needsRebuild) RebuildCommandBuffer(); + } + + #endregion Unity Events + + #region Public Methods + + public static void Setup(Camera camera, params Renderer[] renderers) + { + CommandBufferManager manager = camera.gameObject.AddComponent(); + manager.targetCamera = camera; + manager.targetRenderers = renderers; + } + + #endregion Public Methods + + #region Private Methods + + private void SetupEnabledStateCollection() + { + if (rendererEnabledStates != null) + Array.Resize(ref rendererEnabledStates, targetRenderers.Length); + else + rendererEnabledStates = new bool[targetRenderers.Length]; + } + + private void SetupCommandBuffer() + { + commandBuffer = new CommandBuffer(); + commandBuffer.name = CommandBufferName; + + // Set render target and clear depth + commandBuffer.SetRenderTarget(new RenderTargetIdentifier(BuiltinRenderTextureType.CameraTarget, + 0, CubemapFace.Unknown, RenderTargetIdentifier.AllDepthSlices)); + + commandBuffer.ClearRenderTarget(true, false, Color.clear); + + for (int i = 0; i < targetRenderers.Length; i++) + { + Renderer renderer = targetRenderers[i]; + if (renderer == null || !rendererEnabledStates[i]) + continue; + + commandBuffer.DrawRenderer(renderer, renderer.sharedMaterial); + renderer.forceRenderingOff = true; + } + + targetCamera.AddCommandBuffer(CameraEvent.AfterImageEffects, commandBuffer); + + Debug.Log($"Command buffer setup for {targetCamera.name} with {targetRenderers.Length} renderers."); + } + + private void RebuildCommandBuffer() + { + CleanupCommandBuffer(); + SetupCommandBuffer(); + } + + private void CleanupCommandBuffer() + { + if (targetCamera == null || commandBuffer == null) + return; + + // Re-enable normal rendering for all renderers + if (targetRenderers != null) + { + foreach (Renderer renderer in targetRenderers) + { + if (renderer != null) + renderer.forceRenderingOff = false; + } + } + + targetCamera.RemoveCommandBuffer(CameraEvent.AfterImageEffects, commandBuffer); + commandBuffer = null; + } + + #endregion Private Methods +} \ No newline at end of file diff --git a/.DepricatedMods/NoDepthOnlyFlat/NoDepthOnlyFlat.csproj b/.Deprecated/FuckOffUICamera/FuckOffUICamera.csproj similarity index 100% rename from .DepricatedMods/NoDepthOnlyFlat/NoDepthOnlyFlat.csproj rename to .Deprecated/FuckOffUICamera/FuckOffUICamera.csproj diff --git a/.Deprecated/FuckOffUICamera/Main.cs b/.Deprecated/FuckOffUICamera/Main.cs new file mode 100644 index 0000000..e4c9092 --- /dev/null +++ b/.Deprecated/FuckOffUICamera/Main.cs @@ -0,0 +1,73 @@ +using System.Reflection; +using ABI_RC.Core; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Player; +using ABI_RC.Core.UI; +using HarmonyLib; +using MelonLoader; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace NAK.FuckOffUICamera; + +public class FuckOffUICameraMod : MelonMod +{ + private static MelonLogger.Instance Logger; + + public override void OnInitializeMelon() + { + Logger = LoggerInstance; + } + + public override void OnSceneWasLoaded(int buildIndex, string sceneName) + { + if (buildIndex != 2) return; + if (_isInitialized) return; + SetupShittyMod(); + _isInitialized = true; + } + + private bool _isInitialized; + + private static void SetupShittyMod() + { + // Find all renderers under Cohtml object + GameObject cohtml = GameObject.Find("Cohtml"); + if (cohtml == null) + { + Logger.Error("Cohtml object not found!"); + return; + } + + // Find all CohtmlControlledView objects + var allMenuCohtml = Object.FindObjectsOfType(includeInactive: true); + var allUiInternalRenderers = Object.FindObjectsOfType(includeInactive: true) + .Where(x => x.gameObject.layer == CVRLayers.UIInternal) + .ToArray(); + + //var allMenuRenderers = cohtml.GetComponentsInChildren(true); + + // Add hud renderer to the list of renderers + Renderer hudRenderer = CohtmlHud.Instance.GetComponent(); + // Array.Resize(ref allMenuRenderers, allMenuRenderers.Length + 1); + // allMenuRenderers[^1] = hudRenderer; + + // Fix shader on the hud renderer + Material material = hudRenderer.sharedMaterial; + material.shader = Shader.Find("Alpha Blend Interactive/MenuFX"); + + // Setup command buffer manager for desktop camera + CommandBufferManager.Setup(PlayerSetup.Instance.desktopCam, allUiInternalRenderers); + CohtmlRenderForwarder.Setup(PlayerSetup.Instance.desktopCam, allMenuCohtml); + + // Setup command buffer manager for vr camera + CommandBufferManager.Setup(PlayerSetup.Instance.vrCam, allUiInternalRenderers); + CohtmlRenderForwarder.Setup(PlayerSetup.Instance.vrCam, allMenuCohtml); + + // Disable the ui cameras + PlayerSetup.Instance.desktopUiCam.gameObject.SetActive(false); + PlayerSetup.Instance.vrUiCam.gameObject.SetActive(false); + + Logger.Msg("Disabled UI cameras and setup command buffer manager for Cohtml renderers."); + } +} \ No newline at end of file diff --git a/PhysicsGunMod/Properties/AssemblyInfo.cs b/.Deprecated/FuckOffUICamera/Properties/AssemblyInfo.cs similarity index 67% rename from PhysicsGunMod/Properties/AssemblyInfo.cs rename to .Deprecated/FuckOffUICamera/Properties/AssemblyInfo.cs index df4ffd2..b7a9e9f 100644 --- a/PhysicsGunMod/Properties/AssemblyInfo.cs +++ b/.Deprecated/FuckOffUICamera/Properties/AssemblyInfo.cs @@ -1,30 +1,30 @@ using MelonLoader; -using NAK.PhysicsGunMod.Properties; +using NAK.FuckOffUICamera.Properties; using System.Reflection; [assembly: AssemblyVersion(AssemblyInfoParams.Version)] [assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] [assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] -[assembly: AssemblyTitle(nameof(NAK.PhysicsGunMod))] +[assembly: AssemblyTitle(nameof(NAK.FuckOffUICamera))] [assembly: AssemblyCompany(AssemblyInfoParams.Author)] -[assembly: AssemblyProduct(nameof(NAK.PhysicsGunMod))] +[assembly: AssemblyProduct(nameof(NAK.FuckOffUICamera))] [assembly: MelonInfo( - typeof(NAK.PhysicsGunMod.PhysicsGunMod), - nameof(NAK.PhysicsGunMod), + typeof(NAK.FuckOffUICamera.FuckOffUICameraMod), + nameof(NAK.FuckOffUICamera), AssemblyInfoParams.Version, AssemblyInfoParams.Author, - downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/PhysicsGunMod" + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/FuckOffUICamera" )] [assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] -[assembly: MelonColor(255, 241, 200, 82)] -[assembly: MelonAuthorColor(255, 114, 17, 25)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red [assembly: HarmonyDontPatchAll] -namespace NAK.PhysicsGunMod.Properties; +namespace NAK.FuckOffUICamera.Properties; internal static class AssemblyInfoParams { public const string Version = "1.0.0"; diff --git a/.Deprecated/FuckOffUICamera/README.md b/.Deprecated/FuckOffUICamera/README.md new file mode 100644 index 0000000..1c4c5bc --- /dev/null +++ b/.Deprecated/FuckOffUICamera/README.md @@ -0,0 +1,14 @@ +# SearchWithSpacesFix + +Fixes search terms that use spaces. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation 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/.Deprecated/FuckOffUICamera/format.json b/.Deprecated/FuckOffUICamera/format.json new file mode 100644 index 0000000..f8950ca --- /dev/null +++ b/.Deprecated/FuckOffUICamera/format.json @@ -0,0 +1,23 @@ +{ + "_id": -1, + "name": "SearchWithSpacesFix", + "modversion": "1.0.0", + "gameversion": "2024r177", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Fixes search terms that include spaces.", + "searchtags": [ + "search", + "spaces", + "fix", + "meow" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r42/SearchWithSpacesFix.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/SearchWithSpacesFix/", + "changelog": "- Initial release", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/.DepricatedMods/FuckVivox/FuckVivox.csproj b/.Deprecated/FuckVivox/FuckVivox.csproj similarity index 100% rename from .DepricatedMods/FuckVivox/FuckVivox.csproj rename to .Deprecated/FuckVivox/FuckVivox.csproj diff --git a/.DepricatedMods/FuckVivox/HarmonyPatches.cs b/.Deprecated/FuckVivox/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/FuckVivox/HarmonyPatches.cs rename to .Deprecated/FuckVivox/HarmonyPatches.cs diff --git a/.DepricatedMods/FuckVivox/Main.cs b/.Deprecated/FuckVivox/Main.cs similarity index 100% rename from .DepricatedMods/FuckVivox/Main.cs rename to .Deprecated/FuckVivox/Main.cs diff --git a/.DepricatedMods/FuckVivox/Properties/AssemblyInfo.cs b/.Deprecated/FuckVivox/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/FuckVivox/Properties/AssemblyInfo.cs rename to .Deprecated/FuckVivox/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/FuckVivox/VivoxHelpers.cs b/.Deprecated/FuckVivox/VivoxHelpers.cs similarity index 100% rename from .DepricatedMods/FuckVivox/VivoxHelpers.cs rename to .Deprecated/FuckVivox/VivoxHelpers.cs diff --git a/.DepricatedMods/FuckVivox/WindowFocusManager.cs b/.Deprecated/FuckVivox/WindowFocusManager.cs similarity index 100% rename from .DepricatedMods/FuckVivox/WindowFocusManager.cs rename to .Deprecated/FuckVivox/WindowFocusManager.cs diff --git a/.DepricatedMods/FuckVivox/format.json b/.Deprecated/FuckVivox/format.json similarity index 100% rename from .DepricatedMods/FuckVivox/format.json rename to .Deprecated/FuckVivox/format.json diff --git a/GestureLock/GestureLock.csproj b/.Deprecated/GestureLock/GestureLock.csproj similarity index 100% rename from GestureLock/GestureLock.csproj rename to .Deprecated/GestureLock/GestureLock.csproj diff --git a/GestureLock/HarmonyPatches.cs b/.Deprecated/GestureLock/HarmonyPatches.cs similarity index 100% rename from GestureLock/HarmonyPatches.cs rename to .Deprecated/GestureLock/HarmonyPatches.cs diff --git a/GestureLock/Main.cs b/.Deprecated/GestureLock/Main.cs similarity index 100% rename from GestureLock/Main.cs rename to .Deprecated/GestureLock/Main.cs diff --git a/GestureLock/Properties/AssemblyInfo.cs b/.Deprecated/GestureLock/Properties/AssemblyInfo.cs similarity index 100% rename from GestureLock/Properties/AssemblyInfo.cs rename to .Deprecated/GestureLock/Properties/AssemblyInfo.cs diff --git a/GestureLock/README.md b/.Deprecated/GestureLock/README.md similarity index 100% rename from GestureLock/README.md rename to .Deprecated/GestureLock/README.md diff --git a/GestureLock/format.json b/.Deprecated/GestureLock/format.json similarity index 100% rename from GestureLock/format.json rename to .Deprecated/GestureLock/format.json diff --git a/.DepricatedMods/HeadBobbingFix/HarmonyPatches.cs b/.Deprecated/HeadBobbingFix/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/HeadBobbingFix/HarmonyPatches.cs rename to .Deprecated/HeadBobbingFix/HarmonyPatches.cs diff --git a/.DepricatedMods/HeadBobbingFix/HeadBobbingFix.csproj b/.Deprecated/HeadBobbingFix/HeadBobbingFix.csproj similarity index 100% rename from .DepricatedMods/HeadBobbingFix/HeadBobbingFix.csproj rename to .Deprecated/HeadBobbingFix/HeadBobbingFix.csproj diff --git a/.DepricatedMods/HeadBobbingFix/Main.cs b/.Deprecated/HeadBobbingFix/Main.cs similarity index 100% rename from .DepricatedMods/HeadBobbingFix/Main.cs rename to .Deprecated/HeadBobbingFix/Main.cs diff --git a/.DepricatedMods/HeadBobbingFix/Properties/AssemblyInfo.cs b/.Deprecated/HeadBobbingFix/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/HeadBobbingFix/Properties/AssemblyInfo.cs rename to .Deprecated/HeadBobbingFix/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/HeadBobbingFix/README.md b/.Deprecated/HeadBobbingFix/README.md similarity index 100% rename from .DepricatedMods/HeadBobbingFix/README.md rename to .Deprecated/HeadBobbingFix/README.md diff --git a/.DepricatedMods/HeadBobbingFix/format.json b/.Deprecated/HeadBobbingFix/format.json similarity index 100% rename from .DepricatedMods/HeadBobbingFix/format.json rename to .Deprecated/HeadBobbingFix/format.json diff --git a/ReconnectionSystemFix/ReconnectionSystemFix.csproj b/.Deprecated/HeadLookLockingInputFix/HeadLookLockingInputFix.csproj similarity index 100% rename from ReconnectionSystemFix/ReconnectionSystemFix.csproj rename to .Deprecated/HeadLookLockingInputFix/HeadLookLockingInputFix.csproj diff --git a/.DepricatedMods/HeadLookLockingInputFix/Main.cs b/.Deprecated/HeadLookLockingInputFix/Main.cs similarity index 100% rename from .DepricatedMods/HeadLookLockingInputFix/Main.cs rename to .Deprecated/HeadLookLockingInputFix/Main.cs diff --git a/.DepricatedMods/HeadLookLockingInputFix/Properties/AssemblyInfo.cs b/.Deprecated/HeadLookLockingInputFix/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/HeadLookLockingInputFix/Properties/AssemblyInfo.cs rename to .Deprecated/HeadLookLockingInputFix/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/HeadLookLockingInputFix/README.md b/.Deprecated/HeadLookLockingInputFix/README.md similarity index 100% rename from .DepricatedMods/HeadLookLockingInputFix/README.md rename to .Deprecated/HeadLookLockingInputFix/README.md diff --git a/.DepricatedMods/HeadLookLockingInputFix/format.json b/.Deprecated/HeadLookLockingInputFix/format.json similarity index 100% rename from .DepricatedMods/HeadLookLockingInputFix/format.json rename to .Deprecated/HeadLookLockingInputFix/format.json diff --git a/.DepricatedMods/IKAdjustments/HarmonyPatches.cs b/.Deprecated/IKAdjustments/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/IKAdjustments/HarmonyPatches.cs rename to .Deprecated/IKAdjustments/HarmonyPatches.cs diff --git a/.DepricatedMods/IKAdjustments/IKAdjuster.cs b/.Deprecated/IKAdjustments/IKAdjuster.cs similarity index 100% rename from .DepricatedMods/IKAdjustments/IKAdjuster.cs rename to .Deprecated/IKAdjustments/IKAdjuster.cs diff --git a/.DepricatedMods/IKAdjustments/IKAdjustments.csproj b/.Deprecated/IKAdjustments/IKAdjustments.csproj similarity index 100% rename from .DepricatedMods/IKAdjustments/IKAdjustments.csproj rename to .Deprecated/IKAdjustments/IKAdjustments.csproj diff --git a/.DepricatedMods/IKAdjustments/Integrations/BTKUIAddon.cs b/.Deprecated/IKAdjustments/Integrations/BTKUIAddon.cs similarity index 100% rename from .DepricatedMods/IKAdjustments/Integrations/BTKUIAddon.cs rename to .Deprecated/IKAdjustments/Integrations/BTKUIAddon.cs diff --git a/.DepricatedMods/IKAdjustments/Main.cs b/.Deprecated/IKAdjustments/Main.cs similarity index 100% rename from .DepricatedMods/IKAdjustments/Main.cs rename to .Deprecated/IKAdjustments/Main.cs diff --git a/.DepricatedMods/IKAdjustments/Properties/AssemblyInfo.cs b/.Deprecated/IKAdjustments/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/IKAdjustments/Properties/AssemblyInfo.cs rename to .Deprecated/IKAdjustments/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/IKFixes/HarmonyPatches.cs b/.Deprecated/IKFixes/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/IKFixes/HarmonyPatches.cs rename to .Deprecated/IKFixes/HarmonyPatches.cs diff --git a/.DepricatedMods/IKFixes/IKFixes.csproj b/.Deprecated/IKFixes/IKFixes.csproj similarity index 100% rename from .DepricatedMods/IKFixes/IKFixes.csproj rename to .Deprecated/IKFixes/IKFixes.csproj diff --git a/.DepricatedMods/IKFixes/Integrations/UIExKitAddon.cs b/.Deprecated/IKFixes/Integrations/UIExKitAddon.cs similarity index 100% rename from .DepricatedMods/IKFixes/Integrations/UIExKitAddon.cs rename to .Deprecated/IKFixes/Integrations/UIExKitAddon.cs diff --git a/.DepricatedMods/IKFixes/Main.cs b/.Deprecated/IKFixes/Main.cs similarity index 100% rename from .DepricatedMods/IKFixes/Main.cs rename to .Deprecated/IKFixes/Main.cs diff --git a/.DepricatedMods/IKFixes/Properties/AssemblyInfo.cs b/.Deprecated/IKFixes/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/IKFixes/Properties/AssemblyInfo.cs rename to .Deprecated/IKFixes/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/IKFixes/README.md b/.Deprecated/IKFixes/README.md similarity index 100% rename from .DepricatedMods/IKFixes/README.md rename to .Deprecated/IKFixes/README.md diff --git a/.DepricatedMods/IKFixes/format.json b/.Deprecated/IKFixes/format.json similarity index 100% rename from .DepricatedMods/IKFixes/format.json rename to .Deprecated/IKFixes/format.json diff --git a/IKSimulatedRootAngleFix/IKSimulatedRootAngleFix.csproj b/.Deprecated/IKSimulatedRootAngleFix/IKSimulatedRootAngleFix.csproj similarity index 100% rename from IKSimulatedRootAngleFix/IKSimulatedRootAngleFix.csproj rename to .Deprecated/IKSimulatedRootAngleFix/IKSimulatedRootAngleFix.csproj diff --git a/IKSimulatedRootAngleFix/Main.cs b/.Deprecated/IKSimulatedRootAngleFix/Main.cs similarity index 100% rename from IKSimulatedRootAngleFix/Main.cs rename to .Deprecated/IKSimulatedRootAngleFix/Main.cs diff --git a/IKSimulatedRootAngleFix/Properties/AssemblyInfo.cs b/.Deprecated/IKSimulatedRootAngleFix/Properties/AssemblyInfo.cs similarity index 100% rename from IKSimulatedRootAngleFix/Properties/AssemblyInfo.cs rename to .Deprecated/IKSimulatedRootAngleFix/Properties/AssemblyInfo.cs diff --git a/.Deprecated/IKSimulatedRootAngleFix/README.md b/.Deprecated/IKSimulatedRootAngleFix/README.md new file mode 100644 index 0000000..8a46af2 --- /dev/null +++ b/.Deprecated/IKSimulatedRootAngleFix/README.md @@ -0,0 +1,14 @@ +# IKSimulatedRootAngleFix + +Fixes a small issue with Desktop & HalfBody root angle being incorrectly calculated while on rotating Movement Parents. If you've ever noticed your body/feet insisting on facing opposite of the direction you are rotating, this fixes that. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation 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/IKSimulatedRootAngleFix/format.json b/.Deprecated/IKSimulatedRootAngleFix/format.json similarity index 100% rename from IKSimulatedRootAngleFix/format.json rename to .Deprecated/IKSimulatedRootAngleFix/format.json diff --git a/.DepricatedMods/InteractionTest/AutoArmIK.cs b/.Deprecated/InteractionTest/AutoArmIK.cs similarity index 100% rename from .DepricatedMods/InteractionTest/AutoArmIK.cs rename to .Deprecated/InteractionTest/AutoArmIK.cs diff --git a/.DepricatedMods/InteractionTest/ColliderTest/AvatarColliderStruct.cs b/.Deprecated/InteractionTest/ColliderTest/AvatarColliderStruct.cs similarity index 100% rename from .DepricatedMods/InteractionTest/ColliderTest/AvatarColliderStruct.cs rename to .Deprecated/InteractionTest/ColliderTest/AvatarColliderStruct.cs diff --git a/.DepricatedMods/InteractionTest/ColliderTest/AvatarColliders.cs b/.Deprecated/InteractionTest/ColliderTest/AvatarColliders.cs similarity index 100% rename from .DepricatedMods/InteractionTest/ColliderTest/AvatarColliders.cs rename to .Deprecated/InteractionTest/ColliderTest/AvatarColliders.cs diff --git a/.DepricatedMods/InteractionTest/ColliderTest/LineColliderTest.cs b/.Deprecated/InteractionTest/ColliderTest/LineColliderTest.cs similarity index 100% rename from .DepricatedMods/InteractionTest/ColliderTest/LineColliderTest.cs rename to .Deprecated/InteractionTest/ColliderTest/LineColliderTest.cs diff --git a/.DepricatedMods/InteractionTest/GrabbableAvatar.cs b/.Deprecated/InteractionTest/GrabbableAvatar.cs similarity index 100% rename from .DepricatedMods/InteractionTest/GrabbableAvatar.cs rename to .Deprecated/InteractionTest/GrabbableAvatar.cs diff --git a/.DepricatedMods/InteractionTest/GrabbingAvatar.cs b/.Deprecated/InteractionTest/GrabbingAvatar.cs similarity index 100% rename from .DepricatedMods/InteractionTest/GrabbingAvatar.cs rename to .Deprecated/InteractionTest/GrabbingAvatar.cs diff --git a/.DepricatedMods/InteractionTest/HarmonyPatches.cs b/.Deprecated/InteractionTest/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/InteractionTest/HarmonyPatches.cs rename to .Deprecated/InteractionTest/HarmonyPatches.cs diff --git a/.DepricatedMods/InteractionTest/InteractionTest.csproj b/.Deprecated/InteractionTest/InteractionTest.csproj similarity index 100% rename from .DepricatedMods/InteractionTest/InteractionTest.csproj rename to .Deprecated/InteractionTest/InteractionTest.csproj diff --git a/.DepricatedMods/InteractionTest/Main.cs b/.Deprecated/InteractionTest/Main.cs similarity index 100% rename from .DepricatedMods/InteractionTest/Main.cs rename to .Deprecated/InteractionTest/Main.cs diff --git a/.DepricatedMods/InteractionTest/Properties/AssemblyInfo.cs b/.Deprecated/InteractionTest/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/InteractionTest/Properties/AssemblyInfo.cs rename to .Deprecated/InteractionTest/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/InteractionTest/README.md b/.Deprecated/InteractionTest/README.md similarity index 100% rename from .DepricatedMods/InteractionTest/README.md rename to .Deprecated/InteractionTest/README.md diff --git a/AvatarScaleMod/format.json b/.Deprecated/InteractionTest/format.json similarity index 100% rename from AvatarScaleMod/format.json rename to .Deprecated/InteractionTest/format.json diff --git a/.DepricatedMods/JumpPatch/HarmonyPatches.cs b/.Deprecated/JumpPatch/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/JumpPatch/HarmonyPatches.cs rename to .Deprecated/JumpPatch/HarmonyPatches.cs diff --git a/.DepricatedMods/JumpPatch/JumpPatch.csproj b/.Deprecated/JumpPatch/JumpPatch.csproj similarity index 100% rename from .DepricatedMods/JumpPatch/JumpPatch.csproj rename to .Deprecated/JumpPatch/JumpPatch.csproj diff --git a/.DepricatedMods/JumpPatch/Main.cs b/.Deprecated/JumpPatch/Main.cs similarity index 100% rename from .DepricatedMods/JumpPatch/Main.cs rename to .Deprecated/JumpPatch/Main.cs diff --git a/.DepricatedMods/JumpPatch/Properties/AssemblyInfo.cs b/.Deprecated/JumpPatch/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/JumpPatch/Properties/AssemblyInfo.cs rename to .Deprecated/JumpPatch/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/JumpPatch/format.json b/.Deprecated/JumpPatch/format.json similarity index 100% rename from .DepricatedMods/JumpPatch/format.json rename to .Deprecated/JumpPatch/format.json diff --git a/.DepricatedMods/LateInitComponentHelperHack/LateInitComponentHelperHack.csproj b/.Deprecated/LateInitComponentHelperHack/LateInitComponentHelperHack.csproj similarity index 100% rename from .DepricatedMods/LateInitComponentHelperHack/LateInitComponentHelperHack.csproj rename to .Deprecated/LateInitComponentHelperHack/LateInitComponentHelperHack.csproj diff --git a/.DepricatedMods/LateInitComponentHelperHack/Main.cs b/.Deprecated/LateInitComponentHelperHack/Main.cs similarity index 100% rename from .DepricatedMods/LateInitComponentHelperHack/Main.cs rename to .Deprecated/LateInitComponentHelperHack/Main.cs diff --git a/.DepricatedMods/LateInitComponentHelperHack/Properties/AssemblyInfo.cs b/.Deprecated/LateInitComponentHelperHack/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/LateInitComponentHelperHack/Properties/AssemblyInfo.cs rename to .Deprecated/LateInitComponentHelperHack/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/LateInitComponentHelperHack/format.json b/.Deprecated/LateInitComponentHelperHack/format.json similarity index 100% rename from .DepricatedMods/LateInitComponentHelperHack/format.json rename to .Deprecated/LateInitComponentHelperHack/format.json diff --git a/LegacyContentMitigation/Components/CameraCallbackLogger.cs b/.Deprecated/LegacyContentMitigation/Components/CameraCallbackLogger.cs similarity index 100% rename from LegacyContentMitigation/Components/CameraCallbackLogger.cs rename to .Deprecated/LegacyContentMitigation/Components/CameraCallbackLogger.cs diff --git a/.Deprecated/LegacyContentMitigation/Components/FaceMirror.cs b/.Deprecated/LegacyContentMitigation/Components/FaceMirror.cs new file mode 100644 index 0000000..65f3e3b --- /dev/null +++ b/.Deprecated/LegacyContentMitigation/Components/FaceMirror.cs @@ -0,0 +1,100 @@ +using ABI_RC.Core; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using NAK.LegacyContentMitigation; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.XR; + +namespace LegacyContentMitigation.Components; + +public class FaceMirror : MonoBehaviour +{ + private Camera _parentCamera; + private Camera _camera; + public Rect shiftRect; + private CommandBuffer _viewportBuffer; + + private void Start() { + _parentCamera = GetComponent(); + _camera = new GameObject("Face Mirror").AddComponent(); + _camera.transform.parent = transform; + _camera.CopyFrom(_parentCamera); + _camera.ResetReplacementShader(); + _camera.depth = 99; + _camera.clearFlags = CameraClearFlags.Depth; + _camera.transform.position += transform.forward * 0.5f; + _camera.transform.rotation *= Quaternion.Euler(0, 180, 0); + + // View only CVRLayers.PlayerLocal + _camera.cullingMask = 1 << CVRLayers.PlayerLocal; + + // Create and cache the command buffer + _viewportBuffer = new CommandBuffer(); + _viewportBuffer.SetViewport(shiftRect); + + _camera.AddCommandBuffer(CameraEvent.BeforeDepthTexture, _viewportBuffer); + _camera.AddCommandBuffer(CameraEvent.BeforeForwardOpaque, _viewportBuffer); + _camera.AddCommandBuffer(CameraEvent.BeforeForwardAlpha, _viewportBuffer); + _camera.AddCommandBuffer(CameraEvent.BeforeImageEffects, _viewportBuffer); + } + + private void Update() + { + if (ModSettings.EntryUseFaceMirror.Value == false) + { + _camera.enabled = false; + return; + } + _camera.enabled = true; + + // Update camera distance + _camera.transform.localPosition = Vector3.forward * ModSettings.EntryFaceMirrorDistance.Value; + + // Get the display resolution based on VR status + int displayWidth, displayHeight; + if (MetaPort.Instance.isUsingVr) + { + displayWidth = XRSettings.eyeTextureWidth; + displayHeight = XRSettings.eyeTextureHeight; + } + else + { + displayWidth = Screen.width; + displayHeight = Screen.height; + } + + // Calculate pixel sizes first + float pixelSizeX = ModSettings.EntryFaceMirrorSizeX.Value * displayWidth; + float pixelSizeY = ModSettings.EntryFaceMirrorSizeY.Value * displayHeight; + + // Calculate offsets from center + float pixelOffsetX = (ModSettings.EntryFaceMirrorOffsetX.Value * displayWidth) - (pixelSizeX * 0.5f) + (displayWidth * 0.5f); + float pixelOffsetY = (ModSettings.EntryFaceMirrorOffsetY.Value * displayHeight) - (pixelSizeY * 0.5f) + (displayHeight * 0.5f); + + _camera.transform.localScale = Vector3.one * ModSettings.EntryFaceMirrorCameraScale.Value; + + Vector3 playerup = PlayerSetup.Instance.transform.up; + Vector3 cameraForward = _parentCamera.transform.forward; + + // Check if playerup and cameraForward are nearly aligned + if (Mathf.Abs(Vector3.Dot(playerup, cameraForward)) <= Mathf.Epsilon) { + playerup = -_parentCamera.transform.forward; + cameraForward = _parentCamera.transform.up; + } + + _camera.transform.rotation = Quaternion.LookRotation(-cameraForward, playerup); + + // Create viewport rect with pixel values + shiftRect = new Rect( + pixelOffsetX, + pixelOffsetY, + pixelSizeX, + pixelSizeY + ); + + // Update the cached buffer's viewport + _viewportBuffer.Clear(); + _viewportBuffer.SetViewport(shiftRect); + } +} \ No newline at end of file diff --git a/LegacyContentMitigation/Components/FakeMultiPassHack.cs b/.Deprecated/LegacyContentMitigation/Components/FakeMultiPassHack.cs similarity index 100% rename from LegacyContentMitigation/Components/FakeMultiPassHack.cs rename to .Deprecated/LegacyContentMitigation/Components/FakeMultiPassHack.cs diff --git a/LegacyContentMitigation/Integrations/BtkUiAddon.cs b/.Deprecated/LegacyContentMitigation/Integrations/BtkUiAddon.cs similarity index 100% rename from LegacyContentMitigation/Integrations/BtkUiAddon.cs rename to .Deprecated/LegacyContentMitigation/Integrations/BtkUiAddon.cs diff --git a/LegacyContentMitigation/LegacyContentMitigation.csproj b/.Deprecated/LegacyContentMitigation/LegacyContentMitigation.csproj similarity index 100% rename from LegacyContentMitigation/LegacyContentMitigation.csproj rename to .Deprecated/LegacyContentMitigation/LegacyContentMitigation.csproj diff --git a/LegacyContentMitigation/Main.cs b/.Deprecated/LegacyContentMitigation/Main.cs similarity index 100% rename from LegacyContentMitigation/Main.cs rename to .Deprecated/LegacyContentMitigation/Main.cs diff --git a/.Deprecated/LegacyContentMitigation/ModSettings.cs b/.Deprecated/LegacyContentMitigation/ModSettings.cs new file mode 100644 index 0000000..a20c93d --- /dev/null +++ b/.Deprecated/LegacyContentMitigation/ModSettings.cs @@ -0,0 +1,52 @@ +using MelonLoader; + +namespace NAK.LegacyContentMitigation; + +internal static class ModSettings +{ + #region Constants + + internal const string ModName = nameof(LegacyContentMitigation); + internal const string LCM_SettingsCategory = "Legacy Content Mitigation"; + + #endregion Constants + + #region Melon Preferences + + private static readonly MelonPreferences_Category Category = + MelonPreferences.CreateCategory(ModName); + + internal static readonly MelonPreferences_Entry EntryAutoForLegacyWorlds = + Category.CreateEntry("auto_for_legacy_worlds", true, + "Auto For Legacy Worlds", description: "Should Legacy View be auto enabled for detected Legacy worlds?"); + + internal static readonly MelonPreferences_Entry EntryFaceMirrorDistance = + Category.CreateEntry("face_mirror_distance", 0.5f, + "Face Mirror Distance", description: "Distance from the camera to place the face mirror."); + + internal static readonly MelonPreferences_Entry EntryFaceMirrorOffsetX = + Category.CreateEntry("face_mirror_offset_x", 0f, + "Face Mirror Offset X", description: "Offset the face mirror on the X axis."); + + internal static readonly MelonPreferences_Entry EntryFaceMirrorOffsetY = + Category.CreateEntry("face_mirror_offset_y", 0f, + "Face Mirror Offset Y", description: "Offset the face mirror on the Y axis."); + + internal static readonly MelonPreferences_Entry EntryFaceMirrorSizeX = + Category.CreateEntry("face_mirror_size_x", 0.5f, + "Face Mirror Size X", description: "Size of the face mirror on the X axis."); + + internal static readonly MelonPreferences_Entry EntryFaceMirrorSizeY = + Category.CreateEntry("face_mirror_size_y", 0.5f, + "Face Mirror Size Y", description: "Size of the face mirror on the Y axis."); + + internal static readonly MelonPreferences_Entry EntryFaceMirrorCameraScale = + Category.CreateEntry("face_mirror_camera_scale", 1f, + "Face Mirror Camera Scale", description: "Scale of the face mirror camera."); + + internal static readonly MelonPreferences_Entry EntryUseFaceMirror = + Category.CreateEntry("use_face_mirror", true, + "Use Face Mirror", description: "Should the face mirror be used?"); + + #endregion Melon Preferences +} \ No newline at end of file diff --git a/LegacyContentMitigation/Patches.cs b/.Deprecated/LegacyContentMitigation/Patches.cs similarity index 97% rename from LegacyContentMitigation/Patches.cs rename to .Deprecated/LegacyContentMitigation/Patches.cs index 2b151e8..a389282 100644 --- a/LegacyContentMitigation/Patches.cs +++ b/.Deprecated/LegacyContentMitigation/Patches.cs @@ -9,6 +9,7 @@ using ABI.CCK.Components; using cohtml; using cohtml.Net; using HarmonyLib; +using LegacyContentMitigation.Components; using UnityEngine; using UnityEngine.Rendering.PostProcessing; using UnityEngine.SceneManagement; @@ -21,6 +22,9 @@ internal static class PlayerSetup_Patches [HarmonyPatch(typeof(PlayerSetup), nameof(PlayerSetup.Start))] private static void Postfix_PlayerSetup_Start(ref PlayerSetup __instance) { + __instance.vrCam.AddComponentIfMissing(); + __instance.desktopCam.AddComponentIfMissing(); + FakeMultiPassHack.Instance = __instance.vrCam.AddComponentIfMissing(); FakeMultiPassHack.Instance.enabled = ModSettings.EntryAutoForLegacyWorlds.Value; } diff --git a/LegacyContentMitigation/Properties/AssemblyInfo.cs b/.Deprecated/LegacyContentMitigation/Properties/AssemblyInfo.cs similarity index 100% rename from LegacyContentMitigation/Properties/AssemblyInfo.cs rename to .Deprecated/LegacyContentMitigation/Properties/AssemblyInfo.cs diff --git a/LegacyContentMitigation/README.md b/.Deprecated/LegacyContentMitigation/README.md similarity index 100% rename from LegacyContentMitigation/README.md rename to .Deprecated/LegacyContentMitigation/README.md diff --git a/LegacyContentMitigation/format.json b/.Deprecated/LegacyContentMitigation/format.json similarity index 96% rename from LegacyContentMitigation/format.json rename to .Deprecated/LegacyContentMitigation/format.json index 480d0fb..e801124 100644 --- a/LegacyContentMitigation/format.json +++ b/.Deprecated/LegacyContentMitigation/format.json @@ -1,7 +1,7 @@ { - "_id": -1, + "_id": 247, "name": "LegacyContentMitigation", - "modversion": "1.0.1", + "modversion": "1.0.2", "gameversion": "2024r177", "loaderversion": "0.6.1", "modtype": "Mod", diff --git a/.DepricatedMods/MenuScalePatch/HarmonyPatches.cs b/.Deprecated/MenuScalePatch/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/MenuScalePatch/HarmonyPatches.cs rename to .Deprecated/MenuScalePatch/HarmonyPatches.cs diff --git a/.DepricatedMods/MenuScalePatch/Helpers/MainMenuHelper.cs b/.Deprecated/MenuScalePatch/Helpers/MainMenuHelper.cs similarity index 100% rename from .DepricatedMods/MenuScalePatch/Helpers/MainMenuHelper.cs rename to .Deprecated/MenuScalePatch/Helpers/MainMenuHelper.cs diff --git a/.DepricatedMods/MenuScalePatch/Helpers/QuickMenuHelper.cs b/.Deprecated/MenuScalePatch/Helpers/QuickMenuHelper.cs similarity index 100% rename from .DepricatedMods/MenuScalePatch/Helpers/QuickMenuHelper.cs rename to .Deprecated/MenuScalePatch/Helpers/QuickMenuHelper.cs diff --git a/.DepricatedMods/MenuScalePatch/MSP_Menus.cs b/.Deprecated/MenuScalePatch/MSP_Menus.cs similarity index 100% rename from .DepricatedMods/MenuScalePatch/MSP_Menus.cs rename to .Deprecated/MenuScalePatch/MSP_Menus.cs diff --git a/.DepricatedMods/MenuScalePatch/Main.cs b/.Deprecated/MenuScalePatch/Main.cs similarity index 100% rename from .DepricatedMods/MenuScalePatch/Main.cs rename to .Deprecated/MenuScalePatch/Main.cs diff --git a/.DepricatedMods/MenuScalePatch/MenuScalePatch.csproj b/.Deprecated/MenuScalePatch/MenuScalePatch.csproj similarity index 100% rename from .DepricatedMods/MenuScalePatch/MenuScalePatch.csproj rename to .Deprecated/MenuScalePatch/MenuScalePatch.csproj diff --git a/.DepricatedMods/MenuScalePatch/Properties/AssemblyInfo.cs b/.Deprecated/MenuScalePatch/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/MenuScalePatch/Properties/AssemblyInfo.cs rename to .Deprecated/MenuScalePatch/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/MenuScalePatch/README.md b/.Deprecated/MenuScalePatch/README.md similarity index 100% rename from .DepricatedMods/MenuScalePatch/README.md rename to .Deprecated/MenuScalePatch/README.md diff --git a/.DepricatedMods/MenuScalePatch/format.json b/.Deprecated/MenuScalePatch/format.json similarity index 100% rename from .DepricatedMods/MenuScalePatch/format.json rename to .Deprecated/MenuScalePatch/format.json diff --git a/.DepricatedMods/MoreMenuOptions/Main.cs b/.Deprecated/MoreMenuOptions/Main.cs similarity index 100% rename from .DepricatedMods/MoreMenuOptions/Main.cs rename to .Deprecated/MoreMenuOptions/Main.cs diff --git a/.DepricatedMods/MoreMenuOptions/ModSettings.cs b/.Deprecated/MoreMenuOptions/ModSettings.cs similarity index 100% rename from .DepricatedMods/MoreMenuOptions/ModSettings.cs rename to .Deprecated/MoreMenuOptions/ModSettings.cs diff --git a/.DepricatedMods/MoreMenuOptions/MoreMenuOptions.csproj b/.Deprecated/MoreMenuOptions/MoreMenuOptions.csproj similarity index 100% rename from .DepricatedMods/MoreMenuOptions/MoreMenuOptions.csproj rename to .Deprecated/MoreMenuOptions/MoreMenuOptions.csproj diff --git a/.DepricatedMods/MoreMenuOptions/Properties/AssemblyInfo.cs b/.Deprecated/MoreMenuOptions/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/MoreMenuOptions/Properties/AssemblyInfo.cs rename to .Deprecated/MoreMenuOptions/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/MoreMenuOptions/README.md b/.Deprecated/MoreMenuOptions/README.md similarity index 100% rename from .DepricatedMods/MoreMenuOptions/README.md rename to .Deprecated/MoreMenuOptions/README.md diff --git a/.DepricatedMods/MoreMenuOptions/format.json b/.Deprecated/MoreMenuOptions/format.json similarity index 100% rename from .DepricatedMods/MoreMenuOptions/format.json rename to .Deprecated/MoreMenuOptions/format.json diff --git a/.DepricatedMods/NAK.CustomComponents/Components/NAKPointerTracker.cs b/.Deprecated/NAK.CustomComponents/Components/NAKPointerTracker.cs similarity index 100% rename from .DepricatedMods/NAK.CustomComponents/Components/NAKPointerTracker.cs rename to .Deprecated/NAK.CustomComponents/Components/NAKPointerTracker.cs diff --git a/.DepricatedMods/NAK.CustomComponents/CustomComponents.csproj b/.Deprecated/NAK.CustomComponents/CustomComponents.csproj similarity index 100% rename from .DepricatedMods/NAK.CustomComponents/CustomComponents.csproj rename to .Deprecated/NAK.CustomComponents/CustomComponents.csproj diff --git a/.DepricatedMods/NAK.CustomComponents/Main.cs b/.Deprecated/NAK.CustomComponents/Main.cs similarity index 100% rename from .DepricatedMods/NAK.CustomComponents/Main.cs rename to .Deprecated/NAK.CustomComponents/Main.cs diff --git a/.DepricatedMods/NAK.CustomComponents/Properties/AssemblyInfo.cs b/.Deprecated/NAK.CustomComponents/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/NAK.CustomComponents/Properties/AssemblyInfo.cs rename to .Deprecated/NAK.CustomComponents/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/NAK.CustomComponents/format.json b/.Deprecated/NAK.CustomComponents/format.json similarity index 100% rename from .DepricatedMods/NAK.CustomComponents/format.json rename to .Deprecated/NAK.CustomComponents/format.json diff --git a/Nevermind/Main.cs b/.Deprecated/Nevermind/Main.cs similarity index 100% rename from Nevermind/Main.cs rename to .Deprecated/Nevermind/Main.cs diff --git a/Nevermind/Nevermind.csproj b/.Deprecated/Nevermind/Nevermind.csproj similarity index 100% rename from Nevermind/Nevermind.csproj rename to .Deprecated/Nevermind/Nevermind.csproj diff --git a/Nevermind/Properties/AssemblyInfo.cs b/.Deprecated/Nevermind/Properties/AssemblyInfo.cs similarity index 100% rename from Nevermind/Properties/AssemblyInfo.cs rename to .Deprecated/Nevermind/Properties/AssemblyInfo.cs diff --git a/Nevermind/README.md b/.Deprecated/Nevermind/README.md similarity index 100% rename from Nevermind/README.md rename to .Deprecated/Nevermind/README.md diff --git a/Nevermind/format.json b/.Deprecated/Nevermind/format.json similarity index 100% rename from Nevermind/format.json rename to .Deprecated/Nevermind/format.json diff --git a/.DepricatedMods/NoDepthOnlyFlat/Main.cs b/.Deprecated/NoDepthOnlyFlat/Main.cs similarity index 100% rename from .DepricatedMods/NoDepthOnlyFlat/Main.cs rename to .Deprecated/NoDepthOnlyFlat/Main.cs diff --git a/SearchWithSpacesFix/SearchWithSpacesFix.csproj b/.Deprecated/NoDepthOnlyFlat/NoDepthOnlyFlat.csproj similarity index 100% rename from SearchWithSpacesFix/SearchWithSpacesFix.csproj rename to .Deprecated/NoDepthOnlyFlat/NoDepthOnlyFlat.csproj diff --git a/.DepricatedMods/NoDepthOnlyFlat/Properties/AssemblyInfo.cs b/.Deprecated/NoDepthOnlyFlat/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/NoDepthOnlyFlat/Properties/AssemblyInfo.cs rename to .Deprecated/NoDepthOnlyFlat/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/NoDepthOnlyFlat/README.md b/.Deprecated/NoDepthOnlyFlat/README.md similarity index 100% rename from .DepricatedMods/NoDepthOnlyFlat/README.md rename to .Deprecated/NoDepthOnlyFlat/README.md diff --git a/.DepricatedMods/NoDepthOnlyFlat/format.json b/.Deprecated/NoDepthOnlyFlat/format.json similarity index 100% rename from .DepricatedMods/NoDepthOnlyFlat/format.json rename to .Deprecated/NoDepthOnlyFlat/format.json diff --git a/.DepricatedMods/PickupPushPull/HarmonyPatches.cs b/.Deprecated/PickupPushPull/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/PickupPushPull/HarmonyPatches.cs rename to .Deprecated/PickupPushPull/HarmonyPatches.cs diff --git a/.DepricatedMods/PickupPushPull/InputModules/PickupPushPull_Module.cs b/.Deprecated/PickupPushPull/InputModules/PickupPushPull_Module.cs similarity index 100% rename from .DepricatedMods/PickupPushPull/InputModules/PickupPushPull_Module.cs rename to .Deprecated/PickupPushPull/InputModules/PickupPushPull_Module.cs diff --git a/.DepricatedMods/PickupPushPull/Main.cs b/.Deprecated/PickupPushPull/Main.cs similarity index 100% rename from .DepricatedMods/PickupPushPull/Main.cs rename to .Deprecated/PickupPushPull/Main.cs diff --git a/.DepricatedMods/PickupPushPull/PickupPushPull.csproj b/.Deprecated/PickupPushPull/PickupPushPull.csproj similarity index 100% rename from .DepricatedMods/PickupPushPull/PickupPushPull.csproj rename to .Deprecated/PickupPushPull/PickupPushPull.csproj diff --git a/.DepricatedMods/PickupPushPull/Properties/AssemblyInfo.cs b/.Deprecated/PickupPushPull/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/PickupPushPull/Properties/AssemblyInfo.cs rename to .Deprecated/PickupPushPull/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/PickupPushPull/format.json b/.Deprecated/PickupPushPull/format.json similarity index 100% rename from .DepricatedMods/PickupPushPull/format.json rename to .Deprecated/PickupPushPull/format.json diff --git a/.DepricatedMods/PlaySpaceScaleFix/HarmonyPatches.cs b/.Deprecated/PlaySpaceScaleFix/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/PlaySpaceScaleFix/HarmonyPatches.cs rename to .Deprecated/PlaySpaceScaleFix/HarmonyPatches.cs diff --git a/.DepricatedMods/PlaySpaceScaleFix/Main.cs b/.Deprecated/PlaySpaceScaleFix/Main.cs similarity index 100% rename from .DepricatedMods/PlaySpaceScaleFix/Main.cs rename to .Deprecated/PlaySpaceScaleFix/Main.cs diff --git a/.DepricatedMods/PlaySpaceScaleFix/PlaySpaceScaleFix.csproj b/.Deprecated/PlaySpaceScaleFix/PlaySpaceScaleFix.csproj similarity index 100% rename from .DepricatedMods/PlaySpaceScaleFix/PlaySpaceScaleFix.csproj rename to .Deprecated/PlaySpaceScaleFix/PlaySpaceScaleFix.csproj diff --git a/.DepricatedMods/PlaySpaceScaleFix/Properties/AssemblyInfo.cs b/.Deprecated/PlaySpaceScaleFix/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/PlaySpaceScaleFix/Properties/AssemblyInfo.cs rename to .Deprecated/PlaySpaceScaleFix/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/PlaySpaceScaleFix/README.md b/.Deprecated/PlaySpaceScaleFix/README.md similarity index 100% rename from .DepricatedMods/PlaySpaceScaleFix/README.md rename to .Deprecated/PlaySpaceScaleFix/README.md diff --git a/.DepricatedMods/PlaySpaceScaleFix/format.json b/.Deprecated/PlaySpaceScaleFix/format.json similarity index 100% rename from .DepricatedMods/PlaySpaceScaleFix/format.json rename to .Deprecated/PlaySpaceScaleFix/format.json diff --git a/ReconnectionSystemFix/Main.cs b/.Deprecated/ReconnectionSystemFix/Main.cs similarity index 100% rename from ReconnectionSystemFix/Main.cs rename to .Deprecated/ReconnectionSystemFix/Main.cs diff --git a/ReconnectionSystemFix/Patches.cs b/.Deprecated/ReconnectionSystemFix/Patches.cs similarity index 100% rename from ReconnectionSystemFix/Patches.cs rename to .Deprecated/ReconnectionSystemFix/Patches.cs diff --git a/ReconnectionSystemFix/Properties/AssemblyInfo.cs b/.Deprecated/ReconnectionSystemFix/Properties/AssemblyInfo.cs similarity index 100% rename from ReconnectionSystemFix/Properties/AssemblyInfo.cs rename to .Deprecated/ReconnectionSystemFix/Properties/AssemblyInfo.cs diff --git a/ReconnectionSystemFix/README.md b/.Deprecated/ReconnectionSystemFix/README.md similarity index 100% rename from ReconnectionSystemFix/README.md rename to .Deprecated/ReconnectionSystemFix/README.md diff --git a/.Deprecated/ReconnectionSystemFix/ReconnectionSystemFix.csproj b/.Deprecated/ReconnectionSystemFix/ReconnectionSystemFix.csproj new file mode 100644 index 0000000..bec5b03 --- /dev/null +++ b/.Deprecated/ReconnectionSystemFix/ReconnectionSystemFix.csproj @@ -0,0 +1,6 @@ + + + + LoadedObjectHack + + diff --git a/ReconnectionSystemFix/format.json b/.Deprecated/ReconnectionSystemFix/format.json similarity index 100% rename from ReconnectionSystemFix/format.json rename to .Deprecated/ReconnectionSystemFix/format.json diff --git a/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/Main.cs b/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/Main.cs new file mode 100644 index 0000000..7687ea6 --- /dev/null +++ b/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/Main.cs @@ -0,0 +1,43 @@ +using System.Reflection; +using ABI_RC.Core.Player; +using HarmonyLib; +using MelonLoader; +using UnityEngine; + +namespace NAK.RemoteAvatarDisablingCameraOnFirstFrameFix; + +public class RemoteAvatarDisablingCameraOnFirstFrameFixMod : MelonMod +{ + public override void OnInitializeMelon() + { + HarmonyInstance.Patch( + typeof(PuppetMaster).GetMethod(nameof(PuppetMaster.AvatarInstantiated), + BindingFlags.Public | BindingFlags.Instance), + postfix: new HarmonyMethod(typeof(RemoteAvatarDisablingCameraOnFirstFrameFixMod).GetMethod(nameof(OnPuppetMasterAvatarInstantiated), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + } + + private static void OnPuppetMasterAvatarInstantiated(PuppetMaster __instance) + { + if (__instance._animator == null) return; + + __instance._animator.WriteDefaultValues(); + __instance._animator.keepAnimatorStateOnDisable = false; + __instance._animator.writeDefaultValuesOnDisable = false; + } + + // private static void OnPuppetMasterAvatarInstantiated(PuppetMaster __instance) + // { + // if (__instance._animator == null) return; + // + // // Set culling mode to always animate + // __instance._animator.cullingMode = AnimatorCullingMode.AlwaysAnimate; + // + // // Update the animator to force it to do the first frame + // __instance._animator.Update(0f); + // + // // Set culling mode back to cull update transforms + // __instance._animator.cullingMode = AnimatorCullingMode.CullUpdateTransforms; + // } +} \ No newline at end of file diff --git a/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/Properties/AssemblyInfo.cs b/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..9f70d66 --- /dev/null +++ b/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/Properties/AssemblyInfo.cs @@ -0,0 +1,30 @@ +using MelonLoader; +using NAK.RemoteAvatarDisablingCameraOnFirstFrameFix.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.RemoteAvatarDisablingCameraOnFirstFrameFix))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.RemoteAvatarDisablingCameraOnFirstFrameFix))] + +[assembly: MelonInfo( + typeof(NAK.RemoteAvatarDisablingCameraOnFirstFrameFix.RemoteAvatarDisablingCameraOnFirstFrameFixMod), + nameof(NAK.RemoteAvatarDisablingCameraOnFirstFrameFix), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/RemoteAvatarDisablingCameraOnFirstFrameFix" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: HarmonyDontPatchAll] + +namespace NAK.RemoteAvatarDisablingCameraOnFirstFrameFix.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/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/README.md b/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/README.md new file mode 100644 index 0000000..8a46af2 --- /dev/null +++ b/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/README.md @@ -0,0 +1,14 @@ +# IKSimulatedRootAngleFix + +Fixes a small issue with Desktop & HalfBody root angle being incorrectly calculated while on rotating Movement Parents. If you've ever noticed your body/feet insisting on facing opposite of the direction you are rotating, this fixes that. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation 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/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/RemoteAvatarDisablingCameraOnFirstFrameFix.csproj b/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/RemoteAvatarDisablingCameraOnFirstFrameFix.csproj new file mode 100644 index 0000000..bec5b03 --- /dev/null +++ b/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/RemoteAvatarDisablingCameraOnFirstFrameFix.csproj @@ -0,0 +1,6 @@ + + + + LoadedObjectHack + + diff --git a/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/format.json b/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/format.json new file mode 100644 index 0000000..ddf506b --- /dev/null +++ b/.Deprecated/RemoteAvatarDisablingCameraOnFirstFrameFix/format.json @@ -0,0 +1,24 @@ +{ + "_id": -1, + "name": "AASDefaultProfileFix", + "modversion": "1.0.0", + "gameversion": "2024r175", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Fixes the Default AAS profile not being applied when loading into an avatar without a profile selected.\n\nBy default, the game will not apply anything and the avatar will default to the state found within the Controller parameters.", + "searchtags": [ + "aas", + "profile", + "default", + "fix", + "meow" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r33/AASDefaultProfileFix.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/AASDefaultProfileFix/", + "changelog": "- Initial release", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/SearchWithSpacesFix/Main.cs b/.Deprecated/SearchWithSpacesFix/Main.cs similarity index 100% rename from SearchWithSpacesFix/Main.cs rename to .Deprecated/SearchWithSpacesFix/Main.cs diff --git a/SearchWithSpacesFix/Properties/AssemblyInfo.cs b/.Deprecated/SearchWithSpacesFix/Properties/AssemblyInfo.cs similarity index 100% rename from SearchWithSpacesFix/Properties/AssemblyInfo.cs rename to .Deprecated/SearchWithSpacesFix/Properties/AssemblyInfo.cs diff --git a/.Deprecated/SearchWithSpacesFix/README.md b/.Deprecated/SearchWithSpacesFix/README.md new file mode 100644 index 0000000..1c4c5bc --- /dev/null +++ b/.Deprecated/SearchWithSpacesFix/README.md @@ -0,0 +1,14 @@ +# SearchWithSpacesFix + +Fixes search terms that use spaces. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation 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/.Deprecated/SearchWithSpacesFix/SearchWithSpacesFix.csproj b/.Deprecated/SearchWithSpacesFix/SearchWithSpacesFix.csproj new file mode 100644 index 0000000..e94f9dc --- /dev/null +++ b/.Deprecated/SearchWithSpacesFix/SearchWithSpacesFix.csproj @@ -0,0 +1,2 @@ + + diff --git a/.Deprecated/SearchWithSpacesFix/format.json b/.Deprecated/SearchWithSpacesFix/format.json new file mode 100644 index 0000000..f8950ca --- /dev/null +++ b/.Deprecated/SearchWithSpacesFix/format.json @@ -0,0 +1,23 @@ +{ + "_id": -1, + "name": "SearchWithSpacesFix", + "modversion": "1.0.0", + "gameversion": "2024r177", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Fixes search terms that include spaces.", + "searchtags": [ + "search", + "spaces", + "fix", + "meow" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r42/SearchWithSpacesFix.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/SearchWithSpacesFix/", + "changelog": "- Initial release", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/ShadowCloneFallback/Main.cs b/.Deprecated/ShadowCloneFallback/Main.cs similarity index 100% rename from ShadowCloneFallback/Main.cs rename to .Deprecated/ShadowCloneFallback/Main.cs diff --git a/ShadowCloneFallback/Properties/AssemblyInfo.cs b/.Deprecated/ShadowCloneFallback/Properties/AssemblyInfo.cs similarity index 100% rename from ShadowCloneFallback/Properties/AssemblyInfo.cs rename to .Deprecated/ShadowCloneFallback/Properties/AssemblyInfo.cs diff --git a/ShadowCloneFallback/README.md b/.Deprecated/ShadowCloneFallback/README.md similarity index 100% rename from ShadowCloneFallback/README.md rename to .Deprecated/ShadowCloneFallback/README.md diff --git a/ShadowCloneFallback/ShadowCloneFallback.csproj b/.Deprecated/ShadowCloneFallback/ShadowCloneFallback.csproj similarity index 100% rename from ShadowCloneFallback/ShadowCloneFallback.csproj rename to .Deprecated/ShadowCloneFallback/ShadowCloneFallback.csproj diff --git a/ShadowCloneFallback/format.json b/.Deprecated/ShadowCloneFallback/format.json similarity index 100% rename from ShadowCloneFallback/format.json rename to .Deprecated/ShadowCloneFallback/format.json diff --git a/SmartReticle/Main.cs b/.Deprecated/SmartReticle/Main.cs similarity index 100% rename from SmartReticle/Main.cs rename to .Deprecated/SmartReticle/Main.cs diff --git a/SmartReticle/Properties/AssemblyInfo.cs b/.Deprecated/SmartReticle/Properties/AssemblyInfo.cs similarity index 100% rename from SmartReticle/Properties/AssemblyInfo.cs rename to .Deprecated/SmartReticle/Properties/AssemblyInfo.cs diff --git a/SmartReticle/README.md b/.Deprecated/SmartReticle/README.md similarity index 100% rename from SmartReticle/README.md rename to .Deprecated/SmartReticle/README.md diff --git a/.Deprecated/SmartReticle/SmartReticle.csproj b/.Deprecated/SmartReticle/SmartReticle.csproj new file mode 100644 index 0000000..728edb7 --- /dev/null +++ b/.Deprecated/SmartReticle/SmartReticle.csproj @@ -0,0 +1,6 @@ + + + + net48 + + diff --git a/SmartReticle/format.json b/.Deprecated/SmartReticle/format.json similarity index 100% rename from SmartReticle/format.json rename to .Deprecated/SmartReticle/format.json diff --git a/StopClosingMyMenuOnWorldLoad/Main.cs b/.Deprecated/StopClosingMyMenuOnWorldLoad/Main.cs similarity index 100% rename from StopClosingMyMenuOnWorldLoad/Main.cs rename to .Deprecated/StopClosingMyMenuOnWorldLoad/Main.cs diff --git a/StopClosingMyMenuOnWorldLoad/Properties/AssemblyInfo.cs b/.Deprecated/StopClosingMyMenuOnWorldLoad/Properties/AssemblyInfo.cs similarity index 100% rename from StopClosingMyMenuOnWorldLoad/Properties/AssemblyInfo.cs rename to .Deprecated/StopClosingMyMenuOnWorldLoad/Properties/AssemblyInfo.cs diff --git a/StopClosingMyMenuOnWorldLoad/README.md b/.Deprecated/StopClosingMyMenuOnWorldLoad/README.md similarity index 100% rename from StopClosingMyMenuOnWorldLoad/README.md rename to .Deprecated/StopClosingMyMenuOnWorldLoad/README.md diff --git a/StopClosingMyMenuOnWorldLoad/StopClosingMyMenuOnWorldLoad.csproj b/.Deprecated/StopClosingMyMenuOnWorldLoad/StopClosingMyMenuOnWorldLoad.csproj similarity index 100% rename from StopClosingMyMenuOnWorldLoad/StopClosingMyMenuOnWorldLoad.csproj rename to .Deprecated/StopClosingMyMenuOnWorldLoad/StopClosingMyMenuOnWorldLoad.csproj diff --git a/StopClosingMyMenuOnWorldLoad/format.json b/.Deprecated/StopClosingMyMenuOnWorldLoad/format.json similarity index 100% rename from StopClosingMyMenuOnWorldLoad/format.json rename to .Deprecated/StopClosingMyMenuOnWorldLoad/format.json diff --git a/.Deprecated/SuperAwesomeMod/Interaction/CVRPlayerHand.cs b/.Deprecated/SuperAwesomeMod/Interaction/CVRPlayerHand.cs new file mode 100644 index 0000000..949b638 --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Interaction/CVRPlayerHand.cs @@ -0,0 +1,42 @@ +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.InteractionSystem.Base; +using ABI_RC.Systems.InputManagement; +using UnityEngine; +using UnityEngine.Serialization; + +namespace ABI_RC.Core.Player.Interaction +{ + public class CVRPlayerHand : MonoBehaviour + { + #region Fields + + [SerializeField] + private CVRHand _hand; + + // Pickup rig + [SerializeField] private Transform rayDirection; + [SerializeField] private Transform _attachmentPoint; + [SerializeField] private Transform _pivotPoint; + [SerializeField] private VelocityTracker _velocityTracker; + + // Pickup state + private bool _isHoldingObject; + private Pickupable _heldPickupable; + private Pickupable _proximityPickupable; + + #endregion Fields + + #region Unity Events + + + #endregion Unity Events + + #region Private Methods + + #endregion Private Methods + + #region Public Methods + + #endregion Public Methods + } +} \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Interaction/CVRPlayerInteractionManager.cs b/.Deprecated/SuperAwesomeMod/Interaction/CVRPlayerInteractionManager.cs new file mode 100644 index 0000000..2c0d56e --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Interaction/CVRPlayerInteractionManager.cs @@ -0,0 +1,214 @@ +using ABI_RC.Core.Player.Interaction.RaycastImpl; +using ABI_RC.Core.Savior; +using ABI_RC.Systems.InputManagement; +using UnityEngine; + +namespace ABI_RC.Core.Player.Interaction +{ + public class CVRPlayerInteractionManager : MonoBehaviour + { + #region Singleton + + public static CVRPlayerInteractionManager Instance { get; private set; } + + #endregion Singleton + + #region Serialized Fields + + [Header("Hand Components")] + [SerializeField] private CVRPlayerHand handVrLeft; + [SerializeField] private CVRPlayerHand handVrRight; + [SerializeField] private CVRPlayerHand handDesktopRight; // Desktop does not have a left hand + + [Header("Raycast Transforms")] + [SerializeField] private Transform raycastTransformVrRight; + [SerializeField] private Transform raycastTransformVrLeft; + [SerializeField] private Transform raycastTransformDesktopRight; + + [Header("Settings")] + [SerializeField] private bool interactionEnabled = true; + [SerializeField] private LayerMask interactionLayerMask = -1; // Default to all layers, will be filtered + + #endregion Serialized Fields + + #region Properties + + private CVRPlayerHand _rightHand; + private CVRPlayerHand _leftHand; + + private CVRPlayerRaycaster _rightRaycaster; + private CVRPlayerRaycaster _leftRaycaster; + + private CVRRaycastResult _rightRaycastResult; + private CVRRaycastResult _leftRaycastResult; + + // Input handler + private CVRPlayerInputHandler _inputHandler; + + // Interaction flags + public bool InteractionEnabled + { + get => interactionEnabled; + set => interactionEnabled = value; + } + + #endregion Properties + + #region Unity Events + + private void Awake() + { + if (Instance != null && Instance != this) + { + Destroy(gameObject); + return; + } + Instance = this; + + // Create the input handler + _inputHandler = gameObject.AddComponent(); + } + + private void Start() + { + // Setup interaction for current device mode + SetupInteractionForDeviceMode(); + + // Listen for VR mode changes + MetaPort.Instance.onVRModeSwitch.AddListener(SetupInteractionForDeviceMode); + } + + private void Update() + { + if (!interactionEnabled) + return; + + // Process right hand + if (_rightRaycaster != null) + { + // Determine raycast flags based on current mode + CVRPlayerRaycaster.RaycastFlags flags = DetermineRaycastFlags(_rightHand); + + // Get raycast results + _rightRaycastResult = _rightRaycaster.GetRaycastResults(flags); + + // Process input based on raycast results + _inputHandler.ProcessInput(CVRHand.Right, _rightRaycastResult); + } + + // Process left hand (if available) + if (_leftRaycaster != null) + { + // Determine raycast flags based on current mode + CVRPlayerRaycaster.RaycastFlags flags = DetermineRaycastFlags(_leftHand); + + // Get raycast results + _leftRaycastResult = _leftRaycaster.GetRaycastResults(flags); + + // Process input based on raycast results + _inputHandler.ProcessInput(CVRHand.Left, _leftRaycastResult); + } + } + + private void OnDestroy() + { + // Clean up event listener + if (MetaPort.Instance != null) + MetaPort.Instance.onVRModeSwitch.RemoveListener(SetupInteractionForDeviceMode); + } + + #endregion Unity Events + + #region Public Methods + + /// + /// Register a custom tool mode + /// + public void RegisterCustomToolMode(System.Action callback) + { + _inputHandler.RegisterCustomTool(callback); + } + + /// + /// Unregister the current custom tool mode + /// + public void UnregisterCustomToolMode() + { + _inputHandler.UnregisterCustomTool(); + } + + /// + /// Set the interaction mode + /// + public void SetInteractionMode(CVRPlayerInputHandler.InteractionMode mode) + { + _inputHandler.SetInteractionMode(mode); + } + + /// + /// Get the raycast result for a specific hand + /// + public CVRRaycastResult GetRaycastResult(CVRHand hand) + { + return hand == CVRHand.Left ? _leftRaycastResult : _rightRaycastResult; + } + + #endregion Public Methods + + #region Private Methods + + private void SetupInteractionForDeviceMode() + { + bool isVr = MetaPort.Instance.isUsingVr; + + if (isVr) + { + // VR mode + _rightHand = handVrRight; + _leftHand = handVrLeft; + + // VR uses the controller transform for raycasting + _rightRaycaster = new CVRPlayerRaycasterTransform(raycastTransformVrRight); + _leftRaycaster = new CVRPlayerRaycasterTransform(raycastTransformVrLeft); + } + else + { + // Desktop mode + _rightHand = handDesktopRight; + _leftHand = null; + + // Desktop uses the mouse position for raycasting when unlocked + Camera desktopCamera = PlayerSetup.Instance.desktopCam; + _rightRaycaster = new CVRPlayerRaycasterMouse(raycastTransformDesktopRight, desktopCamera); + _leftRaycaster = null; + } + + // Set the layer mask for raycasters + if (_rightRaycaster != null) + _rightRaycaster.SetLayerMask(interactionLayerMask); + + if (_leftRaycaster != null) + _leftRaycaster.SetLayerMask(interactionLayerMask); + } + + private static CVRPlayerRaycaster.RaycastFlags DetermineRaycastFlags(CVRPlayerHand hand) + { + // Default to all flags + CVRPlayerRaycaster.RaycastFlags flags = CVRPlayerRaycaster.RaycastFlags.All; + + // Check if hand is holding a pickup + if (hand != null && hand.IsHoldingObject) + { + // When holding an object, only check for COHTML interaction + flags = CVRPlayerRaycaster.RaycastFlags.CohtmlInteract; + } + + // Could add more conditional flag adjustments here based on the current mode + // For example, in a teleport tool mode, you might only want world hits + + return flags; + } + + #endregion Private Methods + } +} \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Interaction/Components/CVRCanvasWrapper.cs b/.Deprecated/SuperAwesomeMod/Interaction/Components/CVRCanvasWrapper.cs new file mode 100644 index 0000000..2ec46bd --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Interaction/Components/CVRCanvasWrapper.cs @@ -0,0 +1,121 @@ +using ABI_RC.Core.Base; +using ABI_RC.Core.Player; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace NAK.SuperAwesomeMod.Components +{ + public class CVRCanvasWrapper : MonoBehaviour + { + public bool IsInteractable = true; + public float MaxInteractDistance = 10f; + + private Canvas _canvas; + private GraphicRaycaster _graphicsRaycaster; + private static readonly List _raycastResults = new(); + private static readonly PointerEventData _pointerEventData = new(EventSystem.current); + + private static Selectable _workingSelectable; + private Camera _camera; + private RectTransform _rectTransform; + + #region Unity Events + + private void Awake() + { + if (!TryGetComponent(out _canvas) + || _canvas.renderMode != RenderMode.WorldSpace) + { + IsInteractable = false; + return; + } + + _rectTransform = _canvas.GetComponent(); + } + + private void Start() + { + _graphicsRaycaster = _canvas.gameObject.AddComponent(); + _camera = PlayerSetup.Instance.activeCam; + _canvas.worldCamera = _camera; + } + + #endregion Unity Events + + #region Public Methods + + public bool GetGraphicsHit(Ray worldRay, out RaycastResult result) + { + result = default; + + if (!IsInteractable || _camera == null) return false; + + // Get the plane of the canvas + Plane canvasPlane = new(transform.forward, transform.position); + + // Find where the ray intersects the canvas plane + if (!canvasPlane.Raycast(worldRay, out float distance)) + return false; + + // Get the world point of intersection + Vector3 worldHitPoint = worldRay.origin + worldRay.direction * distance; + + // Check if hit point is within max interaction distance + if (Vector3.Distance(worldRay.origin, worldHitPoint) > MaxInteractDistance) + return false; + + // Check if hit point is within canvas bounds + Vector3 localHitPoint = transform.InverseTransformPoint(worldHitPoint); + Rect canvasRect = _rectTransform.rect; + if (!canvasRect.Contains(new Vector2(localHitPoint.x, localHitPoint.y))) + return false; + + // Convert world hit point to screen space + Vector2 screenPoint = _camera.WorldToScreenPoint(worldHitPoint); + + // Update pointer event data + _pointerEventData.position = screenPoint; + _pointerEventData.delta = Vector2.zero; + + // Clear previous results and perform raycast + _raycastResults.Clear(); + _graphicsRaycaster.Raycast(_pointerEventData, _raycastResults); + + // Early out if no hits + if (_raycastResults.Count == 0) + { + //Debug.Log($"No hits on canvas {_canvas.name}"); + return false; + } + + // Find first valid interactive UI element + foreach (RaycastResult hit in _raycastResults) + { + if (!hit.isValid) + { + //Debug.Log($"Invalid hit on canvas {_canvas.name}"); + continue; + } + + // Check if the hit object has a Selectable component and is interactable + GameObject hitObject = hit.gameObject; + if (!hitObject.TryGetComponent(out _workingSelectable) + || !_workingSelectable.interactable) + { + //Debug.Log($"Non-interactable hit on canvas {_canvas.name} - {hitObject.name}"); + continue; + } + + //Debug.Log($"Hit on canvas {_canvas.name} with {hitObject.name}"); + + result = hit; + return true; + } + + return false; + } + + #endregion Public Methods + } +} \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycaster.cs b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycaster.cs new file mode 100644 index 0000000..aa4205a --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycaster.cs @@ -0,0 +1,385 @@ +using ABI_RC.Core.InteractionSystem.Base; +using ABI_RC.Core.UI; +using ABI.CCK.Components; +using NAK.SuperAwesomeMod.Components; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace ABI_RC.Core.Player.Interaction.RaycastImpl +{ + public abstract class CVRPlayerRaycaster + { + #region Enums + + [Flags] + public enum RaycastFlags + { + None = 0, + TelepathicCandidate = 1 << 0, + ProximityInteract = 1 << 1, + RayInteract = 1 << 2, + CohtmlInteract = 1 << 3, + All = ~0 + } + + #endregion Enums + + #region Constants + + private const float MAX_RAYCAST_DISTANCE = 100f; // Max distance you can raycast + private const float RAYCAST_SPHERE_RADIUS = 0.1f; // Radius of the proximity sphere + private const float TELEPATHIC_SPHERE_RADIUS = 0.3f; // Radius of the telepathic sphere + private const float MAX_TELEPATHIC_DISTANCE = 20f; // Max distance for telepathic grab + private const int MAX_RAYCAST_HITS = 100; // Hit buffer size, high due to triggers, which we use lots in CCK + + // Global setting is Collide, but better to be explicit about what we need + private const QueryTriggerInteraction _triggerInteraction = QueryTriggerInteraction.Collide; + + // Layers that are reserved for other purposes or illegal to interact with + private const int RESERVED_OR_ILLEGAL_LAYERS = (1 << CVRLayers.IgnoreRaycast) + | (1 << CVRLayers.MirrorReflection) + | (1 << CVRLayers.PlayerLocal); + + #endregion Constants + + #region Static Fields + + private static readonly RaycastHit[] _hits = new RaycastHit[MAX_RAYCAST_HITS]; + private static readonly Comparer _hitsComparer = Comparer.Create((hit1, hit2) => + { + bool isUI1 = hit1.collider.gameObject.layer == CVRLayers.UIInternal; + bool isUI2 = hit2.collider.gameObject.layer == CVRLayers.UIInternal; + + // Prioritize UIInternal hits + if (isUI1 && !isUI2) return -1; // UIInternal comes first + if (!isUI1 && isUI2) return 1; // Non-UIInternal comes after + + // If both are UIInternal or both are not, sort by distance + return hit1.distance.CompareTo(hit2.distance); + }); + + private static readonly LayerMask _telepathicLayerMask = 1 << CVRLayers.MirrorReflection; + + // Working variables to avoid repeated allocations + private static Collider _workingCollider; + private static GameObject _workingGameObject; + private static Pickupable _workingPickupable; + private static Interactable _workingInteractable; + private static Selectable _workingSelectable; + private static ICanvasElement _workingCanvasElement; + + #endregion Static Fields + + #region Private Fields + + private LayerMask _layerMask; // Default to no layers so we know if we fucked up + + #endregion Private Fields + + #region Constructor + + protected CVRPlayerRaycaster(Transform rayOrigin) => _rayOrigin = rayOrigin; + protected readonly Transform _rayOrigin; + + #endregion Constructor + + #region Public Methods + + public void SetLayerMask(LayerMask layerMask) + { + layerMask &= ~RESERVED_OR_ILLEGAL_LAYERS; + _layerMask = layerMask; + } + + public CVRRaycastResult GetRaycastResults(RaycastFlags flags = RaycastFlags.All) + { + // Early out if we don't want to do anything + if (flags == RaycastFlags.None) return default; + + Ray ray = GetRayFromImpl(); + CVRRaycastResult result = new(); + + // Always check COHTML first + if ((flags & RaycastFlags.CohtmlInteract) != 0 + && TryProcessCohtmlHit(ray, ref result)) + return result; + + // Check if there are pickups or interactables in immediate proximity + if ((flags & RaycastFlags.ProximityInteract) != 0) + { + ProcessProximityHits(ray, ref result); // TODO: Offset origin to center of palm based on hand type + if (result.isProximityHit) + return result; + } + + // Check for regular raycast hits + if ((flags & RaycastFlags.RayInteract) != 0) + ProcessRaycastHits(ray, ref result); + + // If we hit something, check for telepathic grab candidates at the hit point + if ((flags & RaycastFlags.TelepathicCandidate) != 0 && result.hit.collider) + ProcessTelepathicGrabCandidate(result.hit.point, ref result); + + return result; + } + + #endregion Public Methods + + #region Private Methods + + private static bool TryProcessCohtmlHit(Ray ray, ref CVRRaycastResult result) + { + CohtmlControlledView hitView = CohtmlViewInputHandler.Instance.RayToView(ray, + out float _, out Vector2 hitCoords); + if (hitView == null) return false; + + result.hitCohtml = true; + result.hitCohtmlView = hitView; + result.hitCohtmlCoords = hitCoords; + + // Manually check for pickups & interactables on the hit view (future-proofing for menu grabbing) + if (hitView.TryGetComponent(out _workingInteractable)) result.hitInteractable = _workingInteractable; + if (hitView.TryGetComponent(out _workingPickupable)) result.hitPickupable = _workingPickupable; + + return true; + } + + private void ProcessProximityHits(Ray ray, ref CVRRaycastResult result) + { + int proximityHits = Physics.SphereCastNonAlloc( + ray.origin, + RAYCAST_SPHERE_RADIUS, + Vector3.up, + _hits, + 0.001f, + _layerMask, + _triggerInteraction + ); + + if (proximityHits <= 0) return; + + Array.Sort(_hits, 0, proximityHits, _hitsComparer); + + for (int i = 0; i < proximityHits; i++) + { + RaycastHit hit = _hits[i]; + _workingCollider = hit.collider; + _workingGameObject = _workingCollider.gameObject; + + // Skip things behind the ray origin + if (Vector3.Dot(ray.direction, hit.point - ray.origin) < 0) + continue; + + // Check for interactables & pickupables in proximity + if (!TryProcessInteractables(hit, ref result)) + continue; + + result.isProximityHit = true; + break; + } + } + + private void ProcessRaycastHits(Ray ray, ref CVRRaycastResult result) + { + // Get all hits including triggers, sorted by UI Internal layer & distance + int hitCount = Physics.RaycastNonAlloc(ray, + _hits, + MAX_RAYCAST_DISTANCE, + _layerMask, + _triggerInteraction); + + if (hitCount <= 0) return; + + Array.Sort(_hits, 0, hitCount, _hitsComparer); + + for (int i = 0; i < hitCount; i++) + { + RaycastHit hit = _hits[i]; + _workingCollider = hit.collider; + _workingGameObject = _workingCollider.gameObject; + + // Special case where we only get the closest water hit position. + // As the array is sorted by distance, we only need to check if we didn't hit water yet. + if (!result.hitWater) TryProcessFluidVolume(hit, ref result); + + // Check for hits in order of priority + + if (TryProcessSelectable(hit, ref result)) + break; // Hit a Unity UI Selectable (Button, Slider, etc.) + + if (TryProcessCanvasElement(hit, ref result)) + break; // Hit a Unity UI Canvas Element (ScrollRect, idk what else yet) + + if (TryProcessInteractables(hit, ref result)) + break; // Hit an in-range Interactable or Pickup + + if (TryProcessWorldHit(hit, ref result)) + break; // Hit a non-trigger collider (world, end of ray) + } + } + + private void ProcessTelepathicGrabCandidate(Vector3 hitPoint, ref CVRRaycastResult result) + { + // If we already hit a pickupable, we don't need to check for telepathic grab candidates + if (result.hitPickupable) + { + result.hasTelepathicGrabCandidate = true; + result.telepathicPickupable = result.hitPickupable; + result.telepathicGrabPoint = hitPoint; + return; + } + + // If the hit distance is too far, don't bother checking for telepathic grab candidates + if (Vector3.Distance(hitPoint, _rayOrigin.position) > MAX_TELEPATHIC_DISTANCE) + return; + + // Check for mirror reflection triggers in a sphere around the hit point + int telepathicHits = Physics.SphereCastNonAlloc( + hitPoint, + TELEPATHIC_SPHERE_RADIUS, + Vector3.up, + _hits, + 0.001f, + _telepathicLayerMask, + QueryTriggerInteraction.Collide + ); + + if (telepathicHits <= 0) return; + + // Look for pickupable objects near our hit point + var nearestDistance = float.MaxValue; + for (int i = 0; i < telepathicHits; i++) + { + RaycastHit hit = _hits[i]; + _workingCollider = hit.collider; + // _workingGameObject = _workingCollider.gameObject; + + Transform parentTransform = _workingCollider.transform.parent; + if (!parentTransform + || !parentTransform.TryGetComponent(out _workingPickupable) + || !_workingPickupable.CanPickup) + continue; + + var distance = Vector3.Distance(hitPoint, hit.point); + if (!(distance < nearestDistance)) + continue; + + result.hasTelepathicGrabCandidate = true; + result.telepathicPickupable = _workingPickupable; + result.telepathicGrabPoint = hitPoint; + nearestDistance = distance; + } + } + + private static bool TryProcessSelectable(RaycastHit hit, ref CVRRaycastResult result) + { + if (!_workingGameObject.TryGetComponent(out _workingSelectable)) + return false; + + result.hitUnityUi = true; + result.hitSelectable = _workingSelectable; + result.hit = hit; + return true; + } + + private static bool TryProcessCanvasElement(RaycastHit hit, ref CVRRaycastResult result) + { + if (!_workingGameObject.TryGetComponent(out _workingCanvasElement)) + return false; + + result.hitUnityUi = true; + result.hitCanvasElement = _workingCanvasElement; + result.hit = hit; + return true; + } + + private static void TryProcessFluidVolume(RaycastHit hit, ref CVRRaycastResult result) + { + if (_workingGameObject.layer != CVRLayers.Water) return; + + result.hitWater = true; + result.waterHit = hit; + } + + private static bool TryProcessInteractables(RaycastHit hit, ref CVRRaycastResult result) + { + bool hitValidComponent = false; + + if (_workingGameObject.TryGetComponent(out _workingInteractable) + && _workingInteractable.CanInteract + && IsCVRInteractableWithinRange(_workingInteractable, hit)) + { + result.hitInteractable = _workingInteractable; + hitValidComponent = true; + } + if (_workingGameObject.TryGetComponent(out _workingPickupable) + && _workingPickupable.CanPickup + && IsCVRPickupableWithinRange(_workingPickupable, hit)) + { + result.hitPickupable = _workingPickupable; + hitValidComponent = true; + } + + if (!hitValidComponent) + return false; + + result.hit = hit; + return true; + } + + private static bool TryProcessWorldHit(RaycastHit hit, ref CVRRaycastResult result) + { + if (_workingCollider.isTrigger) + return false; + + result.hitWorld = true; + result.hit = hit; + return true; + } + + #endregion Private Methods + + #region Protected Methods + + protected abstract Ray GetRayFromImpl(); + + #endregion Protected Methods + + #region Utility Because Original Methods Are Broken + + private static bool IsCVRInteractableWithinRange(Interactable interactable, RaycastHit hit) + { + if (interactable is not CVRInteractable cvrInteractable) + return true; + + foreach (CVRInteractableAction action in cvrInteractable.actions) + { + if (action.actionType + is not (CVRInteractableAction.ActionRegister.OnInteractDown + or CVRInteractableAction.ActionRegister.OnInteractUp + or CVRInteractableAction.ActionRegister.OnInputDown + or CVRInteractableAction.ActionRegister.OnInputUp)) + continue; + + float maxDistance = action.floatVal; + if (Mathf.Approximately(maxDistance, 0f) + || hit.distance <= maxDistance) + return true; // Interactable is within range + } + return false; + } + + private static bool IsCVRPickupableWithinRange(Pickupable pickupable, RaycastHit hit) + { + return hit.distance <= pickupable.MaxGrabDistance; + } + + private static bool IsCVRCanvasWrapperWithinRange(CVRCanvasWrapper canvasWrapper, RaycastHit hit) + { + return hit.distance <= canvasWrapper.MaxInteractDistance; + } + + #endregion Utility Because Original Methods Are Broken + } +} \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterMouse.cs b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterMouse.cs new file mode 100644 index 0000000..5f5e638 --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterMouse.cs @@ -0,0 +1,13 @@ +using UnityEngine; + +namespace ABI_RC.Core.Player.Interaction.RaycastImpl +{ + public class CVRPlayerRaycasterMouse : CVRPlayerRaycaster + { + private readonly Camera _camera; + public CVRPlayerRaycasterMouse(Transform rayOrigin, Camera camera) : base(rayOrigin) { _camera = camera; } + protected override Ray GetRayFromImpl() => Cursor.lockState == CursorLockMode.Locked + ? new Ray(_camera.transform.position, _camera.transform.forward) + : _camera.ScreenPointToRay(Input.mousePosition); + } +} \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterTransform.cs b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterTransform.cs new file mode 100644 index 0000000..cc62dab --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterTransform.cs @@ -0,0 +1,10 @@ +using UnityEngine; + +namespace ABI_RC.Core.Player.Interaction.RaycastImpl +{ + public class CVRPlayerRaycasterTransform : CVRPlayerRaycaster + { + public CVRPlayerRaycasterTransform(Transform rayOrigin) : base(rayOrigin) { } + protected override Ray GetRayFromImpl() => new(_rayOrigin.position, _rayOrigin.forward); + } +} \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRRaycastResult.cs b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRRaycastResult.cs new file mode 100644 index 0000000..6165354 --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRRaycastResult.cs @@ -0,0 +1,38 @@ +using ABI_RC.Core.InteractionSystem.Base; +using ABI_RC.Core.UI; +using NAK.SuperAwesomeMod.Components; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace ABI_RC.Core.Player.Interaction.RaycastImpl +{ + public struct CVRRaycastResult + { + // Hit flags + public bool hitWorld; // Any non-specific collision + public bool hitWater; // Hit a fluid volume + public bool hitCohtml; // Specifically hit a COHTML view (Main/Quick Menu) + public bool isProximityHit; // Hit was from proximity sphere check + public bool hitUnityUi; // Hit a canvas + + // Main raycast hit info + public RaycastHit hit; + public RaycastHit? waterHit; // Only valid if hitWater is true + + // Specific hit components + public Pickupable hitPickupable; + public Interactable hitInteractable; + public Selectable hitSelectable; + public ICanvasElement hitCanvasElement; + + // COHTML specific results + public CohtmlControlledView hitCohtmlView; + public Vector2 hitCohtmlCoords; + + // Telepathic pickup + public bool hasTelepathicGrabCandidate; + public Pickupable telepathicPickupable; + public Vector3 telepathicGrabPoint; + } +} \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/RaycastDebug.cs b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/RaycastDebug.cs new file mode 100644 index 0000000..5000f89 --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/RaycastDebug.cs @@ -0,0 +1,312 @@ +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace ABI_RC.Core.Player.Interaction.RaycastImpl +{ +public class CVRRaycastDebugManager : MonoBehaviour +{ + #region Singleton + + private static CVRRaycastDebugManager _instance; + public static CVRRaycastDebugManager Instance => _instance; + + public static void Initialize(Camera camera) + { + if (_instance != null) return; + + var go = new GameObject("RaycastDebugManager"); + _instance = go.AddComponent(); + DontDestroyOnLoad(go); + + _instance.Setup(camera); + } + + #endregion + + #region Private Fields + + private CVRPlayerRaycasterMouse _raycaster; + private CVRRaycastResult _lastResult; + private System.Diagnostics.Stopwatch _stopwatch; + + // Performance tracking + private const int ROLLING_AVERAGE_SAMPLES = 60; // 1 second at 60fps + private readonly float[] _timeHistory = new float[ROLLING_AVERAGE_SAMPLES]; + private int _currentSampleIndex; + private float _lastRaycastTime; + private float _minRaycastTime = float.MaxValue; + private float _maxRaycastTime; + private float _rollingAverageTime; + private bool _historyFilled; + + private const int DEBUG_PANEL_WIDTH = 300; + private const int DEBUG_PANEL_MARGIN = 10; + private const float MOUSE_CURSOR_SIZE = 24f; + private const float CURSOR_OFFSET = MOUSE_CURSOR_SIZE / 2f; + + private GUIStyle _labelStyle; + private GUIStyle _headerStyle; + private GUIStyle _boxStyle; + + private static readonly Color32 TIMING_COLOR = new(255, 255, 150, 255); // Yellow + private static readonly Color32 COHTML_COLOR = new(150, 255, 150, 255); // Green + private static readonly Color32 UI_COLOR = new(150, 150, 255, 255); // Blue + private static readonly Color32 UNITY_UI_COLOR = new(255, 200, 150, 255); // Orange + private static readonly Color32 INTERACT_COLOR = new(255, 150, 150, 255); // Red + private static readonly Color32 WATER_COLOR = new(150, 255, 255, 255); // Cyan + private static readonly Color32 TELEPATHIC_COLOR = new(255, 150, 255, 255);// Purple + private static readonly Color32 SELECTABLE_COLOR = new(200, 150, 255, 255);// Light Purple + + #endregion + + #region Setup + + private void Setup(Camera camera) + { + _raycaster = new CVRPlayerRaycasterMouse(transform, camera); + _raycaster.SetLayerMask(Physics.DefaultRaycastLayers); + _stopwatch = new System.Diagnostics.Stopwatch(); + } + + #endregion + + #region MonoBehaviour + + private void Update() + { + _stopwatch.Restart(); + _lastResult = _raycaster.GetRaycastResults(); + _stopwatch.Stop(); + + UpdatePerformanceMetrics(); + } + + private void UpdatePerformanceMetrics() + { + // Calculate current frame time + _lastRaycastTime = _stopwatch.ElapsedTicks / (float)System.TimeSpan.TicksPerMillisecond; + + // Update min/max + _minRaycastTime = Mathf.Min(_minRaycastTime, _lastRaycastTime); + _maxRaycastTime = Mathf.Max(_maxRaycastTime, _lastRaycastTime); + + // Update rolling average + _timeHistory[_currentSampleIndex] = _lastRaycastTime; + + // Calculate rolling average based on filled samples + float sum = 0f; + int sampleCount = _historyFilled ? ROLLING_AVERAGE_SAMPLES : _currentSampleIndex + 1; + + for (int i = 0; i < sampleCount; i++) + sum += _timeHistory[i]; + + _rollingAverageTime = sum / sampleCount; + + // Update index for next frame + _currentSampleIndex = (_currentSampleIndex + 1) % ROLLING_AVERAGE_SAMPLES; + if (_currentSampleIndex == 0) + _historyFilled = true; + } + + private void OnGUI() + { + InitializeStyles(); + DrawDebugPanel(); + } + + #endregion + + #region Drawing Methods + + private void InitializeStyles() + { + if (_labelStyle != null) return; + + _labelStyle = new GUIStyle + { + normal = { textColor = Color.white }, + fontSize = 12, + padding = new RectOffset(5, 5, 2, 2), + margin = new RectOffset(5, 5, 0, 0) + }; + + _headerStyle = new GUIStyle + { + normal = { textColor = Color.white }, + fontSize = 14, + fontStyle = FontStyle.Bold, + padding = new RectOffset(5, 5, 5, 5), + margin = new RectOffset(5, 5, 5, 5) + }; + + _boxStyle = new GUIStyle(GUI.skin.box) + { + padding = new RectOffset(10, 10, 5, 5), + margin = new RectOffset(5, 5, 5, 5) + }; + } + + private void DrawDebugPanel() + { + var rect = new Rect( + Screen.width - DEBUG_PANEL_WIDTH - DEBUG_PANEL_MARGIN, + DEBUG_PANEL_MARGIN, + DEBUG_PANEL_WIDTH, + Screen.height - (DEBUG_PANEL_MARGIN * 2) + ); + + GUI.Box(rect, ""); + GUILayout.BeginArea(rect); + + GUI.backgroundColor = Color.black; + GUILayout.Label("Raycast Debug Info", _headerStyle); + + DrawPerformanceSection(); + DrawCohtmlSection(); + DrawUnityUISection(); + DrawSelectableSection(); + DrawInteractionSection(); + DrawWaterSection(); + DrawTelepathicSection(); + DrawWorldHitSection(); + + GUILayout.EndArea(); + } + + private void DrawPerformanceSection() + { + GUI.backgroundColor = TIMING_COLOR; + GUILayout.BeginVertical(_boxStyle); + GUILayout.Label("Performance", _headerStyle); + DrawLabel("Last Raycast", $"{_lastRaycastTime:F3} ms"); + DrawLabel("Average (1s)", $"{_rollingAverageTime:F3} ms"); + DrawLabel("Min", $"{_minRaycastTime:F3} ms"); + DrawLabel("Max", $"{_maxRaycastTime:F3} ms"); + GUILayout.EndVertical(); + } + + private void DrawCohtmlSection() + { + if (!_lastResult.hitCohtml) return; + + GUI.backgroundColor = COHTML_COLOR; + GUILayout.BeginVertical(_boxStyle); + GUILayout.Label("COHTML Hit", _headerStyle); + DrawLabel("View", _lastResult.hitCohtmlView.name); + DrawLabel("Coords", _lastResult.hitCohtmlCoords.ToString()); + GUILayout.EndVertical(); + } + + private void DrawUnityUISection() + { + if (!_lastResult.hitUnityUi || _lastResult.hitCanvasElement == null) return; + + GUI.backgroundColor = UNITY_UI_COLOR; + GUILayout.BeginVertical(_boxStyle); + GUILayout.Label("Unity UI Hit", _headerStyle); + + var canvasElement = _lastResult.hitCanvasElement; + var gameObject = canvasElement as MonoBehaviour; + + DrawLabel("Canvas Element", gameObject != null ? gameObject.name : "Unknown"); + DrawLabel("Element Type", canvasElement.GetType().Name); + + if (gameObject != null) + { + DrawLabel("GameObject", gameObject.gameObject.name); + + if (gameObject.transform.parent != null) + DrawLabel("Parent", gameObject.transform.parent.name); + } + + GUILayout.EndVertical(); + } + + private void DrawSelectableSection() + { + if (_lastResult.hitSelectable == null) return; + + GUI.backgroundColor = SELECTABLE_COLOR; + GUILayout.BeginVertical(_boxStyle); + GUILayout.Label("UI Selectable", _headerStyle); + DrawLabel("Selectable", _lastResult.hitSelectable.name); + DrawLabel("Selectable Type", _lastResult.hitSelectable.GetType().Name); + DrawLabel("Is Interactable", _lastResult.hitSelectable.interactable.ToString()); + DrawLabel("Navigation Mode", _lastResult.hitSelectable.navigation.mode.ToString()); + + if (_lastResult.hitSelectable is Toggle toggle) + DrawLabel("Toggle State", toggle.isOn.ToString()); + else if (_lastResult.hitSelectable is Slider slider) + DrawLabel("Slider Value", slider.value.ToString("F2")); + else if (_lastResult.hitSelectable is Scrollbar scrollbar) + DrawLabel("Scrollbar Value", scrollbar.value.ToString("F2")); + + GUILayout.EndVertical(); + } + + private void DrawInteractionSection() + { + if (!_lastResult.hitPickupable && !_lastResult.hitInteractable) return; + + GUI.backgroundColor = INTERACT_COLOR; + GUILayout.BeginVertical(_boxStyle); + GUILayout.Label("Interaction", _headerStyle); + if (_lastResult.hitPickupable) + DrawLabel("Pickupable", _lastResult.hitPickupable.name); + if (_lastResult.hitInteractable) + DrawLabel("Interactable", _lastResult.hitInteractable.name); + DrawLabel("Is Proximity", _lastResult.isProximityHit.ToString()); + GUILayout.EndVertical(); + } + + private void DrawWaterSection() + { + if (!_lastResult.hitWater || !_lastResult.waterHit.HasValue) return; + + GUI.backgroundColor = WATER_COLOR; + GUILayout.BeginVertical(_boxStyle); + GUILayout.Label("Water Surface", _headerStyle); + DrawLabel("Hit Point", _lastResult.waterHit.Value.point.ToString("F2")); + DrawLabel("Surface Normal", _lastResult.waterHit.Value.normal.ToString("F2")); + GUILayout.EndVertical(); + } + + private void DrawTelepathicSection() + { + if (!_lastResult.hasTelepathicGrabCandidate) return; + + GUI.backgroundColor = TELEPATHIC_COLOR; + GUILayout.BeginVertical(_boxStyle); + GUILayout.Label("Telepathic Grab", _headerStyle); + DrawLabel("Target", _lastResult.telepathicPickupable.name); + DrawLabel("Grab Point", _lastResult.telepathicGrabPoint.ToString("F2")); + GUILayout.EndVertical(); + } + + private void DrawWorldHitSection() + { + if (_lastResult.hitCohtml || + _lastResult.hitPickupable || + _lastResult.hitInteractable || + _lastResult.hitUnityUi || + !_lastResult.hitWorld || + _lastResult.hit.collider == null) return; + + GUI.backgroundColor = Color.grey; + GUILayout.BeginVertical(_boxStyle); + GUILayout.Label("World Hit", _headerStyle); + DrawLabel("Object", _lastResult.hit.collider.name); + DrawLabel("Distance", _lastResult.hit.distance.ToString("F2")); + DrawLabel("Point", _lastResult.hit.point.ToString("F2")); + GUILayout.EndVertical(); + } + + private void DrawLabel(string label, string value) + { + GUILayout.Label($"{label}: {value}", _labelStyle); + } + + #endregion +} +} \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Main.cs b/.Deprecated/SuperAwesomeMod/Main.cs new file mode 100644 index 0000000..5c410f2 --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Main.cs @@ -0,0 +1,81 @@ +using System.Reflection; +using ABI_RC.Core.Base.Jobs; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Player; +using ABI_RC.Core.Player.Interaction.RaycastImpl; +using ABI_RC.Core.Util.AssetFiltering; +using ABI.CCK.Components; +using HarmonyLib; +using MelonLoader; +using NAK.SuperAwesomeMod.Components; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace NAK.SuperAwesomeMod; + +public class SuperAwesomeModMod : MelonMod +{ + #region Melon Events + + public override void OnInitializeMelon() + { + HarmonyInstance.Patch( + typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.Start), + BindingFlags.NonPublic | BindingFlags.Instance), + postfix: new HarmonyMethod(typeof(SuperAwesomeModMod).GetMethod(nameof(OnPlayerSetupStart), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + HarmonyInstance.Patch( + typeof(SceneLoaded).GetMethod(nameof(SceneLoaded.FilterWorldComponent), + BindingFlags.NonPublic | BindingFlags.Static), + postfix: new HarmonyMethod(typeof(SuperAwesomeModMod).GetMethod(nameof(OnShitLoaded), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + // patch SharedFilter.ProcessCanvas + HarmonyInstance.Patch( + typeof(SharedFilter).GetMethod(nameof(SharedFilter.ProcessCanvas), + BindingFlags.Public | BindingFlags.Static), + postfix: new HarmonyMethod(typeof(SuperAwesomeModMod).GetMethod(nameof(OnProcessCanvas), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + LoggerInstance.Msg("SuperAwesomeModMod! OnInitializeMelon! :D"); + } + + public override void OnApplicationQuit() + { + LoggerInstance.Msg("SuperAwesomeModMod! OnApplicationQuit! D:"); + } + + #endregion Melon Events + + private static void OnPlayerSetupStart() + { + CVRRaycastDebugManager.Initialize(PlayerSetup.Instance.desktopCam); + } + + private static void OnShitLoaded(Component c, List asyncTasks = null, Scene? scene = null) + { + if (c == null) + return; + + if (c.gameObject == null) + return; + + if (c.gameObject.scene.buildIndex > 0) + return; + + if ((scene != null) + && (c.gameObject.scene != scene)) + return; + + if (c is Canvas canvas) canvas.gameObject.AddComponent(); + } + + private static void OnProcessCanvas(string collectionId, Canvas canvas) + { + canvas.gameObject.AddComponent(); + } +} \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Properties/AssemblyInfo.cs b/.Deprecated/SuperAwesomeMod/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f1590e2 --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using MelonLoader; +using NAK.SuperAwesomeMod.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.SuperAwesomeMod))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.SuperAwesomeMod))] + +[assembly: MelonInfo( + typeof(NAK.SuperAwesomeMod.SuperAwesomeModMod), + nameof(NAK.SuperAwesomeMod), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/SuperAwesomeMod" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red +[assembly: HarmonyDontPatchAll] + +namespace NAK.SuperAwesomeMod.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/.Deprecated/SuperAwesomeMod/README.md b/.Deprecated/SuperAwesomeMod/README.md new file mode 100644 index 0000000..399e70a --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/README.md @@ -0,0 +1,54 @@ +# ASTExtension + +Extension mod for [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool): +- VR Gesture to scale +- Persistent height +- Copy height from others + +Best used with Avatar Scale Tool, but will attempt to work with found scaling setups. +Requires already having Avatar Scaling on the avatar. This is **not** Universal Scaling. + +## Supported Setups + +ASTExtension will attempt to work with the following setups: + +**Parameter Names:** +- AvatarScale +- Scale +- Scaler +- Scale/Scale +- Height +- LoliModifier +- AvatarSize +- Size +- SizeScale +- Scaling + +These parameter names are not case sensitive and have been gathered from polling the community for common parameter names. + +Assuming the parameter is a float, ASTExtension will attempt to use it as the height parameter. Will automatically calibrate to the height range of the found parameter, assuming the scaling animation is in a blend tree / state using motion time & is linear. The scaling animation state **must be active** at time of avatar load. + +The max value ASTExtension will drive the parameter to is 100. As the mod is having to guess the max height, it may not be accurate if the max height is not capped at a multiple of 10. + +Examples: +- `AvatarScale` - 0 to 1 (slider) + - This is the default setup for Avatar Scale Tool and will work perfectly. +- `Scale` - 0 to 100 (input single) + - This will also work perfectly as the max height is a multiple of 10. +- `Height` - 0 to 2 (input single) + - This will not work properly. The max value to drive the parameter to is not a multiple of 10, and as such ASTExtension will believe the parameter range is 0 to 1. +- `BurntToast` - 0 to 10 (input single) + - This will not work properly. The parameter name is not recognized by ASTExtension. + +If your setup is theoretically supported but not working, it is likely the scaling animation is not linear or has loop enabled if using Motion Time, making the first and last frame identical height. In this case, you will need to fix your animation clip curves / blend tree to be linear &|| not loop, or use Avatar Scale Tool to generate a new scaling animation. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation 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/InteractionTest/InteractionTest.csproj b/.Deprecated/SuperAwesomeMod/SuperAwesomeMod.csproj similarity index 52% rename from InteractionTest/InteractionTest.csproj rename to .Deprecated/SuperAwesomeMod/SuperAwesomeMod.csproj index 1b7a95f..fa113da 100644 --- a/InteractionTest/InteractionTest.csproj +++ b/.Deprecated/SuperAwesomeMod/SuperAwesomeMod.csproj @@ -1,13 +1,12 @@ + + ASTExtension + ..\.ManagedLibs\BTKUILib.dll + False - - - - - diff --git a/.Deprecated/SuperAwesomeMod/format.json b/.Deprecated/SuperAwesomeMod/format.json new file mode 100644 index 0000000..5ad14ea --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/format.json @@ -0,0 +1,24 @@ +{ + "_id": 223, + "name": "ASTExtension", + "modversion": "1.0.2", + "gameversion": "2025r178", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Extension mod for [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool):\n- VR Gesture to scale\n- Persistent height\n- Copy height from others\n\nBest used with Avatar Scale Tool, but will attempt to work with found scaling setups.\nRequires already having Avatar Scaling on the avatar. This is **not** Universal Scaling.", + "searchtags": [ + "tool", + "scaling", + "height", + "extension", + "avatar" + ], + "requirements": [ + "BTKUILib" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r45/ASTExtension.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ASTExtension/", + "changelog": "- Fixes for 2025r178", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/.DepricatedMods/SwitchToDesktopOnSteamVRExit/Main.cs b/.Deprecated/SwitchToDesktopOnSteamVRExit/Main.cs similarity index 100% rename from .DepricatedMods/SwitchToDesktopOnSteamVRExit/Main.cs rename to .Deprecated/SwitchToDesktopOnSteamVRExit/Main.cs diff --git a/.DepricatedMods/SwitchToDesktopOnSteamVRExit/Properties/AssemblyInfo.cs b/.Deprecated/SwitchToDesktopOnSteamVRExit/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/SwitchToDesktopOnSteamVRExit/Properties/AssemblyInfo.cs rename to .Deprecated/SwitchToDesktopOnSteamVRExit/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/SwitchToDesktopOnSteamVRExit/README.md b/.Deprecated/SwitchToDesktopOnSteamVRExit/README.md similarity index 100% rename from .DepricatedMods/SwitchToDesktopOnSteamVRExit/README.md rename to .Deprecated/SwitchToDesktopOnSteamVRExit/README.md diff --git a/.DepricatedMods/SwitchToDesktopOnSteamVRExit/SwitchToDesktopOnSteamVRExit.csproj b/.Deprecated/SwitchToDesktopOnSteamVRExit/SwitchToDesktopOnSteamVRExit.csproj similarity index 100% rename from .DepricatedMods/SwitchToDesktopOnSteamVRExit/SwitchToDesktopOnSteamVRExit.csproj rename to .Deprecated/SwitchToDesktopOnSteamVRExit/SwitchToDesktopOnSteamVRExit.csproj diff --git a/.DepricatedMods/SwitchToDesktopOnSteamVRExit/format.json b/.Deprecated/SwitchToDesktopOnSteamVRExit/format.json similarity index 100% rename from .DepricatedMods/SwitchToDesktopOnSteamVRExit/format.json rename to .Deprecated/SwitchToDesktopOnSteamVRExit/format.json diff --git a/.DepricatedMods/TrackedControllerFix/HarmonyPatches.cs b/.Deprecated/TrackedControllerFix/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/TrackedControllerFix/HarmonyPatches.cs rename to .Deprecated/TrackedControllerFix/HarmonyPatches.cs diff --git a/.DepricatedMods/TrackedControllerFix/Main.cs b/.Deprecated/TrackedControllerFix/Main.cs similarity index 100% rename from .DepricatedMods/TrackedControllerFix/Main.cs rename to .Deprecated/TrackedControllerFix/Main.cs diff --git a/.DepricatedMods/TrackedControllerFix/Properties/AssemblyInfo.cs b/.Deprecated/TrackedControllerFix/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/TrackedControllerFix/Properties/AssemblyInfo.cs rename to .Deprecated/TrackedControllerFix/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/TrackedControllerFix/README.md b/.Deprecated/TrackedControllerFix/README.md similarity index 100% rename from .DepricatedMods/TrackedControllerFix/README.md rename to .Deprecated/TrackedControllerFix/README.md diff --git a/.DepricatedMods/TrackedControllerFix/TrackedControllerFix.csproj b/.Deprecated/TrackedControllerFix/TrackedControllerFix.csproj similarity index 100% rename from .DepricatedMods/TrackedControllerFix/TrackedControllerFix.csproj rename to .Deprecated/TrackedControllerFix/TrackedControllerFix.csproj diff --git a/.DepricatedMods/TrackedControllerFix/TrackedControllerFixer.cs b/.Deprecated/TrackedControllerFix/TrackedControllerFixer.cs similarity index 100% rename from .DepricatedMods/TrackedControllerFix/TrackedControllerFixer.cs rename to .Deprecated/TrackedControllerFix/TrackedControllerFixer.cs diff --git a/.DepricatedMods/TrackedControllerFix/format.json b/.Deprecated/TrackedControllerFix/format.json similarity index 100% rename from .DepricatedMods/TrackedControllerFix/format.json rename to .Deprecated/TrackedControllerFix/format.json diff --git a/.DepricatedMods/TrackedPointFix/HarmonyPatches.cs b/.Deprecated/TrackedPointFix/HarmonyPatches.cs similarity index 100% rename from .DepricatedMods/TrackedPointFix/HarmonyPatches.cs rename to .Deprecated/TrackedPointFix/HarmonyPatches.cs diff --git a/.DepricatedMods/TrackedPointFix/Main.cs b/.Deprecated/TrackedPointFix/Main.cs similarity index 100% rename from .DepricatedMods/TrackedPointFix/Main.cs rename to .Deprecated/TrackedPointFix/Main.cs diff --git a/.DepricatedMods/TrackedPointFix/Properties/AssemblyInfo.cs b/.Deprecated/TrackedPointFix/Properties/AssemblyInfo.cs similarity index 100% rename from .DepricatedMods/TrackedPointFix/Properties/AssemblyInfo.cs rename to .Deprecated/TrackedPointFix/Properties/AssemblyInfo.cs diff --git a/.DepricatedMods/TrackedPointFix/README.md b/.Deprecated/TrackedPointFix/README.md similarity index 100% rename from .DepricatedMods/TrackedPointFix/README.md rename to .Deprecated/TrackedPointFix/README.md diff --git a/.DepricatedMods/TrackedPointFix/TrackedPointFix.csproj b/.Deprecated/TrackedPointFix/TrackedPointFix.csproj similarity index 100% rename from .DepricatedMods/TrackedPointFix/TrackedPointFix.csproj rename to .Deprecated/TrackedPointFix/TrackedPointFix.csproj diff --git a/.DepricatedMods/TrackedPointFix/format.json b/.Deprecated/TrackedPointFix/format.json similarity index 100% rename from .DepricatedMods/TrackedPointFix/format.json rename to .Deprecated/TrackedPointFix/format.json diff --git a/VisualCloneFix/Main.cs b/.Deprecated/VisualCloneFix/Main.cs similarity index 100% rename from VisualCloneFix/Main.cs rename to .Deprecated/VisualCloneFix/Main.cs diff --git a/.Deprecated/VisualCloneFix/Patches.cs b/.Deprecated/VisualCloneFix/Patches.cs new file mode 100644 index 0000000..d1fb84b --- /dev/null +++ b/.Deprecated/VisualCloneFix/Patches.cs @@ -0,0 +1,157 @@ +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using ABI_RC.Core.Player.LocalClone; +using ABI_RC.Core.Player.TransformHider; +using ABI.CCK.Components; +using HarmonyLib; +using UnityEngine; +using Debug = UnityEngine.Debug; + +namespace NAK.VisualCloneFix; + +public static class Patches +{ + [HarmonyPrefix] + [HarmonyPatch(typeof(TransformHiderUtils), nameof(TransformHiderUtils.SetupAvatar))] + private static bool OnSetupAvatar(GameObject avatar) + { + if (!VisualCloneFixMod.EntryUseVisualClone.Value) return true; + LocalCloneHelper.SetupAvatar(avatar); + return false; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(LocalCloneHelper), nameof(LocalCloneHelper.CollectTransformToExclusionMap))] + private static bool CollectTransformToExclusionMap( + Component root, Transform headBone, + ref Dictionary __result) + { + // add an fpr exclusion to the head bone + if (!headBone.TryGetComponent(out FPRExclusion headExclusion)) + { + headExclusion = headBone.gameObject.AddComponent(); + headExclusion.isShown = false; // default to hidden + headExclusion.target = headBone; + } + + MeshHiderExclusion headExclusionBehaviour = new(); + headExclusion.behaviour = headExclusionBehaviour; + headExclusionBehaviour.id = 1; // head bone is always 1 + + // get all FPRExclusions + var fprExclusions = root.GetComponentsInChildren(true); + + // get all valid exclusion targets, and destroy invalid exclusions + Dictionary exclusionTargets = new(); + + int nextId = 2; + foreach (FPRExclusion exclusion in fprExclusions) + { + if (exclusion.target == null + || exclusionTargets.ContainsKey(exclusion.target) + || !exclusion.target.gameObject.scene.IsValid()) + continue; // invalid exclusion + + if (exclusion.behaviour == null) // head exclusion is already created + { + MeshHiderExclusion meshHiderExclusion = new(); + exclusion.behaviour = meshHiderExclusion; + meshHiderExclusion.id = nextId++; + } + + // first to add wins + exclusionTargets.TryAdd(exclusion.target, exclusion); + } + + // process each FPRExclusion (recursive) + int exclusionCount = exclusionTargets.Values.Count; + for (var index = 0; index < exclusionCount; index++) + { + FPRExclusion exclusion = exclusionTargets.Values.ElementAt(index); + ProcessExclusion(exclusion, exclusion.target); + exclusion.UpdateExclusions(); // initial state + } + + __result = exclusionTargets; + return false; + + void ProcessExclusion(FPRExclusion exclusion, Transform transform) + { + if (exclusionTargets.ContainsKey(transform) + && exclusionTargets[transform] != exclusion) return; // found other exclusion root + + exclusionTargets.TryAdd(transform, exclusion); // add to the dictionary (yes its wasteful) + foreach (Transform child in transform) + ProcessExclusion(exclusion, child); // process children + } + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(SkinnedLocalClone), nameof(SkinnedLocalClone.FindExclusionVertList))] + private static bool FindExclusionVertList( + SkinnedMeshRenderer renderer, IReadOnlyDictionary exclusions, + ref int[] __result) + { + // Start the stopwatch + Stopwatch stopwatch = new(); + stopwatch.Start(); + + var boneWeights = renderer.sharedMesh.boneWeights; + var bones = renderer.bones; + int boneCount = bones.Length; + + bool[] boneHasExclusion = new bool[boneCount]; + + // Populate the weights array + for (int i = 0; i < boneCount; i++) + { + Transform bone = bones[i]; + if (bone == null) continue; + if (exclusions.ContainsKey(bone)) + boneHasExclusion[i] = true; + } + + const float minWeightThreshold = 0.2f; + + int[] vertexIndices = new int[renderer.sharedMesh.vertexCount]; + + // Check bone weights and add vertex to exclusion list if needed + for (int i = 0; i < boneWeights.Length; i++) + { + BoneWeight weight = boneWeights[i]; + Transform bone; + + if (boneHasExclusion[weight.boneIndex0] && weight.weight0 > minWeightThreshold) + bone = bones[weight.boneIndex0]; + else if (boneHasExclusion[weight.boneIndex1] && weight.weight1 > minWeightThreshold) + bone = bones[weight.boneIndex1]; + else if (boneHasExclusion[weight.boneIndex2] && weight.weight2 > minWeightThreshold) + bone = bones[weight.boneIndex2]; + else if (boneHasExclusion[weight.boneIndex3] && weight.weight3 > minWeightThreshold) + bone = bones[weight.boneIndex3]; + else continue; + + if (exclusions.TryGetValue(bone, out FPRExclusion exclusion)) + vertexIndices[i] = ((MeshHiderExclusion)(exclusion.behaviour)).id; + } + + // Stop the stopwatch + stopwatch.Stop(); + + // Log the execution time + Debug.Log($"FindExclusionVertList execution time: {stopwatch.ElapsedMilliseconds} ms"); + + __result = vertexIndices; + return false; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(MeshHiderExclusion), nameof(MeshHiderExclusion.UpdateExclusions))] + private static bool OnUpdateExclusions(bool isShown, bool shrinkToZero, ref int ___id) + { + if (isShown) LocalCloneManager.cullingMask &= ~(1 << ___id); + else LocalCloneManager.cullingMask |= 1 << ___id; + return false; + } +} \ No newline at end of file diff --git a/VisualCloneFix/Properties/AssemblyInfo.cs b/.Deprecated/VisualCloneFix/Properties/AssemblyInfo.cs similarity index 100% rename from VisualCloneFix/Properties/AssemblyInfo.cs rename to .Deprecated/VisualCloneFix/Properties/AssemblyInfo.cs diff --git a/VisualCloneFix/README.md b/.Deprecated/VisualCloneFix/README.md similarity index 100% rename from VisualCloneFix/README.md rename to .Deprecated/VisualCloneFix/README.md diff --git a/VisualCloneFix/VisualCloneFix.csproj b/.Deprecated/VisualCloneFix/VisualCloneFix.csproj similarity index 100% rename from VisualCloneFix/VisualCloneFix.csproj rename to .Deprecated/VisualCloneFix/VisualCloneFix.csproj diff --git a/VisualCloneFix/format.json b/.Deprecated/VisualCloneFix/format.json similarity index 100% rename from VisualCloneFix/format.json rename to .Deprecated/VisualCloneFix/format.json diff --git a/.Deprecated/WhereAmIPointing/Main.cs b/.Deprecated/WhereAmIPointing/Main.cs new file mode 100644 index 0000000..24529b4 --- /dev/null +++ b/.Deprecated/WhereAmIPointing/Main.cs @@ -0,0 +1,106 @@ +using ABI_RC.Core.InteractionSystem; +using HarmonyLib; +using MelonLoader; +using UnityEngine; + +namespace NAK.WhereAmIPointing; + +public class WhereAmIPointingMod : MelonMod +{ + #region Melon Preferences + + // cannot disable because then id need extra logic to reset the alpha :) + // private const string SettingsCategory = nameof(WhereAmIPointingMod); + // + // private static readonly MelonPreferences_Category Category = + // MelonPreferences.CreateCategory(SettingsCategory); + // + // private static readonly MelonPreferences_Entry Entry_Enabled = + // Category.CreateEntry("enabled", true, display_name: "Enabled",description: "Toggle WhereAmIPointingMod entirely."); + + #endregion Melon Preferences + + public override void OnInitializeMelon() + { + ApplyPatches(typeof(ControllerRay_Patches)); + } + + private void ApplyPatches(Type type) + { + try + { + HarmonyInstance.PatchAll(type); + } + catch (Exception e) + { + LoggerInstance.Msg($"Failed while patching {type.Name}!"); + LoggerInstance.Error(e); + } + } + + #region Patches + + private static class ControllerRay_Patches + { + private const float ORIGINAL_ALPHA = 0.502f; + private const float INTERACTION_ALPHA = 0.1f; + private const float RAY_LENGTH = 1000f; // game normally raycasts to PositiveInfinity... -_- + + [HarmonyPostfix] + [HarmonyPatch(typeof(ControllerRay), nameof(ControllerRay.LateUpdate))] + private static void Postfix_ControllerRay_LateUpdate(ref ControllerRay __instance) + { + if (__instance.isDesktopRay + || !__instance.enabled + || !__instance.IsTracking() + || !__instance.lineRenderer) + return; + + UpdateLineRendererAlpha(__instance); + + if (__instance.lineRenderer.enabled + || !ShouldOverrideLineRenderer(__instance)) + return; + + UpdateLineRendererPosition(__instance); + } + + private static void UpdateLineRendererAlpha(ControllerRay instance) + { + Material material = instance.lineRenderer.material; + Color color = material.color; + + bool anyMenuOpen = ViewManager.Instance.IsAnyMenuOpen; + float targetAlpha = (!anyMenuOpen || instance.uiActive) ? ORIGINAL_ALPHA : INTERACTION_ALPHA; + if (!(Math.Abs(color.a - targetAlpha) > float.Epsilon)) + return; + + color.a = targetAlpha; + material.color = color; + } + + private static bool ShouldOverrideLineRenderer(ControllerRay instance) + { + if (!ViewManager.Instance.IsAnyMenuOpen) + return false; + + if (CVR_MenuManager.Instance.IsQuickMenuOpen + && instance.hand == CVR_MenuManager.Instance.SelectedQuickMenuHand) + return false; + + return true; + } + + private static void UpdateLineRendererPosition(ControllerRay instance) + { + Vector3 rayOrigin = instance.rayDirectionTransform.position; + Vector3 rayEnd = rayOrigin + instance.rayDirectionTransform.forward * RAY_LENGTH; + + instance.lineRenderer.SetPosition(0, instance.lineRenderer.transform.InverseTransformPoint(rayOrigin)); + instance.lineRenderer.SetPosition(1, instance.lineRenderer.transform.InverseTransformPoint(rayEnd)); + instance.lineRenderer.enabled = true; + } + } + + #endregion Patches +} \ No newline at end of file diff --git a/.Deprecated/WhereAmIPointing/Properties/AssemblyInfo.cs b/.Deprecated/WhereAmIPointing/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..48c359f --- /dev/null +++ b/.Deprecated/WhereAmIPointing/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using NAK.WhereAmIPointing.Properties; +using MelonLoader; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.WhereAmIPointing))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.WhereAmIPointing))] + +[assembly: MelonInfo( + typeof(NAK.WhereAmIPointing.WhereAmIPointingMod), + nameof(NAK.WhereAmIPointing), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/WhereAmIPointing" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red +[assembly: HarmonyDontPatchAll] + +namespace NAK.WhereAmIPointing.Properties; +internal static class AssemblyInfoParams +{ + public const string Version = "1.0.1"; + public const string Author = "NotAKidoS"; +} \ No newline at end of file diff --git a/.Deprecated/WhereAmIPointing/README.md b/.Deprecated/WhereAmIPointing/README.md new file mode 100644 index 0000000..c78a56a --- /dev/null +++ b/.Deprecated/WhereAmIPointing/README.md @@ -0,0 +1,14 @@ +# WhereAmIPointing + +Simple mod that makes your controller rays always visible when the menus are open. Useful for when you're trying to aim at something in the distance. Also visualizes which ray is being used for menu interaction. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation 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/.Deprecated/WhereAmIPointing/WhereAmIPointing.csproj b/.Deprecated/WhereAmIPointing/WhereAmIPointing.csproj new file mode 100644 index 0000000..728edb7 --- /dev/null +++ b/.Deprecated/WhereAmIPointing/WhereAmIPointing.csproj @@ -0,0 +1,6 @@ + + + + net48 + + diff --git a/.Deprecated/WhereAmIPointing/format.json b/.Deprecated/WhereAmIPointing/format.json new file mode 100644 index 0000000..654911a --- /dev/null +++ b/.Deprecated/WhereAmIPointing/format.json @@ -0,0 +1,23 @@ +{ + "_id": 234, + "name": "WhereAmIPointing", + "modversion": "1.0.1", + "gameversion": "2024r175", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Simple mod that makes your controller rays always visible when the menus are open. Useful for when you're trying to aim at something in the distance. Also visualizes which ray is being used for menu interaction.", + "searchtags": [ + "controller", + "ray", + "line", + "tomato" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r40/WhereAmIPointing.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/WhereAmIPointing/", + "changelog": "- Fixed line renderer alpha not being reset when the menu is closed.", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7a3e958..2abd364 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,9 @@ ## ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore +# NAK +.Experimental/ + # Nstrip & ManagedLibs stuff NStrip.exe .ManagedLibs/*.dll diff --git a/ASTExtension/Integrations/BTKUI/BtkUiAddon.cs b/ASTExtension/Integrations/BTKUI/BtkUiAddon.cs index cbb7534..e0e294a 100644 --- a/ASTExtension/Integrations/BTKUI/BtkUiAddon.cs +++ b/ASTExtension/Integrations/BTKUI/BtkUiAddon.cs @@ -1,7 +1,9 @@ using ABI_RC.Core.Player; +using ABI_RC.Core.Util.AnimatorManager; using BTKUILib; using BTKUILib.UIObjects; using BTKUILib.UIObjects.Components; +using UnityEngine; namespace NAK.ASTExtension.Integrations; @@ -29,6 +31,9 @@ public static partial class BtkUiAddon Category category = QuickMenuAPI.PlayerSelectPage.AddCategory(ASTExtensionMod.ModName, ASTExtensionMod.ModName); Button button = category.AddButton("Copy Height", "ASM_Icon_AvatarHeightCopy", "Copy selected players Eye Height."); button.OnPress += OnCopyPlayerHeight; + + Button button2 = category.AddButton("Copy AAS", string.Empty, "Copy selected players AAS."); + button2.OnPress += OnCopyPlayerAAS; } private static void OnPlayerSelected(string _, string id) @@ -38,18 +43,56 @@ public static partial class BtkUiAddon private static void OnCopyPlayerHeight() { - if (string.IsNullOrEmpty(_selectedPlayer)) - return; - - if (!CVRPlayerManager.Instance.GetPlayerPuppetMaster(_selectedPlayer, out PuppetMaster player)) - return; - - if (player._avatar == null) - return; + if (string.IsNullOrEmpty(_selectedPlayer)) + return; + + if (!CVRPlayerManager.Instance.GetPlayerPuppetMaster(_selectedPlayer, out PuppetMaster player)) + return; + + if (player._avatar == null) + return; - float height = player.netIkController.GetRemoteHeight(); - ASTExtensionMod.Instance.SetAvatarHeight(height); + float height = player.netIkController.GetRemoteHeight(); + ASTExtensionMod.Instance.SetAvatarHeight(height); + } + + private static void OnCopyPlayerAAS() + { + if (string.IsNullOrEmpty(_selectedPlayer)) + return; + + if (!CVRPlayerManager.Instance.GetPlayerPuppetMaster(_selectedPlayer, out PuppetMaster player)) + return; + + AvatarAnimatorManager localAnimator = PlayerSetup.Instance.animatorManager; + AvatarAnimatorManager remoteAnimator = player.animatorManager; + if (!localAnimator.IsInitialized + || !remoteAnimator.IsInitialized) + return; + + // Copy AAS + foreach ((var parameterName, CVRAnimatorManager.ParamDef paramDef) in remoteAnimator.Parameters) + { + switch (paramDef.type) + { + case AnimatorControllerParameterType.Trigger: + case AnimatorControllerParameterType.Bool: + remoteAnimator.GetParameter(parameterName, out bool value); + localAnimator.SetParameter(parameterName, value); + break; + case AnimatorControllerParameterType.Float: + remoteAnimator.GetParameter(parameterName, out float value2); + localAnimator.SetParameter(parameterName, value2); + break; + case AnimatorControllerParameterType.Int: + remoteAnimator.GetParameter(parameterName, out int value3); + localAnimator.SetParameter(parameterName, value3); + break; + } } + + } + #endregion Player Select Page } \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.API.cs b/AvatarCloneTest/AvatarClone/AvatarClone.API.cs deleted file mode 100644 index 89835bd..0000000 --- a/AvatarCloneTest/AvatarClone/AvatarClone.API.cs +++ /dev/null @@ -1,68 +0,0 @@ -using UnityEngine; - -namespace NAK.AvatarCloneTest; - -public partial class AvatarClone -{ - #region Public API Methods - - /// - /// Sets whether the specific renderer requires additional runtime checks when copying to the clone. - /// For example, Magica Cloth modifies the sharedMesh & bones of the renderer at runtime. This is not needed - /// for most renderers, so copying for all renderers would be inefficient. - /// - public void SetRendererNeedsAdditionalChecks(Renderer rend, bool needsChecks) - { - switch (rend) - { - case MeshRenderer meshRenderer: - { - int index = _standardRenderers.IndexOf(meshRenderer); - if (index == -1) return; - - if (needsChecks && !_standardRenderersNeedingChecks.Contains(index)) - { - int insertIndex = _standardRenderersNeedingChecks.Count; - _standardRenderersNeedingChecks.Add(index); - _cachedSharedMeshes.Insert(insertIndex, null); - } - else if (!needsChecks) - { - int removeIndex = _standardRenderersNeedingChecks.IndexOf(index); - if (removeIndex != -1) - { - _standardRenderersNeedingChecks.RemoveAt(removeIndex); - _cachedSharedMeshes.RemoveAt(removeIndex); - } - } - return; - } - case SkinnedMeshRenderer skinnedRenderer: - { - int index = _skinnedRenderers.IndexOf(skinnedRenderer); - if (index == -1) return; - - if (needsChecks && !_skinnedRenderersNeedingChecks.Contains(index)) - { - int insertIndex = _skinnedRenderersNeedingChecks.Count; - _skinnedRenderersNeedingChecks.Add(index); - _cachedSharedMeshes.Insert(_standardRenderersNeedingChecks.Count + insertIndex, null); - _cachedSkinnedBoneCounts.Add(0); - } - else if (!needsChecks) - { - int removeIndex = _skinnedRenderersNeedingChecks.IndexOf(index); - if (removeIndex != -1) - { - _skinnedRenderersNeedingChecks.RemoveAt(removeIndex); - _cachedSharedMeshes.RemoveAt(_standardRenderersNeedingChecks.Count + removeIndex); - _cachedSkinnedBoneCounts.RemoveAt(removeIndex); - } - } - break; - } - } - } - - #endregion Public API Methods -} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Clones.cs b/AvatarCloneTest/AvatarClone/AvatarClone.Clones.cs deleted file mode 100644 index 8fb54ec..0000000 --- a/AvatarCloneTest/AvatarClone/AvatarClone.Clones.cs +++ /dev/null @@ -1,103 +0,0 @@ -using ABI_RC.Core; -using UnityEngine; -using UnityEngine.Rendering; - -namespace NAK.AvatarCloneTest; - -public partial class AvatarClone -{ - #region Clone Creation - - private void CreateClones() - { - int standardCount = _standardRenderers.Count; - _standardClones = new List(standardCount); - _standardCloneFilters = new List(standardCount); - for (int i = 0; i < standardCount; i++) CreateStandardClone(i); - - int skinnedCount = _skinnedRenderers.Count; - _skinnedClones = new List(skinnedCount); - for (int i = 0; i < skinnedCount; i++) CreateSkinnedClone(i); - } - - private void CreateStandardClone(int index) - { - MeshRenderer sourceRenderer = _standardRenderers[index]; - MeshFilter sourceFilter = _standardFilters[index]; - - GameObject go = new(sourceRenderer.name + "_VisualClone") - { - layer = CVRLayers.PlayerClone - }; - - go.transform.SetParent(sourceRenderer.transform, false); - //go.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); - - MeshRenderer cloneRenderer = go.AddComponent(); - MeshFilter cloneFilter = go.AddComponent(); - - // Initial setup - cloneRenderer.sharedMaterials = sourceRenderer.sharedMaterials; - cloneRenderer.shadowCastingMode = ShadowCastingMode.Off; - cloneRenderer.probeAnchor = sourceRenderer.probeAnchor; - cloneRenderer.localBounds = new Bounds(Vector3.zero, Vector3.positiveInfinity); - cloneFilter.sharedMesh = sourceFilter.sharedMesh; - - // Optimizations to enforce - cloneRenderer.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; - cloneRenderer.allowOcclusionWhenDynamic = false; - - // Optimizations to enforce - sourceRenderer.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; - sourceRenderer.allowOcclusionWhenDynamic = false; - - _standardClones.Add(cloneRenderer); - _standardCloneFilters.Add(cloneFilter); - } - - private void CreateSkinnedClone(int index) - { - SkinnedMeshRenderer source = _skinnedRenderers[index]; - - GameObject go = new(source.name + "_VisualClone") - { - layer = CVRLayers.PlayerClone - }; - - go.transform.SetParent(source.transform, false); - //go.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); - - SkinnedMeshRenderer clone = go.AddComponent(); - - // Initial setup - clone.sharedMaterials = source.sharedMaterials; - clone.shadowCastingMode = ShadowCastingMode.Off; - clone.probeAnchor = source.probeAnchor; - clone.localBounds = new Bounds(Vector3.zero, Vector3.positiveInfinity); - clone.sharedMesh = source.sharedMesh; - clone.rootBone = source.rootBone; - clone.bones = source.bones; - clone.quality = source.quality; - clone.updateWhenOffscreen = source.updateWhenOffscreen; - - // Optimizations to enforce - clone.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; - clone.allowOcclusionWhenDynamic = false; - clone.updateWhenOffscreen = false; - clone.skinnedMotionVectors = false; - clone.forceMatrixRecalculationPerRender = false; - clone.quality = SkinQuality.Bone4; - - // Optimizations to enforce - source.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; - source.allowOcclusionWhenDynamic = false; - source.updateWhenOffscreen = false; - source.skinnedMotionVectors = false; - source.forceMatrixRecalculationPerRender = false; - source.quality = SkinQuality.Bone4; - - _skinnedClones.Add(clone); - } - - #endregion Clone Creation -} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Exclusion.cs b/AvatarCloneTest/AvatarClone/AvatarClone.Exclusion.cs deleted file mode 100644 index d5136e3..0000000 --- a/AvatarCloneTest/AvatarClone/AvatarClone.Exclusion.cs +++ /dev/null @@ -1,141 +0,0 @@ -using ABI.CCK.Components; -using UnityEngine; - -namespace NAK.AvatarCloneTest; - -public partial class AvatarClone -{ - private readonly Dictionary> _exclusionDirectRenderers = new(); - private readonly Dictionary> _exclusionControlledBones = new(); - - private void InitializeExclusions() - { - // Add head exclusion for humanoid avatars if not present - var animator = GetComponent(); - if (animator != null && animator.isHuman) - { - var headBone = animator.GetBoneTransform(HumanBodyBones.Head); - if (headBone != null && headBone.GetComponent() == null) - { - var exclusion = headBone.gameObject.AddComponent(); - exclusion.isShown = false; - exclusion.target = headBone; - exclusion.shrinkToZero = true; - } - } - - // Process existing exclusions bottom-up - var exclusions = GetComponentsInChildren(true); - - for (int i = exclusions.Length - 1; i >= 0; i--) - { - var exclusion = exclusions[i]; - if (exclusion.target == null) - exclusion.target = exclusion.transform; - - // Skip invalid exclusions or already processed targets - if (exclusion.target == null || _exclusionDirectRenderers.ContainsKey(exclusion.target)) - { - Destroy(exclusion); - continue; - } - - // Initialize data for this exclusion - _exclusionDirectRenderers[exclusion.target] = new HashSet(); - _exclusionControlledBones[exclusion.target] = new HashSet(); - - // Set up our behaviour - exclusion.behaviour = new AvatarCloneExclusion(this, exclusion.target); - - // Collect affected renderers and bones - CollectExclusionData(exclusion.target); - - // Initial update - exclusion.UpdateExclusions(); - } - } - - private void CollectExclusionData(Transform target) - { - var stack = new Stack(); - stack.Push(target); - - while (stack.Count > 0) - { - var current = stack.Pop(); - - // Skip if this transform belongs to another exclusion - if (current != target && current.GetComponent() != null) - continue; - - _exclusionControlledBones[target].Add(current); - - // Add renderers that will need their clone visibility toggled - foreach (var renderer in current.GetComponents()) - { - // Find corresponding clone renderer - if (renderer is MeshRenderer meshRenderer) - { - int index = _standardRenderers.IndexOf(meshRenderer); - if (index != -1) - _exclusionDirectRenderers[target].Add(_standardClones[index]); - } - else if (renderer is SkinnedMeshRenderer skinnedRenderer) - { - int index = _skinnedRenderers.IndexOf(skinnedRenderer); - if (index != -1) - _exclusionDirectRenderers[target].Add(_skinnedClones[index]); - } - } - - // Add children to stack - foreach (Transform child in current) - { - stack.Push(child); - } - } - } - - public void HandleExclusionUpdate(Transform target, Transform shrinkBone, bool isShown) - { - if (!_exclusionDirectRenderers.TryGetValue(target, out var directCloneRenderers) || - !_exclusionControlledBones.TryGetValue(target, out var controlledBones)) - return; - - // Handle direct clone renderers - foreach (var cloneRenderer in directCloneRenderers) - { - cloneRenderer.enabled = isShown; - } - - // Update bone references in clone renderers - int cloneCount = _skinnedClones.Count; - var cloneRenderers = _skinnedClones; - var sourceRenderers = _skinnedRenderers; - - for (int i = 0; i < cloneCount; i++) - { - var clone = cloneRenderers[i]; - var source = sourceRenderers[i]; - var sourceBones = source.bones; - var cloneBones = clone.bones; - int boneCount = cloneBones.Length; - bool needsUpdate = false; - - for (int j = 0; j < boneCount; j++) - { - // Check if this bone is in our controlled set - if (controlledBones.Contains(sourceBones[j])) - { - cloneBones[j] = isShown ? sourceBones[j] : shrinkBone; - needsUpdate = true; - } - } - - if (needsUpdate) - { - clone.bones = cloneBones; - } - } - } -} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Exclusions.cs b/AvatarCloneTest/AvatarClone/AvatarClone.Exclusions.cs new file mode 100644 index 0000000..cedbcdd --- /dev/null +++ b/AvatarCloneTest/AvatarClone/AvatarClone.Exclusions.cs @@ -0,0 +1,229 @@ +using ABI.CCK.Components; +using UnityEngine; + +namespace NAK.AvatarCloneTest; + +public partial class AvatarClone +{ + #region Exclusions + + private FPRExclusion[] _exclusions; + + private void AddExclusionToHeadIfNeeded() + { + if (!TryGetComponent(out Animator animator) + || !animator.isHuman + || !animator.avatar + || !animator.avatar.isValid) + return; + + Transform head = animator.GetBoneTransform(HumanBodyBones.Head); + if (!head) + return; + + GameObject headGo = head.gameObject; + if (headGo.TryGetComponent(out FPRExclusion exclusion)) + return; + + exclusion = headGo.AddComponent(); + exclusion.target = head; + exclusion.isShown = false; + } + + private void InitializeExclusions() + { + _exclusions = GetComponentsInChildren(true); + var exclusionRoots = new Dictionary(_exclusions.Length); + + // **1. Precompute Exclusions** + foreach (FPRExclusion exclusion in _exclusions) + { + Transform target = exclusion.target ??= exclusion.transform; + if (exclusionRoots.ContainsKey(target) || !target.gameObject.scene.IsValid()) + continue; + + AvatarCloneExclusion behaviour = new AvatarCloneExclusion(this, target); + exclusion.behaviour = behaviour; + exclusionRoots.Add(target, behaviour); + } + + // Process Exclusion Transforms + Renderer ourRenderer; + + void ProcessTransformHierarchy(Transform current, Transform root, AvatarCloneExclusion behaviour) + { + if (exclusionRoots.ContainsKey(current) && current != root) return; + + behaviour.affectedTransforms.Add(current); + if (current.TryGetComponent(out ourRenderer)) + behaviour.affectedRenderers.Add(ourRenderer); + + for (int i = 0; i < current.childCount; i++) + { + Transform child = current.GetChild(i); + if (!exclusionRoots.ContainsKey(child)) + ProcessTransformHierarchy(child, root, behaviour); + } + } + + foreach (var entry in exclusionRoots) + { + Transform rootTransform = entry.Key; + AvatarCloneExclusion behaviour = entry.Value; + ProcessTransformHierarchy(rootTransform, rootTransform, behaviour); + behaviour.affectedTransformSet = new HashSet(behaviour.affectedTransforms); + } + + // ------------------------------ + // **OPTIMIZED EXCLUSION BONE MAPPING** + // ------------------------------ + + Dictionary.ValueCollection exclusionBehaviours = exclusionRoots.Values; + int skinnedCount = _skinnedClones.Count; + + // **2. Precompute Bone-to-Exclusion Mapping** + int estimatedBoneCount = skinnedCount * 20; // Estimated bones per skinned mesh + var boneToExclusion = new Dictionary>(estimatedBoneCount); + + foreach (AvatarCloneExclusion behaviour in exclusionBehaviours) + { + foreach (Transform bone in behaviour.affectedTransformSet) + { + if (!boneToExclusion.TryGetValue(bone, out var list)) + { + list = new List(2); + boneToExclusion[bone] = list; + } + list.Add(behaviour); + } + } + + // **3. Process Skinned Mesh Renderers** + for (int s = 0; s < skinnedCount; s++) + { + SkinnedMeshRenderer source = _skinnedRenderers[s]; + var bones = source.bones; // Cache bones array + + SkinnedMeshRenderer smr = _skinnedClones[s]; + int boneCount = bones.Length; + + for (int i = 0; i < boneCount; i++) + { + Transform bone = bones[i]; + + // **Skip if the bone isn't mapped to exclusions** + if (!bone // Skip null bones + || !boneToExclusion.TryGetValue(bone, out var behaviours)) + continue; + + // **Avoid redundant dictionary lookups** + for (int j = 0; j < behaviours.Count; j++) + { + AvatarCloneExclusion behaviour = behaviours[j]; + + if (!behaviour.skinnedToBoneIndex.TryGetValue(smr, out var indices)) + { + indices = new List(4); + behaviour.skinnedToBoneIndex[smr] = indices; + } + + indices.Add(i); + } + } + } + + ApplyInitialExclusionState(); + } + + public void ApplyInitialExclusionState() + { + foreach (FPRExclusion exclusion in _exclusions) + { + exclusion._wasShown = exclusion.isShown; + if (!exclusion.isShown) exclusion.UpdateExclusions(); + } + } + + public void HandleExclusionUpdate(AvatarCloneExclusion exclusion, bool isShown) + { +#if ENABLE_PROFILER + s_UpdateExclusions.Begin(); +#endif + + // **1. Update Renderer Visibility** + foreach (Renderer renderer in exclusion.affectedRenderers) + { + if (renderer is SkinnedMeshRenderer skinned) + { + int index = _skinnedRenderers.IndexOf(skinned); + if (index >= 0) _skinnedClones[index].gameObject.SetActive(isShown); + } + else if (renderer is MeshRenderer mesh) + { + int index = _meshRenderers.IndexOf(mesh); + if (index >= 0) + { + if (Setting_CloneMeshRenderers) + { + _meshClones[index].gameObject.SetActive(isShown); + } + else + { + // Other renderer (never cloned) - update shadow casting state + _sourceShouldBeHiddenFromFPR[index] = !isShown; // When hidden, use for shadows + } + } + } + else if (renderer) + { + int index = _otherRenderers.IndexOf(renderer); + if (index >= 0) + { + int shadowIndex = index + (Setting_CloneMeshRenderers ? _meshRenderers.Count : 0); + _sourceShouldBeHiddenFromFPR[shadowIndex] = !isShown; // When hidden, use for shadows + } + } + } + + // **2. Update Bone References in Skinned Mesh Renderers** + UpdateSkinnedMeshBones(exclusion, exclusion._shrinkBone, isShown); + +#if ENABLE_PROFILER + s_UpdateExclusions.End(); +#endif + } + + private void UpdateSkinnedMeshBones(AvatarCloneExclusion exclusion, Transform shrinkBone, bool isShown) + { +#if ENABLE_PROFILER + s_HandleBoneUpdates.Begin(); +#endif + + foreach (var smrEntry in exclusion.skinnedToBoneIndex) + { + SkinnedMeshRenderer smr = smrEntry.Key; + var indices = smrEntry.Value; + bool needsUpdate = false; + + var parentBones = smr.transform.parent.GetComponent().bones; + var cloneBones = smr.bones; + Array.Resize(ref cloneBones, parentBones.Length); + + // Only modify our bones, other exclusions may have modified others + for (int i = 0; i < indices.Count; i++) + { + int index = indices[i]; + if (!isShown) cloneBones[index] = shrinkBone; + else cloneBones[index] = parentBones[index]; + needsUpdate = true; + } + if (needsUpdate) smr.bones = cloneBones; + } + +#if ENABLE_PROFILER + s_HandleBoneUpdates.End(); +#endif + } + + #endregion Exclusions +} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Fields.cs b/AvatarCloneTest/AvatarClone/AvatarClone.Fields.cs deleted file mode 100644 index 0ba69b0..0000000 --- a/AvatarCloneTest/AvatarClone/AvatarClone.Fields.cs +++ /dev/null @@ -1,67 +0,0 @@ -using UnityEngine; - -namespace NAK.AvatarCloneTest; - -public partial class AvatarClone -{ - #region Profile Markers -//#if UNITY_EDITOR - private static readonly UnityEngine.Profiling.CustomSampler s_CopyMaterials = - UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.CopyMaterials"); - private static readonly UnityEngine.Profiling.CustomSampler s_CopyBlendShapes = - UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.CopyBlendShapes"); - private static readonly UnityEngine.Profiling.CustomSampler s_CopyMeshes = - UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.CopyMeshes"); - - private static readonly UnityEngine.Profiling.CustomSampler s_MyOnPreRender = - UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.MyOnPreRender"); - private static readonly UnityEngine.Profiling.CustomSampler s_SetShadowsOnly = - UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.SetShadowsOnly"); - private static readonly UnityEngine.Profiling.CustomSampler s_UndoShadowsOnly = - UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.UndoShadowsOnly"); - private static readonly UnityEngine.Profiling.CustomSampler s_SetUiCulling = - UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.SetUiCulling"); - private static readonly UnityEngine.Profiling.CustomSampler s_UndoUiCulling = - UnityEngine.Profiling.CustomSampler.Create("AvatarClone2.UndoUiCulling"); - -//#endif - #endregion Profile Markers - - #region Source Renderers - private List _standardRenderers; - private List _standardFilters; - private List _skinnedRenderers; - private List _allSourceRenderers; // For shadow casting only - #endregion Source Renderers - - #region Clone Renderers - private List _standardClones; - private List _standardCloneFilters; - private List _skinnedClones; - #endregion Clone Renderers - - #region Dynamic Check Lists - private List _standardRenderersNeedingChecks; // Stores indices into _standardRenderers - private List _skinnedRenderersNeedingChecks; // Stores indices into _skinnedRenderers - private List _cachedSkinnedBoneCounts; // So we don't copy the bones unless they've changed - private List _cachedSharedMeshes; // So we don't copy the mesh unless it's changed - #endregion Dynamic Check Lists - - #region Material Data - private List _localMaterials; - private List _cullingMaterials; - private List _mainMaterials; - private MaterialPropertyBlock _propertyBlock; - #endregion Material Data - - #region Blend Shape Data - private List> _blendShapeWeights; - #endregion Blend Shape Data - - #region Shadow and UI Culling Settings - private bool _uiCullingActive; - private bool _shadowsOnlyActive; - private bool[] _originallyHadShadows; - private bool[] _originallyWasEnabled; - #endregion Shadow and UI Culling Settings -} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Init.cs b/AvatarCloneTest/AvatarClone/AvatarClone.Init.cs index 41bd84b..f02fe9b 100644 --- a/AvatarCloneTest/AvatarClone/AvatarClone.Init.cs +++ b/AvatarCloneTest/AvatarClone/AvatarClone.Init.cs @@ -1,5 +1,6 @@ using ABI_RC.Core.Player.ShadowClone; using UnityEngine; +using UnityEngine.Rendering; namespace NAK.AvatarCloneTest; @@ -9,120 +10,295 @@ public partial class AvatarClone private void InitializeCollections() { - _standardRenderers = new List(); - _standardFilters = new List(); +#if ENABLE_PROFILER + s_InitializeData.Begin(); +#endif + + // Initialize source collections _skinnedRenderers = new List(); - _allSourceRenderers = new List(); + _blendShapeWeights = new List>(); - _standardClones = new List(); - _standardCloneFilters = new List(); + _meshRenderers = new List(); + _meshFilters = new List(); + + _otherRenderers = new List(); + + // Initialize clone collections _skinnedClones = new List(); + _skinnedCloneMaterials = new List(); + _skinnedCloneCullingMaterials = new List(); - _standardRenderersNeedingChecks = new List(); - _skinnedRenderersNeedingChecks = new List(); - _cachedSkinnedBoneCounts = new List(); - _cachedSharedMeshes = new List(); + if (Setting_CloneMeshRenderers) + { + _meshClones = new List(); + _meshCloneFilters = new List(); + _meshCloneMaterials = new List(); + _meshCloneCullingMaterials = new List(); + } - _localMaterials = new List(); - _cullingMaterials = new List(); - _mainMaterials = new List(); + // Initialize shared resources + _materialWorkingList = new List(); _propertyBlock = new MaterialPropertyBlock(); - _blendShapeWeights = new List>(); +#if ENABLE_PROFILER + s_InitializeData.End(); +#endif } - private void InitializeRenderers() + private void CollectRenderers() { - var renderers = GetComponentsInChildren(true); + #if ENABLE_PROFILER + s_InitializeData.Begin(); + #endif - // Pre-size lists based on found renderers - // _standardRenderers.Capacity = renderers.Length; - // _standardFilters.Capacity = renderers.Length; - // _skinnedRenderers.Capacity = renderers.Length; - // _allSourceRenderers.Capacity = renderers.Length; - - // Sort renderers into their respective lists - foreach (Renderer render in renderers) + var renderers = GetComponentsInChildren(true); + var currentIndex = 0; + var nonCloned = 0; + + // Single pass: directly categorize renderers + foreach (Renderer renderer in renderers) { - _allSourceRenderers.Add(render); - - switch (render) + switch (renderer) { - case MeshRenderer meshRenderer: - { - MeshFilter filter = meshRenderer.GetComponent(); + case SkinnedMeshRenderer skinned when skinned.sharedMesh != null: + AddSkinnedRenderer(skinned); + currentIndex++; + break; + + case MeshRenderer mesh: + MeshFilter filter = mesh.GetComponent(); if (filter != null && filter.sharedMesh != null) { - _standardRenderers.Add(meshRenderer); - _standardFilters.Add(filter); + if (Setting_CloneMeshRenderers) + { + AddMeshRenderer(mesh, filter); + } + else + { + AddMeshRenderer(mesh, filter); + nonCloned++; + } + currentIndex++; } break; - } - case SkinnedMeshRenderer skinnedRenderer: - { - if (skinnedRenderer.sharedMesh != null) _skinnedRenderers.Add(skinnedRenderer); + + default: + AddOtherRenderer(renderer); + currentIndex++; + nonCloned++; break; - } } } - } - - private void SetupMaterialsAndBlendShapes() - { - // Cache counts - int standardCount = _standardRenderers.Count; - int skinnedCount = _skinnedRenderers.Count; - var standardRenderers = _standardRenderers; - var skinnedRenderers = _skinnedRenderers; - var localMats = _localMaterials; - var cullingMats = _cullingMaterials; - var blendWeights = _blendShapeWeights; - // Setup standard renderer materials - for (int i = 0; i < standardCount; i++) - { - MeshRenderer render = standardRenderers[i]; - int matCount = render.sharedMaterials.Length; - - // Local materials array - var localMatArray = new Material[matCount]; - for (int j = 0; j < matCount; j++) localMatArray[j] = render.sharedMaterials[j]; - localMats.Add(localMatArray); - - // Culling materials array - var cullingMatArray = new Material[matCount]; - for (int j = 0; j < matCount; j++) cullingMatArray[j] = ShadowCloneUtils.cullingMaterial; - cullingMats.Add(cullingMatArray); - } - - // Setup skinned renderer materials and blend shapes - for (int i = 0; i < skinnedCount; i++) - { - SkinnedMeshRenderer render = skinnedRenderers[i]; - int matCount = render.sharedMaterials.Length; - - // Local materials array - var localMatArray = new Material[matCount]; - for (int j = 0; j < matCount; j++) localMatArray[j] = render.sharedMaterials[j]; - localMats.Add(localMatArray); - - // Culling materials array - var cullingMatArray = new Material[matCount]; - for (int j = 0; j < matCount; j++) cullingMatArray[j] = ShadowCloneUtils.cullingMaterial; - cullingMats.Add(cullingMatArray); - - // Blend shape weights - int blendShapeCount = render.sharedMesh.blendShapeCount; - var weights = new List(blendShapeCount); - for (int j = 0; j < blendShapeCount; j++) weights.Add(0f); - blendWeights.Add(weights); - } - - // Initialize renderer state arrays - int totalRenderers = _allSourceRenderers.Count; - _originallyHadShadows = new bool[totalRenderers]; - _originallyWasEnabled = new bool[totalRenderers]; + _rendererActiveStates = new bool[currentIndex]; + _originalShadowCastingMode = new ShadowCastingMode[currentIndex]; + _sourceShouldBeHiddenFromFPR = new bool[nonCloned]; + + #if ENABLE_PROFILER + s_InitializeData.End(); + #endif } + private void AddSkinnedRenderer(SkinnedMeshRenderer renderer) + { +#if ENABLE_PROFILER + s_AddRenderer.Begin(); +#endif + + _skinnedRenderers.Add(renderer); + + // Clone materials array for clone renderer + var materials = renderer.sharedMaterials; + var cloneMaterials = new Material[materials.Length]; + for (int i = 0; i < materials.Length; i++) cloneMaterials[i] = materials[i]; + _skinnedCloneMaterials.Add(cloneMaterials); + + // Cache culling materials + var cullingMaterialArray = new Material[materials.Length]; +#if !UNITY_EDITOR + for (int i = 0; i < materials.Length; i++) cullingMaterialArray[i] = ShadowCloneUtils.cullingMaterial; +#else + for (int i = 0; i < materials.Length; i++) cullingMaterialArray[i] = cullingMaterial; +#endif + _skinnedCloneCullingMaterials.Add(cullingMaterialArray); + + // Cache blend shape weights + var weights = new List(renderer.sharedMesh.blendShapeCount); + for (int i = 0; i < renderer.sharedMesh.blendShapeCount; i++) weights.Add(0f); + _blendShapeWeights.Add(weights); + +#if ENABLE_PROFILER + s_AddRenderer.End(); +#endif + } + + private void AddMeshRenderer(MeshRenderer renderer, MeshFilter filter) + { +#if ENABLE_PROFILER + s_AddRenderer.Begin(); +#endif + + _meshRenderers.Add(renderer); + _meshFilters.Add(filter); + + if (!Setting_CloneMeshRenderers) return; + + // Clone materials array for clone renderer + var materials = renderer.sharedMaterials; + var cloneMaterials = new Material[materials.Length]; + for (int i = 0; i < materials.Length; i++) cloneMaterials[i] = materials[i]; + _meshCloneMaterials.Add(cloneMaterials); + + // Cache culling materials + var cullingMaterialArray = new Material[materials.Length]; +#if !UNITY_EDITOR + for (int i = 0; i < materials.Length; i++) cullingMaterialArray[i] = ShadowCloneUtils.cullingMaterial; +#else + for (int i = 0; i < materials.Length; i++) cullingMaterialArray[i] = cullingMaterial; +#endif + _meshCloneCullingMaterials.Add(cullingMaterialArray); + +#if ENABLE_PROFILER + s_AddRenderer.End(); +#endif + } + + private void AddOtherRenderer(Renderer renderer) + { +#if ENABLE_PROFILER + s_AddRenderer.Begin(); +#endif + _otherRenderers.Add(renderer); +#if ENABLE_PROFILER + s_AddRenderer.End(); +#endif + } + + private void CreateClones() + { +#if ENABLE_PROFILER + s_InitializeData.Begin(); +#endif + + // Always create skinned mesh clones + int skinnedCount = _skinnedRenderers.Count; + for (int i = 0; i < skinnedCount; i++) + { + CreateSkinnedClone(i); + } + + // Optionally create mesh clones + if (Setting_CloneMeshRenderers) + { + int meshCount = _meshRenderers.Count; + for (int i = 0; i < meshCount; i++) + { + CreateMeshClone(i); + } + } + +#if ENABLE_PROFILER + s_InitializeData.End(); +#endif + } + + private void CreateSkinnedClone(int index) + { +#if ENABLE_PROFILER + s_CreateClone.Begin(); +#endif + + SkinnedMeshRenderer source = _skinnedRenderers[index]; + + GameObject clone = new(source.name + "_Clone") + { + layer = CLONE_LAYER + }; + + clone.transform.SetParent(source.transform, false); + + SkinnedMeshRenderer cloneRenderer = clone.AddComponent(); + + // Basic setup + cloneRenderer.sharedMaterials = _skinnedCloneMaterials[index]; + cloneRenderer.shadowCastingMode = ShadowCastingMode.Off; + cloneRenderer.probeAnchor = source.probeAnchor; + cloneRenderer.sharedMesh = source.sharedMesh; + cloneRenderer.rootBone = source.rootBone; + cloneRenderer.bones = source.bones; + +#if !UNITY_EDITOR + cloneRenderer.localBounds = new Bounds(source.localBounds.center, source.localBounds.size * 2f); +#endif + + // Quality settings + cloneRenderer.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; + cloneRenderer.allowOcclusionWhenDynamic = false; + cloneRenderer.updateWhenOffscreen = false; + cloneRenderer.skinnedMotionVectors = false; + cloneRenderer.forceMatrixRecalculationPerRender = false; + cloneRenderer.quality = SkinQuality.Bone4; + + source.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; + source.allowOcclusionWhenDynamic = false; + source.updateWhenOffscreen = false; + source.skinnedMotionVectors = false; + source.forceMatrixRecalculationPerRender = false; + source.quality = SkinQuality.Bone4; + + // Add to clone list + _skinnedClones.Add(cloneRenderer); + +#if ENABLE_PROFILER + s_CreateClone.End(); +#endif + } + + private void CreateMeshClone(int index) + { +#if ENABLE_PROFILER + s_CreateClone.Begin(); +#endif + + MeshRenderer source = _meshRenderers[index]; + MeshFilter sourceFilter = _meshFilters[index]; + + GameObject clone = new(source.name + "_Clone") + { + layer = CLONE_LAYER + }; + + clone.transform.SetParent(source.transform, false); + + MeshRenderer cloneRenderer = clone.AddComponent(); + MeshFilter cloneFilter = clone.AddComponent(); + + // Basic setup + cloneRenderer.sharedMaterials = _meshCloneMaterials[index]; + cloneRenderer.shadowCastingMode = ShadowCastingMode.Off; + cloneRenderer.probeAnchor = source.probeAnchor; + +#if !UNITY_EDITOR + cloneRenderer.localBounds = new Bounds(source.localBounds.center, source.localBounds.size * 2f); +#endif + + cloneFilter.sharedMesh = sourceFilter.sharedMesh; + + // Quality settings + cloneRenderer.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; + cloneRenderer.allowOcclusionWhenDynamic = false; + + source.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; + source.allowOcclusionWhenDynamic = false; + + // Add to clone lists + _meshClones.Add(cloneRenderer); + _meshCloneFilters.Add(cloneFilter); + +#if ENABLE_PROFILER + s_CreateClone.End(); +#endif + } + #endregion Initialization } \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.MagicaSupport.cs b/AvatarCloneTest/AvatarClone/AvatarClone.MagicaSupport.cs deleted file mode 100644 index 7ae5855..0000000 --- a/AvatarCloneTest/AvatarClone/AvatarClone.MagicaSupport.cs +++ /dev/null @@ -1,34 +0,0 @@ -using MagicaCloth; -using MagicaCloth2; -using UnityEngine; - -namespace NAK.AvatarCloneTest; - -public partial class AvatarClone -{ - #region Magica Cloth Support - - private void SetupMagicaClothSupport() - { - var magicaCloths1 = GetComponentsInChildren(true); - foreach (MagicaRenderDeformer magicaCloth in magicaCloths1) - { - // Get the renderer on the same object - Renderer renderer = magicaCloth.gameObject.GetComponent(); - SetRendererNeedsAdditionalChecks(renderer, true); - } - - var magicaCloths2 = GetComponentsInChildren(true); - foreach (MagicaCloth2.MagicaCloth magicaCloth in magicaCloths2) - { - if (magicaCloth.serializeData.clothType != ClothProcess.ClothType.MeshCloth) - continue; // Only matters for cloth physics - - // Set the affected renderers as requiring extra checks - var renderers = magicaCloth.serializeData.sourceRenderers; - foreach (Renderer renderer in renderers) SetRendererNeedsAdditionalChecks(renderer, true); - } - } - - #endregion Magica Cloth Support -} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.RenderState.cs b/AvatarCloneTest/AvatarClone/AvatarClone.RenderState.cs new file mode 100644 index 0000000..40c1df7 --- /dev/null +++ b/AvatarCloneTest/AvatarClone/AvatarClone.RenderState.cs @@ -0,0 +1,212 @@ +using UnityEngine; +using UnityEngine.Rendering; + +namespace NAK.AvatarCloneTest; + +public partial class AvatarClone +{ + #region Render State Management + + private void MyOnPreCull(Camera cam) + { +#if UNITY_EDITOR + // Scene & Preview cameras are not needed + if (cam.cameraType != CameraType.Game) + return; +#endif + +#if ENABLE_PROFILER + s_PreCullUpdate.Begin(); +#endif + + bool isOurUiCamera = IsUIInternalCamera(cam); + bool rendersOurPlayerLayer = CameraRendersPlayerLocalLayer(cam); + bool rendersOurCloneLayer = CameraRendersPlayerCloneLayer(cam); + + bool rendersBothPlayerLayers = rendersOurPlayerLayer && rendersOurCloneLayer; + + // Handle shadow casting when camera renders both layers + if (!_sourcesSetForShadowCasting + && rendersBothPlayerLayers) + { + ConfigureSourceShadowCasting(true); + _sourcesSetForShadowCasting = true; + } + else if (_sourcesSetForShadowCasting && !rendersBothPlayerLayers) + { + ConfigureSourceShadowCasting(false); + _sourcesSetForShadowCasting = false; + } + + // Handle UI culling for clone layer + if (!_clonesSetForUiCulling + && isOurUiCamera && rendersOurCloneLayer) + { + ConfigureCloneUICulling(true); + _clonesSetForUiCulling = true; + } + else if (_clonesSetForUiCulling) + { + ConfigureCloneUICulling(false); + _clonesSetForUiCulling = false; + } + +#if ENABLE_PROFILER + s_PreCullUpdate.End(); +#endif + } + + private void ConfigureSourceShadowCasting(bool setSourcesToShadowCast) + { +#if ENABLE_PROFILER + s_ConfigureShadowCasting.Begin(); +#endif + + int currentIndex = 0; + int shadowArrayIndex = 0; + + // Handle skinned mesh renderers (always have clones) + int skinnedCount = _skinnedRenderers.Count; + for (int i = 0; i < skinnedCount; i++, currentIndex++) + { + if (!_rendererActiveStates[currentIndex]) continue; + + SkinnedMeshRenderer source = _skinnedRenderers[i]; + + if (setSourcesToShadowCast) + { + ShadowCastingMode originalMode = _originalShadowCastingMode[currentIndex] = source.shadowCastingMode; + if (originalMode == ShadowCastingMode.Off) + source.forceRenderingOff = true; + else + source.shadowCastingMode = ShadowCastingMode.ShadowsOnly; + } + else + { + source.shadowCastingMode = _originalShadowCastingMode[currentIndex]; + source.forceRenderingOff = false; + } + } + + // Handle mesh renderers based on clone setting + if (Setting_CloneMeshRenderers) + { + int meshCount = _meshRenderers.Count; + for (int i = 0; i < meshCount; i++, currentIndex++) + { + if (!_rendererActiveStates[currentIndex]) continue; + + MeshRenderer source = _meshRenderers[i]; + + if (setSourcesToShadowCast) + { + ShadowCastingMode originalMode = _originalShadowCastingMode[currentIndex] = source.shadowCastingMode; + if (originalMode == ShadowCastingMode.Off) + source.forceRenderingOff = true; + else + source.shadowCastingMode = ShadowCastingMode.ShadowsOnly; + } + else + { + source.shadowCastingMode = _originalShadowCastingMode[currentIndex]; + source.forceRenderingOff = false; + } + } + } + else + { + // When not cloned, mesh renderers use the shadow casting array + int meshCount = _meshRenderers.Count; + for (int i = 0; i < meshCount; i++, shadowArrayIndex++, currentIndex++) + { + if (!_rendererActiveStates[currentIndex]) continue; + if (!_sourceShouldBeHiddenFromFPR[shadowArrayIndex]) continue; + + MeshRenderer source = _meshRenderers[i]; + + if (setSourcesToShadowCast) + { + ShadowCastingMode originalMode = _originalShadowCastingMode[currentIndex] = source.shadowCastingMode; + if (originalMode == ShadowCastingMode.Off) + source.forceRenderingOff = true; + else + source.shadowCastingMode = ShadowCastingMode.ShadowsOnly; + } + else + { + source.shadowCastingMode = _originalShadowCastingMode[currentIndex]; + source.forceRenderingOff = false; + } + } + } + + // Handle other renderers (never cloned) + int otherCount = _otherRenderers.Count; + for (int i = 0; i < otherCount; i++, shadowArrayIndex++, currentIndex++) + { + if (!_rendererActiveStates[currentIndex]) continue; + if (!_sourceShouldBeHiddenFromFPR[shadowArrayIndex]) continue; + + Renderer source = _otherRenderers[i]; + + if (setSourcesToShadowCast) + { + ShadowCastingMode originalMode = _originalShadowCastingMode[currentIndex] = source.shadowCastingMode; + if (originalMode == ShadowCastingMode.Off) + source.forceRenderingOff = true; + else + source.shadowCastingMode = ShadowCastingMode.ShadowsOnly; + } + else + { + source.shadowCastingMode = _originalShadowCastingMode[currentIndex]; + source.forceRenderingOff = false; + } + } + +#if ENABLE_PROFILER + s_ConfigureShadowCasting.End(); +#endif + } + + private void ConfigureCloneUICulling(bool enableCulling) + { +#if ENABLE_PROFILER + s_ConfigureUICulling.Begin(); +#endif + + // Set the materials to our culling materials + int currentIndex = 0; + + int skinnedCount = _skinnedRenderers.Count; + for (int i = 0; i < skinnedCount; i++, currentIndex++) + { + if (!_rendererActiveStates[currentIndex]) + continue; + + _skinnedClones[i].sharedMaterials = enableCulling ? + _skinnedCloneCullingMaterials[i] : + _skinnedCloneMaterials[i]; + } + + if (Setting_CloneMeshRenderers) + { + int meshCount = _meshRenderers.Count; + for (int i = 0; i < meshCount; i++, currentIndex++) + { + if (!_rendererActiveStates[currentIndex]) + continue; + + _meshClones[i].sharedMaterials = enableCulling ? + _meshCloneCullingMaterials[i] : + _meshCloneMaterials[i]; + } + } + +#if ENABLE_PROFILER + s_ConfigureUICulling.End(); +#endif + } + + #endregion Render State Management +} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.StateSync.cs b/AvatarCloneTest/AvatarClone/AvatarClone.StateSync.cs new file mode 100644 index 0000000..eb70282 --- /dev/null +++ b/AvatarCloneTest/AvatarClone/AvatarClone.StateSync.cs @@ -0,0 +1,156 @@ +using UnityEngine; + +namespace NAK.AvatarCloneTest; + +public partial class AvatarClone +{ + #region State Syncing + + private void SyncEnabledState() + { +#if ENABLE_PROFILER + s_CopyEnabledState.Begin(); +#endif + + int currentIndex = 0; + + // Update skinned mesh renderers + int skinnedCount = _skinnedRenderers.Count; + for (int i = 0; i < skinnedCount; i++, currentIndex++) + { + SkinnedMeshRenderer source = _skinnedRenderers[i]; + _skinnedClones[i].enabled = _rendererActiveStates[currentIndex] = IsRendererActive(source); + } + + // Update mesh renderers + int meshCount = _meshRenderers.Count; + for (int i = 0; i < meshCount; i++, currentIndex++) + { + MeshRenderer source = _meshRenderers[i]; + if (Setting_CloneMeshRenderers) _meshClones[i].enabled = _rendererActiveStates[currentIndex] = IsRendererActive(source); + else _rendererActiveStates[currentIndex] = IsRendererActive(source); + } + + // Update other renderers + int otherCount = _otherRenderers.Count; + for (int i = 0; i < otherCount; i++, currentIndex++) + { + Renderer source = _otherRenderers[i]; + _rendererActiveStates[currentIndex] = IsRendererActive(source); + } + +#if ENABLE_PROFILER + s_CopyEnabledState.End(); +#endif + } + + private void SyncMaterials() + { +#if ENABLE_PROFILER + s_CopyMaterials.Begin(); +#endif + int currentIndex = 0; + + // Sync skinned mesh materials + int skinnedCount = _skinnedRenderers.Count; + for (int i = 0; i < skinnedCount; i++, currentIndex++) + { + if (!_rendererActiveStates[currentIndex]) + continue; + + CopyMaterialsAndProperties( + _skinnedRenderers[i], + _skinnedClones[i], + _propertyBlock, + _materialWorkingList, + _skinnedCloneMaterials[i]); + } + + // Sync mesh materials if enabled + if (Setting_CloneMeshRenderers) + { + int meshCount = _meshRenderers.Count; + for (int i = 0; i < meshCount; i++, currentIndex++) + { + if (!_rendererActiveStates[currentIndex]) + continue; + + CopyMaterialsAndProperties( + _meshRenderers[i], + _meshClones[i], + _propertyBlock, + _materialWorkingList, + _meshCloneMaterials[i]); + } + } + +#if ENABLE_PROFILER + s_CopyMaterials.End(); +#endif + } + + private void SyncBlendShapes() + { +#if ENABLE_PROFILER + s_CopyBlendShapes.Begin(); +#endif + + int skinnedCount = _skinnedRenderers.Count; + for (int i = 0; i < skinnedCount; i++) + { + SkinnedMeshRenderer source = _skinnedRenderers[i]; + if (!_rendererActiveStates[i]) + continue; + + CopyBlendShapes( + source, + _skinnedClones[i], + _blendShapeWeights[i]); + } + +#if ENABLE_PROFILER + s_CopyBlendShapes.End(); +#endif + } + + private static void CopyMaterialsAndProperties( + Renderer source, + Renderer clone, + MaterialPropertyBlock propertyBlock, + List workingList, + Material[] cloneMaterials) + { + source.GetSharedMaterials(workingList); + + int matCount = workingList.Count; + bool hasChanged = false; + + for (int i = 0; i < matCount; i++) + { + if (ReferenceEquals(workingList[i], cloneMaterials[i])) continue; + cloneMaterials[i] = workingList[i]; + hasChanged = true; + } + if (hasChanged) clone.sharedMaterials = cloneMaterials; + + source.GetPropertyBlock(propertyBlock); + clone.SetPropertyBlock(propertyBlock); + } + + private static void CopyBlendShapes( + SkinnedMeshRenderer source, + SkinnedMeshRenderer clone, + List weights) + { + int weightCount = weights.Count; + for (int i = 0; i < weightCount; i++) + { + float weight = source.GetBlendShapeWeight(i); + // ReSharper disable once CompareOfFloatsByEqualityOperator + if (weight == weights[i]) continue; // Halves the work + clone.SetBlendShapeWeight(i, weights[i] = weight); + } + } + + #endregion State Syncing +} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Update.cs b/AvatarCloneTest/AvatarClone/AvatarClone.Update.cs deleted file mode 100644 index 42cef73..0000000 --- a/AvatarCloneTest/AvatarClone/AvatarClone.Update.cs +++ /dev/null @@ -1,181 +0,0 @@ -using UnityEngine; - -namespace NAK.AvatarCloneTest; - -public partial class AvatarClone -{ - #region Update Methods - - private void UpdateStandardRenderers() - { - int count = _standardRenderers.Count; - var sourceRenderers = _standardRenderers; - var cloneRenderers = _standardClones; - var localMats = _localMaterials; - - for (int i = 0; i < count; i++) - { - if (!IsRendererValid(sourceRenderers[i])) continue; - CopyMaterialsAndProperties( - sourceRenderers[i], - cloneRenderers[i], - _propertyBlock, - _mainMaterials, - localMats[i]); - } - } - - private void UpdateSkinnedRenderers() - { - int standardCount = _standardRenderers.Count; - int count = _skinnedRenderers.Count; - var sourceRenderers = _skinnedRenderers; - var cloneRenderers = _skinnedClones; - var localMats = _localMaterials; - var blendWeights = _blendShapeWeights; - - for (int i = 0; i < count; i++) - { - SkinnedMeshRenderer source = sourceRenderers[i]; - if (!IsRendererValid(source)) continue; - - SkinnedMeshRenderer clone = cloneRenderers[i]; - CopyMaterialsAndProperties( - source, - clone, - _propertyBlock, - _mainMaterials, - localMats[i + standardCount]); - - CopyBlendShapes(source, clone, blendWeights[i]); - } - } - - private void UpdateStandardRenderersWithChecks() - { - s_CopyMeshes.Begin(); - - var cloneFilters = _standardCloneFilters; - var sourceFilters = _standardFilters; - var cachedMeshes = _cachedSharedMeshes; - var checkIndices = _standardRenderersNeedingChecks; - int checkCount = checkIndices.Count; - - while (cachedMeshes.Count < checkCount) cachedMeshes.Add(null); - - for (int i = 0; i < checkCount; i++) - { - int rendererIndex = checkIndices[i]; - Mesh newMesh = sourceFilters[rendererIndex].sharedMesh; - if (ReferenceEquals(newMesh, cachedMeshes[i])) continue; - cloneFilters[rendererIndex].sharedMesh = newMesh; // expensive & allocates - cachedMeshes[i] = newMesh; - } - - s_CopyMeshes.End(); - } - - private void UpdateSkinnedRenderersWithChecks() - { - s_CopyMeshes.Begin(); - - var sourceRenderers = _skinnedRenderers; - var cloneRenderers = _skinnedClones; - var cachedMeshes = _cachedSharedMeshes; - var cachedBoneCounts = _cachedSkinnedBoneCounts; - var checkIndices = _skinnedRenderersNeedingChecks; - int checkCount = checkIndices.Count; - int meshOffset = _standardRenderersNeedingChecks.Count; - - // Ensure cache lists are properly sized - while (cachedMeshes.Count < meshOffset + checkCount) cachedMeshes.Add(null); - while (cachedBoneCounts.Count < checkCount) cachedBoneCounts.Add(0); - - for (int i = 0; i < checkCount; i++) - { - int rendererIndex = checkIndices[i]; - SkinnedMeshRenderer source = sourceRenderers[rendererIndex]; - SkinnedMeshRenderer clone = cloneRenderers[rendererIndex]; - - // Check mesh changes - Mesh newMesh = source.sharedMesh; // expensive & allocates - if (!ReferenceEquals(newMesh, cachedMeshes[meshOffset + i])) - { - clone.sharedMesh = newMesh; - cachedMeshes[meshOffset + i] = newMesh; - } - - // Check bone changes - var sourceBones = source.bones; - int newBoneCount = sourceBones.Length; - int oldBoneCount = cachedBoneCounts[i]; - if (newBoneCount == oldBoneCount) - continue; - - var cloneBones = clone.bones; // expensive & allocates - if (newBoneCount > oldBoneCount) - { - // Resize array and copy only the new bones (Magica Cloth appends bones when enabling Mesh Cloth) - Array.Resize(ref cloneBones, newBoneCount); - for (int boneIndex = oldBoneCount; boneIndex < newBoneCount; boneIndex++) - cloneBones[boneIndex] = sourceBones[boneIndex]; - clone.bones = cloneBones; - } - else - { - // If shrinking, just set the whole array - clone.bones = sourceBones; - } - - cachedBoneCounts[i] = newBoneCount; - } - - s_CopyMeshes.End(); - } - - private static void CopyMaterialsAndProperties( - Renderer source, Renderer clone, - MaterialPropertyBlock propertyBlock, - List mainMaterials, - Material[] localMaterials) - { - s_CopyMaterials.Begin(); - - source.GetSharedMaterials(mainMaterials); - - int matCount = mainMaterials.Count; - bool hasChanged = false; - for (var i = 0; i < matCount; i++) - { - if (ReferenceEquals(mainMaterials[i], localMaterials[i])) continue; - localMaterials[i] = mainMaterials[i]; - hasChanged = true; - } - if (hasChanged) clone.sharedMaterials = localMaterials; - - source.GetPropertyBlock(propertyBlock); - clone.SetPropertyBlock(propertyBlock); - - s_CopyMaterials.End(); - } - - private static void CopyBlendShapes( - SkinnedMeshRenderer source, - SkinnedMeshRenderer target, - List blendShapeWeights) - { - s_CopyBlendShapes.Begin(); - - int weightCount = blendShapeWeights.Count; - for (var i = 0; i < weightCount; i++) - { - var weight = source.GetBlendShapeWeight(i); - // ReSharper disable once CompareOfFloatsByEqualityOperator - if (weight == blendShapeWeights[i]) continue; // Halves the work - target.SetBlendShapeWeight(i, blendShapeWeights[i] = weight); - } - - s_CopyBlendShapes.End(); - } - #endregion Update Methods -} \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Util.cs b/AvatarCloneTest/AvatarClone/AvatarClone.Util.cs index c6fb033..63f0d45 100644 --- a/AvatarCloneTest/AvatarClone/AvatarClone.Util.cs +++ b/AvatarCloneTest/AvatarClone/AvatarClone.Util.cs @@ -1,20 +1,81 @@ -using ABI_RC.Core; -using ABI_RC.Core.Player; +using ABI_RC.Core.Player; +using MagicaCloth; +using MagicaCloth2; using UnityEngine; namespace NAK.AvatarCloneTest; public partial class AvatarClone { + #region Utilities + + private static bool IsRendererActive(Renderer renderer) + => renderer && renderer.enabled && renderer.gameObject.activeInHierarchy; + private static bool CameraRendersPlayerLocalLayer(Camera cam) - => (cam.cullingMask & (1 << CVRLayers.PlayerLocal)) != 0; + => (cam.cullingMask & (1 << LOCAL_LAYER)) != 0; private static bool CameraRendersPlayerCloneLayer(Camera cam) - => (cam.cullingMask & (1 << CVRLayers.PlayerClone)) != 0; - + => (cam.cullingMask & (1 << CLONE_LAYER)) != 0; + private static bool IsUIInternalCamera(Camera cam) +#if !UNITY_EDITOR => cam == PlayerSetup.Instance.activeUiCam; +#else + => cam.gameObject.layer == 15; +#endif - private static bool IsRendererValid(Renderer renderer) - => renderer && renderer.gameObject.activeInHierarchy; + #endregion Utilities + + #region Magica Cloth Support + + private void SetupMagicaClothSupport() + { + var magicaCloths1 = GetComponentsInChildren(true); + foreach (BaseCloth magicaCloth1 in magicaCloths1) + magicaCloth1.SetCullingMode(PhysicsTeam.TeamCullingMode.Off); + + var magicaCloths2 = base.GetComponentsInChildren(true); + foreach (MagicaCloth2.MagicaCloth magicaCloth2 in magicaCloths2) + magicaCloth2.serializeData.cullingSettings.cameraCullingMode = CullingSettings.CameraCullingMode.AnimatorLinkage; + } + + public void OnMagicaClothMeshSwapped(Renderer render, Mesh newMesh) + { + switch (render) + { + case MeshRenderer mesh: + { + int index = _meshRenderers.IndexOf(mesh); + if (index != -1) _meshCloneFilters[index].sharedMesh = newMesh; + break; + } + case SkinnedMeshRenderer skinned: + { + int index = _skinnedRenderers.IndexOf(skinned); + if (index != -1) + { + // Copy the mesh + _skinnedClones[index].sharedMesh = newMesh; + + // Copy appended bones if count is different + var cloneBones = _skinnedClones[index].bones; // alloc + var sourceBones = skinned.bones; // alloc + + int cloneBoneCount = cloneBones.Length; + int sourceBoneCount = sourceBones.Length; + if (cloneBoneCount != sourceBoneCount) + { + // Copy the new bones only + Array.Resize(ref cloneBones, sourceBoneCount); + for (int i = cloneBoneCount; i < sourceBoneCount; i++) cloneBones[i] = sourceBones[i]; + _skinnedClones[index].bones = cloneBones; + } + } + break; + } + } + } + + #endregion Magica Cloth Support } \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.cs b/AvatarCloneTest/AvatarClone/AvatarClone.cs index 88c8112..ed15ec1 100644 --- a/AvatarCloneTest/AvatarClone/AvatarClone.cs +++ b/AvatarCloneTest/AvatarClone/AvatarClone.cs @@ -1,3 +1,4 @@ +using NAK.AvatarCloneTest; using UnityEngine; using UnityEngine.Rendering; @@ -5,130 +6,142 @@ namespace NAK.AvatarCloneTest; public partial class AvatarClone : MonoBehaviour { + #region Constants + + private const int LOCAL_LAYER = 8; + private const int CLONE_LAYER = 9; + + #endregion Constants + + #region Profiler Markers + +#if ENABLE_PROFILER + private static readonly ProfilerMarker s_CopyEnabledState = new($"{nameof(AvatarClone)}.{nameof(SyncEnabledState)}"); + private static readonly ProfilerMarker s_CopyMaterials = new($"{nameof(AvatarClone)}.{nameof(CopyMaterialsAndProperties)}"); + private static readonly ProfilerMarker s_CopyBlendShapes = new($"{nameof(AvatarClone)}.{nameof(CopyBlendShapes)}"); + private static readonly ProfilerMarker s_InitializeData = new($"{nameof(AvatarClone)}.Initialize"); + private static readonly ProfilerMarker s_UpdateExclusions = new($"{nameof(AvatarClone)}.{nameof(HandleExclusionUpdate)}"); + private static readonly ProfilerMarker s_CollectExclusionData = new($"{nameof(AvatarClone)}.{nameof(CollectExclusionData)}"); + private static readonly ProfilerMarker s_HandleBoneUpdates = new($"{nameof(AvatarClone)}.{nameof(UpdateSkinnedMeshBones)}"); + private static readonly ProfilerMarker s_PreCullUpdate = new($"{nameof(AvatarClone)}.{nameof(MyOnPreCull)}"); + private static readonly ProfilerMarker s_ConfigureShadowCasting = new($"{nameof(AvatarClone)}.{nameof(ConfigureSourceShadowCasting)}"); + private static readonly ProfilerMarker s_ConfigureUICulling = new($"{nameof(AvatarClone)}.{nameof(ConfigureCloneUICulling)}"); + private static readonly ProfilerMarker s_AddRenderer = new($"{nameof(AvatarClone)}.AddRenderer"); + private static readonly ProfilerMarker s_CreateClone = new($"{nameof(AvatarClone)}.CreateClone"); +#endif + + #endregion Profiler Markers + + #region Settings + + public bool Setting_CloneMeshRenderers; + public bool Setting_CopyMaterials = true; + public bool Setting_CopyBlendShapes = true; + + #endregion Settings + + #region Source Collections - Cloned Renderers + + // Skinned mesh renderers (always cloned) + private List _skinnedRenderers; + private List> _blendShapeWeights; + + // Mesh renderers (optionally cloned) + private List _meshRenderers; + private List _meshFilters; + + #endregion Source Collections - Cloned Renderers + + #region Source Collections - Non-Cloned Renderers + + // All other renderers (never cloned) + private List _otherRenderers; + + // True if source renderer should hide. False if source renderer should show. + // Only used for non-cloned renderers (MeshRenderers and other Renderers). + private bool[] _sourceShouldBeHiddenFromFPR; + // Three states: On, ShadowsOnly, Off + private ShadowCastingMode[] _originalShadowCastingMode; + + #endregion Source Collections - Non-Cloned Renderers + + #region Clone Collections + + // Skinned mesh clones + private List _skinnedClones; + private List _skinnedCloneMaterials; + private List _skinnedCloneCullingMaterials; + + // Mesh clones (optional) + private List _meshClones; + private List _meshCloneFilters; + private List _meshCloneMaterials; + private List _meshCloneCullingMaterials; + + #endregion Clone Collections + + #region Shared Resources + + private List _materialWorkingList; // Used for GetSharedMaterials + private MaterialPropertyBlock _propertyBlock; + + #endregion Shared Resources + + #region State + + private bool _sourcesSetForShadowCasting; + private bool _clonesSetForUiCulling; + private bool[] _rendererActiveStates; + + #endregion State + #region Unity Events private void Start() { - InitializeCollections(); - InitializeRenderers(); - SetupMaterialsAndBlendShapes(); - CreateClones(); + Setting_CloneMeshRenderers = AvatarCloneTestMod.EntryCloneMeshRenderers.Value; + InitializeCollections(); + CollectRenderers(); + CreateClones(); + AddExclusionToHeadIfNeeded(); InitializeExclusions(); SetupMagicaClothSupport(); - Camera.onPreCull += MyOnPreRender; - } + // bool animatesClone = transform.Find("[ExplicitlyAnimatesVisualClones]") != null; + // Setting_CopyMaterials = !animatesClone; + // Setting_CopyBlendShapes = !animatesClone; + // Animator animator = GetComponent(); + // if (animator && animatesClone) animator.Rebind(); - private void OnDestroy() - { - Camera.onPreCull -= MyOnPreRender; - } - - private void LateUpdate() - { - // Update all renderers with basic properties (Materials & BlendShapes) - UpdateStandardRenderers(); - UpdateSkinnedRenderers(); - - // Additional pass for renderers needing extra checks (Shared Mesh & Bone Changes) - UpdateStandardRenderersWithChecks(); - UpdateSkinnedRenderersWithChecks(); + // Likely a Unity bug with where we can touch shadowCastingMode & forceRenderingOff +#if !UNITY_EDITOR + Camera.onPreCull += MyOnPreCull; +#else + Camera.onPreRender += MyOnPreCull; +#endif } - private void MyOnPreRender(Camera cam) + private void LateUpdate() { - s_MyOnPreRender.Begin(); + SyncEnabledState(); - bool isOurUiCamera = IsUIInternalCamera(cam); - bool rendersOurPlayerLayer = CameraRendersPlayerLocalLayer(cam); - bool rendersOurCloneLayer = CameraRendersPlayerCloneLayer(cam); + if (Setting_CopyMaterials && AvatarCloneTestMod.EntryCopyMaterials.Value) + SyncMaterials(); - // Renders both player layers. - // PlayerLocal will now act as a shadow caster, while PlayerClone will act as the actual head-hidden renderer. - bool rendersBothPlayerLayers = rendersOurPlayerLayer && rendersOurCloneLayer; - if (!_shadowsOnlyActive && rendersBothPlayerLayers) - { - s_SetShadowsOnly.Begin(); - - int sourceCount = _allSourceRenderers.Count; - var sourceRenderers = _allSourceRenderers; - for (int i = 0; i < sourceCount; i++) - { - Renderer renderer = sourceRenderers[i]; - if (!IsRendererValid(renderer)) continue; - - bool shouldRender = renderer.shadowCastingMode != ShadowCastingMode.Off; - _originallyWasEnabled[i] = renderer.enabled; - _originallyHadShadows[i] = shouldRender; - renderer.shadowCastingMode = ShadowCastingMode.ShadowsOnly; - if (renderer.forceRenderingOff == shouldRender) renderer.forceRenderingOff = !shouldRender; // TODO: Eval if check is needed - } - _shadowsOnlyActive = true; - - s_SetShadowsOnly.End(); - } - else if (_shadowsOnlyActive && !rendersBothPlayerLayers) - { - s_UndoShadowsOnly.Begin(); - - int sourceCount = _allSourceRenderers.Count; - var sourceRenderers = _allSourceRenderers; - for (int i = 0; i < sourceCount; i++) - { - Renderer renderer = sourceRenderers[i]; - if (!IsRendererValid(renderer)) continue; - - renderer.shadowCastingMode = _originallyHadShadows[i] ? ShadowCastingMode.On : ShadowCastingMode.Off; - if (renderer.forceRenderingOff == _originallyWasEnabled[i]) renderer.forceRenderingOff = !_originallyWasEnabled[i]; // TODO: Eval if check is needed - } - _shadowsOnlyActive = false; - - s_UndoShadowsOnly.End(); - } - - // Handle UI culling material changes - if (isOurUiCamera && !_uiCullingActive && rendersOurCloneLayer) - { - s_SetUiCulling.Begin(); - - int standardCount = _standardRenderers.Count; - var standardClones = _standardClones; - var cullingMaterials = _cullingMaterials; - for (int i = 0; i < standardCount; i++) - standardClones[i].sharedMaterials = cullingMaterials[i]; - - int skinnedCount = _skinnedRenderers.Count; - var skinnedClones = _skinnedClones; - for (int i = 0; i < skinnedCount; i++) - skinnedClones[i].sharedMaterials = cullingMaterials[i + standardCount]; - - _uiCullingActive = true; - - s_SetUiCulling.End(); - } - else if (!isOurUiCamera && _uiCullingActive) - { - s_UndoUiCulling.Begin(); - - int standardCount = _standardRenderers.Count; - var standardClones = _standardClones; - var localMaterials = _localMaterials; - for (int i = 0; i < standardCount; i++) - standardClones[i].sharedMaterials = localMaterials[i]; - - int skinnedCount = _skinnedRenderers.Count; - var skinnedClones = _skinnedClones; - for (int i = 0; i < skinnedCount; i++) - skinnedClones[i].sharedMaterials = localMaterials[i + standardCount]; - - _uiCullingActive = false; - - s_UndoUiCulling.End(); - } - - s_MyOnPreRender.End(); + if (Setting_CopyBlendShapes && AvatarCloneTestMod.EntryCopyBlendShapes.Value) + SyncBlendShapes(); } - + + private void OnDestroy() + { + // Likely a Unity bug with where we can touch shadowCastingMode & forceRenderingOff +#if !UNITY_EDITOR + Camera.onPreCull -= MyOnPreCull; +#else + Camera.onPreRender -= MyOnPreCull; +#endif + } + #endregion Unity Events } \ No newline at end of file diff --git a/AvatarCloneTest/AvatarClone/FPRExclusion/AvatarCloneExclusion.cs b/AvatarCloneTest/AvatarClone/FPRExclusion/AvatarCloneExclusion.cs index 5681761..4f38900 100644 --- a/AvatarCloneTest/AvatarClone/FPRExclusion/AvatarCloneExclusion.cs +++ b/AvatarCloneTest/AvatarClone/FPRExclusion/AvatarCloneExclusion.cs @@ -5,9 +5,14 @@ namespace NAK.AvatarCloneTest; public class AvatarCloneExclusion : IExclusionBehaviour { + public readonly Dictionary> skinnedToBoneIndex = new(); + public readonly List affectedTransforms = new(); + public readonly List affectedRenderers = new(); + public HashSet affectedTransformSet = new(); + private readonly AvatarClone _cloneSystem; private readonly Transform _target; - private Transform _shrinkBone; + internal Transform _shrinkBone; public bool isImmuneToGlobalState { get; set; } @@ -19,20 +24,16 @@ public class AvatarCloneExclusion : IExclusionBehaviour public void UpdateExclusions(bool isShown, bool shrinkToZero) { - Debug.Log($"[AvatarClone2] Updating exclusion for {_target.name}: isShown={isShown}, shrinkToZero={shrinkToZero}"); - if (_shrinkBone == null) { // Create shrink bone parented directly to target _shrinkBone = new GameObject($"{_target.name}_Shrink").transform; _shrinkBone.SetParent(_target, false); - Debug.Log($"[AvatarClone2] Created shrink bone for {_target.name}"); } - // Set scale based on shrink mode _shrinkBone.localScale = shrinkToZero ? Vector3.zero : Vector3.positiveInfinity; - // Let the clone system handle the update - _cloneSystem.HandleExclusionUpdate(_target, _shrinkBone, isShown); + // Replace the bone references with the shrink bone for the indicies we modify + _cloneSystem.HandleExclusionUpdate(this, isShown); } } \ No newline at end of file diff --git a/AvatarCloneTest/Main.cs b/AvatarCloneTest/Main.cs index 21a34bf..3bb4f09 100644 --- a/AvatarCloneTest/Main.cs +++ b/AvatarCloneTest/Main.cs @@ -1,4 +1,6 @@ using ABI_RC.Core; +using ABI_RC.Core.EventSystem; +using ABI_RC.Core.Savior; using MelonLoader; using UnityEngine; @@ -15,17 +17,17 @@ public class AvatarCloneTestMod : MelonMod Category.CreateEntry("use_avatar_clone_test", true, "Use Avatar Clone", description: "Uses the Avatar Clone setup for the local avatar."); - // internal static readonly MelonPreferences_Entry EntryCopyBlendShapes = - // Category.CreateEntry("copy_blend_shapes", true, - // "Copy Blend Shapes", description: "Copies the blend shapes from the original avatar to the clone."); - // - // internal static readonly MelonPreferences_Entry EntryCopyMaterials = - // Category.CreateEntry("copy_materials", true, - // "Copy Materials", description: "Copies the materials from the original avatar to the clone."); - // - // internal static readonly MelonPreferences_Entry EntryCopyMeshes = - // Category.CreateEntry("copy_meshes", true, - // "Copy Meshes", description: "Copies the meshes from the original avatar to the clone."); + internal static readonly MelonPreferences_Entry EntryCloneMeshRenderers = + Category.CreateEntry("clone_mesh_renderers", false, + "Clone Mesh Renderers", description: "Clones the mesh renderers from the original avatar to the clone."); + + internal static readonly MelonPreferences_Entry EntryCopyBlendShapes = + Category.CreateEntry("copy_blend_shapes", true, + "Copy Blend Shapes", description: "Copies the blend shapes from the original avatar to the clone."); + + internal static readonly MelonPreferences_Entry EntryCopyMaterials = + Category.CreateEntry("copy_materials", true, + "Copy Materials", description: "Copies the materials from the original avatar to the clone."); #endregion Melon Preferences @@ -49,6 +51,13 @@ public class AvatarCloneTestMod : MelonMod } } } + + // if pressing ctrl + r, reload avatar + if (Input.GetKey(KeyCode.LeftControl) && Input.GetKeyDown(KeyCode.R)) + { + var player = MetaPort.Instance.currentAvatarGuid; + AssetManagement.Instance.LoadLocalAvatar(player); + } } #endregion Melon Events diff --git a/AvatarCloneTest/Patches.cs b/AvatarCloneTest/Patches.cs index b4cec17..ecd64c5 100644 --- a/AvatarCloneTest/Patches.cs +++ b/AvatarCloneTest/Patches.cs @@ -18,70 +18,5 @@ public static class Patches avatar.AddComponent(); return false; } - - // [HarmonyPostfix] - // [HarmonyPatch(typeof(FPRExclusion), nameof(FPRExclusion.UpdateExclusions))] - // private static void OnUpdateExclusions(ref FPRExclusion __instance) - // { - // AvatarClone clone = PlayerSetup.Instance._avatar.GetComponent(); - // if (clone == null) return; - // clone.SetBoneChainVisibility(__instance.target, !__instance.isShown, !__instance.shrinkToZero); - // } - - [HarmonyPostfix] - [HarmonyPatch(typeof(CVRMirror), nameof(CVRMirror.Start))] - private static void OnMirrorStart(CVRMirror __instance) - { - if (!AvatarCloneTestMod.EntryUseAvatarCloneTest.Value) - return; - - // Don't reflect the player clone layer - __instance.m_ReflectLayers &= ~(1 << CVRLayers.PlayerClone); - } - - [HarmonyPostfix] - [HarmonyPatch(typeof(PlayerSetup), nameof(PlayerSetup.Update))] - private static void OnTransformHiderManagerUpdate(PlayerSetup __instance) - { - if (!AvatarCloneTestMod.EntryUseAvatarCloneTest.Value) - return; - - if (MetaPort.Instance.settings.GetSettingsBool("ExperimentalAvatarOverrenderUI")) - __instance.activeUiCam.cullingMask |= 1 << CVRLayers.PlayerClone; - else - __instance.activeUiCam.cullingMask &= ~(1 << CVRLayers.PlayerClone); - } - - private static bool _wasDebugInPortableCamera; - - [HarmonyPostfix] - [HarmonyPatch(typeof(PortableCamera), nameof(PortableCamera.Update))] - private static void OnPortableCameraUpdate(ref PortableCamera __instance) - { - if (!AvatarCloneTestMod.EntryUseAvatarCloneTest.Value) - { - // Show both PlayerLocal and PlayerClone - __instance.cameraComponent.cullingMask |= 1 << CVRLayers.PlayerLocal; - __instance.cameraComponent.cullingMask |= 1 << CVRLayers.PlayerClone; - return; - } - - if (TransformHiderManager.s_DebugInPortableCamera == _wasDebugInPortableCamera) - return; - - if (TransformHiderManager.s_DebugInPortableCamera) - { - // Hide PlayerLocal, show PlayerClone - __instance.cameraComponent.cullingMask &= ~(1 << CVRLayers.PlayerLocal); - __instance.cameraComponent.cullingMask |= 1 << CVRLayers.PlayerClone; - } - else - { - // Show PlayerLocal, hide PlayerClone - __instance.cameraComponent.cullingMask |= 1 << CVRLayers.PlayerLocal; - __instance.cameraComponent.cullingMask &= ~(1 << CVRLayers.PlayerClone); - } - - _wasDebugInPortableCamera = TransformHiderManager.s_DebugInPortableCamera; - } -} \ No newline at end of file +} + \ No newline at end of file diff --git a/AvatarCloneTest/Properties/AssemblyInfo.cs b/AvatarCloneTest/Properties/AssemblyInfo.cs index 3334b28..84f8de2 100644 --- a/AvatarCloneTest/Properties/AssemblyInfo.cs +++ b/AvatarCloneTest/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.AvatarCloneTest.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.0"; + public const string Version = "1.0.3"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_Utils.cs b/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_Utils.cs deleted file mode 100644 index 473dc45..0000000 --- a/AvatarScaleMod/Integrations/BTKUI/BtkUiAddon_Utils.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System.Reflection; -using BTKUILib; -using BTKUILib.UIObjects; -using BTKUILib.UIObjects.Components; -using MelonLoader; -using UnityEngine; - -namespace NAK.AvatarScaleMod.Integrations -{ - public static partial class BtkUiAddon - { - #region Melon Preference Helpers - - private static ToggleButton AddMelonToggle(ref Category category, MelonPreferences_Entry entry) - { - ToggleButton toggle = category.AddToggle(entry.DisplayName, entry.Description, entry.Value); - toggle.OnValueUpdated += b => entry.Value = b; - return toggle; - } - - private static SliderFloat AddMelonSlider(ref Category category, MelonPreferences_Entry entry, float min, - float max, int decimalPlaces = 2, bool allowReset = true) - { - SliderFloat slider = category.AddSlider(entry.DisplayName, entry.Description, - Mathf.Clamp(entry.Value, min, max), min, max, decimalPlaces, entry.DefaultValue, allowReset); - slider.OnValueUpdated += f => entry.Value = f; - return slider; - } - - private static Button AddMelonStringInput(ref Category category, MelonPreferences_Entry entry, string buttonIcon = "", ButtonStyle buttonStyle = ButtonStyle.TextOnly) - { - Button button = category.AddButton(entry.DisplayName, buttonIcon, entry.Description, buttonStyle); - button.OnPress += () => QuickMenuAPI.OpenKeyboard(entry.Value, s => entry.Value = s); - return button; - } - - private static Button AddMelonNumberInput(ref Category category, MelonPreferences_Entry entry, string buttonIcon = "", ButtonStyle buttonStyle = ButtonStyle.TextOnly) - { - Button button = category.AddButton(entry.DisplayName, buttonIcon, entry.Description, buttonStyle); - button.OnPress += () => QuickMenuAPI.OpenNumberInput(entry.DisplayName, entry.Value, f => entry.Value = f); - return button; - } - - // private static SliderFloat AddMelonSlider(ref Page page, MelonPreferences_Entry entry, float min, float max, int decimalPlaces = 2, bool allowReset = true) - // { - // SliderFloat slider = page.AddSlider(entry.DisplayName, entry.Description, Mathf.Clamp(entry.Value, min, max), min, max, decimalPlaces, entry.DefaultValue, allowReset); - // slider.OnValueUpdated += f => entry.Value = f; - // return slider; - // } - - /// - /// Helper method to create a category that saves its collapsed state to a MelonPreferences entry. - /// - /// - /// - /// - /// - private static Category AddMelonCategory(ref Page page, MelonPreferences_Entry entry, bool showHeader = true) - { - Category category = page.AddCategory(entry.DisplayName, showHeader, true, entry.Value); - category.OnCollapse += b => entry.Value = b; - return category; - } - - #endregion - - #region Icon Utils - - private static Stream GetIconStream(string iconName) - { - Assembly assembly = Assembly.GetExecutingAssembly(); - string assemblyName = assembly.GetName().Name; - return assembly.GetManifestResourceStream($"{assemblyName}.resources.{iconName}"); - } - - #endregion - } -} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading.csproj b/BetterContentLoading/BetterContentLoading.csproj new file mode 100644 index 0000000..67cef19 --- /dev/null +++ b/BetterContentLoading/BetterContentLoading.csproj @@ -0,0 +1,15 @@ + + + + net48 + NAK.BetterContentLoading + + + + ..\.ManagedLibs\BTKUILib.dll + + + ..\.ManagedLibs\TheClapper.dll + + + diff --git a/BetterContentLoading/BetterContentLoading/BetterDownloadManager.cs b/BetterContentLoading/BetterContentLoading/BetterDownloadManager.cs new file mode 100644 index 0000000..749483f --- /dev/null +++ b/BetterContentLoading/BetterContentLoading/BetterDownloadManager.cs @@ -0,0 +1,210 @@ +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Networking.IO.Instancing; +using ABI_RC.Core.Networking.IO.Social; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using ABI_RC.Core.Util; +using ABI_RC.Systems.GameEventSystem; +using NAK.BetterContentLoading.Queue; +using UnityEngine; + +namespace NAK.BetterContentLoading; + +// Download world -> connect to instance -> receive all Avatar data +// -> initial connection to instance -> receive all props data + +// We receive Prop download data only after we have connected to the instance. Avatar data we seem to receive +// prior to our initial connection event firing. + +public class BetterDownloadManager +{ + #region Singleton + + private static BetterDownloadManager _instance; + public static BetterDownloadManager Instance => _instance ??= new BetterDownloadManager(); + + #endregion Singleton + + #region Constructor + + private BetterDownloadManager() + { + _downloadProcessor = new DownloadProcessor(); + + _worldQueue = new WorldDownloadQueue(this); // Only one world at a time + _avatarQueue = new AvatarDownloadQueue(this); // Up to 3 avatars at once + _propQueue = new PropDownloadQueue(this); // Up to 2 props at once + + // Set to 100MBs by default + MaxDownloadBandwidth = 100 * 1024 * 1024; + + CVRGameEventSystem.Instance.OnConnected.AddListener(_ => + { + if (!Instances.IsReconnecting) OnInitialConnectionToInstance(); + }); + } + + #endregion Constructor + + #region Settings + + /// Log debug messages + public bool IsDebugEnabled { get; set; } = true; + + /// Prioritize friends first in download queue + public bool PrioritizeFriends { get; set; } = true; + + /// Prioritize content closest to player first in download queue + public bool PrioritizeDistance { get; set; } = true; + public float PriorityDownloadDistance { get; set; } = 25f; + + public int MaxDownloadBandwidth + { + get => _downloadProcessor.MaxDownloadBandwidth; + set => _downloadProcessor.MaxDownloadBandwidth = value; + } + + #endregion Settings + + private readonly DownloadProcessor _downloadProcessor; + + private readonly AvatarDownloadQueue _avatarQueue; + private readonly PropDownloadQueue _propQueue; + private readonly WorldDownloadQueue _worldQueue; + + #region Game Events + + private void OnInitialConnectionToInstance() + { + if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg("Initial connection established."); + // await few seconds before chewing through the download queue, to allow for download priorities to be set + // once we have received most of the data from the server + } + + #endregion Game Events + + #region Public Queue Methods + + public void QueueAvatarDownload( + in DownloadInfo info, + string playerId, + CVRLoadingAvatarController loadingController) + { + if (IsDebugEnabled) + { + BetterContentLoadingMod.Logger.Msg( + $"Queuing Avatar Download:\n{info.GetLogString()}\n" + + $"PlayerId: {playerId}\n" + + $"LoadingController: {loadingController}"); + } + + _avatarQueue.QueueDownload(in info, playerId); + } + + /// + /// Queues a prop download. + /// + /// The download info. + /// The instance ID for the prop. + /// The user who spawned the prop. + public void QueuePropDownload( + in DownloadInfo info, + string instanceId, + string spawnerId) + { + if (IsDebugEnabled) + { + BetterContentLoadingMod.Logger.Msg( + $"Queuing Prop Download:\n{info.GetLogString()}\n" + + $"InstanceId: {instanceId}\n" + + $"SpawnerId: {spawnerId}"); + } + + _propQueue.QueueDownload(in info, instanceId, spawnerId); + } + + /// + /// Queues a world download. + /// + /// Download info. + /// Whether to load into this world once downloaded. + /// Whether the home world is requested. + public void QueueWorldDownload( + in DownloadInfo info, + bool joinOnComplete, + bool isHomeRequested) + { + if (IsDebugEnabled) + { + BetterContentLoadingMod.Logger.Msg( + $"Queuing World Download:\n{info.GetLogString()}\n" + + $"JoinOnComplete: {joinOnComplete}\n" + + $"IsHomeRequested: {isHomeRequested}"); + } + + _worldQueue.QueueDownload(in info, joinOnComplete, isHomeRequested); + } + + #endregion Public Queue Methods + + #region Internal Methods + + internal Task ProcessDownload(DownloadInfo info, Action progressCallback = null) + { + return _downloadProcessor.ProcessDownload(info); + } + + #endregion Internal Methods + + #region Private Helper Methods + + internal static bool TryGetPlayerEntity(string playerId, out CVRPlayerEntity playerEntity) + { + CVRPlayerEntity player = CVRPlayerManager.Instance.NetworkPlayers.Find(p => p.Uuid == playerId); + if (player == null) + { + // BetterContentLoadingMod.Logger.Error($"Player entity not found for ID: {playerId}"); + playerEntity = null; + return false; + } + playerEntity = player; + return true; + } + + internal static bool TryGetPropData(string instanceId, out CVRSyncHelper.PropData propData) + { + CVRSyncHelper.PropData prop = CVRSyncHelper.Props.Find(p => p.InstanceId == instanceId); + if (prop == null) + { + // BetterContentLoadingMod.Logger.Error($"Prop data not found for ID: {instanceId}"); + propData = null; + return false; + } + propData = prop; + return true; + } + + internal static bool IsPlayerLocal(string playerId) + { + return playerId == MetaPort.Instance.ownerId; + } + + internal static bool IsPlayerFriend(string playerId) + { + return Friends.FriendsWith(playerId); + } + + internal bool IsPlayerWithinPriorityDistance(CVRPlayerEntity player) + { + if (player.PuppetMaster == null) return false; + return player.PuppetMaster.animatorManager.DistanceTo < PriorityDownloadDistance; + } + + internal bool IsPropWithinPriorityDistance(CVRSyncHelper.PropData prop) + { + Vector3 propPosition = new(prop.PositionX, prop.PositionY, prop.PositionZ); + return Vector3.Distance(propPosition, PlayerSetup.Instance.GetPlayerPosition()) < PriorityDownloadDistance; + } + + #endregion Private Helper Methods +} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/DownloadInfo.cs b/BetterContentLoading/BetterContentLoading/DownloadInfo.cs new file mode 100644 index 0000000..038f6bf --- /dev/null +++ b/BetterContentLoading/BetterContentLoading/DownloadInfo.cs @@ -0,0 +1,63 @@ +using System.Security.Cryptography; +using System.Text; +using ABI_RC.Core.Networking.API.Responses; + +namespace NAK.BetterContentLoading; + +public readonly struct DownloadInfo +{ + public readonly string AssetId; + public readonly string AssetUrl; + public readonly string FileId; + public readonly long FileSize; + public readonly string FileKey; + public readonly string FileHash; + public readonly int CompatibilityVersion; + public readonly int EncryptionAlgorithm; + public readonly UgcTagsData TagsData; + + public readonly string DownloadId; + + public DownloadInfo( + string assetId, string assetUrl, string fileId, + long fileSize, string fileKey, string fileHash, + int compatibilityVersion, int encryptionAlgorithm, + UgcTagsData tagsData) + { + AssetId = assetId + "meow"; + AssetUrl = assetUrl; + FileId = fileId; + FileSize = fileSize; + FileKey = fileKey; + FileHash = fileHash; + CompatibilityVersion = compatibilityVersion; + EncryptionAlgorithm = encryptionAlgorithm; + TagsData = tagsData; + + using SHA256 sha = SHA256.Create(); + StringBuilder sb = new(); + sb.Append(assetId) + .Append('|').Append(assetUrl) + .Append('|').Append(fileId) + .Append('|').Append(fileSize) + .Append('|').Append(fileKey) + .Append('|').Append(fileHash) + .Append('|').Append(compatibilityVersion) + .Append('|').Append(encryptionAlgorithm); + + var bytes = Encoding.UTF8.GetBytes(sb.ToString()); + var hash = sha.ComputeHash(bytes); + DownloadId = Convert.ToBase64String(hash); + } + + public string GetLogString() => + $"AssetId: {AssetId}\n" + + $"DownloadId: {DownloadId}\n" + + $"AssetUrl: {AssetUrl}\n" + + $"FileId: {FileId}\n" + + $"FileSize: {FileSize}\n" + + $"FileKey: {FileKey}\n" + + $"FileHash: {FileHash}\n" + + $"CompatibilityVersion: {CompatibilityVersion}\n" + + $"EncryptionAlgorithm: {EncryptionAlgorithm}"; +} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/DownloadProcessor.cs b/BetterContentLoading/BetterContentLoading/DownloadProcessor.cs new file mode 100644 index 0000000..e77acdc --- /dev/null +++ b/BetterContentLoading/BetterContentLoading/DownloadProcessor.cs @@ -0,0 +1,152 @@ +using System.Net.Http; +using ABI_RC.Core; +using ABI_RC.Core.IO.AssetManagement; + +namespace NAK.BetterContentLoading; + +public class DownloadProcessor +{ + private readonly HttpClient _client = new(); + private readonly SemaphoreSlim _bandwidthSemaphore = new(1); + private long _bytesReadLastSecond; + + private int _maxDownloadBandwidth = 10 * 1024 * 1024; // Default 10MB/s + private const int MinBufferSize = 16384; // 16KB min buffer + private const long ThrottleThreshold = 25 * 1024 * 1024; // 25MB threshold for throttling + private const long KnownSizeDifference = 1000; // API reported size is 1000 bytes larger than actual content + + public int MaxDownloadBandwidth + { + get => _maxDownloadBandwidth; + set => _maxDownloadBandwidth = Math.Max(1024 * 1024, value); + } + + private int ActiveDownloads { get; set; } + private int CurrentBandwidthPerDownload => MaxDownloadBandwidth / Math.Max(1, ActiveDownloads); + + public int GetProgress(string downloadId) => _downloadProgress.GetValueOrDefault(downloadId, 0); + private readonly Dictionary _downloadProgress = new(); + + public async Task ProcessDownload(DownloadInfo downloadInfo) + { + try + { + if (await CacheManager.Instance.IsCachedFileUpToDate( + downloadInfo.AssetId, + downloadInfo.FileId, + downloadInfo.FileHash)) + return true; + + var filePath = CacheManager.Instance.GetCachePath(downloadInfo.AssetId, downloadInfo.FileId); + if (!CVRTools.HasEnoughDiskSpace(filePath, downloadInfo.FileSize)) + { + BetterContentLoadingMod.Logger.Error($"Not enough disk space to download {downloadInfo.AssetId}"); + return false; + } + + CacheManager.Instance.EnsureCacheDirectoryExists(downloadInfo.AssetId); + + bool success = false; + Exception lastException = null; + + for (int attempt = 0; attempt <= 1; attempt++) + { + try + { + if (attempt > 0) + await Task.Delay(1000); + + success = await DownloadWithBandwidthLimit(downloadInfo, filePath); + if (success) break; + } + catch (Exception ex) + { + lastException = ex; + } + } + + if (!success && lastException != null) + BetterContentLoadingMod.Logger.Error($"Failed to download {downloadInfo.AssetId}: {lastException}"); + + _downloadProgress.Remove(downloadInfo.DownloadId); + return success; + } + catch (Exception ex) + { + BetterContentLoadingMod.Logger.Error($"Error processing download for {downloadInfo.AssetId}: {ex}"); + _downloadProgress.Remove(downloadInfo.DownloadId); + return false; + } + } + + private async Task DownloadWithBandwidthLimit(DownloadInfo downloadInfo, string filePath) + { + await _bandwidthSemaphore.WaitAsync(); + try { ActiveDownloads++; } + finally { _bandwidthSemaphore.Release(); } + + string tempFilePath = filePath + ".download"; + try + { + using var response = await _client.GetAsync(downloadInfo.AssetUrl, HttpCompletionOption.ResponseHeadersRead); + if (!response.IsSuccessStatusCode) + return false; + + var expectedContentSize = downloadInfo.FileSize - KnownSizeDifference; + using var stream = await response.Content.ReadAsStreamAsync(); + using var fileStream = File.Open(tempFilePath, FileMode.Create); + + var isEligibleForThrottle = downloadInfo.FileSize >= ThrottleThreshold; + var totalBytesRead = 0L; + byte[] buffer = null; + + while (true) + { + var lengthToRead = isEligibleForThrottle ? MinBufferSize : CurrentBandwidthPerDownload; + if (buffer == null || lengthToRead != buffer.Length) + buffer = new byte[lengthToRead]; + + var bytesRead = await stream.ReadAsync(buffer, 0, lengthToRead); + if (bytesRead == 0) break; + + if (isEligibleForThrottle) + Interlocked.Add(ref _bytesReadLastSecond, bytesRead); + + fileStream.Write(buffer, 0, bytesRead); + totalBytesRead += bytesRead; + + var progress = (int)(((float)totalBytesRead / expectedContentSize) * 100f); + _downloadProgress[downloadInfo.DownloadId] = Math.Clamp(progress, 0, 100); + } + + fileStream.Flush(); + + var fileInfo = new FileInfo(tempFilePath); + if (fileInfo.Length != expectedContentSize) + return false; + + if (File.Exists(filePath)) + File.Delete(filePath); + File.Move(tempFilePath, filePath); + + CacheManager.Instance.QueuePrune(); + return true; + } + finally + { + await _bandwidthSemaphore.WaitAsync(); + try { ActiveDownloads--; } + finally { _bandwidthSemaphore.Release(); } + + try + { + if (File.Exists(tempFilePath)) + File.Delete(tempFilePath); + } + catch + { + // Ignore cleanup errors + } + } + } +} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/DownloadQueue/AvatarDownloadQueue.cs b/BetterContentLoading/BetterContentLoading/DownloadQueue/AvatarDownloadQueue.cs new file mode 100644 index 0000000..60060c5 --- /dev/null +++ b/BetterContentLoading/BetterContentLoading/DownloadQueue/AvatarDownloadQueue.cs @@ -0,0 +1,83 @@ +namespace NAK.BetterContentLoading.Queue; + +public class AvatarDownloadQueue : ContentDownloadQueueBase +{ + public AvatarDownloadQueue(BetterDownloadManager manager) : base(manager, 3) { } + + public void QueueDownload(in DownloadInfo info, string playerId, Action onComplete = null) + { + float priority = CalculateAvatarPriority(in info, playerId); + QueueDownload(in info, playerId, priority, onComplete); + } + + protected override async Task ProcessDownload(DownloadInfo info) + { + await base.ProcessDownload(info); + } + + protected override void OnDownloadProgress(string downloadId, float progress) + { + if (DownloadOwners.TryGetValue(downloadId, out var owners)) + { + foreach (var playerId in owners) + { + if (BetterDownloadManager.IsPlayerLocal(playerId)) + { + // Update loading progress on local player + BetterContentLoadingMod.Logger.Msg($"Progress for local player ({playerId}): {progress:P}"); + continue; + } + if (BetterDownloadManager.TryGetPlayerEntity(playerId, out var player)) + { + // Update loading progress on avatar controller if needed + BetterContentLoadingMod.Logger.Msg($"Progress for {player.Username} ({playerId}): {progress:P}"); + } + } + } + } + + protected override float RecalculatePriority(string downloadId) + { + if (!DownloadOwners.TryGetValue(downloadId, out var owners)) + return float.MaxValue; + + float lowestPriority = float.MaxValue; + DownloadInfo? downloadInfo = null; + + // Find the queue item to get the DownloadInfo + var queueItem = Queue.Find(x => x.Info.DownloadId == downloadId); + if (queueItem.Info.AssetId != null) + downloadInfo = queueItem.Info; + + if (downloadInfo == null) + return lowestPriority; + + // Calculate priority for each owner and use the lowest (highest priority) value + foreach (var playerId in owners) + { + var priority = CalculateAvatarPriority(downloadInfo.Value, playerId); + lowestPriority = Math.Min(lowestPriority, priority); + } + + return lowestPriority; + } + + private float CalculateAvatarPriority(in DownloadInfo info, string playerId) + { + float priority = info.FileSize; + + if (BetterDownloadManager.IsPlayerLocal(playerId)) + return 0f; + + if (!BetterDownloadManager.TryGetPlayerEntity(playerId, out var player)) + return priority; + + if (Manager.PrioritizeFriends && BetterDownloadManager.IsPlayerFriend(playerId)) + priority *= 0.5f; + + if (Manager.PrioritizeDistance && Manager.IsPlayerWithinPriorityDistance(player)) + priority *= 0.75f; + + return priority; + } +} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/DownloadQueue/ContentDownloadQueueBase.cs b/BetterContentLoading/BetterContentLoading/DownloadQueue/ContentDownloadQueueBase.cs new file mode 100644 index 0000000..66e366b --- /dev/null +++ b/BetterContentLoading/BetterContentLoading/DownloadQueue/ContentDownloadQueueBase.cs @@ -0,0 +1,177 @@ +namespace NAK.BetterContentLoading.Queue; + +public abstract class ContentDownloadQueueBase +{ + protected readonly struct QueueItem + { + public readonly DownloadInfo Info; + public readonly float Priority; + public readonly Action OnComplete; // Callback with (downloadId, ownerId) + + public QueueItem(DownloadInfo info, float priority, Action onComplete) + { + Info = info; + Priority = priority; + OnComplete = onComplete; + } + } + + protected readonly List Queue = new(); + private readonly HashSet ActiveDownloads = new(); // By DownloadId + protected readonly Dictionary> DownloadOwners = new(); // DownloadId -> Set of OwnerIds + private readonly SemaphoreSlim DownloadSemaphore; + protected readonly BetterDownloadManager Manager; + + protected ContentDownloadQueueBase(BetterDownloadManager manager, int maxParallelDownloads) + { + Manager = manager; + DownloadSemaphore = new SemaphoreSlim(maxParallelDownloads); + } + + protected void QueueDownload(in DownloadInfo info, string ownerId, float priority, Action onComplete) + { + if (Manager.IsDebugEnabled) + BetterContentLoadingMod.Logger.Msg($"Attempting to queue download for {info.AssetId} (DownloadId: {info.DownloadId})"); + + // Add to owners tracking + if (!DownloadOwners.TryGetValue(info.DownloadId, out var owners)) + { + owners = new HashSet(); + DownloadOwners[info.DownloadId] = owners; + } + owners.Add(ownerId); + + // If already downloading, just add the owner and callback + if (ActiveDownloads.Contains(info.DownloadId)) + { + if (Manager.IsDebugEnabled) + BetterContentLoadingMod.Logger.Msg($"Already downloading {info.DownloadId}, added owner {ownerId}"); + return; + } + + DownloadInfo downloadInfo = info; + var existingIndex = Queue.FindIndex(x => x.Info.DownloadId == downloadInfo.DownloadId); + if (existingIndex >= 0) + { + // Update priority if needed based on new owner + var newPriority = RecalculatePriority(info.DownloadId); + Queue[existingIndex] = new QueueItem(info, newPriority, onComplete); + SortQueue(); + return; + } + + Queue.Add(new QueueItem(info, priority, onComplete)); + SortQueue(); + TryStartNextDownload(); + } + + public void RemoveOwner(string downloadId, string ownerId) + { + if (!DownloadOwners.TryGetValue(downloadId, out var owners)) + return; + + owners.Remove(ownerId); + + if (owners.Count == 0) + { + // No more owners, cancel the download + DownloadOwners.Remove(downloadId); + CancelDownload(downloadId); + } + else if (!ActiveDownloads.Contains(downloadId)) + { + // Still has owners and is queued, recalculate priority + var existingIndex = Queue.FindIndex(x => x.Info.DownloadId == downloadId); + if (existingIndex >= 0) + { + var item = Queue[existingIndex]; + var newPriority = RecalculatePriority(downloadId); + Queue[existingIndex] = new QueueItem(item.Info, newPriority, item.OnComplete); + SortQueue(); + } + } + } + + protected virtual async void TryStartNextDownload() + { + try + { + if (Queue.Count == 0) return; + + await DownloadSemaphore.WaitAsync(); + + if (Queue.Count > 0) + { + var item = Queue[0]; + Queue.RemoveAt(0); + + // Double check we still have owners before starting download + if (!DownloadOwners.TryGetValue(item.Info.DownloadId, out var owners) || owners.Count == 0) + { + DownloadSemaphore.Release(); + TryStartNextDownload(); + return; + } + + ActiveDownloads.Add(item.Info.DownloadId); + + try + { + await ProcessDownload(item.Info); + BetterContentLoadingMod.Logger.Msg($"Download completed for {item.Info.DownloadId}"); + + // Notify all owners of completion + if (DownloadOwners.TryGetValue(item.Info.DownloadId, out owners)) + { + foreach (var owner in owners) + { + item.OnComplete?.Invoke(item.Info.DownloadId, owner); + } + } + } + catch (Exception ex) + { + if (Manager.IsDebugEnabled) + BetterContentLoadingMod.Logger.Error($"Download failed for {item.Info.DownloadId}: {ex}"); + } + finally + { + ActiveDownloads.Remove(item.Info.DownloadId); + DownloadSemaphore.Release(); + TryStartNextDownload(); + } + } + else + { + DownloadSemaphore.Release(); + } + } + catch (Exception e) + { + BetterContentLoadingMod.Logger.Error($"Error in TryStartNextDownload: {e}"); + } + } + + protected virtual async Task ProcessDownload(DownloadInfo info) + { + bool success = await Manager.ProcessDownload(info); + + if (!success) + throw new Exception($"Failed to download {info.AssetId}"); + } + + protected abstract void OnDownloadProgress(string downloadId, float progress); + + protected abstract float RecalculatePriority(string downloadId); + + protected virtual void SortQueue() + { + Queue.Sort((a, b) => a.Priority.CompareTo(b.Priority)); + } + + protected virtual void CancelDownload(string downloadId) + { + Queue.RemoveAll(x => x.Info.DownloadId == downloadId); + if (ActiveDownloads.Remove(downloadId)) DownloadSemaphore.Release(); + } +} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/DownloadQueue/PropDownloadQueue.cs b/BetterContentLoading/BetterContentLoading/DownloadQueue/PropDownloadQueue.cs new file mode 100644 index 0000000..f100e0b --- /dev/null +++ b/BetterContentLoading/BetterContentLoading/DownloadQueue/PropDownloadQueue.cs @@ -0,0 +1,81 @@ +using ABI_RC.Core.Util; + +namespace NAK.BetterContentLoading.Queue; + +public class PropDownloadQueue : ContentDownloadQueueBase +{ + private readonly Dictionary _ownerToSpawner = new(); // InstanceId -> SpawnerId + + public PropDownloadQueue(BetterDownloadManager manager) : base(manager, 2) { } + + public void QueueDownload(in DownloadInfo info, string instanceId, string spawnerId, Action onComplete = null) + { + _ownerToSpawner[instanceId] = spawnerId; + float priority = CalculatePropPriority(in info, instanceId, spawnerId); + QueueDownload(in info, instanceId, priority, onComplete); + } + + protected override async Task ProcessDownload(DownloadInfo info) + { + await base.ProcessDownload(info); + } + + protected override void OnDownloadProgress(string downloadId, float progress) + { + if (DownloadOwners.TryGetValue(downloadId, out var owners)) + { + foreach (var instanceId in owners) + { + if (BetterDownloadManager.TryGetPropData(instanceId, out CVRSyncHelper.PropData prop)) + { + BetterContentLoadingMod.Logger.Msg($"Progress for {prop.InstanceId}: {progress:P}"); + } + } + } + } + + protected override float RecalculatePriority(string downloadId) + { + if (!DownloadOwners.TryGetValue(downloadId, out var owners)) + return float.MaxValue; + + float lowestPriority = float.MaxValue; + DownloadInfo? downloadInfo = null; + + // Find the queue item to get the DownloadInfo + var queueItem = Queue.Find(x => x.Info.DownloadId == downloadId); + if (queueItem.Info.AssetId != null) + downloadInfo = queueItem.Info; + + if (downloadInfo == null) + return lowestPriority; + + // Calculate priority for each owner and use the lowest (highest priority) value + foreach (var instanceId in owners) + { + if (_ownerToSpawner.TryGetValue(instanceId, out var spawnerId)) + { + var priority = CalculatePropPriority(downloadInfo.Value, instanceId, spawnerId); + lowestPriority = Math.Min(lowestPriority, priority); + } + } + + return lowestPriority; + } + + private float CalculatePropPriority(in DownloadInfo info, string instanceId, string spawnerId) + { + float priority = info.FileSize; + + if (!BetterDownloadManager.TryGetPropData(instanceId, out var prop)) + return priority; + + if (Manager.PrioritizeFriends && BetterDownloadManager.IsPlayerFriend(spawnerId)) + priority *= 0.5f; + + if (Manager.PrioritizeDistance && Manager.IsPropWithinPriorityDistance(prop)) + priority *= 0.75f; + + return priority; + } +} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/DownloadQueue/WorldDownloadQueue.cs b/BetterContentLoading/BetterContentLoading/DownloadQueue/WorldDownloadQueue.cs new file mode 100644 index 0000000..1cea689 --- /dev/null +++ b/BetterContentLoading/BetterContentLoading/DownloadQueue/WorldDownloadQueue.cs @@ -0,0 +1,66 @@ +namespace NAK.BetterContentLoading.Queue; + +public class WorldDownloadQueue : ContentDownloadQueueBase +{ + private readonly Queue<(DownloadInfo Info, bool JoinOnComplete, bool IsHomeRequest)> _backgroundQueue = new(); + private bool _isProcessingPriorityDownload; + + public WorldDownloadQueue(BetterDownloadManager manager) : base(manager, 1) { } + + public void QueueDownload(in DownloadInfo info, bool joinOnComplete, bool isHomeRequest, Action onComplete = null) + { + if (joinOnComplete || isHomeRequest) + { + // Priority download - clear queue and download immediately + Queue.Clear(); + _isProcessingPriorityDownload = true; + QueueDownload(in info, info.DownloadId, 0f, onComplete); + } + else + { + // Background download - add to background queue + _backgroundQueue.Enqueue((info, false, false)); + if (!_isProcessingPriorityDownload) + ProcessBackgroundQueue(); + } + } + + protected override async Task ProcessDownload(DownloadInfo info) + { + await base.ProcessDownload(info); + + if (_isProcessingPriorityDownload) + { + _isProcessingPriorityDownload = false; + ProcessBackgroundQueue(); + } + } + + protected override void OnDownloadProgress(string downloadId, float progress) + { + BetterContentLoadingMod.Logger.Msg($"World download progress: {progress:P}"); + } + + protected override float RecalculatePriority(string downloadId) + { + // For worlds, priority is based on whether it's a priority download and file size + var queueItem = Queue.Find(x => x.Info.DownloadId == downloadId); + return queueItem.Priority; + } + + private void ProcessBackgroundQueue() + { + while (_backgroundQueue.Count > 0) + { + (DownloadInfo info, var join, var home) = _backgroundQueue.Dequeue(); + QueueDownload(in info, info.DownloadId, info.FileSize, null); + } + } + + protected override void CancelDownload(string downloadId) + { + base.CancelDownload(downloadId); + _backgroundQueue.Clear(); + _isProcessingPriorityDownload = false; + } +} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/DownloadState.cs b/BetterContentLoading/BetterContentLoading/DownloadState.cs new file mode 100644 index 0000000..785396b --- /dev/null +++ b/BetterContentLoading/BetterContentLoading/DownloadState.cs @@ -0,0 +1,26 @@ +namespace NAK.BetterContentLoading; + +public readonly struct DownloadState +{ + public readonly string DownloadId; + public readonly long BytesRead; + public readonly long TotalBytes; + public readonly int ProgressPercent; + public readonly float BytesPerSecond; + + public DownloadState(string downloadId, long bytesRead, long totalBytes, float bytesPerSecond) + { + DownloadId = downloadId; + BytesRead = bytesRead; + TotalBytes = totalBytes; + BytesPerSecond = bytesPerSecond; + ProgressPercent = (int)(((float)bytesRead / totalBytes) * 100f); + } +} + +public interface IDownloadMonitor +{ + void OnDownloadProgress(DownloadState state); + void OnDownloadStarted(string downloadId); + void OnDownloadCompleted(string downloadId, bool success); +} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/Util/ThreadingHelper.cs b/BetterContentLoading/BetterContentLoading/Util/ThreadingHelper.cs new file mode 100644 index 0000000..280aeb2 --- /dev/null +++ b/BetterContentLoading/BetterContentLoading/Util/ThreadingHelper.cs @@ -0,0 +1,109 @@ +using JetBrains.Annotations; +using UnityEngine; + +namespace NAK.BetterContentLoading.Util; + +[PublicAPI] +public static class ThreadingHelper +{ + private static readonly SynchronizationContext _mainThreadContext; + + static ThreadingHelper() + { + _mainThreadContext = SynchronizationContext.Current; + } + + public static bool IsMainThread => SynchronizationContext.Current == _mainThreadContext; + + /// + /// Runs an action on the main thread. Optionally waits for its completion. + /// + public static void RunOnMainThread(Action action, bool waitForCompletion = true, Action onError = null) + { + if (SynchronizationContext.Current == _mainThreadContext) + { + // Already on the main thread + TryExecute(action, onError); + } + else + { + if (waitForCompletion) + { + ManualResetEvent done = new(false); + _mainThreadContext.Post(_ => + { + TryExecute(action, onError); + done.Set(); + }, null); + done.WaitOne(50000); // Block until action is completed + } + else + { + // Fire and forget (don't wait for the action to complete) + _mainThreadContext.Post(_ => TryExecute(action, onError), null); + } + } + } + + /// + /// Runs an action asynchronously on the main thread and returns a Task. + /// + public static Task RunOnMainThreadAsync(Action action, Action onError = null) + { + if (SynchronizationContext.Current == _mainThreadContext) + { + // Already on the main thread + TryExecute(action, onError); + return Task.CompletedTask; + } + + var tcs = new TaskCompletionSource(); + _mainThreadContext.Post(_ => + { + try + { + TryExecute(action, onError); + tcs.SetResult(true); + } + catch (Exception ex) + { + tcs.SetException(ex); + } + }, null); + return tcs.Task; + } + + /// + /// Runs a task on a background thread with cancellation support. + /// + public static async Task RunOffMainThreadAsync(Action action, CancellationToken cancellationToken, Action onError = null) + { + try + { + await Task.Run(() => + { + cancellationToken.ThrowIfCancellationRequested(); + TryExecute(action, onError); + }, cancellationToken); + } + catch (OperationCanceledException) + { + Debug.LogWarning("Task was canceled."); + } + } + + /// + /// Helper method for error handling. + /// + private static void TryExecute(Action action, Action onError) + { + try + { + action(); + } + catch (Exception ex) + { + onError?.Invoke(ex); + } + } +} diff --git a/BetterContentLoading/DownloadManager/DownloadManager.Core.cs b/BetterContentLoading/DownloadManager/DownloadManager.Core.cs new file mode 100644 index 0000000..ce484cd --- /dev/null +++ b/BetterContentLoading/DownloadManager/DownloadManager.Core.cs @@ -0,0 +1,237 @@ +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Networking.API.Responses; +using ABI_RC.Core.Networking.IO.Social; +using ABI_RC.Core.Savior; + +namespace NAK.BetterContentLoading; + +public partial class DownloadManager +{ + #region Singleton + private static DownloadManager _instance; + public static DownloadManager Instance => _instance ??= new DownloadManager(); + #endregion + + private DownloadManager() + { + + } + + #region Settings + public bool IsDebugEnabled { get; set; } = true; + public bool PrioritizeFriends { get; set; } = true; + public bool PrioritizeDistance { get; set; } = true; + public float PriorityDownloadDistance { get; set; } = 25f; + public int MaxConcurrentDownloads { get; set; } = 3; + public int MaxDownloadBandwidth { get; set; } = 100 * 1024 * 1024; // 100MB default + private const int THROTTLE_THRESHOLD = 25 * 1024 * 1024; // 25MB threshold for throttling + + public long MaxAvatarDownloadSize { get; set; } = 25 * 1024 * 1024; // 25MB default + public long MaxPropDownloadSize { get; set; } = 25 * 1024 * 1024; // 25MB default + + #endregion Settings + + #region State + + // priority -> downloadtask + private readonly SortedList _downloadQueue = new(); + + // downloadId -> downloadtask + private readonly Dictionary _cachedDownloads = new(); + + #endregion State + + #region Public Queue Methods + + public void QueueAvatarDownload( + in DownloadInfo info, + string playerId, + CVRLoadingAvatarController loadingController) + { + if (IsDebugEnabled) + { + BetterContentLoadingMod.Logger.Msg( + $"Queuing Avatar Download:\n{info.GetLogString()}\n" + + $"PlayerId: {playerId}\n" + + $"LoadingController: {loadingController}"); + } + + if (!ShouldQueueAvatarDownload(info, playerId)) + { + if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Avatar Download not eligible: {info.DownloadId}"); + return; + } + + if (_cachedDownloads.TryGetValue(info.DownloadId, out DownloadTask cachedDownload)) + { + if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Avatar Download already queued: {info.DownloadId}"); + cachedDownload.AddInstantiationTarget(playerId); + cachedDownload.BasePriority = CalculatePriority(cachedDownload); + return; + } + + DownloadTask task = new() + { + Info = info, + Type = DownloadTaskType.Avatar + }; + task.AddInstantiationTarget(playerId); + task.BasePriority = CalculatePriority(task); + } + + private bool ShouldQueueAvatarDownload( + in DownloadInfo info, + string playerId) + { + // Check if content is incompatible or banned + if (info.TagsData.Incompatible || info.TagsData.AdminBanned) + { + if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Avatar is incompatible or banned"); + return false; + } + + // Check if player is blocked + if (MetaPort.Instance.blockedUserIds.Contains(playerId)) + { + if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Player is blocked: {playerId}"); + return false; + } + + // Check if mature content is disabled + UgcTagsData tags = info.TagsData; + if (!MetaPort.Instance.matureContentAllowed && (tags.Gore || tags.Nudity)) + { + if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Mature content is disabled"); + return false; + } + + // Check file size + if (info.FileSize > MaxAvatarDownloadSize) + { + if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Avatar Download too large: {info.FileSize} > {MaxAvatarDownloadSize}"); + return false; + } + + // Get visibility status for the avatar + // ForceHidden means player avatar or avatar itself is forced off. + // ForceShown will bypass all checks and return true. + MetaPort.Instance.SelfModerationManager.GetAvatarVisibility(playerId, info.AssetId, + out bool wasForceHidden, out bool wasForceShown); + + if (!wasForceHidden) + { + if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Avatar is not visible either because player avatar or avatar itself is forced off"); + return false; + } + + if (!wasForceShown) + { + // Check content filter settings if not force shown + CVRSettings settings = MetaPort.Instance.settings; + bool isLocalPlayer = playerId == MetaPort.Instance.ownerId; + bool isFriend = Friends.FriendsWith(playerId); + bool CheckFilterSettings(string settingName) + { + int settingVal = settings.GetSettingInt(settingName); + switch (settingVal) + { + // Only Self + case 0 when !isLocalPlayer: + // Only Friends + case 1 when !isFriend: + return false; + } + return true; + } + + if (!CheckFilterSettings("ContentFilterVisibility")) return false; + if (!CheckFilterSettings("ContentFilterNudity")) return false; + if (!CheckFilterSettings("ContentFilterGore")) return false; + if (!CheckFilterSettings("ContentFilterSuggestive")) return false; + if (!CheckFilterSettings("ContentFilterFlashingColors")) return false; + if (!CheckFilterSettings("ContentFilterFlashingLights")) return false; + if (!CheckFilterSettings("ContentFilterScreenEffects")) return false; + if (!CheckFilterSettings("ContentFilterExtremelyBright")) return false; + if (!CheckFilterSettings("ContentFilterViolence")) return false; + if (!CheckFilterSettings("ContentFilterJumpscare")) return false; + if (!CheckFilterSettings("ContentFilterExcessivelyHuge")) return false; + if (!CheckFilterSettings("ContentFilterExcessivelySmall")) return false; + } + + // All eligibility checks passed + return true; + } + + /// + /// Queues a prop download. + /// + /// The download info. + /// The instance ID for the prop. + /// The user who spawned the prop. + public void QueuePropDownload( + in DownloadInfo info, + string instanceId, + string spawnerId) + { + if (IsDebugEnabled) + { + BetterContentLoadingMod.Logger.Msg( + $"Queuing Prop Download:\n{info.GetLogString()}\n" + + $"InstanceId: {instanceId}\n" + + $"SpawnerId: {spawnerId}"); + } + + if (_cachedDownloads.TryGetValue(info.DownloadId, out DownloadTask cachedDownload)) + { + if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Prop Download already queued: {info.DownloadId}"); + cachedDownload.AddInstantiationTarget(instanceId); + cachedDownload.BasePriority = CalculatePriority(cachedDownload); + return; + } + + DownloadTask task = new() + { + Info = info, + Type = DownloadTaskType.Prop + }; + task.AddInstantiationTarget(instanceId); + task.BasePriority = CalculatePriority(task); + } + + /// + /// Queues a world download. + /// + /// Download info. + /// Whether to load into this world once downloaded. + /// Whether the home world is requested. + public void QueueWorldDownload( + in DownloadInfo info, + bool joinOnComplete, + bool isHomeRequested) + { + if (IsDebugEnabled) + { + BetterContentLoadingMod.Logger.Msg( + $"Queuing World Download:\n{info.GetLogString()}\n" + + $"JoinOnComplete: {joinOnComplete}\n" + + $"IsHomeRequested: {isHomeRequested}"); + } + + if (_cachedDownloads.TryGetValue(info.DownloadId, out DownloadTask cachedDownload)) + { + if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"World Download already queued: {info.DownloadId}"); + cachedDownload.BasePriority = CalculatePriority(cachedDownload); + return; + } + + DownloadTask task = new() + { + Info = info, + Type = DownloadTaskType.World + }; + task.BasePriority = CalculatePriority(task); + } + + #endregion Public Queue Methods + +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager/DownloadManager.Helpers.cs b/BetterContentLoading/DownloadManager/DownloadManager.Helpers.cs new file mode 100644 index 0000000..3664ed4 --- /dev/null +++ b/BetterContentLoading/DownloadManager/DownloadManager.Helpers.cs @@ -0,0 +1,58 @@ +using ABI_RC.Core.Networking.IO.Social; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using ABI_RC.Core.Util; +using UnityEngine; + +namespace NAK.BetterContentLoading; + +public partial class DownloadManager +{ + internal static bool TryGetPlayerEntity(string playerId, out CVRPlayerEntity playerEntity) + { + CVRPlayerEntity player = CVRPlayerManager.Instance.NetworkPlayers.Find(p => p.Uuid == playerId); + if (player == null) + { + // BetterContentLoadingMod.Logger.Error($"Player entity not found for ID: {playerId}"); + playerEntity = null; + return false; + } + playerEntity = player; + return true; + } + + internal static bool TryGetPropData(string instanceId, out CVRSyncHelper.PropData propData) + { + CVRSyncHelper.PropData prop = CVRSyncHelper.Props.Find(p => p.InstanceId == instanceId); + if (prop == null) + { + // BetterContentLoadingMod.Logger.Error($"Prop data not found for ID: {instanceId}"); + propData = null; + return false; + } + propData = prop; + return true; + } + + private static bool IsPlayerLocal(string playerId) + { + return playerId == MetaPort.Instance.ownerId; + } + + private static bool IsPlayerFriend(string playerId) + { + return Friends.FriendsWith(playerId); + } + + private bool IsPlayerWithinPriorityDistance(CVRPlayerEntity player) + { + if (player.PuppetMaster == null) return false; + return player.PuppetMaster.animatorManager.DistanceTo < PriorityDownloadDistance; + } + + internal bool IsPropWithinPriorityDistance(CVRSyncHelper.PropData prop) + { + Vector3 propPosition = new(prop.PositionX, prop.PositionY, prop.PositionZ); + return Vector3.Distance(propPosition, PlayerSetup.Instance.GetPlayerPosition()) < PriorityDownloadDistance; + } +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager/DownloadManager.Priority.cs b/BetterContentLoading/DownloadManager/DownloadManager.Priority.cs new file mode 100644 index 0000000..ae28cbc --- /dev/null +++ b/BetterContentLoading/DownloadManager/DownloadManager.Priority.cs @@ -0,0 +1,38 @@ +using ABI_RC.Core.Player; + +namespace NAK.BetterContentLoading; + +public partial class DownloadManager +{ + private float CalculatePriority(DownloadTask task) + { + return task.Type switch + { + DownloadTaskType.Avatar => CalculateAvatarPriority(task), + // DownloadTaskType.Prop => CalculatePropPriority(task2), + // DownloadTaskType.World => CalculateWorldPriority(task2), + _ => task.Info.FileSize + }; + } + + private float CalculateAvatarPriority(DownloadTask task) + { + float priority = task.Info.FileSize; + + foreach (string target in task.InstantiationTargets) + { + if (IsPlayerLocal(target)) return 0f; + + if (!TryGetPlayerEntity(target, out CVRPlayerEntity player)) + return priority; + + if (PrioritizeFriends && IsPlayerFriend(target)) + priority *= 0.5f; + + if (PrioritizeDistance && IsPlayerWithinPriorityDistance(player)) + priority *= 0.75f; + } + + return priority; + } +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager/DownloadTask.Main.cs b/BetterContentLoading/DownloadManager/DownloadTask.Main.cs new file mode 100644 index 0000000..5397cf7 --- /dev/null +++ b/BetterContentLoading/DownloadManager/DownloadTask.Main.cs @@ -0,0 +1,33 @@ +namespace NAK.BetterContentLoading; + +public partial class DownloadTask +{ + public DownloadInfo Info { get; set; } + public DownloadTaskStatus Status { get; set; } + public DownloadTaskType Type { get; set; } + + public float BasePriority { get; set; } + public float CurrentPriority => BasePriority * (1 + Progress / 100f); + + public long BytesRead { get; set; } + public int Progress { get; set; } + + /// The avatar/prop instances that wish to utilize this bundle. + public List InstantiationTargets { get; } = new(); + + public void AddInstantiationTarget(string target) + { + if (InstantiationTargets.Contains(target)) + return; + + InstantiationTargets.Add(target); + } + + public void RemoveInstantiationTarget(string target) + { + if (!InstantiationTargets.Contains(target)) + return; + + InstantiationTargets.Remove(target); + } +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager/DownloadTask.Priority.cs b/BetterContentLoading/DownloadManager/DownloadTask.Priority.cs new file mode 100644 index 0000000..f697a5e --- /dev/null +++ b/BetterContentLoading/DownloadManager/DownloadTask.Priority.cs @@ -0,0 +1,6 @@ +namespace NAK.BetterContentLoading; + +public partial class DownloadTask +{ + +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/ConcurrentPriorityQueue.cs b/BetterContentLoading/DownloadManager2/ConcurrentPriorityQueue.cs new file mode 100644 index 0000000..df844d5 --- /dev/null +++ b/BetterContentLoading/DownloadManager2/ConcurrentPriorityQueue.cs @@ -0,0 +1,43 @@ +namespace NAK.BetterContentLoading; + +public class ConcurrentPriorityQueue where TPriority : IComparable +{ + private readonly object _lock = new(); + private readonly SortedDictionary> _queues = new(); + + public void Enqueue(TElement item, TPriority priority) + { + lock (_lock) + { + if (!_queues.TryGetValue(priority, out var queue)) + { + queue = new Queue(); + _queues[priority] = queue; + } + queue.Enqueue(item); + } + } + + public bool TryDequeue(out TElement item, out TPriority priority) + { + lock (_lock) + { + if (_queues.Count == 0) + { + item = default; + priority = default; + return false; + } + + var firstQueue = _queues.First(); + priority = firstQueue.Key; + var queue = firstQueue.Value; + item = queue.Dequeue(); + + if (queue.Count == 0) + _queues.Remove(priority); + + return true; + } + } +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/DownloadManager.Bandwidth.cs b/BetterContentLoading/DownloadManager2/DownloadManager.Bandwidth.cs new file mode 100644 index 0000000..54d5792 --- /dev/null +++ b/BetterContentLoading/DownloadManager2/DownloadManager.Bandwidth.cs @@ -0,0 +1,24 @@ +namespace NAK.BetterContentLoading; + +public partial class DownloadManager2 +{ + private void StartBandwidthMonitor() + { + Task.Run(async () => + { + while (true) + { + await Task.Delay(1000); + Interlocked.Exchange(ref _bytesReadLastSecond, 0); + Interlocked.Exchange(ref _completedDownloads, 0); + } + }); + } + + private int ComputeUsableBandwidthPerDownload() + { + var activeCount = _activeDownloads.Count; + if (activeCount == 0) return MaxDownloadBandwidth; + return MaxDownloadBandwidth / activeCount; + } +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/DownloadManager.Core.cs b/BetterContentLoading/DownloadManager2/DownloadManager.Core.cs new file mode 100644 index 0000000..63fd4c2 --- /dev/null +++ b/BetterContentLoading/DownloadManager2/DownloadManager.Core.cs @@ -0,0 +1,126 @@ +using System.Collections.Concurrent; +using ABI_RC.Core; +using ABI_RC.Core.IO; +using ABI_RC.Core.IO.AssetManagement; + +namespace NAK.BetterContentLoading; + +public partial class DownloadManager2 +{ + #region Singleton + private static DownloadManager2 _instance; + public static DownloadManager2 Instance => _instance ??= new DownloadManager2(); + #endregion + + #region Settings + public bool IsDebugEnabled { get; set; } = true; + public bool PrioritizeFriends { get; set; } = true; + public bool PrioritizeDistance { get; set; } = true; + public float PriorityDownloadDistance { get; set; } = 25f; + public int MaxConcurrentDownloads { get; set; } = 5; + public int MaxDownloadBandwidth { get; set; } // 100MB default + private const int THROTTLE_THRESHOLD = 25 * 1024 * 1024; // 25MB threshold for throttling + #endregion + + #region State + private readonly ConcurrentDictionary _activeDownloads; + private readonly ConcurrentPriorityQueue _queuedDownloads; + private readonly ConcurrentDictionary _completedDownloads; + private readonly object _downloadLock = new(); + private long _bytesReadLastSecond; + #endregion + + private DownloadManager2() + { + _activeDownloads = new ConcurrentDictionary(); + _queuedDownloads = new ConcurrentPriorityQueue(); + MaxDownloadBandwidth = 100 * 1024 * 1024; + StartBandwidthMonitor(); + } + + public async Task QueueAvatarDownload(DownloadInfo info, string playerId) + { + if (await ValidateAndCheckCache(info)) + return true; + + DownloadTask2 task2 = GetOrCreateDownloadTask(info, DownloadTaskType.Avatar); + task2.AddTarget(playerId); + QueueDownload(task2); + return false; + } + + public async Task QueuePropDownload(DownloadInfo info, string instanceId, string spawnerId) + { + if (await ValidateAndCheckCache(info)) + return true; + + DownloadTask2 task2 = GetOrCreateDownloadTask(info, DownloadTaskType.Prop); + task2.AddTarget(instanceId, spawnerId); + QueueDownload(task2); + return false; + } + + public async Task QueueWorldDownload(DownloadInfo info, bool loadOnComplete) + { + if (await ValidateAndCheckCache(info)) + return true; + + DownloadTask2 task2 = GetOrCreateDownloadTask(info, DownloadTaskType.World, loadOnComplete); + QueueDownload(task2); + return false; + } + + private async Task ValidateAndCheckCache(DownloadInfo info) + { + // Check if already cached and up to date + if (await CacheManager.Instance.IsCachedFileUpToDate( + info.AssetId, + info.FileId, + info.FileHash)) + { + return true; + } + + // Validate disk space + var filePath = CacheManager.Instance.GetCachePath(info.AssetId, info.FileId); + if (!CVRTools.HasEnoughDiskSpace(filePath, info.FileSize)) + { + BetterContentLoadingMod.Logger.Error($"Not enough disk space to download {info.AssetId}"); + return false; + } + + // Ensure cache directory exists + CacheManager.Instance.EnsureCacheDirectoryExists(info.AssetId); + return false; + } + + private DownloadTask2 GetOrCreateDownloadTask(DownloadInfo info, DownloadTaskType type, bool loadOnComplete = false) + { + // Check if task already exists in active downloads + if (_activeDownloads.TryGetValue(info.DownloadId, out var activeTask)) + return activeTask; + + // Check if task exists in queued downloads + var queuedTask = _queuedDownloads.TryFind(t => t.Info.DownloadId == info.DownloadId); + if (queuedTask != null) + return queuedTask; + + // Create new task + var cachePath = CacheManager.Instance.GetCachePath(info.AssetId, info.FileId); + return new DownloadTask2(info, cachePath, type, loadOnComplete); + } + + public bool TryFindTask(string downloadId, out DownloadTask2 task2) + { + return _activeDownloads.TryGetValue(downloadId, out task2) || + _completedDownloads.TryGetValue(downloadId, out task2) || + TryFindQueuedTask(downloadId, out task2); + } + + private bool TryFindQueuedTask(string downloadId, out DownloadTask2 task2) + { + task2 = _queuedDownloads.UnorderedItems + .FirstOrDefault(x => x.Element.Info.DownloadId == downloadId).Element; + return task2 != null; + } +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/DownloadManager.Helpers.cs b/BetterContentLoading/DownloadManager2/DownloadManager.Helpers.cs new file mode 100644 index 0000000..2dd205d --- /dev/null +++ b/BetterContentLoading/DownloadManager2/DownloadManager.Helpers.cs @@ -0,0 +1,58 @@ +using ABI_RC.Core.Networking.IO.Social; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using ABI_RC.Core.Util; +using UnityEngine; + +namespace NAK.BetterContentLoading; + +public partial class DownloadManager2 +{ + internal static bool TryGetPlayerEntity(string playerId, out CVRPlayerEntity playerEntity) + { + CVRPlayerEntity player = CVRPlayerManager.Instance.NetworkPlayers.Find(p => p.Uuid == playerId); + if (player == null) + { + // BetterContentLoadingMod.Logger.Error($"Player entity not found for ID: {playerId}"); + playerEntity = null; + return false; + } + playerEntity = player; + return true; + } + + internal static bool TryGetPropData(string instanceId, out CVRSyncHelper.PropData propData) + { + CVRSyncHelper.PropData prop = CVRSyncHelper.Props.Find(p => p.InstanceId == instanceId); + if (prop == null) + { + // BetterContentLoadingMod.Logger.Error($"Prop data not found for ID: {instanceId}"); + propData = null; + return false; + } + propData = prop; + return true; + } + + private static bool IsPlayerLocal(string playerId) + { + return playerId == MetaPort.Instance.ownerId; + } + + private static bool IsPlayerFriend(string playerId) + { + return Friends.FriendsWith(playerId); + } + + private bool IsPlayerWithinPriorityDistance(CVRPlayerEntity player) + { + if (player.PuppetMaster == null) return false; + return player.PuppetMaster.animatorManager.DistanceTo < PriorityDownloadDistance; + } + + internal bool IsPropWithinPriorityDistance(CVRSyncHelper.PropData prop) + { + Vector3 propPosition = new(prop.PositionX, prop.PositionY, prop.PositionZ); + return Vector3.Distance(propPosition, PlayerSetup.Instance.GetPlayerPosition()) < PriorityDownloadDistance; + } +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/DownloadManager.Priority.cs b/BetterContentLoading/DownloadManager2/DownloadManager.Priority.cs new file mode 100644 index 0000000..1132b8e --- /dev/null +++ b/BetterContentLoading/DownloadManager2/DownloadManager.Priority.cs @@ -0,0 +1,47 @@ +using ABI_RC.Core.IO; + +namespace NAK.BetterContentLoading; + +public partial class DownloadManager2 +{ + private float CalculatePriority(DownloadTask2 task2) + { + return task2.Type switch + { + DownloadTaskType.Avatar => CalculateAvatarPriority(task2), + DownloadTaskType.Prop => CalculatePropPriority(task2), + DownloadTaskType.World => CalculateWorldPriority(task2), + _ => task2.Info.FileSize + }; + } + + private float CalculateAvatarPriority(DownloadTask2 task2) + { + float priority = task2.Info.FileSize; + + if (IsPlayerLocal(task2.PlayerId)) + return 0f; + + if (!TryGetPlayerEntity(task2.PlayerId, out var player)) + return priority; + + if (PrioritizeFriends && IsPlayerFriend(task2.PlayerId)) + priority *= 0.5f; + + if (PrioritizeDistance && IsPlayerWithinPriorityDistance(player)) + priority *= 0.75f; + + // Factor in download progress + priority *= (1 + task2.Progress / 100f); + + return priority; + } + + private float CalculatePropPriority(DownloadTask2 task2) + { + float priority = task2.Info.FileSize; + + if (IsPlayerLocal(task2.PlayerId)) + return 0f; + } +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/DownloadManager.Processing.cs b/BetterContentLoading/DownloadManager2/DownloadManager.Processing.cs new file mode 100644 index 0000000..698ac06 --- /dev/null +++ b/BetterContentLoading/DownloadManager2/DownloadManager.Processing.cs @@ -0,0 +1,144 @@ +using System.Diagnostics; +using System.Net.Http.Headers; +using ABI_RC.Core.IO; + +namespace NAK.BetterContentLoading; + +public partial class DownloadManager2 +{ + private async Task ProcessDownload(DownloadTask2 task2) + { + using var client = new HttpClient(); + + // Set up resume headers if we have a resume token + if (!string.IsNullOrEmpty(task2.ResumeToken)) + { + client.DefaultRequestHeaders.Range = new RangeHeaderValue(task2.BytesRead, null); + } + + using var response = await client.GetAsync(task2.Info.AssetUrl, HttpCompletionOption.ResponseHeadersRead); + using var dataStream = await response.Content.ReadAsStreamAsync(); + + // Open file in append mode if resuming, otherwise create new + using var fileStream = new FileStream( + task2.TargetPath, + string.IsNullOrEmpty(task2.ResumeToken) ? FileMode.Create : FileMode.Append, + FileAccess.Write); + + bool isEligibleForThrottle = task2.Info.FileSize > THROTTLE_THRESHOLD; + var stopwatch = new Stopwatch(); + + int bytesRead; + do + { + if (task2.Status == DownloadTaskStatus.Paused) + { + task2.ResumeToken = GenerateResumeToken(task2); + await fileStream.FlushAsync(); + return; + } + + if (task2.Status != DownloadTaskStatus.Downloading) + { + HandleCancellation(task2, dataStream, fileStream); + return; + } + + stopwatch.Restart(); + var lengthToRead = isEligibleForThrottle ? + ComputeUsableBandwidthPerDownload() : + 16384; + + var buffer = new byte[lengthToRead]; + bytesRead = await dataStream.ReadAsync(buffer, 0, lengthToRead); + + if (isEligibleForThrottle) + Interlocked.Add(ref _bytesReadLastSecond, bytesRead); + + await fileStream.WriteAsync(buffer, 0, bytesRead); + UpdateProgress(task2, bytesRead); + + } while (bytesRead > 0); + + CompleteDownload(task2); + } + + private string GenerateResumeToken(DownloadTask2 task2) + { + // Generate a unique token that includes file position and hash + return $"{task2.BytesRead}:{DateTime.UtcNow.Ticks}"; + } + + private async Task FinalizeDownload(DownloadTask2 task2) + { + var tempPath = task2.CachePath + ".tmp"; + + try + { + // Decrypt the file if needed + if (task2.Info.EncryptionAlgorithm != 0) + { + await DecryptFile(tempPath, task2.CachePath, task2.Info); + File.Delete(tempPath); + } + else + { + File.Move(tempPath, task2.CachePath); + } + + CompleteDownload(task2); + } + catch (Exception ex) + { + // _logger.Error($"Failed to finalize download for {task.Info.AssetId}: {ex.Message}"); + task2.Status = DownloadTaskStatus.Failed; + File.Delete(tempPath); + _activeDownloads.TryRemove(task2.Info.DownloadId, out _); + } + } + + private async Task DecryptFile(string sourcePath, string targetPath, DownloadInfo info) + { + // Implementation of file decryption based on EncryptionAlgorithm + // This would use the FileKey from the DownloadInfo + throw new NotImplementedException("File decryption not implemented"); + } + + private void HandleCancellation(DownloadTask2 task2, Stream dataStream, Stream fileStream) + { + if (task2.Status != DownloadTaskStatus.Failed) + task2.Status = DownloadTaskStatus.Cancelled; + + dataStream.Close(); + fileStream.Close(); + + task2.Progress = 0; + task2.BytesRead = 0; + + _activeDownloads.TryRemove(task2.Info.DownloadId, out _); + } + + private void UpdateProgress(DownloadTask2 task2, int bytesRead) + { + task2.BytesRead += bytesRead; + task2.Progress = Math.Clamp( + (int)(((float)task2.BytesRead / task2.Info.FileSize) * 100f), + 0, 100); + } + + private void CompleteDownload(DownloadTask2 task2) + { + task2.Status = DownloadTaskStatus.Complete; + task2.Progress = 100; + _activeDownloads.TryRemove(task2.Info.DownloadId, out _); + _completedDownloads.TryAdd(task2.Info.DownloadId, task2); + + lock (_downloadLock) + { + if (_queuedDownloads.TryDequeue(out var nextTask, out _)) + { + StartDownload(nextTask); + } + } + } +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/DownloadManager.Queue.cs b/BetterContentLoading/DownloadManager2/DownloadManager.Queue.cs new file mode 100644 index 0000000..e8a580a --- /dev/null +++ b/BetterContentLoading/DownloadManager2/DownloadManager.Queue.cs @@ -0,0 +1,80 @@ +using ABI_RC.Core.IO; + +namespace NAK.BetterContentLoading; + +public partial class DownloadManager2 +{ + public void QueueDownload(DownloadTask2 newTask2) + { + if (_completedDownloads.TryGetValue(newTask2.Info.DownloadId, out var completedTask)) + { + completedTask.AddPlayer(newTask2.PlayerIds.FirstOrDefault()); + return; + } + + if (TryFindTask(newTask2.Info.DownloadId, out var existingTask)) + { + existingTask.AddPlayer(newTask2.PlayerIds.FirstOrDefault()); + RecalculatePriority(existingTask); + return; + } + + float priority = CalculatePriority(newTask2); + newTask2.CurrentPriority = priority; + + lock (_downloadLock) + { + if (_activeDownloads.Count < MaxConcurrentDownloads) + { + StartDownload(newTask2); + return; + } + + var lowestPriorityTask = _activeDownloads.Values + .OrderByDescending(t => t.CurrentPriority * (1 + t.Progress / 100f)) + .LastOrDefault(); + + if (lowestPriorityTask != null && priority < lowestPriorityTask.CurrentPriority) + { + PauseDownload(lowestPriorityTask); + StartDownload(newTask2); + } + else + { + _queuedDownloads.Enqueue(newTask2, priority); + } + } + } + + private void StartDownload(DownloadTask2 task2) + { + task2.Status = DownloadTaskStatus.Downloading; + _activeDownloads.TryAdd(task2.Info.DownloadId, task2); + Task.Run(() => ProcessDownload(task2)); + } + + private void PauseDownload(DownloadTask2 task2) + { + task2.Status = DownloadTaskStatus.Queued; + _activeDownloads.TryRemove(task2.Info.DownloadId, out _); + _queuedDownloads.Enqueue(task2, task2.CurrentPriority); + } + + + + + private void RecalculatePriority(DownloadTask2 task2) + { + var newPriority = CalculatePriority(task2); + if (Math.Abs(newPriority - task2.CurrentPriority) < float.Epsilon) + return; + + task2.CurrentPriority = newPriority; + + if (task2.Status == DownloadTaskStatus.Queued || task2.Status == DownloadTaskStatus.Paused) + { + // Re-enqueue with new priority + _queuedDownloads.UpdatePriority(task2, newPriority); + } + } +} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/DownloadTask2.cs b/BetterContentLoading/DownloadManager2/DownloadTask2.cs new file mode 100644 index 0000000..0c531f6 --- /dev/null +++ b/BetterContentLoading/DownloadManager2/DownloadTask2.cs @@ -0,0 +1,62 @@ +namespace NAK.BetterContentLoading; + +public class DownloadTask2 +{ + public DownloadInfo Info { get; } + public DownloadTaskStatus Status { get; set; } + public DownloadTaskType Type { get; } + + public float BasePriority { get; set; } + public float CurrentPriority => BasePriority * (1 + Progress / 100f); + + public long BytesRead { get; set; } + public int Progress { get; set; } + + public string CachePath { get; } + public Dictionary Targets { get; } // Key: targetId (playerId/instanceId), Value: spawnerId + public bool LoadOnComplete { get; } // For worlds only + + public DownloadTask2( + DownloadInfo info, + string cachePath, + DownloadTaskType type, + bool loadOnComplete = false) + { + Info = info; + CachePath = cachePath; + Type = type; + LoadOnComplete = loadOnComplete; + Targets = new Dictionary(); + Status = DownloadTaskStatus.Queued; + } + + public void AddTarget(string targetId, string spawnerId = null) + { + if (Type == DownloadTaskType.World && Targets.Count > 0) + throw new InvalidOperationException("World downloads cannot have multiple targets"); + + Targets[targetId] = spawnerId; + } + + public void RemoveTarget(string targetId) + { + Targets.Remove(targetId); + } +} + +public enum DownloadTaskType +{ + Avatar, + Prop, + World +} + +public enum DownloadTaskStatus +{ + Queued, + Downloading, + Paused, + Complete, + Failed, + Cancelled +} \ No newline at end of file diff --git a/InteractionTest/Main.cs b/BetterContentLoading/Main.cs similarity index 68% rename from InteractionTest/Main.cs rename to BetterContentLoading/Main.cs index a88cbfd..5b5d812 100644 --- a/InteractionTest/Main.cs +++ b/BetterContentLoading/Main.cs @@ -1,22 +1,23 @@ using MelonLoader; +using NAK.BetterContentLoading.Patches; -namespace NAK.InteractionTest; +namespace NAK.BetterContentLoading; -public class InteractionTestMod : MelonMod +public class BetterContentLoadingMod : MelonMod { internal static MelonLogger.Instance Logger; - - #region Melon Mod Overrides + + #region Melon Events public override void OnInitializeMelon() { Logger = LoggerInstance; - ApplyPatches(typeof(Patches.ControllerRayPatches)); + ApplyPatches(typeof(CVRDownloadManager_Patches)); } - #endregion Melon Mod Overrides - + #endregion Melon Events + #region Melon Mod Utilities private void ApplyPatches(Type type) @@ -33,4 +34,4 @@ public class InteractionTestMod : MelonMod } #endregion Melon Mod Utilities -} +} \ No newline at end of file diff --git a/BetterContentLoading/ModSettings.cs b/BetterContentLoading/ModSettings.cs new file mode 100644 index 0000000..f07436c --- /dev/null +++ b/BetterContentLoading/ModSettings.cs @@ -0,0 +1,31 @@ +using MelonLoader; + +namespace NAK.RCCVirtualSteeringWheel; + +internal static class ModSettings +{ + #region Constants + + private const string ModName = nameof(RCCVirtualSteeringWheel); + + #endregion Constants + + #region Melon Preferences + + private static readonly MelonPreferences_Category Category = + MelonPreferences.CreateCategory(ModName); + + internal static readonly MelonPreferences_Entry EntryOverrideSteeringRange = + Category.CreateEntry("override_steering_range", false, + "Override Steering Range", description: "Should the steering wheel use a custom steering range instead of the vehicle's default?"); + + internal static readonly MelonPreferences_Entry EntryCustomSteeringRange = + Category.CreateEntry("custom_steering_range", 60f, + "Custom Steering Range", description: "The custom steering range in degrees when override is enabled (default: 60)"); + + internal static readonly MelonPreferences_Entry EntryInvertSteering = + Category.CreateEntry("invert_steering", false, + "Invert Steering", description: "Inverts the steering direction"); + + #endregion Melon Preferences +} \ No newline at end of file diff --git a/BetterContentLoading/Patches.cs b/BetterContentLoading/Patches.cs new file mode 100644 index 0000000..d3c452b --- /dev/null +++ b/BetterContentLoading/Patches.cs @@ -0,0 +1,71 @@ +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.IO; +using ABI_RC.Core.Networking.API; +using ABI_RC.Core.Networking.API.Responses; +using HarmonyLib; +using NAK.BetterContentLoading.Util; + +namespace NAK.BetterContentLoading.Patches; + +internal static class CVRDownloadManager_Patches +{ + [HarmonyPrefix] + [HarmonyPatch(typeof(CVRDownloadManager), nameof(CVRDownloadManager.QueueTask))] + private static bool Prefix_CVRDownloadManager_QueueTask( + string assetId, + DownloadTask2.ObjectType type, + string assetUrl, + string fileId, + long fileSize, + string fileKey, + string toAttach, + string fileHash = null, + UgcTagsData tagsData = null, + CVRLoadingAvatarController loadingAvatarController = null, + bool joinOnComplete = false, + bool isHomeRequested = false, + int compatibilityVersion = 0, + int encryptionAlgorithm = 0, + string spawnerId = null) + { + DownloadInfo info; + + switch (type) + { + case DownloadTask2.ObjectType.Avatar: + info = new DownloadInfo( + assetId, assetUrl, fileId, fileSize, fileKey, fileHash, + compatibilityVersion, encryptionAlgorithm, tagsData); + BetterDownloadManager.Instance.QueueAvatarDownload(in info, toAttach, loadingAvatarController); + return true; + case DownloadTask2.ObjectType.Prop: + info = new DownloadInfo( + assetId, assetUrl, fileId, fileSize, fileKey, fileHash, + compatibilityVersion, encryptionAlgorithm, tagsData); + BetterDownloadManager.Instance.QueuePropDownload(in info, toAttach, spawnerId); + return true; + case DownloadTask2.ObjectType.World: + _ = ThreadingHelper.RunOffMainThreadAsync(() => + { + var response = ApiConnection.MakeRequest( + ApiConnection.ApiOperation.WorldMeta, + new { worldID = assetId } + ); + + if (response?.Result.Data == null) + return; + + info = new DownloadInfo( + assetId, response.Result.Data.FileLocation, response.Result.Data.FileId, + response.Result.Data.FileSize, response.Result.Data.FileKey, response.Result.Data.FileHash, + (int)response.Result.Data.CompatibilityVersion, (int)response.Result.Data.EncryptionAlgorithm, + null); + + BetterDownloadManager.Instance.QueueWorldDownload(in info, joinOnComplete, isHomeRequested); + }, CancellationToken.None); + return true; + default: + return true; + } + } +} \ No newline at end of file diff --git a/BetterContentLoading/Properties/AssemblyInfo.cs b/BetterContentLoading/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..9ab241d --- /dev/null +++ b/BetterContentLoading/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using MelonLoader; +using NAK.BetterContentLoading; +using NAK.BetterContentLoading.Properties; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.BetterContentLoading))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.BetterContentLoading))] + +[assembly: MelonInfo( + typeof(BetterContentLoadingMod), + nameof(NAK.BetterContentLoading), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/BetterContentLoading" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red +[assembly: HarmonyDontPatchAll] + +namespace NAK.BetterContentLoading.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/BetterContentLoading/README.md b/BetterContentLoading/README.md new file mode 100644 index 0000000..8d9f529 --- /dev/null +++ b/BetterContentLoading/README.md @@ -0,0 +1,14 @@ +# RCCVirtualSteeringWheel + +Allows you to physically grab rigged RCC steering wheels in VR to provide steering input. No explicit setup required other than defining the Steering Wheel transform within the RCC component. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation 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.~~~~ \ No newline at end of file diff --git a/BetterContentLoading/format.json b/BetterContentLoading/format.json new file mode 100644 index 0000000..f565d36 --- /dev/null +++ b/BetterContentLoading/format.json @@ -0,0 +1,23 @@ +{ + "_id": -1, + "name": "RCCVirtualSteeringWheel", + "modversion": "1.0.1", + "gameversion": "2024r177", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Allows you to physically grab rigged RCC steering wheels in VR to provide steering input. No explicit setup required other than defining the Steering Wheel transform within the RCC component.\n", + "searchtags": [ + "rcc", + "steering", + "vehicle", + "car" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r44/RCCVirtualSteeringWheel.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/RCCVirtualSteeringWheel/", + "changelog": "- Initial release", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/CVRGizmos/Popcron.Gizmos/Constants.cs b/CVRGizmos/Popcron.Gizmos/Constants.cs deleted file mode 100644 index e5884c9..0000000 --- a/CVRGizmos/Popcron.Gizmos/Constants.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Popcron -{ - public class Constants - { - public const string UniqueIdentifier = "Popcron.Gizmos"; - public const string EnabledKey = UniqueIdentifier + ".Enabled"; - } -} \ No newline at end of file diff --git a/CVRGizmos/Popcron.Gizmos/Drawers/LineDrawer.cs b/CVRGizmos/Popcron.Gizmos/Drawers/LineDrawer.cs deleted file mode 100644 index f9193cf..0000000 --- a/CVRGizmos/Popcron.Gizmos/Drawers/LineDrawer.cs +++ /dev/null @@ -1,19 +0,0 @@ -using UnityEngine; - -namespace Popcron -{ - public class LineDrawer : Drawer - { - public LineDrawer() - { - - } - - public override int Draw(ref Vector3[] buffer, params object[] args) - { - buffer[0] = (Vector3)args[0]; - buffer[1] = (Vector3)args[1]; - return 2; - } - } -} diff --git a/CVRGizmos/Popcron.Gizmos/Element.cs b/CVRGizmos/Popcron.Gizmos/Element.cs deleted file mode 100644 index 361fd59..0000000 --- a/CVRGizmos/Popcron.Gizmos/Element.cs +++ /dev/null @@ -1,12 +0,0 @@ -using UnityEngine; - -namespace Popcron -{ - internal class Element - { - public Vector3[] points = { }; - public Color color = Color.white; - public bool dashed = false; - public Matrix4x4 matrix = Matrix4x4.identity; - } -} \ No newline at end of file diff --git a/CVRLuaToolsExtension/LuaToolsExtension/Extensions/CVRLuaClientBehaviourExtensions.cs b/CVRLuaToolsExtension/LuaToolsExtension/Extensions/CVRLuaClientBehaviourExtensions.cs index 6f77a61..8c07542 100644 --- a/CVRLuaToolsExtension/LuaToolsExtension/Extensions/CVRLuaClientBehaviourExtensions.cs +++ b/CVRLuaToolsExtension/LuaToolsExtension/Extensions/CVRLuaClientBehaviourExtensions.cs @@ -2,17 +2,21 @@ using ABI.Scripting.CVRSTL.Client; using System.Diagnostics; using MTJobSystem; +using UnityEngine; namespace NAK.CVRLuaToolsExtension; public static class CVRLuaClientBehaviourExtensions { internal static readonly Dictionary _isRestarting = new(); + private static string PersistentDataPath; #region Public Methods public static void Restart(this CVRLuaClientBehaviour behaviour) { + PersistentDataPath ??= Application.persistentDataPath; // needs to be set on main + if (_isRestarting.TryGetValue(behaviour, out bool isRestarting) && isRestarting) { CVRLuaToolsExtensionMod.Logger.Warning($"Restart is already in progress for {behaviour.ScriptName}."); @@ -105,7 +109,7 @@ public static class CVRLuaClientBehaviourExtensions behaviour.LogInfo("[CVRLuaToolsExtension] Resetting script...\n"); behaviour.script = null; - behaviour.script = LuaScriptFactory.ForLuaBehaviour(behaviour, boundObjectEntries, behaviour.gameObject, behaviour.transform); + behaviour.script = LuaScriptFactory.ForLuaBehaviour(behaviour, boundObjectEntries, behaviour.gameObject, behaviour.transform, PersistentDataPath); behaviour.InitTimerIfNeeded(); // only null if crashed prior behaviour.script.AttachDebugger(behaviour.timer); // reattach the debugger diff --git a/CustomRichPresence/CustomRichPresence.csproj b/CustomRichPresence/CustomRichPresence.csproj new file mode 100644 index 0000000..4e44ed3 --- /dev/null +++ b/CustomRichPresence/CustomRichPresence.csproj @@ -0,0 +1,11 @@ + + + + net48 + + + + ..\.ManagedLibs\TheClapper.dll + + + diff --git a/CustomRichPresence/Main.cs b/CustomRichPresence/Main.cs new file mode 100644 index 0000000..a2702d5 --- /dev/null +++ b/CustomRichPresence/Main.cs @@ -0,0 +1,123 @@ +using System.Reflection; +using ABI_RC.Core.Networking; +using ABI_RC.Core.Savior; +using ABI_RC.Core.Util.AnimatorManager; +using ABI_RC.Helpers; +using HarmonyLib; +using MagicaCloth; +using MelonLoader; +using Steamworks; +using UnityEngine; + +namespace NAK.CustomRichPresence; + +public class CustomRichPresenceMod : MelonMod +{ + #region Melon Preferences + + private static readonly MelonPreferences_Category Category = + MelonPreferences.CreateCategory(nameof(CustomRichPresence)); + + private static readonly MelonPreferences_Entry EntryUseCustomPresence = + Category.CreateEntry("use_custom_presence", true, + "Use Custom Presence", description: "Uses the custom rich presence setup."); + + // Discord Rich Presence Customization + private static readonly MelonPreferences_Entry DiscordStatusFormat = + Category.CreateEntry("discord_status_format", "Online using {mode}.", + "Discord Status Format", description: "Format for Discord status message. Available variables: {mode}, {instance_name}, {privacy}"); + + private static readonly MelonPreferences_Entry DiscordDetailsFormat = + Category.CreateEntry("discord_details_format", "{instance_name} [{privacy}]", + "Discord Details Format", description: "Format for Discord details. Available variables: {instance_name}, {privacy}, {world_name}, {mission_name}"); + + // Steam Rich Presence Customization + private static readonly MelonPreferences_Entry SteamStatusFormat = + Category.CreateEntry("steam_status_format", "Exploring ({mode}) {instance_name} [{privacy}].", + "Steam Status Format", description: "Format for Steam status. Available variables: {mode}, {instance_name}, {privacy}"); + + private static readonly MelonPreferences_Entry SteamGameStatusFormat = + Category.CreateEntry("steam_game_status_format", "Connected to a server, Privacy: {privacy}.", + "Steam Game Status Format", description: "Format for Steam game status. Available variables: {privacy}, {instance_name}, {world_name}"); + + private static readonly MelonPreferences_Entry SteamDisplayStatus = + Category.CreateEntry("steam_display_status", "#Status_Online", + "Steam Display Status", description: "Steam display status localization key."); + + #endregion Melon Preferences + + public override void OnInitializeMelon() + { + HarmonyInstance.Patch( + typeof(RichPresence).GetMethod(nameof(RichPresence.PopulateLastMessage), + BindingFlags.NonPublic | BindingFlags.Static), + prefix: new HarmonyMethod(typeof(CustomRichPresenceMod).GetMethod(nameof(OnPopulateLastMessage), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + } + + private static string FormatPresenceText(string format, string mode) + { + return format + .Replace("{mode}", mode) + .Replace("{instance_name}", RichPresence.LastMsg.InstanceName) + .Replace("{privacy}", RichPresence.LastMsg.InstancePrivacy) + .Replace("{world_name}", RichPresence.LastMsg.InstanceWorldName) + .Replace("{mission_name}", RichPresence.LastMsg.InstanceMissionName) + .Replace("{current_players}", RichPresence.LastMsg.CurrentPlayers.ToString()) + .Replace("{max_players}", RichPresence.LastMsg.MaxPlayers.ToString()); + } + + private static bool OnPopulateLastMessage() + { + if (!EntryUseCustomPresence.Value) + return true; + + string mode = MetaPort.Instance.isUsingVr ? "VR Mode" : "Desktop Mode"; + + PresenceManager.ClearPresence(); + if (RichPresence.DiscordEnabled) + { + string status = FormatPresenceText(DiscordStatusFormat.Value, mode); + string details = FormatPresenceText(DiscordDetailsFormat.Value, mode); + + PresenceManager.UpdatePresence( + status, + details, + RichPresence.LastConnectedToServer, + 0L, + "discordrp-cvrmain", + null, + null, + null, + RichPresence.LastMsg.InstanceMeshId, + RichPresence.LastMsg.CurrentPlayers, + RichPresence.LastMsg.MaxPlayers + ); + } + + if (!CheckVR.Instance.skipSteamApiRegister && SteamManager.Initialized) + { + SteamFriends.ClearRichPresence(); + if (RichPresence.SteamEnabled) + { + string status = FormatPresenceText(SteamStatusFormat.Value, mode); + string gameStatus = FormatPresenceText(SteamGameStatusFormat.Value, mode); + + SteamFriends.SetRichPresence("status", status); + SteamFriends.SetRichPresence("gamestatus", gameStatus); + SteamFriends.SetRichPresence("steam_display", SteamDisplayStatus.Value); + SteamFriends.SetRichPresence("steam_player_group", RichPresence.LastMsg.InstanceMeshId); + SteamFriends.SetRichPresence("steam_player_group_size", RichPresence.LastMsg.CurrentPlayers.ToString()); + SteamFriends.SetRichPresence("gamemode", RichPresence.LastMsg.InstanceMissionName); + SteamFriends.SetRichPresence("worldname", RichPresence.LastMsg.InstanceWorldName); + SteamFriends.SetRichPresence("instancename", RichPresence.LastMsg.InstanceName); + SteamFriends.SetRichPresence("instanceprivacy", RichPresence.LastMsg.InstancePrivacy); + SteamFriends.SetRichPresence("currentplayer", RichPresence.LastMsg.CurrentPlayers.ToString()); + SteamFriends.SetRichPresence("maxplayer", RichPresence.LastMsg.MaxPlayers.ToString()); + } + } + + return false; + } +} \ No newline at end of file diff --git a/InteractionTest/Properties/AssemblyInfo.cs b/CustomRichPresence/Properties/AssemblyInfo.cs similarity index 65% rename from InteractionTest/Properties/AssemblyInfo.cs rename to CustomRichPresence/Properties/AssemblyInfo.cs index ffc8f5e..0e00c7b 100644 --- a/InteractionTest/Properties/AssemblyInfo.cs +++ b/CustomRichPresence/Properties/AssemblyInfo.cs @@ -1,30 +1,30 @@ -using NAK.InteractionTest.Properties; +using NAK.CustomRichPresence.Properties; using MelonLoader; using System.Reflection; [assembly: AssemblyVersion(AssemblyInfoParams.Version)] [assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] [assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] -[assembly: AssemblyTitle(nameof(NAK.InteractionTest))] +[assembly: AssemblyTitle(nameof(NAK.CustomRichPresence))] [assembly: AssemblyCompany(AssemblyInfoParams.Author)] -[assembly: AssemblyProduct(nameof(NAK.InteractionTest))] +[assembly: AssemblyProduct(nameof(NAK.CustomRichPresence))] [assembly: MelonInfo( - typeof(NAK.InteractionTest.InteractionTestMod), - nameof(NAK.InteractionTest), + typeof(NAK.CustomRichPresence.CustomRichPresenceMod), + nameof(NAK.CustomRichPresence), AssemblyInfoParams.Version, AssemblyInfoParams.Author, - downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/InteractionTest" + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/CustomRichPresence" )] [assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] -[assembly: MelonColor(255, 125, 126, 129)] -[assembly: MelonAuthorColor(255, 158, 21, 32)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red [assembly: HarmonyDontPatchAll] -namespace NAK.InteractionTest.Properties; +namespace NAK.CustomRichPresence.Properties; internal static class AssemblyInfoParams { public const string Version = "1.0.0"; diff --git a/CustomRichPresence/README.md b/CustomRichPresence/README.md new file mode 100644 index 0000000..33bd3fd --- /dev/null +++ b/CustomRichPresence/README.md @@ -0,0 +1,14 @@ +# DropPropTweak + +Gives the Drop Prop button more utility by allowing you to drop props in the air. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation 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/CustomRichPresence/format.json b/CustomRichPresence/format.json new file mode 100644 index 0000000..a599614 --- /dev/null +++ b/CustomRichPresence/format.json @@ -0,0 +1,23 @@ +{ + "_id": -1, + "name": "DropPropTweak", + "modversion": "1.0.0", + "gameversion": "2024r175", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Gives the Drop Prop button more utility by allowing you to drop props in the air.", + "searchtags": [ + "prop", + "spawn", + "indicator", + "loading" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r34/DropPropTweak.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/DropPropTweak/", + "changelog": "- Initial Release", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/CustomSpawnPoint/SpawnPointManager.cs b/CustomSpawnPoint/SpawnPointManager.cs index 12bcd43..350d07c 100644 --- a/CustomSpawnPoint/SpawnPointManager.cs +++ b/CustomSpawnPoint/SpawnPointManager.cs @@ -7,38 +7,38 @@ using Object = UnityEngine.Object; using ABI_RC.Core; using Newtonsoft.Json; -namespace NAK.CustomSpawnPoint +namespace NAK.CustomSpawnPoint; + +internal static class SpawnPointManager { - internal static class SpawnPointManager - { - #region Fields + #region Fields - private static string currentWorldId = string.Empty; - private static SpawnPointData? currentSpawnPoint; + private static string currentWorldId = string.Empty; + private static SpawnPointData? currentSpawnPoint; - private static string requestedWorldId = string.Empty; - private static SpawnPointData? requestedSpawnPoint; + private static string requestedWorldId = string.Empty; + private static SpawnPointData? requestedSpawnPoint; - private static Dictionary spawnPoints = new(); - private static readonly string jsonFilePath = Path.Combine("UserData", "customspawnpoints.json"); + private static Dictionary spawnPoints = new(); + private static readonly string jsonFilePath = Path.Combine("UserData", "customspawnpoints.json"); - private static GameObject[] customSpawnPointsArray; - private static GameObject[] originalSpawnPointsArray; + private static GameObject[] customSpawnPointsArray; + private static GameObject[] originalSpawnPointsArray; - #endregion Fields + #endregion Fields - #region Initialization + #region Initialization - internal static void Init() - { + internal static void Init() + { LoadSpawnpoints(); CVRGameEventSystem.World.OnLoad.AddListener(OnWorldLoaded); CVRGameEventSystem.World.OnUnload.AddListener(OnWorldUnloaded); MelonLoader.MelonCoroutines.Start(WaitMainMenuUi()); } - private static System.Collections.IEnumerator WaitMainMenuUi() - { + private static System.Collections.IEnumerator WaitMainMenuUi() + { while (ViewManager.Instance == null) yield return null; while (ViewManager.Instance.gameMenuView == null) @@ -65,12 +65,12 @@ namespace NAK.CustomSpawnPoint customSpawnPointsArray = new[] { customSpawnPointObject }; } - #endregion Initialization + #endregion Initialization - #region Game Events + #region Game Events - private static void OnWorldLoaded(string worldId) - { + private static void OnWorldLoaded(string worldId) + { CVRWorld world = CVRWorld.Instance; if (world == null) return; @@ -90,13 +90,13 @@ namespace NAK.CustomSpawnPoint } } - private static void OnWorldUnloaded(string worldId) - { + private static void OnWorldUnloaded(string worldId) + { ClearCurrentWorldState(); } - internal static void OnRequestWorldDetailsPage(string worldId) - { + internal static void OnRequestWorldDetailsPage(string worldId) + { //CustomSpawnPointMod.Logger.Msg("Requesting world details page for world: " + worldId); requestedWorldId = worldId; @@ -106,24 +106,24 @@ namespace NAK.CustomSpawnPoint UpdateMenuButtonState(hasSpawnpoint, worldId == currentWorldId && CVRWorld.Instance != null && CVRWorld.Instance.allowFlying); } - private static void OnClearSpawnpointConfirm(string id, string value, string data) - { + private static void OnClearSpawnpointConfirm(string id, string value, string data) + { if (id != "nak_clear_spawnpoint") return; if (value == "true") ClearSpawnPoint(); } - #endregion Game Events + #endregion Game Events - #region Spawnpoint Management + #region Spawnpoint Management - public static void SetSpawnPoint() - => SetSpawnPointForWorld(currentWorldId); + public static void SetSpawnPoint() + => SetSpawnPointForWorld(currentWorldId); - public static void ClearSpawnPoint() - => ClearSpawnPointForWorld(currentWorldId); + public static void ClearSpawnPoint() + => ClearSpawnPointForWorld(currentWorldId); - private static void SetSpawnPointForWorld(string worldId) - { + private static void SetSpawnPointForWorld(string worldId) + { CustomSpawnPointMod.Logger.Msg("Setting spawn point for world: " + worldId); Vector3 playerPosition = PlayerSetup.Instance.GetPlayerPosition(); @@ -152,8 +152,8 @@ namespace NAK.CustomSpawnPoint UpdateMenuButtonState(true, worldId == currentWorldId); } - private static void ClearSpawnPointForWorld(string worldId) - { + private static void ClearSpawnPointForWorld(string worldId) + { CustomSpawnPointMod.Logger.Msg("Clearing spawn point for world: " + worldId); if (spawnPoints.ContainsKey(worldId)) @@ -172,29 +172,29 @@ namespace NAK.CustomSpawnPoint UpdateMenuButtonState(false, worldId == currentWorldId); } - private static void UpdateCustomSpawnPointTransform(SpawnPointData spawnPoint) - { + private static void UpdateCustomSpawnPointTransform(SpawnPointData spawnPoint) + { customSpawnPointsArray[0].transform.SetPositionAndRotation(spawnPoint.Position, Quaternion.Euler(spawnPoint.Rotation)); } - private static void UpdateMenuButtonState(bool hasSpawnpoint, bool isInWorld) - { + private static void UpdateMenuButtonState(bool hasSpawnpoint, bool isInWorld) + { ViewManager.Instance.gameMenuView.View.TriggerEvent("NAKUpdateSpawnpointStatus", hasSpawnpoint.ToString(), isInWorld.ToString()); } - private static void ClearCurrentWorldState() - { + private static void ClearCurrentWorldState() + { currentWorldId = string.Empty; currentSpawnPoint = null; originalSpawnPointsArray = null; } - #endregion Spawnpoint Management + #endregion Spawnpoint Management - #region JSON Management + #region JSON Management - private static void LoadSpawnpoints() - { + private static void LoadSpawnpoints() + { if (File.Exists(jsonFilePath)) { string json = File.ReadAllText(jsonFilePath); @@ -206,18 +206,18 @@ namespace NAK.CustomSpawnPoint } } - private static void SaveSpawnpoints() - { + private static void SaveSpawnpoints() + { File.WriteAllText(jsonFilePath, JsonConvert.SerializeObject(spawnPoints, Formatting.Indented, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore } // death )); } - #endregion JSON Management + #endregion JSON Management - #region Spawnpoint JS + #region Spawnpoint JS - private const string spawnpointJs = @" + private const string spawnpointJs = @" let hasSpawnpointForThisWorld = false; let spawnpointButton = null; @@ -249,17 +249,16 @@ engine.on('NAKUpdateSpawnpointStatus', function (hasSpawnpoint, isInWorld) { }); "; - #endregion Spawnpoint JS - } + #endregion Spawnpoint JS +} - #region Serializable +#region Serializable - [Serializable] - public struct SpawnPointData - { - public Vector3 Position; - public Vector3 Rotation; - } +[Serializable] +public struct SpawnPointData +{ + public Vector3 Position; + public Vector3 Rotation; +} - #endregion Serializable -} \ No newline at end of file +#endregion Serializable \ No newline at end of file diff --git a/InteractionTest/Components/InteractionTracker.cs b/InteractionTest/Components/InteractionTracker.cs deleted file mode 100644 index b5ea1b1..0000000 --- a/InteractionTest/Components/InteractionTracker.cs +++ /dev/null @@ -1,213 +0,0 @@ -using System.Collections; -using ABI_RC.Core; -using ABI_RC.Systems.GameEventSystem; -using ABI_RC.Systems.IK; -using ABI_RC.Systems.Movement; -using ABI.CCK.Components; -using RootMotion.FinalIK; -using UnityEngine; - -namespace NAK.InteractionTest.Components; - -public class InteractionTracker : MonoBehaviour -{ - #region Setup - - public static void Setup(GameObject parentObject, bool isLeft = true) - { - // LeapMotion: RotationTarget - - GameObject trackerObject = new("NAK.InteractionTracker"); - trackerObject.transform.SetParent(parentObject.transform); - trackerObject.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); - - GameObject ikObject = new("NAK.InteractionTracker.IK"); - ikObject.transform.SetParent(trackerObject.transform); - ikObject.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); - - SphereCollider sphereCol = trackerObject.AddComponent(); - sphereCol.radius = 0f; - sphereCol.isTrigger = true; - - BetterBetterCharacterController.QueueRemovePlayerCollision(sphereCol); - - InteractionTracker tracker = trackerObject.AddComponent(); - tracker.isLeft = isLeft; - tracker.Initialize(); - } - - #endregion Setup - - #region Actions - - public Action OnPenetrationDetected; // called on start of penetration - public Action OnPenetrationLost; // called on end of penetration - public Action OnPenetrationNormalChanged; // called when penetration normal changes after 2 degree threshold - - #endregion Actions - - public bool isLeft; - - public bool IsColliding => _isColliding; - public Vector3 ClosestPoint { get; private set; } - public Vector3 LastPenetrationNormal => _lastPenetrationNormal; - - private bool _isColliding; - private bool _wasPenetrating; - public Vector3 _lastPenetrationNormal = Vector3.forward; - private Collider _selfCollider; - private const float NormalChangeThreshold = 0.2f; - - #region Unity Events - - private void Initialize() - { - _selfCollider = GetComponent(); - CVRGameEventSystem.Avatar.OnLocalAvatarLoad.AddListener(OnLocalAvatarLoaded); - } - - private void OnDestroy() - { - CVRGameEventSystem.Avatar.OnLocalAvatarLoad.RemoveListener(OnLocalAvatarLoaded); - } - - private void OnLocalAvatarLoaded(CVRAvatar _) - { - StartCoroutine(FrameLateInit()); - } - - private IEnumerator FrameLateInit() - { - yield return null; - yield return null; - OnInitSolver(); - IKSystem.vrik.onPreSolverUpdate.AddListener(OnPreSolverUpdate); - IKSystem.vrik.onPostSolverUpdate.AddListener(OnPostSolverUpdate); - } - - private void OnTriggerStay(Collider other) - { - if (other.gameObject.layer == CVRLayers.PlayerLocal) - return; - - if (_selfCollider == null) - return; - - Transform selfTransform = transform; - Transform otherTransform = other.transform; - - bool isPenetrating = Physics.ComputePenetration( - _selfCollider, selfTransform.position, selfTransform.rotation, - other, otherTransform.position, otherTransform.rotation, - out Vector3 direction, out float distance); - - if (isPenetrating) - { - ClosestPoint = selfTransform.position + direction * distance; - Debug.DrawRay(ClosestPoint, direction * 10, Color.red); - - if (!_wasPenetrating) - { - OnPenetrationDetected?.Invoke(); - _wasPenetrating = true; - _lastPenetrationNormal = direction; - } - - float angleChange = Vector3.Angle(_lastPenetrationNormal, direction); - Debug.Log("Angle change: " + angleChange); - if (angleChange > NormalChangeThreshold) - { - _lastPenetrationNormal = direction; - OnPenetrationNormalChanged?.Invoke(); - } - } - else - { - if (_wasPenetrating) - { - OnPenetrationLost?.Invoke(); - _wasPenetrating = false; - } - } - } - - private void OnTriggerEnter(Collider other) - { - if (other.gameObject.layer == CVRLayers.PlayerLocal) - return; - - Debug.Log("Triggered with " + other.gameObject.name); - _isColliding = true; - } - - private void OnTriggerExit(Collider other) - { - if (other.gameObject.layer == CVRLayers.PlayerLocal) - return; - - Debug.Log("Exited trigger with " + other.gameObject.name); - _isColliding = false; - - if (_wasPenetrating) - { - OnPenetrationLost?.Invoke(); - _wasPenetrating = false; - } - } - - #endregion Unity Events - - private Transform _oldTarget; - - private Vector3 _initialPosOffset; - private Quaternion _initialRotOffset; - - private IKSolverVR.Arm _armSolver; - - private void OnInitSolver() - { - _armSolver = isLeft ? IKSystem.vrik.solver.arms[0] : IKSystem.vrik.solver.arms[1]; - - Transform target = _armSolver.target; - if (target == null) - target = transform.parent.Find("RotationTarget"); // LeapMotion: RotationTarget - - if (target == null) return; - - _initialPosOffset = target.localPosition; - _initialRotOffset = target.localRotation; - } - - private void OnPreSolverUpdate() - { - if (!IsColliding) - return; - - Transform selfTransform = transform; - - float dot = Vector3.Dot(_lastPenetrationNormal, selfTransform.forward); - if (dot > -0.45f) - return; - - _oldTarget = _armSolver.target; - _armSolver.target = selfTransform.GetChild(0); - - _armSolver.target.position = ClosestPoint + selfTransform.rotation * _initialPosOffset; - _armSolver.target.rotation = _initialRotOffset * Quaternion.LookRotation(-_lastPenetrationNormal, selfTransform.up); - - _armSolver.positionWeight = 1f; - _armSolver.rotationWeight = 1f; - } - - private void OnPostSolverUpdate() - { - if (!_oldTarget) - return; - - _armSolver.target = _oldTarget; - _oldTarget = null; - - _armSolver.positionWeight = 0f; - _armSolver.rotationWeight = 0f; - } -} \ No newline at end of file diff --git a/InteractionTest/ModSettings.cs b/InteractionTest/ModSettings.cs deleted file mode 100644 index 010f81b..0000000 --- a/InteractionTest/ModSettings.cs +++ /dev/null @@ -1,7 +0,0 @@ -using MelonLoader; - -namespace NAK.InteractionTest; - -internal static class ModSettings -{ -} \ No newline at end of file diff --git a/InteractionTest/Patches.cs b/InteractionTest/Patches.cs deleted file mode 100644 index 1fa65fd..0000000 --- a/InteractionTest/Patches.cs +++ /dev/null @@ -1,17 +0,0 @@ - -using ABI_RC.Core; -using ABI_RC.Core.InteractionSystem; -using HarmonyLib; -using NAK.InteractionTest.Components; - -namespace NAK.InteractionTest.Patches; - -internal static class ControllerRayPatches -{ - [HarmonyPostfix] - [HarmonyPatch(typeof(ControllerRay), nameof(ControllerRay.Start))] - private static void Postfix_BetterCharacterController_Start(ref ControllerRay __instance) - { - InteractionTracker.Setup(__instance.gameObject, __instance.hand == CVRHand.Left); - } -} \ No newline at end of file diff --git a/InteractionTest/README.md b/InteractionTest/README.md deleted file mode 100644 index 35bb285..0000000 --- a/InteractionTest/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# OriginShift - -Experimental mod that allows world origin to be shifted to prevent floating point precision issues. - -## Compromises -- Steam Audio data cannot be shifted. -- NavMesh data cannot be shifted. -- Light Probe data cannot be shifted (until [unity 2022](https://docs.unity3d.com/2022.3/Documentation/Manual/LightProbes-Moving.html)). -- Occlusion Culling data cannot be shifted. - - When using "Forced" mode, occlusion culling is disabled. -- Only 10k trail positions can be shifted per Trail Renderer (artificial limit). -- Only 10k particle positions can be shifted per Particle System (artificial limit). - - Potentially can fix by changing Particle System to Custom Simulation Space ? (untested) -- World Constraints are not shifted. - -## Known Issues -- Mod Network is not yet implemented, so Compatibility Mode is required to play with others. -- Portable Camera drone mode is not yet offset by the world origin shift. -- Chunk threshold past 10 units will break Voice Chat with remote players in some cases (without Compatibility Mode). - - This is because the voice server dictates who can hear who based on distance from each other and the world origin shift messes with that. -- Teleports past 50k units will not work. - - BetterBetterCharacterController prevents teleports past 50k units. -- Magica Cloth. - -## Mod Incompatibilities -- PlayerRagdollMod will freak out when you ragdoll between chunk boundaries. - -## Provided Components -- `OriginShiftController` - World script to configure origin shift. -- `OriginShiftEventReceiver` - Event receiver for OriginShift events. -- `OriginShiftTransformReceiver` - Shifts the transform of the GameObject it is attached to. -- `OriginShiftRigidbodyReceiver` - Shifts the rigidbody of the GameObject it is attached to. -- `OriginShiftTrailRendererReceiver` - Shifts the positions of the Trail Renderer of the GameObject it is attached to. -- `OriginShiftParticleSystemReceiver` - Shifts the positions of the Particle System of the GameObject it is attached to. - -The provided receiver components are automatically added to Props, Players, and Object Syncs. - -## Provided Shader Globals -- `_OriginShiftChunkOffset` - The current amount of chunks offset from the origin. -- `_OriginShiftChunkThreshold` - The size of a chunk in world units. -- `_OriginShiftChunkPosition` - The chunk offset multiplied by the chunk threshold. - ---- - -Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. -https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games - -> This mod is an independent creation 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/InteractionTest/format.json b/InteractionTest/format.json deleted file mode 100644 index 39d8c48..0000000 --- a/InteractionTest/format.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "_id": 211, - "name": "RelativeSync", - "modversion": "1.0.3", - "gameversion": "2024r175", - "loaderversion": "0.6.1", - "modtype": "Mod", - "author": "NotAKidoS", - "description": "Relative sync for Movement Parent & Chairs. Requires both users to have the mod installed. Synced over Mod Network.\n\nProvides some Experimental settings to also fix local jitter on movement parents.", - "searchtags": [ - "relative", - "sync", - "movement", - "chair" - ], - "requirements": [ - "None" - ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r29/RelativeSync.dll", - "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/RelativeSync/", - "changelog": "- Enabled the Experimental settings to fix **local** jitter on Movement Parents by default\n- Adjusted BBCC No Interpolation fix to account for potential native fix (now respects initial value)", - "embedcolor": "#507e64" -} \ No newline at end of file diff --git a/LegacyContentMitigation/ModSettings.cs b/LegacyContentMitigation/ModSettings.cs deleted file mode 100644 index 0fdef02..0000000 --- a/LegacyContentMitigation/ModSettings.cs +++ /dev/null @@ -1,24 +0,0 @@ -using MelonLoader; - -namespace NAK.LegacyContentMitigation; - -internal static class ModSettings -{ - #region Constants - - internal const string ModName = nameof(LegacyContentMitigation); - internal const string LCM_SettingsCategory = "Legacy Content Mitigation"; - - #endregion Constants - - #region Melon Preferences - - private static readonly MelonPreferences_Category Category = - MelonPreferences.CreateCategory(ModName); - - internal static readonly MelonPreferences_Entry EntryAutoForLegacyWorlds = - Category.CreateEntry("auto_for_legacy_worlds", true, - "Auto For Legacy Worlds", description: "Should Legacy View be auto enabled for detected Legacy worlds?"); - - #endregion Melon Preferences -} \ No newline at end of file diff --git a/LuaNetworkVariables/SyncedBehaviour/PickupableBehaviour.cs b/LuaNetworkVariables/SyncedBehaviour/PickupableBehaviour.cs deleted file mode 100644 index 30fddc1..0000000 --- a/LuaNetworkVariables/SyncedBehaviour/PickupableBehaviour.cs +++ /dev/null @@ -1,161 +0,0 @@ -using UnityEngine; -using ABI_RC.Core.InteractionSystem; -using ABI_RC.Systems.ModNetwork; - -namespace NAK.LuaNetVars; - -public class PickupableBehaviour : MNSyncedBehaviour -{ - private enum PickupMessageType : byte - { - GrabState, - Transform - } - - private bool isHeld; - private string holderId; - private Vector3 lastPosition; - private Quaternion lastRotation; - - public PickupableObject Pickupable { get; private set; } - - public PickupableBehaviour(string networkId, PickupableObject pickupable) : base(networkId, autoAcceptTransfers: false) - { - Pickupable = pickupable; - isHeld = false; - holderId = string.Empty; - lastPosition = pickupable.transform.position; - lastRotation = pickupable.transform.rotation; - } - - public void OnGrabbed(InteractionContext context) - { - RequestOwnership(success => { - if (success) - { - isHeld = true; - holderId = LocalUserId; - SendNetworkedData(WriteGrabState); - } - else - { - // Ownership request failed, drop the object - Pickupable.ControllerRay = null; // Force drop - } - }); - } - - public void OnDropped() - { - if (!HasOwnership) return; - - isHeld = false; - holderId = string.Empty; - SendNetworkedData(WriteGrabState); - } - - public void UpdateTransform(Vector3 position, Quaternion rotation) - { - if (!HasOwnership || !isHeld) return; - - lastPosition = position; - lastRotation = rotation; - SendNetworkedData(WriteTransform); - } - - protected override OwnershipResponse OnOwnershipRequested(string requesterId) - { - // If the object is held by the current owner, reject the transfer - if (isHeld && holderId == LocalUserId) - return OwnershipResponse.Rejected; - - // If theft is disallowed and the object is held by someone, reject the transfer - if (Pickupable.DisallowTheft && !string.IsNullOrEmpty(holderId)) - return OwnershipResponse.Rejected; - - return OwnershipResponse.Accepted; - } - - protected override void WriteState(ModNetworkMessage message) - { - message.Write(isHeld); - message.Write(holderId); - message.Write(lastPosition); - message.Write(lastRotation); - } - - protected override void ReadState(ModNetworkMessage message) - { - message.Read(out isHeld); - message.Read(out holderId); - message.Read(out lastPosition); - message.Read(out lastRotation); - - UpdatePickupableState(); - } - - private void WriteGrabState(ModNetworkMessage message) - { - message.Write((byte)PickupMessageType.GrabState); - message.Write(isHeld); - message.Write(holderId); - } - - private void WriteTransform(ModNetworkMessage message) - { - message.Write((byte)PickupMessageType.Transform); - message.Write(lastPosition); - message.Write(lastRotation); - } - - protected override void ReadCustomData(ModNetworkMessage message) - { - message.Read(out byte messageType); - - switch ((PickupMessageType)messageType) - { - case PickupMessageType.GrabState: - message.Read(out isHeld); - message.Read(out holderId); - break; - - case PickupMessageType.Transform: - message.Read(out Vector3 position); - message.Read(out Quaternion rotation); - lastPosition = position; - lastRotation = rotation; - break; - } - - UpdatePickupableState(); - } - - private void UpdatePickupableState() - { - // Update transform if we're not the holder - if (!isHeld || holderId != LocalUserId) - { - Pickupable.transform.position = lastPosition; - Pickupable.transform.rotation = lastRotation; - } - - // Force drop if we were holding but someone else took ownership - if (isHeld && holderId != LocalUserId) - { - Pickupable.ControllerRay = null; // Force drop - } - } - - protected override void OnOwnershipChanged(string newOwnerId) - { - base.OnOwnershipChanged(newOwnerId); - - // If we lost ownership and were holding, force drop - if (!HasOwnership && holderId == LocalUserId) - { - isHeld = false; - holderId = string.Empty; - Pickupable.ControllerRay = null; // Force drop - } - } -} \ No newline at end of file diff --git a/LuaNetworkVariables/SyncedBehaviour/PickupableObject.cs b/LuaNetworkVariables/SyncedBehaviour/PickupableObject.cs deleted file mode 100644 index 76b495a..0000000 --- a/LuaNetworkVariables/SyncedBehaviour/PickupableObject.cs +++ /dev/null @@ -1,72 +0,0 @@ -using ABI_RC.Core.InteractionSystem; -using ABI_RC.Core.InteractionSystem.Base; -using UnityEngine; - -namespace NAK.LuaNetVars; - -public class PickupableObject : Pickupable -{ - [SerializeField] private bool canPickup = true; - [SerializeField] private bool disallowTheft = false; - [SerializeField] private float maxGrabDistance = 2f; - [SerializeField] private float maxPushDistance = 2f; - [SerializeField] private bool isAutoHold = false; - [SerializeField] private bool allowRotation = true; - [SerializeField] private bool allowPushPull = true; - [SerializeField] private bool allowInteraction = true; - - private PickupableBehaviour behaviour; - private bool isInitialized; - - private void Awake() - { - // Generate a unique network ID based on the instance ID - string networkId = $"pickup_{gameObject.name}"; - behaviour = new PickupableBehaviour(networkId, this); - isInitialized = true; - } - - private void OnDestroy() - { - behaviour?.Dispose(); - } - - private void Update() - { - if (behaviour?.HasOwnership == true) - { - transform.SetPositionAndRotation(ControllerRay.pivotPoint.position, ControllerRay.pivotPoint.rotation); - behaviour.UpdateTransform(transform.position, transform.rotation); - } - } - - #region Pickupable Implementation - - public override void OnGrab(InteractionContext context, Vector3 grabPoint) - { - if (!isInitialized) return; - behaviour.OnGrabbed(context); - } - - public override void OnDrop(InteractionContext context) - { - if (!isInitialized) return; - behaviour.OnDropped(); - } - - public override void OnFlingTowardsTarget(Vector3 target) - { - // ignore - } - - public override bool CanPickup => canPickup; - public override bool DisallowTheft => disallowTheft; - public override float MaxGrabDistance => maxGrabDistance; - public override float MaxPushDistance => maxPushDistance; - public override bool IsAutoHold => isAutoHold; - public override bool IsObjectRotationAllowed => allowRotation; - public override bool IsObjectPushPullAllowed => allowPushPull; - public override bool IsObjectInteractionAllowed => allowInteraction; - - #endregion Pickupable Implementation -} \ No newline at end of file diff --git a/LuaTTS/Main.cs b/LuaTTS/Main.cs index 2035bb9..6242c04 100644 --- a/LuaTTS/Main.cs +++ b/LuaTTS/Main.cs @@ -1,4 +1,6 @@ -using MelonLoader; +using ABI_RC.Scripting.ScriptNetwork; +using ABI_RC.Systems.ModNetwork; +using MelonLoader; using NAK.LuaTTS.Patches; namespace NAK.LuaTTS; @@ -8,6 +10,33 @@ public class LuaTTSMod : MelonMod public override void OnInitializeMelon() { ApplyPatches(typeof(LuaScriptFactoryPatches)); + + ModNetworkMessage.AddConverter(ReadScriptID, WriteScriptID); + ModNetworkMessage.AddConverter(ReadScriptInstanceID, WriteScriptInstanceID); + } + + private static ScriptID ReadScriptID(ModNetworkMessage msg) + { + msg.Read(out byte[] value); + ScriptID scriptID = new(value); + return scriptID; + } + + private static void WriteScriptID(ModNetworkMessage msg, ScriptID scriptID) + { + msg.Write(scriptID.value); + } + + private static ScriptInstanceID ReadScriptInstanceID(ModNetworkMessage msg) + { + msg.Read(out byte[] value); + ScriptInstanceID scriptInstanceID = new(value); + return scriptInstanceID; + } + + private static void WriteScriptInstanceID(ModNetworkMessage msg, ScriptInstanceID scriptInstanceID) + { + msg.Write(scriptInstanceID.value); } private void ApplyPatches(Type type) diff --git a/LuaTTS/Patches.cs b/LuaTTS/Patches.cs index 07d4297..c45cec1 100644 --- a/LuaTTS/Patches.cs +++ b/LuaTTS/Patches.cs @@ -11,17 +11,17 @@ internal static class LuaScriptFactoryPatches [HarmonyPostfix] [HarmonyPatch(typeof(LuaScriptFactory.CVRRequireModule), nameof(LuaScriptFactory.CVRRequireModule.Require))] private static void Postfix_CVRRequireModule_require( - string modid, + string moduleFriendlyName, ref LuaScriptFactory.CVRRequireModule __instance, ref object __result, - ref Script ___script, - ref CVRLuaContext ___context) + ref Script ____script, + ref CVRLuaContext ____context) { const string TTSModuleID = "TextToSpeech"; - if (TTSModuleID != modid) + if (TTSModuleID != moduleFriendlyName) return; // not our module - __result = TTSLuaModule.RegisterUserData(___script, ___context); + __result = TTSLuaModule.RegisterUserData(____script, ____context); __instance.RegisteredModules[TTSModuleID] = __result; // add module to cache } } \ No newline at end of file diff --git a/NAK_CVR_Mods.sln b/NAK_CVR_Mods.sln index ce1db86..082aeae 100644 --- a/NAK_CVR_Mods.sln +++ b/NAK_CVR_Mods.sln @@ -87,6 +87,34 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ComponentMonitor", "Compone EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShareBubbles", "ShareBubbles\ShareBubbles.csproj", "{ADD6205B-67A4-4BA8-8BED-DF7D0E857A6A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MutualMute", "MutualMute\MutualMute.csproj", "{6E315182-CC9F-4F62-8385-5E26EFA3B98A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BullshitWatcher", "BullshitWatcher\BullshitWatcher.csproj", "{09238300-4583-45C6-A997-025CBDC44C24}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LegacyContentMitigation", "LegacyContentMitigation\LegacyContentMitigation.csproj", "{21FDAB94-5014-488D-86C7-A366F1902B24}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RCCVirtualSteeringWheel", "RCCVirtualSteeringWheel\RCCVirtualSteeringWheel.csproj", "{4A378F81-3805-41E8-9565-A8A89A8C00D6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BetterContentLoading", "BetterContentLoading\BetterContentLoading.csproj", "{FFCF6FA8-4F38-415E-AC2D-B576FFD5FED5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CameraExperiments", "CameraExperiments\CameraExperiments.csproj", "{71CBD7CC-C787-4796-B05E-4F3BC3C28B48}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RemoteAvatarDisablingCameraOnFirstFrameFix", "RemoteAvatarDisablingCameraOnFirstFrameFix\RemoteAvatarDisablingCameraOnFirstFrameFix.csproj", "{42E626F7-9A7E-4F55-B02C-16EB56E2B540}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AvatarCloneTest", "AvatarCloneTest\AvatarCloneTest.csproj", "{8BF2CBBF-6DAB-4D7A-87E0-AE643D6019AB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FuckOffUICamera", "FuckOffUICamera\FuckOffUICamera.csproj", "{262A8AE0-E610-405F-B4EC-DB714FB54C00}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomRichPresence", "CustomRichPresence\CustomRichPresence.csproj", "{E5F07862-5715-470D-B324-19BDEBB2AA4D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FuckMagicaCloth2", "FuckMagicaCloth2\FuckMagicaCloth2.csproj", "{21B591A0-F6E5-4645-BF2D-4E71F47394A7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperAwesomeMod", "SuperAwesomeMod\SuperAwesomeMod.csproj", "{F093BDE5-1824-459E-B86E-B9F79B548E58}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlToUnlockMouse", "ControlToUnlockMouse\ControlToUnlockMouse.csproj", "{EDA96974-0BEA-404B-8EED-F19CCA2C95A8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EzCurls", ".DepricatedMods\EzCurls\EzCurls.csproj", "{ED2CAA2D-4E49-4636-86C4-367D0CDC3572}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -261,6 +289,62 @@ Global {ADD6205B-67A4-4BA8-8BED-DF7D0E857A6A}.Debug|Any CPU.Build.0 = Debug|Any CPU {ADD6205B-67A4-4BA8-8BED-DF7D0E857A6A}.Release|Any CPU.ActiveCfg = Release|Any CPU {ADD6205B-67A4-4BA8-8BED-DF7D0E857A6A}.Release|Any CPU.Build.0 = Release|Any CPU + {6E315182-CC9F-4F62-8385-5E26EFA3B98A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6E315182-CC9F-4F62-8385-5E26EFA3B98A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6E315182-CC9F-4F62-8385-5E26EFA3B98A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6E315182-CC9F-4F62-8385-5E26EFA3B98A}.Release|Any CPU.Build.0 = Release|Any CPU + {09238300-4583-45C6-A997-025CBDC44C24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {09238300-4583-45C6-A997-025CBDC44C24}.Debug|Any CPU.Build.0 = Debug|Any CPU + {09238300-4583-45C6-A997-025CBDC44C24}.Release|Any CPU.ActiveCfg = Release|Any CPU + {09238300-4583-45C6-A997-025CBDC44C24}.Release|Any CPU.Build.0 = Release|Any CPU + {21FDAB94-5014-488D-86C7-A366F1902B24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {21FDAB94-5014-488D-86C7-A366F1902B24}.Debug|Any CPU.Build.0 = Debug|Any CPU + {21FDAB94-5014-488D-86C7-A366F1902B24}.Release|Any CPU.ActiveCfg = Release|Any CPU + {21FDAB94-5014-488D-86C7-A366F1902B24}.Release|Any CPU.Build.0 = Release|Any CPU + {4A378F81-3805-41E8-9565-A8A89A8C00D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4A378F81-3805-41E8-9565-A8A89A8C00D6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4A378F81-3805-41E8-9565-A8A89A8C00D6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4A378F81-3805-41E8-9565-A8A89A8C00D6}.Release|Any CPU.Build.0 = Release|Any CPU + {FFCF6FA8-4F38-415E-AC2D-B576FFD5FED5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FFCF6FA8-4F38-415E-AC2D-B576FFD5FED5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FFCF6FA8-4F38-415E-AC2D-B576FFD5FED5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FFCF6FA8-4F38-415E-AC2D-B576FFD5FED5}.Release|Any CPU.Build.0 = Release|Any CPU + {71CBD7CC-C787-4796-B05E-4F3BC3C28B48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {71CBD7CC-C787-4796-B05E-4F3BC3C28B48}.Debug|Any CPU.Build.0 = Debug|Any CPU + {71CBD7CC-C787-4796-B05E-4F3BC3C28B48}.Release|Any CPU.ActiveCfg = Release|Any CPU + {71CBD7CC-C787-4796-B05E-4F3BC3C28B48}.Release|Any CPU.Build.0 = Release|Any CPU + {42E626F7-9A7E-4F55-B02C-16EB56E2B540}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {42E626F7-9A7E-4F55-B02C-16EB56E2B540}.Debug|Any CPU.Build.0 = Debug|Any CPU + {42E626F7-9A7E-4F55-B02C-16EB56E2B540}.Release|Any CPU.ActiveCfg = Release|Any CPU + {42E626F7-9A7E-4F55-B02C-16EB56E2B540}.Release|Any CPU.Build.0 = Release|Any CPU + {8BF2CBBF-6DAB-4D7A-87E0-AE643D6019AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8BF2CBBF-6DAB-4D7A-87E0-AE643D6019AB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8BF2CBBF-6DAB-4D7A-87E0-AE643D6019AB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8BF2CBBF-6DAB-4D7A-87E0-AE643D6019AB}.Release|Any CPU.Build.0 = Release|Any CPU + {262A8AE0-E610-405F-B4EC-DB714FB54C00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {262A8AE0-E610-405F-B4EC-DB714FB54C00}.Debug|Any CPU.Build.0 = Debug|Any CPU + {262A8AE0-E610-405F-B4EC-DB714FB54C00}.Release|Any CPU.ActiveCfg = Release|Any CPU + {262A8AE0-E610-405F-B4EC-DB714FB54C00}.Release|Any CPU.Build.0 = Release|Any CPU + {E5F07862-5715-470D-B324-19BDEBB2AA4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E5F07862-5715-470D-B324-19BDEBB2AA4D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E5F07862-5715-470D-B324-19BDEBB2AA4D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E5F07862-5715-470D-B324-19BDEBB2AA4D}.Release|Any CPU.Build.0 = Release|Any CPU + {21B591A0-F6E5-4645-BF2D-4E71F47394A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {21B591A0-F6E5-4645-BF2D-4E71F47394A7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {21B591A0-F6E5-4645-BF2D-4E71F47394A7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {21B591A0-F6E5-4645-BF2D-4E71F47394A7}.Release|Any CPU.Build.0 = Release|Any CPU + {F093BDE5-1824-459E-B86E-B9F79B548E58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F093BDE5-1824-459E-B86E-B9F79B548E58}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F093BDE5-1824-459E-B86E-B9F79B548E58}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F093BDE5-1824-459E-B86E-B9F79B548E58}.Release|Any CPU.Build.0 = Release|Any CPU + {EDA96974-0BEA-404B-8EED-F19CCA2C95A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EDA96974-0BEA-404B-8EED-F19CCA2C95A8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EDA96974-0BEA-404B-8EED-F19CCA2C95A8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EDA96974-0BEA-404B-8EED-F19CCA2C95A8}.Release|Any CPU.Build.0 = Release|Any CPU + {ED2CAA2D-4E49-4636-86C4-367D0CDC3572}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ED2CAA2D-4E49-4636-86C4-367D0CDC3572}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ED2CAA2D-4E49-4636-86C4-367D0CDC3572}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ED2CAA2D-4E49-4636-86C4-367D0CDC3572}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/OriginShift/Integrations/BTKUI/BtkUiAddon_CAT_OriginShiftMod.cs b/OriginShift/Integrations/BTKUI/BtkUiAddon_CAT_OriginShiftMod.cs index 543ea43..cd32e4f 100644 --- a/OriginShift/Integrations/BTKUI/BtkUiAddon_CAT_OriginShiftMod.cs +++ b/OriginShift/Integrations/BTKUI/BtkUiAddon_CAT_OriginShiftMod.cs @@ -4,19 +4,19 @@ using BTKUILib.UIObjects; using BTKUILib.UIObjects.Components; using NAK.OriginShift; -namespace NAK.OriginShiftMod.Integrations +namespace NAK.OriginShiftMod.Integrations; + +public static partial class BtkUiAddon { - public static partial class BtkUiAddon + private static Category _ourCategory; + + private static Button _ourMainButton; + private static bool _isForcedMode; + + private static ToggleButton _ourToggle; + + private static void Setup_OriginShiftModCategory(Page page) { - private static Category _ourCategory; - - private static Button _ourMainButton; - private static bool _isForcedMode; - - private static ToggleButton _ourToggle; - - private static void Setup_OriginShiftModCategory(Page page) - { // dear category _ourCategory = page.AddCategory(ModSettings.OSM_SettingsCategory, ModSettings.ModName, true, true, false); @@ -38,21 +38,21 @@ namespace NAK.OriginShiftMod.Integrations debugToggle.OnValueUpdated += OnDebugToggle; } - #region Category Actions + #region Category Actions - private static void UpdateCategoryModUserCount() - { + private static void UpdateCategoryModUserCount() + { int modUsers = 1; // we are always here :3 int playerCount = CVRPlayerManager.Instance.NetworkPlayers.Count + 1; // +1 for us :3 _ourCategory.CategoryName = $"{ModSettings.OSM_SettingsCategory} ({modUsers}/{playerCount})"; } - #endregion Category Actions + #endregion Category Actions - #region Button Actions + #region Button Actions - private static void SetButtonState(OriginShiftManager.OriginShiftState state) - { + private static void SetButtonState(OriginShiftManager.OriginShiftState state) + { switch (state) { default: @@ -74,8 +74,8 @@ namespace NAK.OriginShiftMod.Integrations } } - private static void OnMainButtonClick() - { + private static void OnMainButtonClick() + { // if active, return as world is using Origin Shift if (OriginShiftManager.Instance.CurrentState is OriginShiftManager.OriginShiftState.Active) @@ -97,19 +97,19 @@ namespace NAK.OriginShiftMod.Integrations } } - private static void OnOriginShiftStateChanged(OriginShiftManager.OriginShiftState state) - { + private static void OnOriginShiftStateChanged(OriginShiftManager.OriginShiftState state) + { _isForcedMode = state == OriginShiftManager.OriginShiftState.Forced; SetButtonState(state); SetToggleLocked(_isForcedMode); } - #endregion Button Actions + #endregion Button Actions - #region Toggle Actions + #region Toggle Actions - private static void SetToggleLocked(bool value) - { + private static void SetToggleLocked(bool value) + { if (value) { // lock the toggle @@ -126,20 +126,19 @@ namespace NAK.OriginShiftMod.Integrations } } - private static void OnCompatibilityModeToggle(bool value) - { + private static void OnCompatibilityModeToggle(bool value) + { ModSettings.EntryCompatibilityMode.Value = value; } - #endregion Toggle Actions + #endregion Toggle Actions - #region Debug Toggle Actions + #region Debug Toggle Actions - private static void OnDebugToggle(bool value) - { + private static void OnDebugToggle(bool value) + { OriginShiftManager.Instance.ToggleDebugOverlay(value); } - #endregion Debug Toggle Actions - } + #endregion Debug Toggle Actions } \ No newline at end of file diff --git a/OriginShift/Integrations/BTKUI/BtkuiAddon.cs b/OriginShift/Integrations/BTKUI/BtkuiAddon.cs index aa64098..f980330 100644 --- a/OriginShift/Integrations/BTKUI/BtkuiAddon.cs +++ b/OriginShift/Integrations/BTKUI/BtkuiAddon.cs @@ -3,23 +3,23 @@ using BTKUILib; using BTKUILib.UIObjects; using NAK.OriginShift; -namespace NAK.OriginShiftMod.Integrations -{ - public static partial class BtkUiAddon - { - private static Page _miscTabPage; - private static string _miscTabElementID; +namespace NAK.OriginShiftMod.Integrations; - public static void Initialize() - { +public static partial class BtkUiAddon +{ + private static Page _miscTabPage; + private static string _miscTabElementID; + + public static void Initialize() + { Prepare_Icons(); Setup_OriginShiftTab(); } - #region Initialization + #region Initialization - private static void Prepare_Icons() - { + private static void Prepare_Icons() + { QuickMenuAPI.PrepareIcon(ModSettings.ModName, "OriginShift-Icon-Active", GetIconStream("OriginShift-Icon-Active.png")); @@ -30,8 +30,8 @@ namespace NAK.OriginShiftMod.Integrations GetIconStream("OriginShift-Icon-Forced.png")); } - private static void Setup_OriginShiftTab() - { + private static void Setup_OriginShiftTab() + { _miscTabPage = QuickMenuAPI.MiscTabPage; _miscTabElementID = _miscTabPage.ElementID; QuickMenuAPI.UserJoin += OnUserJoinLeave; @@ -51,16 +51,15 @@ namespace NAK.OriginShiftMod.Integrations // Setup_DebugOptionsCategory(_miscTabPage); } - #endregion + #endregion - #region Player Count Display + #region Player Count Display - private static void OnWorldLeave() - => UpdateCategoryModUserCount(); + private static void OnWorldLeave() + => UpdateCategoryModUserCount(); - private static void OnUserJoinLeave(CVRPlayerEntity _) - => UpdateCategoryModUserCount(); + private static void OnUserJoinLeave(CVRPlayerEntity _) + => UpdateCategoryModUserCount(); - #endregion - } -} + #endregion +} \ No newline at end of file diff --git a/OriginShift/Integrations/BTKUI/BtkuiAddon_Utils.cs b/OriginShift/Integrations/BTKUI/BtkuiAddon_Utils.cs index a5cec73..823d41f 100644 --- a/OriginShift/Integrations/BTKUI/BtkuiAddon_Utils.cs +++ b/OriginShift/Integrations/BTKUI/BtkuiAddon_Utils.cs @@ -5,60 +5,59 @@ using BTKUILib.UIObjects.Components; using MelonLoader; using UnityEngine; -namespace NAK.OriginShiftMod.Integrations +namespace NAK.OriginShiftMod.Integrations; + +public static partial class BtkUiAddon { - public static partial class BtkUiAddon - { - #region Melon Preference Helpers + #region Melon Preference Helpers - private static ToggleButton AddMelonToggle(ref Category category, MelonPreferences_Entry entry) - { + private static ToggleButton AddMelonToggle(ref Category category, MelonPreferences_Entry entry) + { ToggleButton toggle = category.AddToggle(entry.DisplayName, entry.Description, entry.Value); toggle.OnValueUpdated += b => entry.Value = b; return toggle; } - private static SliderFloat AddMelonSlider(ref Category category, MelonPreferences_Entry entry, float min, - float max, int decimalPlaces = 2, bool allowReset = true) - { + private static SliderFloat AddMelonSlider(ref Category category, MelonPreferences_Entry entry, float min, + float max, int decimalPlaces = 2, bool allowReset = true) + { SliderFloat slider = category.AddSlider(entry.DisplayName, entry.Description, Mathf.Clamp(entry.Value, min, max), min, max, decimalPlaces, entry.DefaultValue, allowReset); slider.OnValueUpdated += f => entry.Value = f; return slider; } - private static Button AddMelonStringInput(ref Category category, MelonPreferences_Entry entry, string buttonIcon = "", ButtonStyle buttonStyle = ButtonStyle.TextOnly) - { + private static Button AddMelonStringInput(ref Category category, MelonPreferences_Entry entry, string buttonIcon = "", ButtonStyle buttonStyle = ButtonStyle.TextOnly) + { Button button = category.AddButton(entry.DisplayName, buttonIcon, entry.Description, buttonStyle); button.OnPress += () => QuickMenuAPI.OpenKeyboard(entry.Value, s => entry.Value = s); return button; } - private static Button AddMelonNumberInput(ref Category category, MelonPreferences_Entry entry, string buttonIcon = "", ButtonStyle buttonStyle = ButtonStyle.TextOnly) - { + private static Button AddMelonNumberInput(ref Category category, MelonPreferences_Entry entry, string buttonIcon = "", ButtonStyle buttonStyle = ButtonStyle.TextOnly) + { Button button = category.AddButton(entry.DisplayName, buttonIcon, entry.Description, buttonStyle); button.OnPress += () => QuickMenuAPI.OpenNumberInput(entry.DisplayName, entry.Value, f => entry.Value = f); return button; } - private static Category AddMelonCategory(ref Page page, MelonPreferences_Entry entry, bool showHeader = true) - { + private static Category AddMelonCategory(ref Page page, MelonPreferences_Entry entry, bool showHeader = true) + { Category category = page.AddCategory(entry.DisplayName, showHeader, true, entry.Value); category.OnCollapse += b => entry.Value = b; return category; } - #endregion Melon Preference Helpers + #endregion Melon Preference Helpers - #region Icon Utils + #region Icon Utils - private static Stream GetIconStream(string iconName) - { + private static Stream GetIconStream(string iconName) + { Assembly assembly = Assembly.GetExecutingAssembly(); string assemblyName = assembly.GetName().Name; return assembly.GetManifestResourceStream($"{assemblyName}.Resources.{iconName}"); } - #endregion Icon Utils - } + #endregion Icon Utils } \ No newline at end of file diff --git a/OriginShift/OriginShift/Components/OriginShiftController.cs b/OriginShift/OriginShift/Components/OriginShiftController.cs index 70784f3..568409a 100644 --- a/OriginShift/OriginShift/Components/OriginShiftController.cs +++ b/OriginShift/OriginShift/Components/OriginShiftController.cs @@ -7,45 +7,45 @@ using NAK.OriginShift.Utility; // Creator Exposed component -namespace NAK.OriginShift.Components +namespace NAK.OriginShift.Components; + +public class OriginShiftController : MonoBehaviour { - public class OriginShiftController : MonoBehaviour - { - public static OriginShiftController Instance { get; private set; } + public static OriginShiftController Instance { get; private set; } - #region Serialized Fields + #region Serialized Fields - [Header("Config / Shift Params")] + [Header("Config / Shift Params")] - [SerializeField] private bool _shiftVertical = true; - [SerializeField] [Range(10, 2500)] private int _shiftThreshold = 15; + [SerializeField] private bool _shiftVertical = true; + [SerializeField] [Range(10, 2500)] private int _shiftThreshold = 15; - [Header("Config / Scene Objects")] + [Header("Config / Scene Objects")] - [SerializeField] private bool _autoMoveSceneRoots = true; - [SerializeField] private Transform[] _toShiftTransforms = Array.Empty(); + [SerializeField] private bool _autoMoveSceneRoots = true; + [SerializeField] private Transform[] _toShiftTransforms = Array.Empty(); - [Header("Config / Additive Objects")] + [Header("Config / Additive Objects")] - [SerializeField] private bool _shiftRemotePlayers = true; - [SerializeField] private bool _shiftSpawnedObjects = true; + [SerializeField] private bool _shiftRemotePlayers = true; + [SerializeField] private bool _shiftSpawnedObjects = true; - #endregion Serialized Fields + #endregion Serialized Fields - #region Internal Fields + #region Internal Fields - internal bool IsForced { get; set; } + internal bool IsForced { get; set; } - #endregion Internal Fields + #endregion Internal Fields #if !UNITY_EDITOR - public static int ORIGIN_SHIFT_THRESHOLD = 15; + public static int ORIGIN_SHIFT_THRESHOLD = 15; - #region Unity Events + #region Unity Events - private void Awake() - { + private void Awake() + { if (Instance != null && Instance != this) { @@ -56,8 +56,8 @@ namespace NAK.OriginShift.Components Instance = this; } - private void Start() - { + private void Start() + { // set threshold (we can not support dynamic threshold change) ORIGIN_SHIFT_THRESHOLD = IsForced ? 1000 : _shiftThreshold; @@ -73,26 +73,26 @@ namespace NAK.OriginShift.Components AnchorAllStaticRenderers(); } - private void OnDestroy() - { + private void OnDestroy() + { OriginShiftManager.OnOriginShifted -= OnOriginShifted; OriginShiftManager.Instance.ResetManager(); } - #endregion Unity Events + #endregion Unity Events - #region Private Methods + #region Private Methods - private void GetAllSceneRootTransforms() - { + private void GetAllSceneRootTransforms() + { Scene scene = gameObject.scene; var sceneRoots = scene.GetRootGameObjects(); _toShiftTransforms = new Transform[sceneRoots.Length + 1]; // +1 for the static batch anchor for (var i = 0; i < sceneRoots.Length; i++) _toShiftTransforms[i] = sceneRoots[i].transform; } - private void AnchorAllStaticRenderers() - { + private void AnchorAllStaticRenderers() + { // create an anchor object at 0,0,0 Transform anchor = new GameObject("NAK.StaticBatchAnchor").transform; anchor.SetPositionAndRotation(Vector3.zero, Quaternion.identity); @@ -113,12 +113,12 @@ namespace NAK.OriginShift.Components } } - #endregion Private Methods + #endregion Private Methods - #region Origin Shift Events + #region Origin Shift Events - private void OnOriginShifted(Vector3 shift) - { + private void OnOriginShifted(Vector3 shift) + { foreach (Transform toShiftTransform in _toShiftTransforms) { if (toShiftTransform == null) continue; // skip nulls @@ -126,8 +126,7 @@ namespace NAK.OriginShift.Components } } - #endregion Origin Shift Events + #endregion Origin Shift Events #endif - } } \ No newline at end of file diff --git a/OriginShift/OriginShift/Components/Receivers/OriginShiftEventReceiver.cs b/OriginShift/OriginShift/Components/Receivers/OriginShiftEventReceiver.cs index fd329bf..11fe6fc 100644 --- a/OriginShift/OriginShift/Components/Receivers/OriginShiftEventReceiver.cs +++ b/OriginShift/OriginShift/Components/Receivers/OriginShiftEventReceiver.cs @@ -1,56 +1,65 @@ -using JetBrains.Annotations; +using ABI.CCK.Components; +using JetBrains.Annotations; using UnityEngine; using UnityEngine.Events; #if !UNITY_EDITOR +using ABI_RC.Core.Util; using ABI_RC.Core.Util.AssetFiltering; #endif -namespace NAK.OriginShift.Components +namespace NAK.OriginShift.Components; + +public class OriginShiftEventReceiver : MonoBehaviour { - public class OriginShiftEventReceiver : MonoBehaviour - { - #region Serialized Fields + #region Serialized Fields - [SerializeField] private UnityEvent _onOriginShifted = new(); - [SerializeField] private bool _filterChunkBoundary; - [SerializeField] private Vector3 _chunkBoundaryMin = Vector3.zero; - [SerializeField] private Vector3 _chunkBoundaryMax = Vector3.one; + [SerializeField] private UnityEvent _onOriginShifted = new(); + [SerializeField] private bool _filterChunkBoundary; + [SerializeField] private Vector3 _chunkBoundaryMin = Vector3.zero; + [SerializeField] private Vector3 _chunkBoundaryMax = Vector3.one; - #endregion Serialized Fields + #endregion Serialized Fields #if !UNITY_EDITOR - #region Private Fields + #region Private Fields - private bool _isInitialized; + private bool _isInitialized; - #endregion Private Fields + #endregion Private Fields - #region Unity Events + #region Unity Events - private void OnEnable() - { + private void OnEnable() + { if (!_isInitialized) { - SharedFilter.SanitizeUnityEvents("OriginShiftEventReceiver", _onOriginShifted); + //SharedFilter.SanitizeUnityEvents("OriginShiftEventReceiver", _onOriginShifted); + + UnityEventsHelper.SanitizeUnityEvents("OriginShiftEventReceiver", + UnityEventsHelper.EventSource.Unknown, + this, + CVRWorld.Instance, + _onOriginShifted); + _isInitialized = true; } OriginShiftManager.OnOriginShifted += HandleOriginShifted; } - private void OnDisable() - { + private void OnDisable() + { OriginShiftManager.OnOriginShifted -= HandleOriginShifted; } - #endregion Unity Events + #endregion Unity Events - #region Origin Shift Events + #region Origin Shift Events - private void HandleOriginShifted(Vector3 shift) - { + private void HandleOriginShifted(Vector3 shift) + { if (_filterChunkBoundary && !IsWithinChunkBoundary(shift)) return; @@ -65,15 +74,14 @@ namespace NAK.OriginShift.Components } } - private bool IsWithinChunkBoundary(Vector3 shift) - { + private bool IsWithinChunkBoundary(Vector3 shift) + { return shift.x >= _chunkBoundaryMin.x && shift.x <= _chunkBoundaryMax.x && shift.y >= _chunkBoundaryMin.y && shift.y <= _chunkBoundaryMax.y && shift.z >= _chunkBoundaryMin.z && shift.z <= _chunkBoundaryMax.z; } - #endregion Origin Shift Events + #endregion Origin Shift Events #endif - } } \ No newline at end of file diff --git a/OriginShift/OriginShift/Components/Receivers/OriginShiftParticleSystemReceiver.cs b/OriginShift/OriginShift/Components/Receivers/OriginShiftParticleSystemReceiver.cs index 819b351..c5f4c52 100644 --- a/OriginShift/OriginShift/Components/Receivers/OriginShiftParticleSystemReceiver.cs +++ b/OriginShift/OriginShift/Components/Receivers/OriginShiftParticleSystemReceiver.cs @@ -1,20 +1,20 @@ using UnityEngine; -namespace NAK.OriginShift.Components +namespace NAK.OriginShift.Components; + +public class OriginShiftParticleSystemReceiver : MonoBehaviour { - public class OriginShiftParticleSystemReceiver : MonoBehaviour - { #if !UNITY_EDITOR - // max particles count cause i said so 2 - private static readonly ParticleSystem.Particle[] _tempParticles = new ParticleSystem.Particle[10000]; + // max particles count cause i said so 2 + private static readonly ParticleSystem.Particle[] _tempParticles = new ParticleSystem.Particle[10000]; - private ParticleSystem[] _particleSystems; + private ParticleSystem[] _particleSystems; - #region Unity Events + #region Unity Events - private void Start() - { + private void Start() + { _particleSystems = GetComponentsInChildren(true); if (_particleSystems.Length == 0) { @@ -23,35 +23,34 @@ namespace NAK.OriginShift.Components } } - private void OnEnable() - { + private void OnEnable() + { OriginShiftManager.OnOriginShifted += OnOriginShifted; } - private void OnDisable() - { + private void OnDisable() + { OriginShiftManager.OnOriginShifted -= OnOriginShifted; } - #endregion Unity Events + #endregion Unity Events - #region Origin Shift Events + #region Origin Shift Events - private void OnOriginShifted(Vector3 offset) - { + private void OnOriginShifted(Vector3 offset) + { foreach (ParticleSystem particleSystem in _particleSystems) ShiftParticleSystem(particleSystem, offset); } - private static void ShiftParticleSystem(ParticleSystem particleSystem, Vector3 offset) - { + private static void ShiftParticleSystem(ParticleSystem particleSystem, Vector3 offset) + { int particleCount = particleSystem.GetParticles(_tempParticles); for (int i = 0; i < particleCount; i++) _tempParticles[i].position += offset; particleSystem.SetParticles(_tempParticles, particleCount); } - #endregion Origin Shift Events + #endregion Origin Shift Events #endif - } } \ No newline at end of file diff --git a/OriginShift/OriginShift/Components/Receivers/OriginShiftRigidbodyReceiver.cs b/OriginShift/OriginShift/Components/Receivers/OriginShiftRigidbodyReceiver.cs index ae2ca54..7fdc939 100644 --- a/OriginShift/OriginShift/Components/Receivers/OriginShiftRigidbodyReceiver.cs +++ b/OriginShift/OriginShift/Components/Receivers/OriginShiftRigidbodyReceiver.cs @@ -1,17 +1,17 @@ using UnityEngine; -namespace NAK.OriginShift.Components +namespace NAK.OriginShift.Components; + +public class OriginShiftRigidbodyReceiver : MonoBehaviour { - public class OriginShiftRigidbodyReceiver : MonoBehaviour - { #if !UNITY_EDITOR - private Rigidbody _rigidbody; + private Rigidbody _rigidbody; - #region Unity Events + #region Unity Events - private void Start() - { + private void Start() + { _rigidbody = GetComponentInChildren(); if (_rigidbody == null) { @@ -20,27 +20,26 @@ namespace NAK.OriginShift.Components } } - private void OnEnable() - { + private void OnEnable() + { OriginShiftManager.OnOriginShifted += OnOriginShifted; } - private void OnDisable() - { + private void OnDisable() + { OriginShiftManager.OnOriginShifted -= OnOriginShifted; } - #endregion Unity Events + #endregion Unity Events - #region Origin Shift Events + #region Origin Shift Events - private void OnOriginShifted(Vector3 shift) - { + private void OnOriginShifted(Vector3 shift) + { _rigidbody.position += shift; } - #endregion Origin Shift Events + #endregion Origin Shift Events #endif - } } \ No newline at end of file diff --git a/OriginShift/OriginShift/Components/Receivers/OriginShiftTrailRendererReceiver.cs b/OriginShift/OriginShift/Components/Receivers/OriginShiftTrailRendererReceiver.cs index da1140c..4c3b34d 100644 --- a/OriginShift/OriginShift/Components/Receivers/OriginShiftTrailRendererReceiver.cs +++ b/OriginShift/OriginShift/Components/Receivers/OriginShiftTrailRendererReceiver.cs @@ -1,20 +1,20 @@ using UnityEngine; -namespace NAK.OriginShift.Components +namespace NAK.OriginShift.Components; + +public class OriginShiftTrailRendererReceiver : MonoBehaviour { - public class OriginShiftTrailRendererReceiver : MonoBehaviour - { #if !UNITY_EDITOR - // max positions count cause i said so - private static readonly Vector3[] _tempPositions = new Vector3[10000]; + // max positions count cause i said so + private static readonly Vector3[] _tempPositions = new Vector3[10000]; - private TrailRenderer[] _trailRenderers; + private TrailRenderer[] _trailRenderers; - #region Unity Events + #region Unity Events - private void Start() - { + private void Start() + { _trailRenderers = GetComponentsInChildren(true); if (_trailRenderers.Length == 0) { @@ -23,35 +23,34 @@ namespace NAK.OriginShift.Components } } - private void OnEnable() - { + private void OnEnable() + { OriginShiftManager.OnOriginShifted += OnOriginShifted; } - private void OnDisable() - { + private void OnDisable() + { OriginShiftManager.OnOriginShifted -= OnOriginShifted; } - #endregion Unity Events + #endregion Unity Events - #region Origin Shift Events + #region Origin Shift Events - private void OnOriginShifted(Vector3 offset) - { + private void OnOriginShifted(Vector3 offset) + { foreach (TrailRenderer trailRenderer in _trailRenderers) ShiftTrailRenderer(trailRenderer, offset); } - private static void ShiftTrailRenderer(TrailRenderer trailRenderer, Vector3 offset) - { + private static void ShiftTrailRenderer(TrailRenderer trailRenderer, Vector3 offset) + { trailRenderer.GetPositions(_tempPositions); for (var i = 0; i < _tempPositions.Length; i++) _tempPositions[i] += offset; trailRenderer.SetPositions(_tempPositions); } - #endregion Origin Shift Events + #endregion Origin Shift Events #endif - } } \ No newline at end of file diff --git a/OriginShift/OriginShift/Components/Receivers/OriginShiftTransformReceiver.cs b/OriginShift/OriginShift/Components/Receivers/OriginShiftTransformReceiver.cs index 1370e34..1e98ce7 100644 --- a/OriginShift/OriginShift/Components/Receivers/OriginShiftTransformReceiver.cs +++ b/OriginShift/OriginShift/Components/Receivers/OriginShiftTransformReceiver.cs @@ -1,34 +1,33 @@ using UnityEngine; -namespace NAK.OriginShift.Components +namespace NAK.OriginShift.Components; + +public class OriginShiftTransformReceiver : MonoBehaviour { - public class OriginShiftTransformReceiver : MonoBehaviour - { #if !UNITY_EDITOR - #region Unity Events + #region Unity Events - private void OnEnable() - { + private void OnEnable() + { OriginShiftManager.OnOriginShifted += OnOriginShifted; } - private void OnDisable() - { + private void OnDisable() + { OriginShiftManager.OnOriginShifted -= OnOriginShifted; } - #endregion Unity Events + #endregion Unity Events - #region Origin Shift Events + #region Origin Shift Events - private void OnOriginShifted(Vector3 shift) - { + private void OnOriginShifted(Vector3 shift) + { transform.position += shift; } - #endregion Origin Shift Events + #endregion Origin Shift Events #endif - } } \ No newline at end of file diff --git a/OriginShift/OriginShift/Hacks/OriginShiftOcclusionCullingDisabler.cs b/OriginShift/OriginShift/Hacks/OriginShiftOcclusionCullingDisabler.cs index 2e78a6c..3fb90f1 100644 --- a/OriginShift/OriginShift/Hacks/OriginShiftOcclusionCullingDisabler.cs +++ b/OriginShift/OriginShift/Hacks/OriginShiftOcclusionCullingDisabler.cs @@ -1,16 +1,16 @@ using UnityEngine; -namespace NAK.OriginShift.Hacks -{ - public class OriginShiftOcclusionCullingDisabler : MonoBehaviour - { - private Camera _camera; - private bool _originalCullingState; - - #region Unity Events +namespace NAK.OriginShift.Hacks; - private void Start() - { +public class OriginShiftOcclusionCullingDisabler : MonoBehaviour +{ + private Camera _camera; + private bool _originalCullingState; + + #region Unity Events + + private void Start() + { _camera = GetComponent(); if (_camera == null) { @@ -21,25 +21,24 @@ namespace NAK.OriginShift.Hacks _originalCullingState = _camera.useOcclusionCulling; } - private void Awake() // we want to execute even if the component is disabled - { + private void Awake() // we want to execute even if the component is disabled + { OriginShiftManager.OnStateChanged += OnOriginShiftStateChanged; } - private void OnDestroy() - { + private void OnDestroy() + { OriginShiftManager.OnStateChanged -= OnOriginShiftStateChanged; } - #endregion Unity Events + #endregion Unity Events - #region Origin Shift Events + #region Origin Shift Events - private void OnOriginShiftStateChanged(OriginShiftManager.OriginShiftState state) - { + private void OnOriginShiftStateChanged(OriginShiftManager.OriginShiftState state) + { _camera.useOcclusionCulling = state != OriginShiftManager.OriginShiftState.Forced && _originalCullingState; } - #endregion Origin Shift Events - } + #endregion Origin Shift Events } \ No newline at end of file diff --git a/OriginShift/OriginShift/Player/OriginShiftMonitor.cs b/OriginShift/OriginShift/Player/OriginShiftMonitor.cs index a812e08..f2157a0 100644 --- a/OriginShift/OriginShift/Player/OriginShiftMonitor.cs +++ b/OriginShift/OriginShift/Player/OriginShiftMonitor.cs @@ -9,35 +9,35 @@ using UnityEngine; using ABI_RC.Systems.Movement; #endif -namespace NAK.OriginShift +namespace NAK.OriginShift; + +[DefaultExecutionOrder(int.MaxValue)] +public class OriginShiftMonitor : MonoBehaviour { - [DefaultExecutionOrder(int.MaxValue)] - public class OriginShiftMonitor : MonoBehaviour - { #if !UNITY_EDITOR - private PlayerSetup _playerSetup; - private BetterBetterCharacterController _characterController; + private PlayerSetup _playerSetup; + private BetterBetterCharacterController _characterController; #endif - #region Unity Events + #region Unity Events - private void Start() - { + private void Start() + { #if !UNITY_EDITOR - _playerSetup = GetComponent(); - _characterController = GetComponent(); + _playerSetup = GetComponent(); + _characterController = GetComponent(); #endif - OriginShiftManager.OnPostOriginShifted += OnPostOriginShifted; - } + OriginShiftManager.OnPostOriginShifted += OnPostOriginShifted; + } - private void OnDestroy() - { + private void OnDestroy() + { OriginShiftManager.OnPostOriginShifted -= OnPostOriginShifted; StopAllCoroutines(); } - private void Update() - { + private void Update() + { // in CVR use GetPlayerPosition to account for VR offset Vector3 position = PlayerSetup.Instance.GetPlayerPosition(); @@ -56,21 +56,20 @@ namespace NAK.OriginShift OriginShiftManager.Instance.ShiftOrigin(position); } - #endregion Unity Events + #endregion Unity Events - #region Origin Shift Events + #region Origin Shift Events - private void OnPostOriginShifted(Vector3 shift) - { + private void OnPostOriginShifted(Vector3 shift) + { #if UNITY_EDITOR // shift our transform back transform.position += shift; #else - _characterController.OffsetBy(shift); - _playerSetup.OffsetAvatarMovementData(shift); + _characterController.OffsetBy(shift); + _playerSetup.OffsetAvatarMovementData(shift); #endif - } - - #endregion Origin Shift Events } + + #endregion Origin Shift Events } \ No newline at end of file diff --git a/OriginShift/Patches.cs b/OriginShift/Patches.cs index 8e17cb0..cd61791 100644 --- a/OriginShift/Patches.cs +++ b/OriginShift/Patches.cs @@ -10,6 +10,7 @@ using ABI_RC.Systems.GameEventSystem; using ABI_RC.Systems.Movement; using ABI.CCK.Components; using DarkRift; +using ECM2; using HarmonyLib; using NAK.OriginShift.Components; using NAK.OriginShift.Hacks; diff --git a/PhysicsGunMod/Components/ObjectSyncBridge.cs b/PhysicsGunMod/Components/ObjectSyncBridge.cs deleted file mode 100644 index fe3c563..0000000 --- a/PhysicsGunMod/Components/ObjectSyncBridge.cs +++ /dev/null @@ -1,92 +0,0 @@ -using ABI_RC.Core.Savior; -using ABI_RC.Core.Util; -using ABI.CCK.Components; -using UnityEngine; - -namespace NAK.PhysicsGunMod.Components; - -public class ObjectSyncBridge : MonoBehaviour -{ - private PhysicsGunInteractionBehavior _physicsGun; - - private void Start() - { - // find physics gun - if (!TryGetComponent(out _physicsGun)) - { - PhysicsGunMod.Logger.Msg("Failed to find physics gun!"); - Destroy(this); - return; - } - - // listen for events - _physicsGun.OnPreGrabbedObject = o => - { - bool canTakeOwnership = false; - - // - CVRObjectSync objectSync = o.GetComponentInParent(); - // if (objectSync != null - // && (objectSync.SyncType == 0 // check if physics synced or synced by us - // || objectSync.SyncedByMe)) - // canTakeOwnership = true; - // - CVRSpawnable spawnable = o.GetComponentInParent(); - // if (spawnable != null) - // { - // CVRSyncHelper.PropData propData = CVRSyncHelper.Props.Find(match => match.InstanceId == spawnable.instanceId); - // if (propData != null - // && (propData.syncType == 0 // check if physics synced or synced by us - // || propData.syncedBy == MetaPort.Instance.ownerId)) - // canTakeOwnership = true; - // } - // - CVRPickupObject pickup = o.GetComponentInParent(); - // if (pickup != null - // && (pickup.grabbedBy == MetaPort.Instance.ownerId // check if already grabbed by us - // || pickup.grabbedBy == "" || !pickup.disallowTheft)) // check if not grabbed or allows theft - // canTakeOwnership = true; - // - // if (!canTakeOwnership // if we can't take ownership, don't grab, unless there is no syncing at all (local object) - // && (objectSync || spawnable || pickup )) - // return false; - - if (pickup) - { - pickup.GrabbedBy = MetaPort.Instance.ownerId; - pickup._grabStartTime = Time.time; - } - if (spawnable) spawnable.isPhysicsSynced = true; - if (objectSync) objectSync.isPhysicsSynced = true; - - return true; - }; - - _physicsGun.OnObjectReleased = o => - { - // CVRObjectSync objectSync = o.GetComponentInParent(); - // if (objectSync != null && objectSync.SyncType == 0) - // objectSync.isPhysicsSynced = false; - // - // CVRSpawnable spawnable = o.GetComponentInParent(); - // if (spawnable != null) - // { - // CVRSyncHelper.PropData propData = CVRSyncHelper.Props.Find(match => match.InstanceId == spawnable.instanceId); - // if (propData != null && (propData.syncType == 0 || propData.syncedBy == MetaPort.Instance.ownerId)) - // spawnable.isPhysicsSynced = false; - // } - - // CVRPickupObject pickup = o.GetComponentInParent(); - // if (pickup != null && pickup.grabbedBy == MetaPort.Instance.ownerId) - // pickup.grabbedBy = ""; - - return false; - }; - } - - private void OnDestroy() - { - // stop listening for events - _physicsGun.OnObjectGrabbed = null; - } -} \ No newline at end of file diff --git a/PhysicsGunMod/Components/PhysicsGunInteractionBehavior.cs b/PhysicsGunMod/Components/PhysicsGunInteractionBehavior.cs deleted file mode 100644 index bce3321..0000000 --- a/PhysicsGunMod/Components/PhysicsGunInteractionBehavior.cs +++ /dev/null @@ -1,572 +0,0 @@ -using ABI_RC.Core.Player; -using ABI_RC.Systems.InputManagement; -using ABI.CCK.Attributes; -using UnityEngine; -using UnityEngine.Events; -using UnityEngine.Scripting.APIUpdating; - -/* - * Physics Gun script from repository - https://github.com/Laumania/Unity3d-PhysicsGun - * Created by: - * Mads Laumann, https://github.com/laumania - * WarmedxMints, https://github.com/WarmedxMints - * - * Original/initial script "Gravity Gun": https://pastebin.com/w1G8m3dH - * Original author: Jake Perry, reddit.com/user/nandos13 -*/ - -namespace NAK.PhysicsGunMod.Components; - -[CCKWhitelistComponent(spawnable: true)] -public class PhysicsGunInteractionBehavior : MonoBehaviour -{ - public static PhysicsGunInteractionBehavior Instance; - - [Header("LayerMask")] [Tooltip("The layer which the gun can grab objects from")] [SerializeField] - private LayerMask _grabLayer; - - [SerializeField] private Camera _camera; - - [Header("Input Setting")] [Space(10)] public KeyCode Rotate = KeyCode.R; - public KeyCode SnapRotation = KeyCode.LeftShift; - public KeyCode SwitchAxis = KeyCode.Tab; - public KeyCode RotateZ = KeyCode.Space; - public KeyCode RotationSpeedIncrease = KeyCode.LeftControl; - public KeyCode ResetRotation = KeyCode.LeftAlt; - - /// The rigidbody we are currently holding - private Rigidbody _grabbedRigidbody; - - /// The offset vector from the object's position to hit point, in local space - private Vector3 _hitOffsetLocal; - - /// The distance we are holding the object at - private float _currentGrabDistance; - - /// The interpolation state when first grabbed - private RigidbodyInterpolation _initialInterpolationSetting; - - /// The difference between player & object rotation, updated when picked up or when rotated by the player - private Quaternion _rotationDifference; - - /// The start point for the Laser. This will typically be on the end of the gun - [SerializeField] private Transform _laserStartPoint; - - /// Tracks player input to rotate current object. Used and reset every fixedupdate call - private Vector3 _rotationInput = Vector3.zero; - - [Header("Rotation Settings")] [Tooltip("Transform of the player, that rotations should be relative to")] - public Transform PlayerTransform; - - [SerializeField] private float _rotationSenstivity = 10f; - - public float SnapRotationDegrees = 45f; - [SerializeField] private float _snappedRotationSens = 25f; - [SerializeField] private float _rotationSpeed = 10f; - - private Quaternion _desiredRotation = Quaternion.identity; - - [SerializeField] [Tooltip("Input values above this will be considered and intentional change in rotation")] - private float _rotationTollerance = 0.8f; - - private bool m_UserRotation; - - public bool UserRotation - { - get => m_UserRotation; - private set - { - if (m_UserRotation == value) - return; - - m_UserRotation = value; - OnRotation?.Invoke(value); - } - } - - private bool m_SnapRotation; - - private bool _snapRotation - { - get => m_SnapRotation; - set - { - if (m_SnapRotation == value) - return; - - m_SnapRotation = value; - OnRotationSnapped?.Invoke(value); - } - } - - private bool m_RotationAxis; - - private bool _rotationAxis - { - get => m_RotationAxis; - set - { - if (m_RotationAxis == value) - return; - - m_RotationAxis = value; - OnAxisChanged?.Invoke(value); - } - } - - private Vector3 _lockedRot; - - private Vector3 _forward; - private Vector3 _up; - private Vector3 _right; - - //ScrollWheel ObjectMovement - private Vector3 _scrollWheelInput = Vector3.zero; - - [Header("Scroll Wheel Object Movement")] [Space(5)] [SerializeField] - private float _scrollWheelSensitivity = 5f; - - [SerializeField] [Tooltip("The min distance the object can be from the player")] - private float _minObjectDistance = 2.5f; - - /// The maximum distance at which a new object can be picked up - [SerializeField] [Tooltip("The maximum distance at which a new object can be picked up")] - private float _maxGrabDistance = 50f; - - private bool _distanceChanged; - - //Vector3.Zero and Vector2.zero create a new Vector3 each time they are called so these simply save that process and a small amount of cpu runtime. - private readonly Vector3 _zeroVector3 = Vector3.zero; - private readonly Vector3 _oneVector3 = Vector3.one; - private readonly Vector3 _zeroVector2 = Vector2.zero; - - private bool _justReleased; - private bool _wasKinematic; - - [Serializable] - public class BoolEvent : UnityEvent {} - - [Serializable] - public class GrabEvent : UnityEvent {} - - [Header("Events")] [Space(10)] - public BoolEvent OnRotation; - public BoolEvent OnRotationSnapped; - public BoolEvent OnAxisChanged; - - public GrabEvent OnObjectGrabbed; - public Func OnObjectReleased; - - // pre event for OnPreGrabbedObject, return false to cancel grab - public Func OnPreGrabbedObject; - // public Action OnGrabbedObject; - - //public properties for the Axis Arrows. These are optional and can be safely removed - // public Vector3 CurrentForward => _forward; - // public Vector3 CurrentUp => _up; - // public Vector3 CurrentRight => _right; - - /// The transfor of the rigidbody we are holding - public Transform CurrentGrabbedTransform { get; private set; } - - //public properties for the Line Renderer - public Vector3 StartPoint { get; private set; } - public Vector3 MidPoint { get; private set; } - public Vector3 EndPoint { get; private set; } - - private void Start() - { - if (Instance != null - && Instance != this) - { - Destroy(this); - return; - } - Instance = this; - gameObject.AddComponent(); - - _camera = PlayerSetup.Instance.GetActiveCamera().GetComponent(); - PlayerTransform = PlayerSetup.Instance.transform; // TODO: this might be fucked in VR - } - - private void OnDestroy() - { - if (Instance == this) - Instance = null; - } - - private void Update() - { - if (!Input.GetMouseButton(0)) - { - // We are not holding the mouse button. Release the object and return before checking for a new one - if (_grabbedRigidbody != null) ReleaseObject(); - - _justReleased = false; - return; - } - - if (_grabbedRigidbody == null && !_justReleased) - { - // We are not holding an object, look for one to pick up - Ray ray = CenterRay(); - RaycastHit hit; - - //Just so These aren't included in a build -#if UNITY_EDITOR - Debug.DrawRay(ray.origin, ray.direction * _maxGrabDistance, Color.blue, 0.01f); -#endif - if (Physics.Raycast(ray, out hit, _maxGrabDistance, _grabLayer)) - // Don't pick up kinematic rigidbodies (they can't move) - if (hit.rigidbody != null /*&& !hit.rigidbody.isKinematic*/) - { - // Check if we are allowed to pick up this object - if (OnPreGrabbedObject != null - && !OnPreGrabbedObject(hit.rigidbody.gameObject)) - return; - - // Track rigidbody's initial information - _grabbedRigidbody = hit.rigidbody; - _wasKinematic = _grabbedRigidbody.isKinematic; - _grabbedRigidbody.isKinematic = false; - _grabbedRigidbody.freezeRotation = true; - _initialInterpolationSetting = _grabbedRigidbody.interpolation; - _rotationDifference = Quaternion.Inverse(PlayerTransform.rotation) * _grabbedRigidbody.rotation; - _hitOffsetLocal = hit.transform.InverseTransformVector(hit.point - hit.transform.position); - _currentGrabDistance = hit.distance; // Vector3.Distance(ray.origin, hit.point); - CurrentGrabbedTransform = _grabbedRigidbody.transform; - // Set rigidbody's interpolation for proper collision detection when being moved by the player - _grabbedRigidbody.interpolation = RigidbodyInterpolation.Interpolate; - - OnObjectGrabbed?.Invoke(_grabbedRigidbody.gameObject); - -#if UNITY_EDITOR - Debug.DrawRay(hit.point, hit.normal * 10f, Color.red, 10f); -#endif - } - } - else if (_grabbedRigidbody != null) - { - UserRotation = Input.GetKey(Rotate); - - if (Input.GetKeyDown(Rotate)) - _desiredRotation = _grabbedRigidbody.rotation; - - if (Input.GetKey(ResetRotation)) - { - _desiredRotation = Quaternion.identity; - } - - // We are already holding an object, listen for rotation input - if (Input.GetKey(Rotate)) - { - var rotateZ = Input.GetKey(RotateZ); - - var increaseSens = Input.GetKey(RotationSpeedIncrease) ? 2.5f : 1f; - - if (Input.GetKeyDown(SwitchAxis)) - { - _rotationAxis = !_rotationAxis; - - OnAxisChanged?.Invoke(_rotationAxis); - } - - //Snap Object nearest _snapRotationDegrees - if (Input.GetKeyDown(SnapRotation)) - { - _snapRotation = true; - - Vector3 newRot = _grabbedRigidbody.transform.rotation.eulerAngles; - - newRot.x = Mathf.Round(newRot.x / SnapRotationDegrees) * SnapRotationDegrees; - newRot.y = Mathf.Round(newRot.y / SnapRotationDegrees) * SnapRotationDegrees; - newRot.z = Mathf.Round(newRot.z / SnapRotationDegrees) * SnapRotationDegrees; - - Quaternion rot = Quaternion.Euler(newRot); - - _desiredRotation = rot; - //_grabbedRigidbody.MoveRotation(rot); - } - else if (Input.GetKeyUp(SnapRotation)) - { - _snapRotation = false; - } - - var x = Input.GetAxisRaw("Mouse X"); - var y = Input.GetAxisRaw("Mouse Y"); - - if (Mathf.Abs(x) > _rotationTollerance) - { - _rotationInput.x = rotateZ ? 0f : x * _rotationSenstivity * increaseSens; - _rotationInput.z = rotateZ ? x * _rotationSenstivity * increaseSens : 0f; - } - - if (Mathf.Abs(y) > _rotationTollerance) _rotationInput.y = y * _rotationSenstivity * increaseSens; - } - else - { - _snapRotation = false; - } - - var direction = Input.GetAxis("Mouse ScrollWheel"); - - //Optional Keyboard inputs - if (Input.GetKeyDown(KeyCode.T)) - direction = -0.1f; - else if (Input.GetKeyDown(KeyCode.G)) - direction = 0.1f; - - if (Mathf.Abs(direction) > 0 && CheckObjectDistance(direction)) - { - _distanceChanged = true; - _scrollWheelInput = PlayerTransform.forward * (_scrollWheelSensitivity * direction); - } - else - { - _scrollWheelInput = _zeroVector3; - } - - if (Input.GetMouseButtonDown(1)) - { - //To prevent warnings in the inpector - _grabbedRigidbody.collisionDetectionMode = !_wasKinematic - ? CollisionDetectionMode.ContinuousSpeculative - : CollisionDetectionMode.Continuous; - _grabbedRigidbody.isKinematic = _wasKinematic = !_wasKinematic; - - _justReleased = true; - ReleaseObject(); - } - } - } - - private void FixedUpdate() - { - if (_grabbedRigidbody) - { - // We are holding an object, time to rotate & move it - Ray ray = CenterRay(); - - UpdateRotationAxis(); - -#if UNITY_EDITOR - Debug.DrawRay(_grabbedTransform.position, _up * 5f , Color.green); - Debug.DrawRay(_grabbedTransform.position, _right * 5f , Color.red); - Debug.DrawRay(_grabbedTransform.position, _forward * 5f , Color.blue); -#endif - // Apply any intentional rotation input made by the player & clear tracked input - Quaternion intentionalRotation = Quaternion.AngleAxis(_rotationInput.z, _forward) * - Quaternion.AngleAxis(_rotationInput.y, _right) * - Quaternion.AngleAxis(-_rotationInput.x, _up) * _desiredRotation; - Quaternion relativeToPlayerRotation = PlayerTransform.rotation * _rotationDifference; - - if (UserRotation && _snapRotation) - { - //Add mouse movement to vector so we can measure the amount of movement - _lockedRot += _rotationInput; - - //If the mouse has moved far enough to rotate the snapped object - if (Mathf.Abs(_lockedRot.x) > _snappedRotationSens || Mathf.Abs(_lockedRot.y) > _snappedRotationSens || - Mathf.Abs(_lockedRot.z) > _snappedRotationSens) - { - for (var i = 0; i < 3; i++) - if (_lockedRot[i] > _snappedRotationSens) - _lockedRot[i] += SnapRotationDegrees; - else if (_lockedRot[i] < -_snappedRotationSens) - _lockedRot[i] += -SnapRotationDegrees; - else - _lockedRot[i] = 0; - - Quaternion q = Quaternion.AngleAxis(-_lockedRot.x, _up) * - Quaternion.AngleAxis(_lockedRot.y, _right) * - Quaternion.AngleAxis(_lockedRot.z, _forward) * _desiredRotation; - - Vector3 newRot = q.eulerAngles; - - newRot.x = Mathf.Round(newRot.x / SnapRotationDegrees) * SnapRotationDegrees; - newRot.y = Mathf.Round(newRot.y / SnapRotationDegrees) * SnapRotationDegrees; - newRot.z = Mathf.Round(newRot.z / SnapRotationDegrees) * SnapRotationDegrees; - - _desiredRotation = Quaternion.Euler(newRot); - - _lockedRot = _zeroVector2; - } - } - else - { - //Rotate the object to remain consistent with any changes in player's rotation - _desiredRotation = UserRotation ? intentionalRotation : relativeToPlayerRotation; - } - - // Remove all torque, reset rotation input & store the rotation difference for next FixedUpdate call - _grabbedRigidbody.angularVelocity = _zeroVector3; - _rotationInput = _zeroVector2; - _rotationDifference = Quaternion.Inverse(PlayerTransform.rotation) * _desiredRotation; - - // Calculate object's center position based on the offset we stored - // NOTE: We need to convert the local-space point back to world coordinates - // Get the destination point for the point on the object we grabbed - Vector3 holdPoint = ray.GetPoint(_currentGrabDistance) + _scrollWheelInput; - Vector3 centerDestination = holdPoint - CurrentGrabbedTransform.TransformVector(_hitOffsetLocal); - -#if UNITY_EDITOR - Debug.DrawLine(ray.origin, holdPoint, Color.blue, Time.fixedDeltaTime); -#endif - // Find vector from current position to destination - Vector3 toDestination = centerDestination - CurrentGrabbedTransform.position; - - // Calculate force - Vector3 force = toDestination / Time.fixedDeltaTime * 0.3f/* / _grabbedRigidbody.mass*/; - - //force += _scrollWheelInput; - // Remove any existing velocity and add force to move to final position - _grabbedRigidbody.velocity = _zeroVector3; - _grabbedRigidbody.AddForce(force, ForceMode.VelocityChange); - - //Rotate object - RotateGrabbedObject(); - - //We need to recalculte the grabbed distance as the object distance from the player has been changed - if (_distanceChanged) - { - _distanceChanged = false; - _currentGrabDistance = Vector3.Distance(ray.origin, holdPoint); - } - - //Update public properties - StartPoint = _laserStartPoint.transform.position; - MidPoint = holdPoint; - EndPoint = CurrentGrabbedTransform.TransformPoint(_hitOffsetLocal); - } - } - - private void RotateGrabbedObject() - { - if (_grabbedRigidbody == null) - return; - - // lerp to desired rotation - _grabbedRigidbody.MoveRotation(Quaternion.Lerp(_grabbedRigidbody.rotation, _desiredRotation, - Time.fixedDeltaTime * _rotationSpeed)); - } - - //Update Rotation axis based on movement - private void UpdateRotationAxis() - { - if (!_snapRotation) - { - _forward = PlayerTransform.forward; - _right = PlayerTransform.right; - _up = PlayerTransform.up; - - return; - } - - if (_rotationAxis) - { - _forward = CurrentGrabbedTransform.forward; - _right = CurrentGrabbedTransform.right; - _up = CurrentGrabbedTransform.up; - - return; - } - - NearestTranformDirection(CurrentGrabbedTransform, PlayerTransform, ref _up, ref _forward, ref _right); - } - - private void NearestTranformDirection(Transform transformToCheck, Transform referenceTransform, ref Vector3 up, - ref Vector3 forward, ref Vector3 right) - { - var directions = new List - { - transformToCheck.forward, - -transformToCheck.forward, - transformToCheck.up, - -transformToCheck.up, - transformToCheck.right, - -transformToCheck.right - }; - - //Find the up Vector - up = GetDirectionVector(directions, referenceTransform.up); - //Remove Vectors from list to prevent duplicates and the opposite vector being found in case where the player is at around a 45 degree angle to the object - directions.Remove(up); - directions.Remove(-up); - //Find the Forward Vector - forward = GetDirectionVector(directions, referenceTransform.forward); - //Remove used directions - directions.Remove(forward); - directions.Remove(-forward); - - right = GetDirectionVector(directions, referenceTransform.right); - } - - private Vector3 GetDirectionVector(List directions, Vector3 direction) - { - var maxDot = -Mathf.Infinity; - Vector3 ret = Vector3.zero; - - for (var i = 0; i < directions.Count; i++) - { - var dot = Vector3.Dot(direction, directions[i]); - - if (dot > maxDot) - { - ret = directions[i]; - maxDot = dot; - } - } - - return ret; - } - - /// Ray from center of the main camera's viewport forward - private Ray CenterRay() - { - return _camera.ViewportPointToRay(_oneVector3 * 0.5f); - } - - //Check distance is within range when moving object with the scroll wheel - private bool CheckObjectDistance(float direction) - { - Vector3 pointA = PlayerTransform.position; - Vector3 pointB = _grabbedRigidbody.position; - - var distance = Vector3.Distance(pointA, pointB); - - if (direction > 0) - return distance <= _maxGrabDistance; - - if (direction < 0) - return distance >= _minObjectDistance; - - return false; - } - - private void ReleaseObject() - { - if (OnObjectReleased != null) - OnObjectReleased(_grabbedRigidbody.gameObject); - - if (_grabbedRigidbody) - { - //Move rotation to desired rotation in case the lerp hasn't finished - //_grabbedRigidbody.MoveRotation(_desiredRotation); - // Reset the rigidbody to how it was before we grabbed it - _grabbedRigidbody.isKinematic = _wasKinematic; - _grabbedRigidbody.interpolation = _initialInterpolationSetting; - _grabbedRigidbody.freezeRotation = false; - _grabbedRigidbody = null; - } - - _scrollWheelInput = _zeroVector3; - CurrentGrabbedTransform = null; - UserRotation = false; - _snapRotation = false; - StartPoint = _zeroVector3; - MidPoint = _zeroVector3; - EndPoint = _zeroVector3; - - OnObjectGrabbed?.Invoke(null); - } -} \ No newline at end of file diff --git a/PhysicsGunMod/HarmonyPatches.cs b/PhysicsGunMod/HarmonyPatches.cs deleted file mode 100644 index 73a618c..0000000 --- a/PhysicsGunMod/HarmonyPatches.cs +++ /dev/null @@ -1,20 +0,0 @@ -using ABI_RC.Systems.InputManagement; -using HarmonyLib; -using NAK.PhysicsGunMod.Components; -using UnityEngine; - -namespace NAK.PhysicsGunMod.HarmonyPatches; - -internal static class CVRInputManagerPatches -{ - [HarmonyPostfix] - [HarmonyPatch(typeof(CVRInputManager), nameof(CVRInputManager.Update))] - private static void Postfix_CVRInputManager_Update(ref CVRInputManager __instance) - { - if (PhysicsGunInteractionBehavior.Instance == null) - return; - - if (PhysicsGunInteractionBehavior.Instance.UserRotation) - __instance.lookVector = Vector2.zero; - } -} diff --git a/PhysicsGunMod/Main.cs b/PhysicsGunMod/Main.cs deleted file mode 100644 index b431ca1..0000000 --- a/PhysicsGunMod/Main.cs +++ /dev/null @@ -1,43 +0,0 @@ -using ABI_RC.Core.Util.AssetFiltering; -using MelonLoader; -using NAK.PhysicsGunMod.Components; -using NAK.PhysicsGunMod.HarmonyPatches; - -namespace NAK.PhysicsGunMod; - -public class PhysicsGunMod : MelonMod -{ - internal static MelonLogger.Instance Logger; - - public override void OnInitializeMelon() - { - Logger = LoggerInstance; - - // // add to prop whitelist - // //SharedFilter._spawnableWhitelist.Add(typeof(PhysicsGunInteractionBehavior)); - // - // // add to event whitelist - // SharedFilter._allowedEventComponents.Add(typeof(PhysicsGunInteractionBehavior)); - // SharedFilter._allowedEventFunctions.Add(typeof(PhysicsGunInteractionBehavior), new List - // { - // "set_enabled", - // // TODO: expose more methods like release ? - // }); - - // apply patches - ApplyPatches(typeof(CVRInputManagerPatches)); - } - - private void ApplyPatches(Type type) - { - try - { - HarmonyInstance.PatchAll(type); - } - catch (Exception e) - { - LoggerInstance.Msg($"Failed while patching {type.Name}!"); - LoggerInstance.Error(e); - } - } -} \ No newline at end of file diff --git a/PhysicsGunMod/ModSettings.cs b/PhysicsGunMod/ModSettings.cs deleted file mode 100644 index 86e4b48..0000000 --- a/PhysicsGunMod/ModSettings.cs +++ /dev/null @@ -1,12 +0,0 @@ -using MelonLoader; - -namespace NAK.PhysicsGunMod; - -internal static class ModSettings -{ - internal const string ModName = nameof(PhysicsGunMod); - internal const string ASM_SettingsCategory = "Physics Gun Mod"; - - private static readonly MelonPreferences_Category Category = - MelonPreferences.CreateCategory(ModName); -} \ No newline at end of file diff --git a/PhysicsGunMod/PhysicsGunMod.csproj b/PhysicsGunMod/PhysicsGunMod.csproj deleted file mode 100644 index 22588f8..0000000 --- a/PhysicsGunMod/PhysicsGunMod.csproj +++ /dev/null @@ -1,37 +0,0 @@ - - - - - netstandard2.1 - - - - - - - - - - - - - - - - - - - - - - - $(MsBuildThisFileDirectory)\..\.ManagedLibs\BTKUILib.dll - False - - - $(MsBuildThisFileDirectory)\..\.ManagedLibs\ActionMenu.dll - False - - - - \ No newline at end of file diff --git a/PhysicsGunMod/README.md b/PhysicsGunMod/README.md deleted file mode 100644 index eca47c9..0000000 --- a/PhysicsGunMod/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# AvatarScaleMod - -Proof of concept mod to add Avatar Scaling to any avatar. This is local-only, but I may toy with using Mod Network. - -Legit threw this together in three hours. ChilloutVR handles all the hard stuff already with its existing animation-clip-based Avatar Scaling. - -https://github.com/NotAKidoS/NAK_CVR_Mods/assets/37721153/7405cef5-fd68-4103-8c18-b3164029eab1 - -## Notes: -* Constraint scaling partially conflicts with avatars run through my [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool). -* This is local-only, at least unless I bother with Mod Network. -* The entire thing is pretty messy and I am unsure of the performance impact, especially with scaling all lights, audio, & constraints. - -## Relevant Feedback Posts: -https://feedback.abinteractive.net/p/built-in-avatar-scaling-system - -This mod is me creating the system I wanted when I wrote the above feedback post. - ---- - -Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. -https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games - -> This mod is an independent creation 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/PhysicsGunMod/format.json b/PhysicsGunMod/format.json deleted file mode 100644 index b1de45e..0000000 --- a/PhysicsGunMod/format.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "_id": 126, - "name": "BetterCalibration", - "modversion": "1.0.0", - "gameversion": "2022r173", - "loaderversion": "0.6.1", - "modtype": "Mod", - "author": "NotAKidoS", - "description": "Mod to improve the calibration process for FBT.", - "searchtags": [ - "IK", - "FBT", - "VRIK", - "calibration", - ], - "requirements": [ - "None" - ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r3/BetterCalibration.dll", - "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/BetterCalibration/", - "changelog": "", - "embedcolor": "9b59b6" -} \ No newline at end of file diff --git a/PlayerColorsAPI/Main.cs b/PlayerColorsAPI/Main.cs new file mode 100644 index 0000000..9e5634d --- /dev/null +++ b/PlayerColorsAPI/Main.cs @@ -0,0 +1,44 @@ +using System; +using MelonLoader; + +namespace NAK.VisualCloneFix; + +public class VisualCloneFixMod : MelonMod +{ + #region Melon Preferences + + private static readonly MelonPreferences_Category Category = + MelonPreferences.CreateCategory(nameof(VisualCloneFix)); + + internal static readonly MelonPreferences_Entry EntryUseVisualClone = + Category.CreateEntry("use_visual_clone", true, + "Use Visual Clone", description: "Uses the potentially faster Visual Clone setup for the local avatar."); + + #endregion Melon Preferences + + #region Melon Events + + public override void OnInitializeMelon() + { + ApplyPatches(typeof(Patches)); // slapped together a fix cause HarmonyInstance.Patch was null ref for no reason? + } + + #endregion Melon Events + + #region Melon Mod Utilities + + private void ApplyPatches(Type type) + { + try + { + HarmonyInstance.PatchAll(type); + } + catch (Exception e) + { + LoggerInstance.Msg($"Failed while patching {type.Name}!"); + LoggerInstance.Error(e); + } + } + + #endregion Melon Mod Utilities +} \ No newline at end of file diff --git a/VisualCloneFix/Patches.cs b/PlayerColorsAPI/Patches.cs similarity index 100% rename from VisualCloneFix/Patches.cs rename to PlayerColorsAPI/Patches.cs diff --git a/PlayerColorsAPI/PlayerColorsAPI.csproj b/PlayerColorsAPI/PlayerColorsAPI.csproj new file mode 100644 index 0000000..8dc4bcd --- /dev/null +++ b/PlayerColorsAPI/PlayerColorsAPI.csproj @@ -0,0 +1,6 @@ + + + + LocalCloneFix + + diff --git a/PlayerColorsAPI/Properties/AssemblyInfo.cs b/PlayerColorsAPI/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..10b75bb --- /dev/null +++ b/PlayerColorsAPI/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using MelonLoader; +using NAK.VisualCloneFix.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.VisualCloneFix))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.VisualCloneFix))] + +[assembly: MelonInfo( + typeof(NAK.VisualCloneFix.VisualCloneFixMod), + nameof(NAK.VisualCloneFix), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/VisualCloneFix" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red +[assembly: HarmonyDontPatchAll] + +namespace NAK.VisualCloneFix.Properties; +internal static class AssemblyInfoParams +{ + public const string Version = "1.0.1"; + public const string Author = "NotAKidoS"; +} \ No newline at end of file diff --git a/PlayerColorsAPI/README.md b/PlayerColorsAPI/README.md new file mode 100644 index 0000000..cc12a9c --- /dev/null +++ b/PlayerColorsAPI/README.md @@ -0,0 +1,18 @@ +# VisualCloneFix + +Fixes the Visual Clone system and allows you to use it again. + +Using the Visual Clone should be faster than the default Head Hiding & Shadow Clones, but will add a longer hitch on initial avatar load. + +**NOTE:** The Visual Clone is still an experimental feature that was temporarily removed in [ChilloutVR 2024r175 Hotfix 1](https://abinteractive.net/blog/chilloutvr_2024r175_hotfix_1), so there may be bugs or issues with it. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation 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/PlayerColorsAPI/format.json b/PlayerColorsAPI/format.json new file mode 100644 index 0000000..6634e9f --- /dev/null +++ b/PlayerColorsAPI/format.json @@ -0,0 +1,23 @@ +{ + "_id": 221, + "name": "VisualCloneFix", + "modversion": "1.0.1", + "gameversion": "2024r175", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Fixes the Visual Clone system and allows you to use it again.\n\nUsing the Visual Clone should be faster than the default Head Hiding & Shadow Clones, but will add a longer hitch on initial avatar load.\n\n**NOTE:** The Visual Clone is still an experimental feature that was temporarily removed in [ChilloutVR 2024r175 Hotfix 1](https://abinteractive.net/blog/chilloutvr_2024r175_hotfix_1), so there may be bugs or issues with it.", + "searchtags": [ + "visual", + "clone", + "head", + "hiding" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r36/VisualCloneFix.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/VisualCloneFix/", + "changelog": "- Fixed FPRExclusions IsShown state being inverted when toggled.\n- Fixed head FPRExclusion generation not checking for existing exclusion.\n- Sped up FindExclusionVertList by 100x by not being an idiot. This heavily reduces avatar hitch with Visual Clone active.", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/Portals/format.json b/Portals/format.json deleted file mode 100644 index d3c7457..0000000 --- a/Portals/format.json +++ /dev/null @@ -1 +0,0 @@ - "None" diff --git a/References.Items.props b/References.Items.props index b618151..275c721 100644 --- a/References.Items.props +++ b/References.Items.props @@ -196,6 +196,18 @@ $(MsBuildThisFileDirectory)\.ManagedLibs\PICO.Platform.dll False + + $(MsBuildThisFileDirectory)\.ManagedLibs\Pico.Spatializer.dll + False + + + $(MsBuildThisFileDirectory)\.ManagedLibs\Pico.Spatializer.Example.dll + False + + + $(MsBuildThisFileDirectory)\.ManagedLibs\PICO.TobSupport.dll + False + $(MsBuildThisFileDirectory)\.ManagedLibs\PWCommon3DLL.dll False @@ -396,6 +408,10 @@ $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.InputSystem.dll False + + $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.InputSystem.ForUI.dll + False + $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.InternalAPIEngineBridge.002.dll False @@ -584,6 +600,10 @@ $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.XR.Hands.Samples.VisualizerSample.dll False + + $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.XR.Interaction.Toolkit.dll + False + $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.XR.Management.dll False @@ -616,16 +636,12 @@ $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.XR.OpenXR.Features.OculusQuestSupport.dll False - - $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.XR.OpenXR.Features.PICOSupport.dll - False - $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.XR.OpenXR.Features.RuntimeDebugger.dll False - - $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.XR.OpenXRPico.dll + + $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.XR.PICO.dll False diff --git a/SmootherRay/Main.cs b/SmootherRay/Main.cs index b1b1056..eb6c36a 100644 --- a/SmootherRay/Main.cs +++ b/SmootherRay/Main.cs @@ -39,6 +39,10 @@ public class SmootherRayMod : MelonMod Category.CreateEntry("Small Angle Threshold (6f)", 6f, description: "Angle difference to consider a 'small' movement. The less shaky your hands are, the lower you probably want to set this. This is probably the primary value you want to tweak. Use the slider to adjust the threshold angle. Range: 4 to 15."); + public static readonly MelonPreferences_Entry EntrySmoothWhenHoldingPickup = + Category.CreateEntry("Smooth When Holding Pickup", false, + description: "Enable or disable smoothing when holding a pickup."); + #endregion Melon Preferences #region Melon Events diff --git a/SmootherRay/Properties/AssemblyInfo.cs b/SmootherRay/Properties/AssemblyInfo.cs index 57dbe09..d7f1704 100644 --- a/SmootherRay/Properties/AssemblyInfo.cs +++ b/SmootherRay/Properties/AssemblyInfo.cs @@ -28,6 +28,6 @@ namespace NAK.SmootherRay.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.5"; + public const string Version = "1.0.6"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/SmootherRay/SmootherRayer.cs b/SmootherRay/SmootherRayer.cs index 44ef320..6262824 100644 --- a/SmootherRay/SmootherRayer.cs +++ b/SmootherRay/SmootherRayer.cs @@ -227,6 +227,10 @@ public class SmootherRayer : MonoBehaviour } } + if (SmootherRayMod.EntrySmoothWhenHoldingPickup.Value + && ray.grabbedObject) + canSmoothRay = true; + return canSmoothRay; } diff --git a/Stickers/Stickers/Networking/ModNetwork.Inbound.cs b/Stickers/Stickers/Networking/ModNetwork.Inbound.cs index e769006..57b355c 100644 --- a/Stickers/Stickers/Networking/ModNetwork.Inbound.cs +++ b/Stickers/Stickers/Networking/ModNetwork.Inbound.cs @@ -1,4 +1,5 @@ using ABI_RC.Core.Networking.IO.Social; +using ABI_RC.Core.Player; using ABI_RC.Core.Savior; using ABI_RC.Systems.ModNetwork; using NAK.Stickers.Utilities; @@ -47,6 +48,9 @@ public static partial class ModNetwork if (StickerSystem.Instance.IsRestrictedInstance) // ignore messages from users when the world is restricted. This also includes older or modified version of Stickers mod. return false; + if (!CVRPlayerManager.Instance.GetPlayerPuppetMaster(sender, out PuppetMaster _)) + return false; // ignore messages from players that don't exist + return true; } @@ -108,7 +112,10 @@ public static partial class ModNetwork msg.Read(out Vector3 up); if (!StickerSystem.Instance.HasTextureHash(msg.Sender, textureHash)) + { SendRequestTexture(stickerSlot, textureHash); + StickerSystem.Instance.ClearStickersForPlayer(msg.Sender, stickerSlot); // Ensure no exploit + } StickerSystem.Instance.OnStickerPlaceReceived(msg.Sender, stickerSlot, position, forward, up); } @@ -158,7 +165,7 @@ public static partial class ModNetwork LoggerInbound($"Received StartTexture message from {sender}: Slot: {stickerSlot}, Hash: {textureHash}, Chunks: {chunkCount}, Resolution: {width}x{height}"); } - + private static void HandleSendTexture(ModNetworkMessage msg) { string sender = msg.Sender; diff --git a/Stickers/Stickers/StickerSystem.PlayerCallbacks.cs b/Stickers/Stickers/StickerSystem.PlayerCallbacks.cs index e8ab380..f2b5dd3 100644 --- a/Stickers/Stickers/StickerSystem.PlayerCallbacks.cs +++ b/Stickers/Stickers/StickerSystem.PlayerCallbacks.cs @@ -62,7 +62,7 @@ public partial class StickerSystem #endregion Player Callbacks - #region Player Callbacks + #region Sticker Callbacks public void OnStickerPlaceReceived(string playerId, int stickerSlot, Vector3 position, Vector3 forward, Vector3 up) => AttemptPlaceSticker(playerId, position, forward, up, alignWithNormal: true, stickerSlot); @@ -81,5 +81,5 @@ public partial class StickerSystem stickerData.IdentifyTime = Time.time + 3f; } - #endregion Player Callbacks + #endregion Sticker Callbacks } diff --git a/Stickers/Stickers/StickerSystem.StickerLifecycle.cs b/Stickers/Stickers/StickerSystem.StickerLifecycle.cs index df4ee96..5f350dd 100644 --- a/Stickers/Stickers/StickerSystem.StickerLifecycle.cs +++ b/Stickers/Stickers/StickerSystem.StickerLifecycle.cs @@ -110,7 +110,7 @@ public partial class StickerSystem stickerData.Clear(); } - private void ClearStickersForPlayer(string playerId, int stickerSlot) + public void ClearStickersForPlayer(string playerId, int stickerSlot) { if (!_playerStickers.TryGetValue(playerId, out StickerData stickerData)) return; diff --git a/ThirdPerson/CameraLogic.cs b/ThirdPerson/CameraLogic.cs index 24d10c5..f1b83ef 100644 --- a/ThirdPerson/CameraLogic.cs +++ b/ThirdPerson/CameraLogic.cs @@ -39,7 +39,6 @@ internal static class CameraLogic if (_state) _storedCamMask = _desktopCam.cullingMask; _desktopCam.cullingMask = _state ? 0 : _storedCamMask; - _uiCam.cullingMask = _state ? _uiCam.cullingMask & ~(1 << CVRLayers.PlayerClone) : _uiCam.cullingMask | (1 << CVRLayers.PlayerClone); _thirdPersonCam.gameObject.SetActive(_state); } } @@ -73,6 +72,9 @@ internal static class CameraLogic ThirdPerson.Logger.Msg("Copying active camera settings & components."); CVRTools.CopyToDestCam(activePlayerCam, _thirdPersonCam, true); + + // Remove PlayerClone + _thirdPersonCam.cullingMask &= ~(1 << CVRLayers.PlayerClone); if (!CheckIsRestricted()) return; diff --git a/ThirdPerson/Patches.cs b/ThirdPerson/Patches.cs index 9267d2e..60dc4dd 100644 --- a/ThirdPerson/Patches.cs +++ b/ThirdPerson/Patches.cs @@ -28,10 +28,6 @@ internal static class Patches typeof(CVRTools).GetMethod(nameof(CVRTools.ConfigureHudAffinity), BindingFlags.Public | BindingFlags.Static), postfix: typeof(Patches).GetMethod(nameof(OnConfigureHudAffinity), BindingFlags.NonPublic | BindingFlags.Static).ToNewHarmonyMethod() ); - harmony.Patch( - typeof(TransformHiderManager).GetMethod(nameof(TransformHiderManager.CheckPlayerCamWithinRange), BindingFlags.NonPublic | BindingFlags.Static), - prefix: typeof(Patches).GetMethod(nameof(OnCheckPlayerCamWithinRange), BindingFlags.NonPublic | BindingFlags.Static).ToNewHarmonyMethod() - ); } //Copy camera settings & postprocessing components @@ -39,5 +35,4 @@ internal static class Patches //Adjust camera distance with height as modifier private static void OnScaleAdjusted(float height) => AdjustScale(height); private static void OnConfigureHudAffinity() => CheckVRMode(); - private static bool OnCheckPlayerCamWithinRange() => !State; // don't hide head if in third person } \ No newline at end of file diff --git a/ThirdPerson/Properties/AssemblyInfo.cs b/ThirdPerson/Properties/AssemblyInfo.cs index ab34afe..6c055d1 100644 --- a/ThirdPerson/Properties/AssemblyInfo.cs +++ b/ThirdPerson/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.ThirdPerson.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.9"; + public const string Version = "1.1.0"; public const string Author = "Davi & NotAKidoS"; } \ No newline at end of file From 4f8dcb0cd0474d37201693cfafed45f096801a39 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 02:59:18 -0500 Subject: [PATCH 009/119] including mutual mute --- {MutualMute => .Deprecated/MutualMute}/Main.cs | 0 {MutualMute => .Deprecated/MutualMute}/MutualMute.csproj | 0 {MutualMute => .Deprecated/MutualMute}/Properties/AssemblyInfo.cs | 0 {MutualMute => .Deprecated/MutualMute}/README.md | 0 {MutualMute => .Deprecated/MutualMute}/format.json | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename {MutualMute => .Deprecated/MutualMute}/Main.cs (100%) rename {MutualMute => .Deprecated/MutualMute}/MutualMute.csproj (100%) rename {MutualMute => .Deprecated/MutualMute}/Properties/AssemblyInfo.cs (100%) rename {MutualMute => .Deprecated/MutualMute}/README.md (100%) rename {MutualMute => .Deprecated/MutualMute}/format.json (100%) diff --git a/MutualMute/Main.cs b/.Deprecated/MutualMute/Main.cs similarity index 100% rename from MutualMute/Main.cs rename to .Deprecated/MutualMute/Main.cs diff --git a/MutualMute/MutualMute.csproj b/.Deprecated/MutualMute/MutualMute.csproj similarity index 100% rename from MutualMute/MutualMute.csproj rename to .Deprecated/MutualMute/MutualMute.csproj diff --git a/MutualMute/Properties/AssemblyInfo.cs b/.Deprecated/MutualMute/Properties/AssemblyInfo.cs similarity index 100% rename from MutualMute/Properties/AssemblyInfo.cs rename to .Deprecated/MutualMute/Properties/AssemblyInfo.cs diff --git a/MutualMute/README.md b/.Deprecated/MutualMute/README.md similarity index 100% rename from MutualMute/README.md rename to .Deprecated/MutualMute/README.md diff --git a/MutualMute/format.json b/.Deprecated/MutualMute/format.json similarity index 100% rename from MutualMute/format.json rename to .Deprecated/MutualMute/format.json From 323eb92f2e0ad7f1ece36537bf9edaf1de37782b Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 03:03:24 -0500 Subject: [PATCH 010/119] further cleanup of repo --- .../AvatarClone/AvatarClone.Exclusions.cs | 0 .../AvatarClone/AvatarClone.Init.cs | 0 .../AvatarClone/AvatarClone.RenderState.cs | 0 .../AvatarClone/AvatarClone.StateSync.cs | 0 .../AvatarClone/AvatarClone.Util.cs | 0 .../AvatarClone/AvatarClone.cs | 0 .../FPRExclusion/AvatarCloneExclusion.cs | 0 .../AvatarCloneTest}/AvatarCloneTest.csproj | 0 .../AvatarCloneTest}/Main.cs | 0 .../AvatarCloneTest}/Patches.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../AvatarCloneTest}/README.md | 0 .../AvatarCloneTest}/format.json | 0 .../ChatBoxExtensions.csproj | 0 .../ChatBoxExtensions}/HarmonyPatches.cs | 0 .../InputModuleChatBoxExtensions.cs | 0 .../ChatBoxExtensions}/Integrations/Base.cs | 0 .../Integrations/ChatBox.cs | 0 .../Integrations/ChilloutVRAAS.cs | 0 .../Integrations/ChilloutVRBase.cs | 0 .../Integrations/ChilloutVRInput.cs | 0 .../Integrations/Commands.cs | 0 .../Integrations/PlayerRagdollMod.cs | 0 .../ChatBoxExtensions}/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../ChatBoxExtensions}/format.json | 0 .../CVRLuaToolsExtension.csproj | 0 .../LuaToolsExtension/Base/Singleton.cs | 0 .../CVRBaseLuaBehaviourExtensions.cs | 0 .../CVRLuaClientBehaviourExtensions.cs | 0 .../LuaToolsExtension/LuaHotReloadManager.cs | 0 .../NamedPipes/NamedPipeServer.cs | 0 .../LuaToolsExtension/ScriptInfo.cs | 0 .../CVRLuaToolsExtension}/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../CVRLuaToolsExtension}/README.md | 0 .../CVRLuaToolsExtension}/format.json | 0 .../LuaNetworkVariables.csproj | 0 .../LuaNetworkVariables}/Main.cs | 0 .../LuaNetworkVariables}/NetLuaModule.cs | 0 .../NetworkVariables/LuaEventContext.cs | 0 .../NetworkVariables/LuaEventTracker.cs | 0 .../LuaNetVarController.Base.cs | 0 .../LuaNetVarController.Networking.cs | 0 .../LuaNetVarController.Registration.cs | 0 .../LuaNetVarController.Serialization.cs | 0 .../LuaNetVarController.Utility.cs | 0 .../LuaNetworkVariables}/Patches.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../LuaNetworkVariables}/README.md | 0 .../SyncedBehaviour/MNSyncedBehaviour.cs | 0 .../SyncedBehaviour/TestSyncedBehaviour.cs | 0 .../SyncedBehaviour/TestSyncedObject.cs | 0 .../LuaNetworkVariables}/format.json | 0 .../LuaTTS}/LuaTTS.csproj | 0 {LuaTTS => .Experimental/LuaTTS}/Main.cs | 0 {LuaTTS => .Experimental/LuaTTS}/Patches.cs | 0 .../LuaTTS}/Properties/AssemblyInfo.cs | 0 {LuaTTS => .Experimental/LuaTTS}/README.md | 0 .../LuaTTS}/TTSLuaModule.cs | 0 {LuaTTS => .Experimental/LuaTTS}/format.json | 0 .../BTKUI/BtkUiAddon_CAT_OriginShiftMod.cs | 0 .../Integrations/BTKUI/BtkuiAddon.cs | 0 .../Integrations/BTKUI/BtkuiAddon_Utils.cs | 0 .../Integrations/Ragdoll/RagdollAddon.cs | 0 .../ThirdPerson/ThirdPersonAddon.cs | 0 .../OriginShift}/Main.cs | 0 .../OriginShift}/ModSettings.cs | 0 .../OriginShift}/Networking/ModNetwork.cs | 0 .../OriginShift}/OriginShift.csproj | 0 .../Components/Chunk/ChunkController.cs | 0 .../Components/Chunk/ChunkCreator.cs | 0 .../Components/Chunk/ChunkListener.cs | 0 .../Components/OriginShiftController.cs | 0 .../Receivers/OriginShiftEventReceiver.cs | 0 .../OriginShiftParticleSystemReceiver.cs | 0 .../Receivers/OriginShiftRigidbodyReceiver.cs | 0 .../OriginShiftTrailRendererReceiver.cs | 0 .../Receivers/OriginShiftTransformReceiver.cs | 0 ...tterBetterCharacterControllerExtensions.cs | 0 .../Extensions/PlayerSetupExtensions.cs | 0 .../OriginShift/Hacks/OcclusionCullingHack.cs | 0 .../OriginShiftOcclusionCullingDisabler.cs | 0 .../OriginShift/OriginShiftManager.cs | 0 .../Dynamics/OriginShiftDbAvatarReceiver.cs | 0 .../OriginShift/Player/OriginShiftMonitor.cs | 0 .../Player/OriginShiftNetIkReceiver.cs | 0 .../Player/OriginShiftObjectSyncReceiver.cs | 0 .../Player/OriginShiftPickupObjectReceiver.cs | 0 .../Player/OriginShiftSpawnableReceiver.cs | 0 .../OriginShift/Utility/DebugTextDisplay.cs | 0 .../Utility/RendererReflectionUtility.cs | 0 .../OriginShift}/Patches.cs | 0 .../OriginShift}/Properties/AssemblyInfo.cs | 0 .../OriginShift}/README.md | 0 .../Resources/OriginShift-Icon-Active.png | Bin .../Resources/OriginShift-Icon-Forced.png | Bin .../Resources/OriginShift-Icon-Inactive.png | Bin .../OriginShift}/format.json | 0 .../ScriptingSpoofer}/Main.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../ScriptingSpoofer}/README.md | 0 .../ScriptingSpoofer}/ScriptingSpoofer.csproj | 0 .../ScriptingSpoofer}/format.json | 0 .gitignore | 2 +- .../BetterContentLoading.csproj | 15 -- .../BetterDownloadManager.cs | 210 ---------------- .../BetterContentLoading/DownloadInfo.cs | 63 ----- .../BetterContentLoading/DownloadProcessor.cs | 152 ----------- .../DownloadQueue/AvatarDownloadQueue.cs | 83 ------ .../DownloadQueue/ContentDownloadQueueBase.cs | 177 ------------- .../DownloadQueue/PropDownloadQueue.cs | 81 ------ .../DownloadQueue/WorldDownloadQueue.cs | 66 ----- .../BetterContentLoading/DownloadState.cs | 26 -- .../Util/ThreadingHelper.cs | 109 -------- .../DownloadManager/DownloadManager.Core.cs | 237 ------------------ .../DownloadManager.Helpers.cs | 58 ----- .../DownloadManager.Priority.cs | 38 --- .../DownloadManager/DownloadTask.Main.cs | 33 --- .../DownloadManager/DownloadTask.Priority.cs | 6 - .../ConcurrentPriorityQueue.cs | 43 ---- .../DownloadManager.Bandwidth.cs | 24 -- .../DownloadManager2/DownloadManager.Core.cs | 126 ---------- .../DownloadManager.Helpers.cs | 58 ----- .../DownloadManager.Priority.cs | 47 ---- .../DownloadManager.Processing.cs | 144 ----------- .../DownloadManager2/DownloadManager.Queue.cs | 80 ------ .../DownloadManager2/DownloadTask2.cs | 62 ----- BetterContentLoading/Main.cs | 37 --- BetterContentLoading/ModSettings.cs | 31 --- BetterContentLoading/Patches.cs | 71 ------ .../Properties/AssemblyInfo.cs | 33 --- BetterContentLoading/README.md | 14 -- BetterContentLoading/format.json | 23 -- PlayerColorsAPI/Main.cs | 44 ---- PlayerColorsAPI/Patches.cs | 159 ------------ PlayerColorsAPI/PlayerColorsAPI.csproj | 6 - PlayerColorsAPI/Properties/AssemblyInfo.cs | 32 --- PlayerColorsAPI/README.md | 18 -- PlayerColorsAPI/format.json | 23 -- 140 files changed, 1 insertion(+), 2430 deletions(-) rename {AvatarCloneTest => .Deprecated/AvatarCloneTest}/AvatarClone/AvatarClone.Exclusions.cs (100%) rename {AvatarCloneTest => .Deprecated/AvatarCloneTest}/AvatarClone/AvatarClone.Init.cs (100%) rename {AvatarCloneTest => .Deprecated/AvatarCloneTest}/AvatarClone/AvatarClone.RenderState.cs (100%) rename {AvatarCloneTest => .Deprecated/AvatarCloneTest}/AvatarClone/AvatarClone.StateSync.cs (100%) rename {AvatarCloneTest => .Deprecated/AvatarCloneTest}/AvatarClone/AvatarClone.Util.cs (100%) rename {AvatarCloneTest => .Deprecated/AvatarCloneTest}/AvatarClone/AvatarClone.cs (100%) rename {AvatarCloneTest => .Deprecated/AvatarCloneTest}/AvatarClone/FPRExclusion/AvatarCloneExclusion.cs (100%) rename {AvatarCloneTest => .Deprecated/AvatarCloneTest}/AvatarCloneTest.csproj (100%) rename {AvatarCloneTest => .Deprecated/AvatarCloneTest}/Main.cs (100%) rename {AvatarCloneTest => .Deprecated/AvatarCloneTest}/Patches.cs (100%) rename {AvatarCloneTest => .Deprecated/AvatarCloneTest}/Properties/AssemblyInfo.cs (100%) rename {AvatarCloneTest => .Deprecated/AvatarCloneTest}/README.md (100%) rename {AvatarCloneTest => .Deprecated/AvatarCloneTest}/format.json (100%) rename {ChatBoxExtensions => .Deprecated/ChatBoxExtensions}/ChatBoxExtensions.csproj (100%) rename {ChatBoxExtensions => .Deprecated/ChatBoxExtensions}/HarmonyPatches.cs (100%) rename {ChatBoxExtensions => .Deprecated/ChatBoxExtensions}/InputModules/InputModuleChatBoxExtensions.cs (100%) rename {ChatBoxExtensions => .Deprecated/ChatBoxExtensions}/Integrations/Base.cs (100%) rename {ChatBoxExtensions => .Deprecated/ChatBoxExtensions}/Integrations/ChatBox.cs (100%) rename {ChatBoxExtensions => .Deprecated/ChatBoxExtensions}/Integrations/ChilloutVRAAS.cs (100%) rename {ChatBoxExtensions => .Deprecated/ChatBoxExtensions}/Integrations/ChilloutVRBase.cs (100%) rename {ChatBoxExtensions => .Deprecated/ChatBoxExtensions}/Integrations/ChilloutVRInput.cs (100%) rename {ChatBoxExtensions => .Deprecated/ChatBoxExtensions}/Integrations/Commands.cs (100%) rename {ChatBoxExtensions => .Deprecated/ChatBoxExtensions}/Integrations/PlayerRagdollMod.cs (100%) rename {ChatBoxExtensions => .Deprecated/ChatBoxExtensions}/Main.cs (100%) rename {ChatBoxExtensions => .Deprecated/ChatBoxExtensions}/Properties/AssemblyInfo.cs (100%) rename {ChatBoxExtensions => .Deprecated/ChatBoxExtensions}/format.json (100%) rename {CVRLuaToolsExtension => .Experimental/CVRLuaToolsExtension}/CVRLuaToolsExtension.csproj (100%) rename {CVRLuaToolsExtension => .Experimental/CVRLuaToolsExtension}/LuaToolsExtension/Base/Singleton.cs (100%) rename {CVRLuaToolsExtension => .Experimental/CVRLuaToolsExtension}/LuaToolsExtension/Extensions/CVRBaseLuaBehaviourExtensions.cs (100%) rename {CVRLuaToolsExtension => .Experimental/CVRLuaToolsExtension}/LuaToolsExtension/Extensions/CVRLuaClientBehaviourExtensions.cs (100%) rename {CVRLuaToolsExtension => .Experimental/CVRLuaToolsExtension}/LuaToolsExtension/LuaHotReloadManager.cs (100%) rename {CVRLuaToolsExtension => .Experimental/CVRLuaToolsExtension}/LuaToolsExtension/NamedPipes/NamedPipeServer.cs (100%) rename {CVRLuaToolsExtension => .Experimental/CVRLuaToolsExtension}/LuaToolsExtension/ScriptInfo.cs (100%) rename {CVRLuaToolsExtension => .Experimental/CVRLuaToolsExtension}/Main.cs (100%) rename {CVRLuaToolsExtension => .Experimental/CVRLuaToolsExtension}/Properties/AssemblyInfo.cs (100%) rename {CVRLuaToolsExtension => .Experimental/CVRLuaToolsExtension}/README.md (100%) rename {CVRLuaToolsExtension => .Experimental/CVRLuaToolsExtension}/format.json (100%) rename {LuaNetworkVariables => .Experimental/LuaNetworkVariables}/LuaNetworkVariables.csproj (100%) rename {LuaNetworkVariables => .Experimental/LuaNetworkVariables}/Main.cs (100%) rename {LuaNetworkVariables => .Experimental/LuaNetworkVariables}/NetLuaModule.cs (100%) rename {LuaNetworkVariables => .Experimental/LuaNetworkVariables}/NetworkVariables/LuaEventContext.cs (100%) rename {LuaNetworkVariables => .Experimental/LuaNetworkVariables}/NetworkVariables/LuaEventTracker.cs (100%) rename {LuaNetworkVariables => .Experimental/LuaNetworkVariables}/NetworkVariables/LuaNetVarController.Base.cs (100%) rename {LuaNetworkVariables => .Experimental/LuaNetworkVariables}/NetworkVariables/LuaNetVarController.Networking.cs (100%) rename {LuaNetworkVariables => .Experimental/LuaNetworkVariables}/NetworkVariables/LuaNetVarController.Registration.cs (100%) rename {LuaNetworkVariables => .Experimental/LuaNetworkVariables}/NetworkVariables/LuaNetVarController.Serialization.cs (100%) rename {LuaNetworkVariables => .Experimental/LuaNetworkVariables}/NetworkVariables/LuaNetVarController.Utility.cs (100%) rename {LuaNetworkVariables => .Experimental/LuaNetworkVariables}/Patches.cs (100%) rename {LuaNetworkVariables => .Experimental/LuaNetworkVariables}/Properties/AssemblyInfo.cs (100%) rename {LuaNetworkVariables => .Experimental/LuaNetworkVariables}/README.md (100%) rename {LuaNetworkVariables => .Experimental/LuaNetworkVariables}/SyncedBehaviour/MNSyncedBehaviour.cs (100%) rename {LuaNetworkVariables => .Experimental/LuaNetworkVariables}/SyncedBehaviour/TestSyncedBehaviour.cs (100%) rename {LuaNetworkVariables => .Experimental/LuaNetworkVariables}/SyncedBehaviour/TestSyncedObject.cs (100%) rename {LuaNetworkVariables => .Experimental/LuaNetworkVariables}/format.json (100%) rename {LuaTTS => .Experimental/LuaTTS}/LuaTTS.csproj (100%) rename {LuaTTS => .Experimental/LuaTTS}/Main.cs (100%) rename {LuaTTS => .Experimental/LuaTTS}/Patches.cs (100%) rename {LuaTTS => .Experimental/LuaTTS}/Properties/AssemblyInfo.cs (100%) rename {LuaTTS => .Experimental/LuaTTS}/README.md (100%) rename {LuaTTS => .Experimental/LuaTTS}/TTSLuaModule.cs (100%) rename {LuaTTS => .Experimental/LuaTTS}/format.json (100%) rename {OriginShift => .Experimental/OriginShift}/Integrations/BTKUI/BtkUiAddon_CAT_OriginShiftMod.cs (100%) rename {OriginShift => .Experimental/OriginShift}/Integrations/BTKUI/BtkuiAddon.cs (100%) rename {OriginShift => .Experimental/OriginShift}/Integrations/BTKUI/BtkuiAddon_Utils.cs (100%) rename {OriginShift => .Experimental/OriginShift}/Integrations/Ragdoll/RagdollAddon.cs (100%) rename {OriginShift => .Experimental/OriginShift}/Integrations/ThirdPerson/ThirdPersonAddon.cs (100%) rename {OriginShift => .Experimental/OriginShift}/Main.cs (100%) rename {OriginShift => .Experimental/OriginShift}/ModSettings.cs (100%) rename {OriginShift => .Experimental/OriginShift}/Networking/ModNetwork.cs (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift.csproj (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift/Components/Chunk/ChunkController.cs (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift/Components/Chunk/ChunkCreator.cs (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift/Components/Chunk/ChunkListener.cs (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift/Components/OriginShiftController.cs (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift/Components/Receivers/OriginShiftEventReceiver.cs (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift/Components/Receivers/OriginShiftParticleSystemReceiver.cs (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift/Components/Receivers/OriginShiftRigidbodyReceiver.cs (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift/Components/Receivers/OriginShiftTrailRendererReceiver.cs (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift/Components/Receivers/OriginShiftTransformReceiver.cs (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift/Extensions/BetterBetterCharacterControllerExtensions.cs (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift/Extensions/PlayerSetupExtensions.cs (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift/Hacks/OcclusionCullingHack.cs (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift/Hacks/OriginShiftOcclusionCullingDisabler.cs (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift/OriginShiftManager.cs (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift/Player/Dynamics/OriginShiftDbAvatarReceiver.cs (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift/Player/OriginShiftMonitor.cs (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift/Player/OriginShiftNetIkReceiver.cs (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift/Player/OriginShiftObjectSyncReceiver.cs (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift/Player/OriginShiftPickupObjectReceiver.cs (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift/Player/OriginShiftSpawnableReceiver.cs (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift/Utility/DebugTextDisplay.cs (100%) rename {OriginShift => .Experimental/OriginShift}/OriginShift/Utility/RendererReflectionUtility.cs (100%) rename {OriginShift => .Experimental/OriginShift}/Patches.cs (100%) rename {OriginShift => .Experimental/OriginShift}/Properties/AssemblyInfo.cs (100%) rename {OriginShift => .Experimental/OriginShift}/README.md (100%) rename {OriginShift => .Experimental/OriginShift}/Resources/OriginShift-Icon-Active.png (100%) rename {OriginShift => .Experimental/OriginShift}/Resources/OriginShift-Icon-Forced.png (100%) rename {OriginShift => .Experimental/OriginShift}/Resources/OriginShift-Icon-Inactive.png (100%) rename {OriginShift => .Experimental/OriginShift}/format.json (100%) rename {ScriptingSpoofer => .Experimental/ScriptingSpoofer}/Main.cs (100%) rename {ScriptingSpoofer => .Experimental/ScriptingSpoofer}/Properties/AssemblyInfo.cs (100%) rename {ScriptingSpoofer => .Experimental/ScriptingSpoofer}/README.md (100%) rename {ScriptingSpoofer => .Experimental/ScriptingSpoofer}/ScriptingSpoofer.csproj (100%) rename {ScriptingSpoofer => .Experimental/ScriptingSpoofer}/format.json (100%) delete mode 100644 BetterContentLoading/BetterContentLoading.csproj delete mode 100644 BetterContentLoading/BetterContentLoading/BetterDownloadManager.cs delete mode 100644 BetterContentLoading/BetterContentLoading/DownloadInfo.cs delete mode 100644 BetterContentLoading/BetterContentLoading/DownloadProcessor.cs delete mode 100644 BetterContentLoading/BetterContentLoading/DownloadQueue/AvatarDownloadQueue.cs delete mode 100644 BetterContentLoading/BetterContentLoading/DownloadQueue/ContentDownloadQueueBase.cs delete mode 100644 BetterContentLoading/BetterContentLoading/DownloadQueue/PropDownloadQueue.cs delete mode 100644 BetterContentLoading/BetterContentLoading/DownloadQueue/WorldDownloadQueue.cs delete mode 100644 BetterContentLoading/BetterContentLoading/DownloadState.cs delete mode 100644 BetterContentLoading/BetterContentLoading/Util/ThreadingHelper.cs delete mode 100644 BetterContentLoading/DownloadManager/DownloadManager.Core.cs delete mode 100644 BetterContentLoading/DownloadManager/DownloadManager.Helpers.cs delete mode 100644 BetterContentLoading/DownloadManager/DownloadManager.Priority.cs delete mode 100644 BetterContentLoading/DownloadManager/DownloadTask.Main.cs delete mode 100644 BetterContentLoading/DownloadManager/DownloadTask.Priority.cs delete mode 100644 BetterContentLoading/DownloadManager2/ConcurrentPriorityQueue.cs delete mode 100644 BetterContentLoading/DownloadManager2/DownloadManager.Bandwidth.cs delete mode 100644 BetterContentLoading/DownloadManager2/DownloadManager.Core.cs delete mode 100644 BetterContentLoading/DownloadManager2/DownloadManager.Helpers.cs delete mode 100644 BetterContentLoading/DownloadManager2/DownloadManager.Priority.cs delete mode 100644 BetterContentLoading/DownloadManager2/DownloadManager.Processing.cs delete mode 100644 BetterContentLoading/DownloadManager2/DownloadManager.Queue.cs delete mode 100644 BetterContentLoading/DownloadManager2/DownloadTask2.cs delete mode 100644 BetterContentLoading/Main.cs delete mode 100644 BetterContentLoading/ModSettings.cs delete mode 100644 BetterContentLoading/Patches.cs delete mode 100644 BetterContentLoading/Properties/AssemblyInfo.cs delete mode 100644 BetterContentLoading/README.md delete mode 100644 BetterContentLoading/format.json delete mode 100644 PlayerColorsAPI/Main.cs delete mode 100644 PlayerColorsAPI/Patches.cs delete mode 100644 PlayerColorsAPI/PlayerColorsAPI.csproj delete mode 100644 PlayerColorsAPI/Properties/AssemblyInfo.cs delete mode 100644 PlayerColorsAPI/README.md delete mode 100644 PlayerColorsAPI/format.json diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Exclusions.cs b/.Deprecated/AvatarCloneTest/AvatarClone/AvatarClone.Exclusions.cs similarity index 100% rename from AvatarCloneTest/AvatarClone/AvatarClone.Exclusions.cs rename to .Deprecated/AvatarCloneTest/AvatarClone/AvatarClone.Exclusions.cs diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Init.cs b/.Deprecated/AvatarCloneTest/AvatarClone/AvatarClone.Init.cs similarity index 100% rename from AvatarCloneTest/AvatarClone/AvatarClone.Init.cs rename to .Deprecated/AvatarCloneTest/AvatarClone/AvatarClone.Init.cs diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.RenderState.cs b/.Deprecated/AvatarCloneTest/AvatarClone/AvatarClone.RenderState.cs similarity index 100% rename from AvatarCloneTest/AvatarClone/AvatarClone.RenderState.cs rename to .Deprecated/AvatarCloneTest/AvatarClone/AvatarClone.RenderState.cs diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.StateSync.cs b/.Deprecated/AvatarCloneTest/AvatarClone/AvatarClone.StateSync.cs similarity index 100% rename from AvatarCloneTest/AvatarClone/AvatarClone.StateSync.cs rename to .Deprecated/AvatarCloneTest/AvatarClone/AvatarClone.StateSync.cs diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.Util.cs b/.Deprecated/AvatarCloneTest/AvatarClone/AvatarClone.Util.cs similarity index 100% rename from AvatarCloneTest/AvatarClone/AvatarClone.Util.cs rename to .Deprecated/AvatarCloneTest/AvatarClone/AvatarClone.Util.cs diff --git a/AvatarCloneTest/AvatarClone/AvatarClone.cs b/.Deprecated/AvatarCloneTest/AvatarClone/AvatarClone.cs similarity index 100% rename from AvatarCloneTest/AvatarClone/AvatarClone.cs rename to .Deprecated/AvatarCloneTest/AvatarClone/AvatarClone.cs diff --git a/AvatarCloneTest/AvatarClone/FPRExclusion/AvatarCloneExclusion.cs b/.Deprecated/AvatarCloneTest/AvatarClone/FPRExclusion/AvatarCloneExclusion.cs similarity index 100% rename from AvatarCloneTest/AvatarClone/FPRExclusion/AvatarCloneExclusion.cs rename to .Deprecated/AvatarCloneTest/AvatarClone/FPRExclusion/AvatarCloneExclusion.cs diff --git a/AvatarCloneTest/AvatarCloneTest.csproj b/.Deprecated/AvatarCloneTest/AvatarCloneTest.csproj similarity index 100% rename from AvatarCloneTest/AvatarCloneTest.csproj rename to .Deprecated/AvatarCloneTest/AvatarCloneTest.csproj diff --git a/AvatarCloneTest/Main.cs b/.Deprecated/AvatarCloneTest/Main.cs similarity index 100% rename from AvatarCloneTest/Main.cs rename to .Deprecated/AvatarCloneTest/Main.cs diff --git a/AvatarCloneTest/Patches.cs b/.Deprecated/AvatarCloneTest/Patches.cs similarity index 100% rename from AvatarCloneTest/Patches.cs rename to .Deprecated/AvatarCloneTest/Patches.cs diff --git a/AvatarCloneTest/Properties/AssemblyInfo.cs b/.Deprecated/AvatarCloneTest/Properties/AssemblyInfo.cs similarity index 100% rename from AvatarCloneTest/Properties/AssemblyInfo.cs rename to .Deprecated/AvatarCloneTest/Properties/AssemblyInfo.cs diff --git a/AvatarCloneTest/README.md b/.Deprecated/AvatarCloneTest/README.md similarity index 100% rename from AvatarCloneTest/README.md rename to .Deprecated/AvatarCloneTest/README.md diff --git a/AvatarCloneTest/format.json b/.Deprecated/AvatarCloneTest/format.json similarity index 100% rename from AvatarCloneTest/format.json rename to .Deprecated/AvatarCloneTest/format.json diff --git a/ChatBoxExtensions/ChatBoxExtensions.csproj b/.Deprecated/ChatBoxExtensions/ChatBoxExtensions.csproj similarity index 100% rename from ChatBoxExtensions/ChatBoxExtensions.csproj rename to .Deprecated/ChatBoxExtensions/ChatBoxExtensions.csproj diff --git a/ChatBoxExtensions/HarmonyPatches.cs b/.Deprecated/ChatBoxExtensions/HarmonyPatches.cs similarity index 100% rename from ChatBoxExtensions/HarmonyPatches.cs rename to .Deprecated/ChatBoxExtensions/HarmonyPatches.cs diff --git a/ChatBoxExtensions/InputModules/InputModuleChatBoxExtensions.cs b/.Deprecated/ChatBoxExtensions/InputModules/InputModuleChatBoxExtensions.cs similarity index 100% rename from ChatBoxExtensions/InputModules/InputModuleChatBoxExtensions.cs rename to .Deprecated/ChatBoxExtensions/InputModules/InputModuleChatBoxExtensions.cs diff --git a/ChatBoxExtensions/Integrations/Base.cs b/.Deprecated/ChatBoxExtensions/Integrations/Base.cs similarity index 100% rename from ChatBoxExtensions/Integrations/Base.cs rename to .Deprecated/ChatBoxExtensions/Integrations/Base.cs diff --git a/ChatBoxExtensions/Integrations/ChatBox.cs b/.Deprecated/ChatBoxExtensions/Integrations/ChatBox.cs similarity index 100% rename from ChatBoxExtensions/Integrations/ChatBox.cs rename to .Deprecated/ChatBoxExtensions/Integrations/ChatBox.cs diff --git a/ChatBoxExtensions/Integrations/ChilloutVRAAS.cs b/.Deprecated/ChatBoxExtensions/Integrations/ChilloutVRAAS.cs similarity index 100% rename from ChatBoxExtensions/Integrations/ChilloutVRAAS.cs rename to .Deprecated/ChatBoxExtensions/Integrations/ChilloutVRAAS.cs diff --git a/ChatBoxExtensions/Integrations/ChilloutVRBase.cs b/.Deprecated/ChatBoxExtensions/Integrations/ChilloutVRBase.cs similarity index 100% rename from ChatBoxExtensions/Integrations/ChilloutVRBase.cs rename to .Deprecated/ChatBoxExtensions/Integrations/ChilloutVRBase.cs diff --git a/ChatBoxExtensions/Integrations/ChilloutVRInput.cs b/.Deprecated/ChatBoxExtensions/Integrations/ChilloutVRInput.cs similarity index 100% rename from ChatBoxExtensions/Integrations/ChilloutVRInput.cs rename to .Deprecated/ChatBoxExtensions/Integrations/ChilloutVRInput.cs diff --git a/ChatBoxExtensions/Integrations/Commands.cs b/.Deprecated/ChatBoxExtensions/Integrations/Commands.cs similarity index 100% rename from ChatBoxExtensions/Integrations/Commands.cs rename to .Deprecated/ChatBoxExtensions/Integrations/Commands.cs diff --git a/ChatBoxExtensions/Integrations/PlayerRagdollMod.cs b/.Deprecated/ChatBoxExtensions/Integrations/PlayerRagdollMod.cs similarity index 100% rename from ChatBoxExtensions/Integrations/PlayerRagdollMod.cs rename to .Deprecated/ChatBoxExtensions/Integrations/PlayerRagdollMod.cs diff --git a/ChatBoxExtensions/Main.cs b/.Deprecated/ChatBoxExtensions/Main.cs similarity index 100% rename from ChatBoxExtensions/Main.cs rename to .Deprecated/ChatBoxExtensions/Main.cs diff --git a/ChatBoxExtensions/Properties/AssemblyInfo.cs b/.Deprecated/ChatBoxExtensions/Properties/AssemblyInfo.cs similarity index 100% rename from ChatBoxExtensions/Properties/AssemblyInfo.cs rename to .Deprecated/ChatBoxExtensions/Properties/AssemblyInfo.cs diff --git a/ChatBoxExtensions/format.json b/.Deprecated/ChatBoxExtensions/format.json similarity index 100% rename from ChatBoxExtensions/format.json rename to .Deprecated/ChatBoxExtensions/format.json diff --git a/CVRLuaToolsExtension/CVRLuaToolsExtension.csproj b/.Experimental/CVRLuaToolsExtension/CVRLuaToolsExtension.csproj similarity index 100% rename from CVRLuaToolsExtension/CVRLuaToolsExtension.csproj rename to .Experimental/CVRLuaToolsExtension/CVRLuaToolsExtension.csproj diff --git a/CVRLuaToolsExtension/LuaToolsExtension/Base/Singleton.cs b/.Experimental/CVRLuaToolsExtension/LuaToolsExtension/Base/Singleton.cs similarity index 100% rename from CVRLuaToolsExtension/LuaToolsExtension/Base/Singleton.cs rename to .Experimental/CVRLuaToolsExtension/LuaToolsExtension/Base/Singleton.cs diff --git a/CVRLuaToolsExtension/LuaToolsExtension/Extensions/CVRBaseLuaBehaviourExtensions.cs b/.Experimental/CVRLuaToolsExtension/LuaToolsExtension/Extensions/CVRBaseLuaBehaviourExtensions.cs similarity index 100% rename from CVRLuaToolsExtension/LuaToolsExtension/Extensions/CVRBaseLuaBehaviourExtensions.cs rename to .Experimental/CVRLuaToolsExtension/LuaToolsExtension/Extensions/CVRBaseLuaBehaviourExtensions.cs diff --git a/CVRLuaToolsExtension/LuaToolsExtension/Extensions/CVRLuaClientBehaviourExtensions.cs b/.Experimental/CVRLuaToolsExtension/LuaToolsExtension/Extensions/CVRLuaClientBehaviourExtensions.cs similarity index 100% rename from CVRLuaToolsExtension/LuaToolsExtension/Extensions/CVRLuaClientBehaviourExtensions.cs rename to .Experimental/CVRLuaToolsExtension/LuaToolsExtension/Extensions/CVRLuaClientBehaviourExtensions.cs diff --git a/CVRLuaToolsExtension/LuaToolsExtension/LuaHotReloadManager.cs b/.Experimental/CVRLuaToolsExtension/LuaToolsExtension/LuaHotReloadManager.cs similarity index 100% rename from CVRLuaToolsExtension/LuaToolsExtension/LuaHotReloadManager.cs rename to .Experimental/CVRLuaToolsExtension/LuaToolsExtension/LuaHotReloadManager.cs diff --git a/CVRLuaToolsExtension/LuaToolsExtension/NamedPipes/NamedPipeServer.cs b/.Experimental/CVRLuaToolsExtension/LuaToolsExtension/NamedPipes/NamedPipeServer.cs similarity index 100% rename from CVRLuaToolsExtension/LuaToolsExtension/NamedPipes/NamedPipeServer.cs rename to .Experimental/CVRLuaToolsExtension/LuaToolsExtension/NamedPipes/NamedPipeServer.cs diff --git a/CVRLuaToolsExtension/LuaToolsExtension/ScriptInfo.cs b/.Experimental/CVRLuaToolsExtension/LuaToolsExtension/ScriptInfo.cs similarity index 100% rename from CVRLuaToolsExtension/LuaToolsExtension/ScriptInfo.cs rename to .Experimental/CVRLuaToolsExtension/LuaToolsExtension/ScriptInfo.cs diff --git a/CVRLuaToolsExtension/Main.cs b/.Experimental/CVRLuaToolsExtension/Main.cs similarity index 100% rename from CVRLuaToolsExtension/Main.cs rename to .Experimental/CVRLuaToolsExtension/Main.cs diff --git a/CVRLuaToolsExtension/Properties/AssemblyInfo.cs b/.Experimental/CVRLuaToolsExtension/Properties/AssemblyInfo.cs similarity index 100% rename from CVRLuaToolsExtension/Properties/AssemblyInfo.cs rename to .Experimental/CVRLuaToolsExtension/Properties/AssemblyInfo.cs diff --git a/CVRLuaToolsExtension/README.md b/.Experimental/CVRLuaToolsExtension/README.md similarity index 100% rename from CVRLuaToolsExtension/README.md rename to .Experimental/CVRLuaToolsExtension/README.md diff --git a/CVRLuaToolsExtension/format.json b/.Experimental/CVRLuaToolsExtension/format.json similarity index 100% rename from CVRLuaToolsExtension/format.json rename to .Experimental/CVRLuaToolsExtension/format.json diff --git a/LuaNetworkVariables/LuaNetworkVariables.csproj b/.Experimental/LuaNetworkVariables/LuaNetworkVariables.csproj similarity index 100% rename from LuaNetworkVariables/LuaNetworkVariables.csproj rename to .Experimental/LuaNetworkVariables/LuaNetworkVariables.csproj diff --git a/LuaNetworkVariables/Main.cs b/.Experimental/LuaNetworkVariables/Main.cs similarity index 100% rename from LuaNetworkVariables/Main.cs rename to .Experimental/LuaNetworkVariables/Main.cs diff --git a/LuaNetworkVariables/NetLuaModule.cs b/.Experimental/LuaNetworkVariables/NetLuaModule.cs similarity index 100% rename from LuaNetworkVariables/NetLuaModule.cs rename to .Experimental/LuaNetworkVariables/NetLuaModule.cs diff --git a/LuaNetworkVariables/NetworkVariables/LuaEventContext.cs b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaEventContext.cs similarity index 100% rename from LuaNetworkVariables/NetworkVariables/LuaEventContext.cs rename to .Experimental/LuaNetworkVariables/NetworkVariables/LuaEventContext.cs diff --git a/LuaNetworkVariables/NetworkVariables/LuaEventTracker.cs b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaEventTracker.cs similarity index 100% rename from LuaNetworkVariables/NetworkVariables/LuaEventTracker.cs rename to .Experimental/LuaNetworkVariables/NetworkVariables/LuaEventTracker.cs diff --git a/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Base.cs b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Base.cs similarity index 100% rename from LuaNetworkVariables/NetworkVariables/LuaNetVarController.Base.cs rename to .Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Base.cs diff --git a/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Networking.cs b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Networking.cs similarity index 100% rename from LuaNetworkVariables/NetworkVariables/LuaNetVarController.Networking.cs rename to .Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Networking.cs diff --git a/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Registration.cs b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Registration.cs similarity index 100% rename from LuaNetworkVariables/NetworkVariables/LuaNetVarController.Registration.cs rename to .Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Registration.cs diff --git a/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Serialization.cs b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Serialization.cs similarity index 100% rename from LuaNetworkVariables/NetworkVariables/LuaNetVarController.Serialization.cs rename to .Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Serialization.cs diff --git a/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Utility.cs b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Utility.cs similarity index 100% rename from LuaNetworkVariables/NetworkVariables/LuaNetVarController.Utility.cs rename to .Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Utility.cs diff --git a/LuaNetworkVariables/Patches.cs b/.Experimental/LuaNetworkVariables/Patches.cs similarity index 100% rename from LuaNetworkVariables/Patches.cs rename to .Experimental/LuaNetworkVariables/Patches.cs diff --git a/LuaNetworkVariables/Properties/AssemblyInfo.cs b/.Experimental/LuaNetworkVariables/Properties/AssemblyInfo.cs similarity index 100% rename from LuaNetworkVariables/Properties/AssemblyInfo.cs rename to .Experimental/LuaNetworkVariables/Properties/AssemblyInfo.cs diff --git a/LuaNetworkVariables/README.md b/.Experimental/LuaNetworkVariables/README.md similarity index 100% rename from LuaNetworkVariables/README.md rename to .Experimental/LuaNetworkVariables/README.md diff --git a/LuaNetworkVariables/SyncedBehaviour/MNSyncedBehaviour.cs b/.Experimental/LuaNetworkVariables/SyncedBehaviour/MNSyncedBehaviour.cs similarity index 100% rename from LuaNetworkVariables/SyncedBehaviour/MNSyncedBehaviour.cs rename to .Experimental/LuaNetworkVariables/SyncedBehaviour/MNSyncedBehaviour.cs diff --git a/LuaNetworkVariables/SyncedBehaviour/TestSyncedBehaviour.cs b/.Experimental/LuaNetworkVariables/SyncedBehaviour/TestSyncedBehaviour.cs similarity index 100% rename from LuaNetworkVariables/SyncedBehaviour/TestSyncedBehaviour.cs rename to .Experimental/LuaNetworkVariables/SyncedBehaviour/TestSyncedBehaviour.cs diff --git a/LuaNetworkVariables/SyncedBehaviour/TestSyncedObject.cs b/.Experimental/LuaNetworkVariables/SyncedBehaviour/TestSyncedObject.cs similarity index 100% rename from LuaNetworkVariables/SyncedBehaviour/TestSyncedObject.cs rename to .Experimental/LuaNetworkVariables/SyncedBehaviour/TestSyncedObject.cs diff --git a/LuaNetworkVariables/format.json b/.Experimental/LuaNetworkVariables/format.json similarity index 100% rename from LuaNetworkVariables/format.json rename to .Experimental/LuaNetworkVariables/format.json diff --git a/LuaTTS/LuaTTS.csproj b/.Experimental/LuaTTS/LuaTTS.csproj similarity index 100% rename from LuaTTS/LuaTTS.csproj rename to .Experimental/LuaTTS/LuaTTS.csproj diff --git a/LuaTTS/Main.cs b/.Experimental/LuaTTS/Main.cs similarity index 100% rename from LuaTTS/Main.cs rename to .Experimental/LuaTTS/Main.cs diff --git a/LuaTTS/Patches.cs b/.Experimental/LuaTTS/Patches.cs similarity index 100% rename from LuaTTS/Patches.cs rename to .Experimental/LuaTTS/Patches.cs diff --git a/LuaTTS/Properties/AssemblyInfo.cs b/.Experimental/LuaTTS/Properties/AssemblyInfo.cs similarity index 100% rename from LuaTTS/Properties/AssemblyInfo.cs rename to .Experimental/LuaTTS/Properties/AssemblyInfo.cs diff --git a/LuaTTS/README.md b/.Experimental/LuaTTS/README.md similarity index 100% rename from LuaTTS/README.md rename to .Experimental/LuaTTS/README.md diff --git a/LuaTTS/TTSLuaModule.cs b/.Experimental/LuaTTS/TTSLuaModule.cs similarity index 100% rename from LuaTTS/TTSLuaModule.cs rename to .Experimental/LuaTTS/TTSLuaModule.cs diff --git a/LuaTTS/format.json b/.Experimental/LuaTTS/format.json similarity index 100% rename from LuaTTS/format.json rename to .Experimental/LuaTTS/format.json diff --git a/OriginShift/Integrations/BTKUI/BtkUiAddon_CAT_OriginShiftMod.cs b/.Experimental/OriginShift/Integrations/BTKUI/BtkUiAddon_CAT_OriginShiftMod.cs similarity index 100% rename from OriginShift/Integrations/BTKUI/BtkUiAddon_CAT_OriginShiftMod.cs rename to .Experimental/OriginShift/Integrations/BTKUI/BtkUiAddon_CAT_OriginShiftMod.cs diff --git a/OriginShift/Integrations/BTKUI/BtkuiAddon.cs b/.Experimental/OriginShift/Integrations/BTKUI/BtkuiAddon.cs similarity index 100% rename from OriginShift/Integrations/BTKUI/BtkuiAddon.cs rename to .Experimental/OriginShift/Integrations/BTKUI/BtkuiAddon.cs diff --git a/OriginShift/Integrations/BTKUI/BtkuiAddon_Utils.cs b/.Experimental/OriginShift/Integrations/BTKUI/BtkuiAddon_Utils.cs similarity index 100% rename from OriginShift/Integrations/BTKUI/BtkuiAddon_Utils.cs rename to .Experimental/OriginShift/Integrations/BTKUI/BtkuiAddon_Utils.cs diff --git a/OriginShift/Integrations/Ragdoll/RagdollAddon.cs b/.Experimental/OriginShift/Integrations/Ragdoll/RagdollAddon.cs similarity index 100% rename from OriginShift/Integrations/Ragdoll/RagdollAddon.cs rename to .Experimental/OriginShift/Integrations/Ragdoll/RagdollAddon.cs diff --git a/OriginShift/Integrations/ThirdPerson/ThirdPersonAddon.cs b/.Experimental/OriginShift/Integrations/ThirdPerson/ThirdPersonAddon.cs similarity index 100% rename from OriginShift/Integrations/ThirdPerson/ThirdPersonAddon.cs rename to .Experimental/OriginShift/Integrations/ThirdPerson/ThirdPersonAddon.cs diff --git a/OriginShift/Main.cs b/.Experimental/OriginShift/Main.cs similarity index 100% rename from OriginShift/Main.cs rename to .Experimental/OriginShift/Main.cs diff --git a/OriginShift/ModSettings.cs b/.Experimental/OriginShift/ModSettings.cs similarity index 100% rename from OriginShift/ModSettings.cs rename to .Experimental/OriginShift/ModSettings.cs diff --git a/OriginShift/Networking/ModNetwork.cs b/.Experimental/OriginShift/Networking/ModNetwork.cs similarity index 100% rename from OriginShift/Networking/ModNetwork.cs rename to .Experimental/OriginShift/Networking/ModNetwork.cs diff --git a/OriginShift/OriginShift.csproj b/.Experimental/OriginShift/OriginShift.csproj similarity index 100% rename from OriginShift/OriginShift.csproj rename to .Experimental/OriginShift/OriginShift.csproj diff --git a/OriginShift/OriginShift/Components/Chunk/ChunkController.cs b/.Experimental/OriginShift/OriginShift/Components/Chunk/ChunkController.cs similarity index 100% rename from OriginShift/OriginShift/Components/Chunk/ChunkController.cs rename to .Experimental/OriginShift/OriginShift/Components/Chunk/ChunkController.cs diff --git a/OriginShift/OriginShift/Components/Chunk/ChunkCreator.cs b/.Experimental/OriginShift/OriginShift/Components/Chunk/ChunkCreator.cs similarity index 100% rename from OriginShift/OriginShift/Components/Chunk/ChunkCreator.cs rename to .Experimental/OriginShift/OriginShift/Components/Chunk/ChunkCreator.cs diff --git a/OriginShift/OriginShift/Components/Chunk/ChunkListener.cs b/.Experimental/OriginShift/OriginShift/Components/Chunk/ChunkListener.cs similarity index 100% rename from OriginShift/OriginShift/Components/Chunk/ChunkListener.cs rename to .Experimental/OriginShift/OriginShift/Components/Chunk/ChunkListener.cs diff --git a/OriginShift/OriginShift/Components/OriginShiftController.cs b/.Experimental/OriginShift/OriginShift/Components/OriginShiftController.cs similarity index 100% rename from OriginShift/OriginShift/Components/OriginShiftController.cs rename to .Experimental/OriginShift/OriginShift/Components/OriginShiftController.cs diff --git a/OriginShift/OriginShift/Components/Receivers/OriginShiftEventReceiver.cs b/.Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftEventReceiver.cs similarity index 100% rename from OriginShift/OriginShift/Components/Receivers/OriginShiftEventReceiver.cs rename to .Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftEventReceiver.cs diff --git a/OriginShift/OriginShift/Components/Receivers/OriginShiftParticleSystemReceiver.cs b/.Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftParticleSystemReceiver.cs similarity index 100% rename from OriginShift/OriginShift/Components/Receivers/OriginShiftParticleSystemReceiver.cs rename to .Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftParticleSystemReceiver.cs diff --git a/OriginShift/OriginShift/Components/Receivers/OriginShiftRigidbodyReceiver.cs b/.Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftRigidbodyReceiver.cs similarity index 100% rename from OriginShift/OriginShift/Components/Receivers/OriginShiftRigidbodyReceiver.cs rename to .Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftRigidbodyReceiver.cs diff --git a/OriginShift/OriginShift/Components/Receivers/OriginShiftTrailRendererReceiver.cs b/.Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftTrailRendererReceiver.cs similarity index 100% rename from OriginShift/OriginShift/Components/Receivers/OriginShiftTrailRendererReceiver.cs rename to .Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftTrailRendererReceiver.cs diff --git a/OriginShift/OriginShift/Components/Receivers/OriginShiftTransformReceiver.cs b/.Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftTransformReceiver.cs similarity index 100% rename from OriginShift/OriginShift/Components/Receivers/OriginShiftTransformReceiver.cs rename to .Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftTransformReceiver.cs diff --git a/OriginShift/OriginShift/Extensions/BetterBetterCharacterControllerExtensions.cs b/.Experimental/OriginShift/OriginShift/Extensions/BetterBetterCharacterControllerExtensions.cs similarity index 100% rename from OriginShift/OriginShift/Extensions/BetterBetterCharacterControllerExtensions.cs rename to .Experimental/OriginShift/OriginShift/Extensions/BetterBetterCharacterControllerExtensions.cs diff --git a/OriginShift/OriginShift/Extensions/PlayerSetupExtensions.cs b/.Experimental/OriginShift/OriginShift/Extensions/PlayerSetupExtensions.cs similarity index 100% rename from OriginShift/OriginShift/Extensions/PlayerSetupExtensions.cs rename to .Experimental/OriginShift/OriginShift/Extensions/PlayerSetupExtensions.cs diff --git a/OriginShift/OriginShift/Hacks/OcclusionCullingHack.cs b/.Experimental/OriginShift/OriginShift/Hacks/OcclusionCullingHack.cs similarity index 100% rename from OriginShift/OriginShift/Hacks/OcclusionCullingHack.cs rename to .Experimental/OriginShift/OriginShift/Hacks/OcclusionCullingHack.cs diff --git a/OriginShift/OriginShift/Hacks/OriginShiftOcclusionCullingDisabler.cs b/.Experimental/OriginShift/OriginShift/Hacks/OriginShiftOcclusionCullingDisabler.cs similarity index 100% rename from OriginShift/OriginShift/Hacks/OriginShiftOcclusionCullingDisabler.cs rename to .Experimental/OriginShift/OriginShift/Hacks/OriginShiftOcclusionCullingDisabler.cs diff --git a/OriginShift/OriginShift/OriginShiftManager.cs b/.Experimental/OriginShift/OriginShift/OriginShiftManager.cs similarity index 100% rename from OriginShift/OriginShift/OriginShiftManager.cs rename to .Experimental/OriginShift/OriginShift/OriginShiftManager.cs diff --git a/OriginShift/OriginShift/Player/Dynamics/OriginShiftDbAvatarReceiver.cs b/.Experimental/OriginShift/OriginShift/Player/Dynamics/OriginShiftDbAvatarReceiver.cs similarity index 100% rename from OriginShift/OriginShift/Player/Dynamics/OriginShiftDbAvatarReceiver.cs rename to .Experimental/OriginShift/OriginShift/Player/Dynamics/OriginShiftDbAvatarReceiver.cs diff --git a/OriginShift/OriginShift/Player/OriginShiftMonitor.cs b/.Experimental/OriginShift/OriginShift/Player/OriginShiftMonitor.cs similarity index 100% rename from OriginShift/OriginShift/Player/OriginShiftMonitor.cs rename to .Experimental/OriginShift/OriginShift/Player/OriginShiftMonitor.cs diff --git a/OriginShift/OriginShift/Player/OriginShiftNetIkReceiver.cs b/.Experimental/OriginShift/OriginShift/Player/OriginShiftNetIkReceiver.cs similarity index 100% rename from OriginShift/OriginShift/Player/OriginShiftNetIkReceiver.cs rename to .Experimental/OriginShift/OriginShift/Player/OriginShiftNetIkReceiver.cs diff --git a/OriginShift/OriginShift/Player/OriginShiftObjectSyncReceiver.cs b/.Experimental/OriginShift/OriginShift/Player/OriginShiftObjectSyncReceiver.cs similarity index 100% rename from OriginShift/OriginShift/Player/OriginShiftObjectSyncReceiver.cs rename to .Experimental/OriginShift/OriginShift/Player/OriginShiftObjectSyncReceiver.cs diff --git a/OriginShift/OriginShift/Player/OriginShiftPickupObjectReceiver.cs b/.Experimental/OriginShift/OriginShift/Player/OriginShiftPickupObjectReceiver.cs similarity index 100% rename from OriginShift/OriginShift/Player/OriginShiftPickupObjectReceiver.cs rename to .Experimental/OriginShift/OriginShift/Player/OriginShiftPickupObjectReceiver.cs diff --git a/OriginShift/OriginShift/Player/OriginShiftSpawnableReceiver.cs b/.Experimental/OriginShift/OriginShift/Player/OriginShiftSpawnableReceiver.cs similarity index 100% rename from OriginShift/OriginShift/Player/OriginShiftSpawnableReceiver.cs rename to .Experimental/OriginShift/OriginShift/Player/OriginShiftSpawnableReceiver.cs diff --git a/OriginShift/OriginShift/Utility/DebugTextDisplay.cs b/.Experimental/OriginShift/OriginShift/Utility/DebugTextDisplay.cs similarity index 100% rename from OriginShift/OriginShift/Utility/DebugTextDisplay.cs rename to .Experimental/OriginShift/OriginShift/Utility/DebugTextDisplay.cs diff --git a/OriginShift/OriginShift/Utility/RendererReflectionUtility.cs b/.Experimental/OriginShift/OriginShift/Utility/RendererReflectionUtility.cs similarity index 100% rename from OriginShift/OriginShift/Utility/RendererReflectionUtility.cs rename to .Experimental/OriginShift/OriginShift/Utility/RendererReflectionUtility.cs diff --git a/OriginShift/Patches.cs b/.Experimental/OriginShift/Patches.cs similarity index 100% rename from OriginShift/Patches.cs rename to .Experimental/OriginShift/Patches.cs diff --git a/OriginShift/Properties/AssemblyInfo.cs b/.Experimental/OriginShift/Properties/AssemblyInfo.cs similarity index 100% rename from OriginShift/Properties/AssemblyInfo.cs rename to .Experimental/OriginShift/Properties/AssemblyInfo.cs diff --git a/OriginShift/README.md b/.Experimental/OriginShift/README.md similarity index 100% rename from OriginShift/README.md rename to .Experimental/OriginShift/README.md diff --git a/OriginShift/Resources/OriginShift-Icon-Active.png b/.Experimental/OriginShift/Resources/OriginShift-Icon-Active.png similarity index 100% rename from OriginShift/Resources/OriginShift-Icon-Active.png rename to .Experimental/OriginShift/Resources/OriginShift-Icon-Active.png diff --git a/OriginShift/Resources/OriginShift-Icon-Forced.png b/.Experimental/OriginShift/Resources/OriginShift-Icon-Forced.png similarity index 100% rename from OriginShift/Resources/OriginShift-Icon-Forced.png rename to .Experimental/OriginShift/Resources/OriginShift-Icon-Forced.png diff --git a/OriginShift/Resources/OriginShift-Icon-Inactive.png b/.Experimental/OriginShift/Resources/OriginShift-Icon-Inactive.png similarity index 100% rename from OriginShift/Resources/OriginShift-Icon-Inactive.png rename to .Experimental/OriginShift/Resources/OriginShift-Icon-Inactive.png diff --git a/OriginShift/format.json b/.Experimental/OriginShift/format.json similarity index 100% rename from OriginShift/format.json rename to .Experimental/OriginShift/format.json diff --git a/ScriptingSpoofer/Main.cs b/.Experimental/ScriptingSpoofer/Main.cs similarity index 100% rename from ScriptingSpoofer/Main.cs rename to .Experimental/ScriptingSpoofer/Main.cs diff --git a/ScriptingSpoofer/Properties/AssemblyInfo.cs b/.Experimental/ScriptingSpoofer/Properties/AssemblyInfo.cs similarity index 100% rename from ScriptingSpoofer/Properties/AssemblyInfo.cs rename to .Experimental/ScriptingSpoofer/Properties/AssemblyInfo.cs diff --git a/ScriptingSpoofer/README.md b/.Experimental/ScriptingSpoofer/README.md similarity index 100% rename from ScriptingSpoofer/README.md rename to .Experimental/ScriptingSpoofer/README.md diff --git a/ScriptingSpoofer/ScriptingSpoofer.csproj b/.Experimental/ScriptingSpoofer/ScriptingSpoofer.csproj similarity index 100% rename from ScriptingSpoofer/ScriptingSpoofer.csproj rename to .Experimental/ScriptingSpoofer/ScriptingSpoofer.csproj diff --git a/ScriptingSpoofer/format.json b/.Experimental/ScriptingSpoofer/format.json similarity index 100% rename from ScriptingSpoofer/format.json rename to .Experimental/ScriptingSpoofer/format.json diff --git a/.gitignore b/.gitignore index 2abd364..e3092f6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore # NAK -.Experimental/ +.Blackbox/ # Nstrip & ManagedLibs stuff NStrip.exe diff --git a/BetterContentLoading/BetterContentLoading.csproj b/BetterContentLoading/BetterContentLoading.csproj deleted file mode 100644 index 67cef19..0000000 --- a/BetterContentLoading/BetterContentLoading.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - net48 - NAK.BetterContentLoading - - - - ..\.ManagedLibs\BTKUILib.dll - - - ..\.ManagedLibs\TheClapper.dll - - - diff --git a/BetterContentLoading/BetterContentLoading/BetterDownloadManager.cs b/BetterContentLoading/BetterContentLoading/BetterDownloadManager.cs deleted file mode 100644 index 749483f..0000000 --- a/BetterContentLoading/BetterContentLoading/BetterDownloadManager.cs +++ /dev/null @@ -1,210 +0,0 @@ -using ABI_RC.Core.InteractionSystem; -using ABI_RC.Core.Networking.IO.Instancing; -using ABI_RC.Core.Networking.IO.Social; -using ABI_RC.Core.Player; -using ABI_RC.Core.Savior; -using ABI_RC.Core.Util; -using ABI_RC.Systems.GameEventSystem; -using NAK.BetterContentLoading.Queue; -using UnityEngine; - -namespace NAK.BetterContentLoading; - -// Download world -> connect to instance -> receive all Avatar data -// -> initial connection to instance -> receive all props data - -// We receive Prop download data only after we have connected to the instance. Avatar data we seem to receive -// prior to our initial connection event firing. - -public class BetterDownloadManager -{ - #region Singleton - - private static BetterDownloadManager _instance; - public static BetterDownloadManager Instance => _instance ??= new BetterDownloadManager(); - - #endregion Singleton - - #region Constructor - - private BetterDownloadManager() - { - _downloadProcessor = new DownloadProcessor(); - - _worldQueue = new WorldDownloadQueue(this); // Only one world at a time - _avatarQueue = new AvatarDownloadQueue(this); // Up to 3 avatars at once - _propQueue = new PropDownloadQueue(this); // Up to 2 props at once - - // Set to 100MBs by default - MaxDownloadBandwidth = 100 * 1024 * 1024; - - CVRGameEventSystem.Instance.OnConnected.AddListener(_ => - { - if (!Instances.IsReconnecting) OnInitialConnectionToInstance(); - }); - } - - #endregion Constructor - - #region Settings - - /// Log debug messages - public bool IsDebugEnabled { get; set; } = true; - - /// Prioritize friends first in download queue - public bool PrioritizeFriends { get; set; } = true; - - /// Prioritize content closest to player first in download queue - public bool PrioritizeDistance { get; set; } = true; - public float PriorityDownloadDistance { get; set; } = 25f; - - public int MaxDownloadBandwidth - { - get => _downloadProcessor.MaxDownloadBandwidth; - set => _downloadProcessor.MaxDownloadBandwidth = value; - } - - #endregion Settings - - private readonly DownloadProcessor _downloadProcessor; - - private readonly AvatarDownloadQueue _avatarQueue; - private readonly PropDownloadQueue _propQueue; - private readonly WorldDownloadQueue _worldQueue; - - #region Game Events - - private void OnInitialConnectionToInstance() - { - if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg("Initial connection established."); - // await few seconds before chewing through the download queue, to allow for download priorities to be set - // once we have received most of the data from the server - } - - #endregion Game Events - - #region Public Queue Methods - - public void QueueAvatarDownload( - in DownloadInfo info, - string playerId, - CVRLoadingAvatarController loadingController) - { - if (IsDebugEnabled) - { - BetterContentLoadingMod.Logger.Msg( - $"Queuing Avatar Download:\n{info.GetLogString()}\n" + - $"PlayerId: {playerId}\n" + - $"LoadingController: {loadingController}"); - } - - _avatarQueue.QueueDownload(in info, playerId); - } - - /// - /// Queues a prop download. - /// - /// The download info. - /// The instance ID for the prop. - /// The user who spawned the prop. - public void QueuePropDownload( - in DownloadInfo info, - string instanceId, - string spawnerId) - { - if (IsDebugEnabled) - { - BetterContentLoadingMod.Logger.Msg( - $"Queuing Prop Download:\n{info.GetLogString()}\n" + - $"InstanceId: {instanceId}\n" + - $"SpawnerId: {spawnerId}"); - } - - _propQueue.QueueDownload(in info, instanceId, spawnerId); - } - - /// - /// Queues a world download. - /// - /// Download info. - /// Whether to load into this world once downloaded. - /// Whether the home world is requested. - public void QueueWorldDownload( - in DownloadInfo info, - bool joinOnComplete, - bool isHomeRequested) - { - if (IsDebugEnabled) - { - BetterContentLoadingMod.Logger.Msg( - $"Queuing World Download:\n{info.GetLogString()}\n" + - $"JoinOnComplete: {joinOnComplete}\n" + - $"IsHomeRequested: {isHomeRequested}"); - } - - _worldQueue.QueueDownload(in info, joinOnComplete, isHomeRequested); - } - - #endregion Public Queue Methods - - #region Internal Methods - - internal Task ProcessDownload(DownloadInfo info, Action progressCallback = null) - { - return _downloadProcessor.ProcessDownload(info); - } - - #endregion Internal Methods - - #region Private Helper Methods - - internal static bool TryGetPlayerEntity(string playerId, out CVRPlayerEntity playerEntity) - { - CVRPlayerEntity player = CVRPlayerManager.Instance.NetworkPlayers.Find(p => p.Uuid == playerId); - if (player == null) - { - // BetterContentLoadingMod.Logger.Error($"Player entity not found for ID: {playerId}"); - playerEntity = null; - return false; - } - playerEntity = player; - return true; - } - - internal static bool TryGetPropData(string instanceId, out CVRSyncHelper.PropData propData) - { - CVRSyncHelper.PropData prop = CVRSyncHelper.Props.Find(p => p.InstanceId == instanceId); - if (prop == null) - { - // BetterContentLoadingMod.Logger.Error($"Prop data not found for ID: {instanceId}"); - propData = null; - return false; - } - propData = prop; - return true; - } - - internal static bool IsPlayerLocal(string playerId) - { - return playerId == MetaPort.Instance.ownerId; - } - - internal static bool IsPlayerFriend(string playerId) - { - return Friends.FriendsWith(playerId); - } - - internal bool IsPlayerWithinPriorityDistance(CVRPlayerEntity player) - { - if (player.PuppetMaster == null) return false; - return player.PuppetMaster.animatorManager.DistanceTo < PriorityDownloadDistance; - } - - internal bool IsPropWithinPriorityDistance(CVRSyncHelper.PropData prop) - { - Vector3 propPosition = new(prop.PositionX, prop.PositionY, prop.PositionZ); - return Vector3.Distance(propPosition, PlayerSetup.Instance.GetPlayerPosition()) < PriorityDownloadDistance; - } - - #endregion Private Helper Methods -} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/DownloadInfo.cs b/BetterContentLoading/BetterContentLoading/DownloadInfo.cs deleted file mode 100644 index 038f6bf..0000000 --- a/BetterContentLoading/BetterContentLoading/DownloadInfo.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.Security.Cryptography; -using System.Text; -using ABI_RC.Core.Networking.API.Responses; - -namespace NAK.BetterContentLoading; - -public readonly struct DownloadInfo -{ - public readonly string AssetId; - public readonly string AssetUrl; - public readonly string FileId; - public readonly long FileSize; - public readonly string FileKey; - public readonly string FileHash; - public readonly int CompatibilityVersion; - public readonly int EncryptionAlgorithm; - public readonly UgcTagsData TagsData; - - public readonly string DownloadId; - - public DownloadInfo( - string assetId, string assetUrl, string fileId, - long fileSize, string fileKey, string fileHash, - int compatibilityVersion, int encryptionAlgorithm, - UgcTagsData tagsData) - { - AssetId = assetId + "meow"; - AssetUrl = assetUrl; - FileId = fileId; - FileSize = fileSize; - FileKey = fileKey; - FileHash = fileHash; - CompatibilityVersion = compatibilityVersion; - EncryptionAlgorithm = encryptionAlgorithm; - TagsData = tagsData; - - using SHA256 sha = SHA256.Create(); - StringBuilder sb = new(); - sb.Append(assetId) - .Append('|').Append(assetUrl) - .Append('|').Append(fileId) - .Append('|').Append(fileSize) - .Append('|').Append(fileKey) - .Append('|').Append(fileHash) - .Append('|').Append(compatibilityVersion) - .Append('|').Append(encryptionAlgorithm); - - var bytes = Encoding.UTF8.GetBytes(sb.ToString()); - var hash = sha.ComputeHash(bytes); - DownloadId = Convert.ToBase64String(hash); - } - - public string GetLogString() => - $"AssetId: {AssetId}\n" + - $"DownloadId: {DownloadId}\n" + - $"AssetUrl: {AssetUrl}\n" + - $"FileId: {FileId}\n" + - $"FileSize: {FileSize}\n" + - $"FileKey: {FileKey}\n" + - $"FileHash: {FileHash}\n" + - $"CompatibilityVersion: {CompatibilityVersion}\n" + - $"EncryptionAlgorithm: {EncryptionAlgorithm}"; -} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/DownloadProcessor.cs b/BetterContentLoading/BetterContentLoading/DownloadProcessor.cs deleted file mode 100644 index e77acdc..0000000 --- a/BetterContentLoading/BetterContentLoading/DownloadProcessor.cs +++ /dev/null @@ -1,152 +0,0 @@ -using System.Net.Http; -using ABI_RC.Core; -using ABI_RC.Core.IO.AssetManagement; - -namespace NAK.BetterContentLoading; - -public class DownloadProcessor -{ - private readonly HttpClient _client = new(); - private readonly SemaphoreSlim _bandwidthSemaphore = new(1); - private long _bytesReadLastSecond; - - private int _maxDownloadBandwidth = 10 * 1024 * 1024; // Default 10MB/s - private const int MinBufferSize = 16384; // 16KB min buffer - private const long ThrottleThreshold = 25 * 1024 * 1024; // 25MB threshold for throttling - private const long KnownSizeDifference = 1000; // API reported size is 1000 bytes larger than actual content - - public int MaxDownloadBandwidth - { - get => _maxDownloadBandwidth; - set => _maxDownloadBandwidth = Math.Max(1024 * 1024, value); - } - - private int ActiveDownloads { get; set; } - private int CurrentBandwidthPerDownload => MaxDownloadBandwidth / Math.Max(1, ActiveDownloads); - - public int GetProgress(string downloadId) => _downloadProgress.GetValueOrDefault(downloadId, 0); - private readonly Dictionary _downloadProgress = new(); - - public async Task ProcessDownload(DownloadInfo downloadInfo) - { - try - { - if (await CacheManager.Instance.IsCachedFileUpToDate( - downloadInfo.AssetId, - downloadInfo.FileId, - downloadInfo.FileHash)) - return true; - - var filePath = CacheManager.Instance.GetCachePath(downloadInfo.AssetId, downloadInfo.FileId); - if (!CVRTools.HasEnoughDiskSpace(filePath, downloadInfo.FileSize)) - { - BetterContentLoadingMod.Logger.Error($"Not enough disk space to download {downloadInfo.AssetId}"); - return false; - } - - CacheManager.Instance.EnsureCacheDirectoryExists(downloadInfo.AssetId); - - bool success = false; - Exception lastException = null; - - for (int attempt = 0; attempt <= 1; attempt++) - { - try - { - if (attempt > 0) - await Task.Delay(1000); - - success = await DownloadWithBandwidthLimit(downloadInfo, filePath); - if (success) break; - } - catch (Exception ex) - { - lastException = ex; - } - } - - if (!success && lastException != null) - BetterContentLoadingMod.Logger.Error($"Failed to download {downloadInfo.AssetId}: {lastException}"); - - _downloadProgress.Remove(downloadInfo.DownloadId); - return success; - } - catch (Exception ex) - { - BetterContentLoadingMod.Logger.Error($"Error processing download for {downloadInfo.AssetId}: {ex}"); - _downloadProgress.Remove(downloadInfo.DownloadId); - return false; - } - } - - private async Task DownloadWithBandwidthLimit(DownloadInfo downloadInfo, string filePath) - { - await _bandwidthSemaphore.WaitAsync(); - try { ActiveDownloads++; } - finally { _bandwidthSemaphore.Release(); } - - string tempFilePath = filePath + ".download"; - try - { - using var response = await _client.GetAsync(downloadInfo.AssetUrl, HttpCompletionOption.ResponseHeadersRead); - if (!response.IsSuccessStatusCode) - return false; - - var expectedContentSize = downloadInfo.FileSize - KnownSizeDifference; - using var stream = await response.Content.ReadAsStreamAsync(); - using var fileStream = File.Open(tempFilePath, FileMode.Create); - - var isEligibleForThrottle = downloadInfo.FileSize >= ThrottleThreshold; - var totalBytesRead = 0L; - byte[] buffer = null; - - while (true) - { - var lengthToRead = isEligibleForThrottle ? MinBufferSize : CurrentBandwidthPerDownload; - if (buffer == null || lengthToRead != buffer.Length) - buffer = new byte[lengthToRead]; - - var bytesRead = await stream.ReadAsync(buffer, 0, lengthToRead); - if (bytesRead == 0) break; - - if (isEligibleForThrottle) - Interlocked.Add(ref _bytesReadLastSecond, bytesRead); - - fileStream.Write(buffer, 0, bytesRead); - totalBytesRead += bytesRead; - - var progress = (int)(((float)totalBytesRead / expectedContentSize) * 100f); - _downloadProgress[downloadInfo.DownloadId] = Math.Clamp(progress, 0, 100); - } - - fileStream.Flush(); - - var fileInfo = new FileInfo(tempFilePath); - if (fileInfo.Length != expectedContentSize) - return false; - - if (File.Exists(filePath)) - File.Delete(filePath); - File.Move(tempFilePath, filePath); - - CacheManager.Instance.QueuePrune(); - return true; - } - finally - { - await _bandwidthSemaphore.WaitAsync(); - try { ActiveDownloads--; } - finally { _bandwidthSemaphore.Release(); } - - try - { - if (File.Exists(tempFilePath)) - File.Delete(tempFilePath); - } - catch - { - // Ignore cleanup errors - } - } - } -} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/DownloadQueue/AvatarDownloadQueue.cs b/BetterContentLoading/BetterContentLoading/DownloadQueue/AvatarDownloadQueue.cs deleted file mode 100644 index 60060c5..0000000 --- a/BetterContentLoading/BetterContentLoading/DownloadQueue/AvatarDownloadQueue.cs +++ /dev/null @@ -1,83 +0,0 @@ -namespace NAK.BetterContentLoading.Queue; - -public class AvatarDownloadQueue : ContentDownloadQueueBase -{ - public AvatarDownloadQueue(BetterDownloadManager manager) : base(manager, 3) { } - - public void QueueDownload(in DownloadInfo info, string playerId, Action onComplete = null) - { - float priority = CalculateAvatarPriority(in info, playerId); - QueueDownload(in info, playerId, priority, onComplete); - } - - protected override async Task ProcessDownload(DownloadInfo info) - { - await base.ProcessDownload(info); - } - - protected override void OnDownloadProgress(string downloadId, float progress) - { - if (DownloadOwners.TryGetValue(downloadId, out var owners)) - { - foreach (var playerId in owners) - { - if (BetterDownloadManager.IsPlayerLocal(playerId)) - { - // Update loading progress on local player - BetterContentLoadingMod.Logger.Msg($"Progress for local player ({playerId}): {progress:P}"); - continue; - } - if (BetterDownloadManager.TryGetPlayerEntity(playerId, out var player)) - { - // Update loading progress on avatar controller if needed - BetterContentLoadingMod.Logger.Msg($"Progress for {player.Username} ({playerId}): {progress:P}"); - } - } - } - } - - protected override float RecalculatePriority(string downloadId) - { - if (!DownloadOwners.TryGetValue(downloadId, out var owners)) - return float.MaxValue; - - float lowestPriority = float.MaxValue; - DownloadInfo? downloadInfo = null; - - // Find the queue item to get the DownloadInfo - var queueItem = Queue.Find(x => x.Info.DownloadId == downloadId); - if (queueItem.Info.AssetId != null) - downloadInfo = queueItem.Info; - - if (downloadInfo == null) - return lowestPriority; - - // Calculate priority for each owner and use the lowest (highest priority) value - foreach (var playerId in owners) - { - var priority = CalculateAvatarPriority(downloadInfo.Value, playerId); - lowestPriority = Math.Min(lowestPriority, priority); - } - - return lowestPriority; - } - - private float CalculateAvatarPriority(in DownloadInfo info, string playerId) - { - float priority = info.FileSize; - - if (BetterDownloadManager.IsPlayerLocal(playerId)) - return 0f; - - if (!BetterDownloadManager.TryGetPlayerEntity(playerId, out var player)) - return priority; - - if (Manager.PrioritizeFriends && BetterDownloadManager.IsPlayerFriend(playerId)) - priority *= 0.5f; - - if (Manager.PrioritizeDistance && Manager.IsPlayerWithinPriorityDistance(player)) - priority *= 0.75f; - - return priority; - } -} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/DownloadQueue/ContentDownloadQueueBase.cs b/BetterContentLoading/BetterContentLoading/DownloadQueue/ContentDownloadQueueBase.cs deleted file mode 100644 index 66e366b..0000000 --- a/BetterContentLoading/BetterContentLoading/DownloadQueue/ContentDownloadQueueBase.cs +++ /dev/null @@ -1,177 +0,0 @@ -namespace NAK.BetterContentLoading.Queue; - -public abstract class ContentDownloadQueueBase -{ - protected readonly struct QueueItem - { - public readonly DownloadInfo Info; - public readonly float Priority; - public readonly Action OnComplete; // Callback with (downloadId, ownerId) - - public QueueItem(DownloadInfo info, float priority, Action onComplete) - { - Info = info; - Priority = priority; - OnComplete = onComplete; - } - } - - protected readonly List Queue = new(); - private readonly HashSet ActiveDownloads = new(); // By DownloadId - protected readonly Dictionary> DownloadOwners = new(); // DownloadId -> Set of OwnerIds - private readonly SemaphoreSlim DownloadSemaphore; - protected readonly BetterDownloadManager Manager; - - protected ContentDownloadQueueBase(BetterDownloadManager manager, int maxParallelDownloads) - { - Manager = manager; - DownloadSemaphore = new SemaphoreSlim(maxParallelDownloads); - } - - protected void QueueDownload(in DownloadInfo info, string ownerId, float priority, Action onComplete) - { - if (Manager.IsDebugEnabled) - BetterContentLoadingMod.Logger.Msg($"Attempting to queue download for {info.AssetId} (DownloadId: {info.DownloadId})"); - - // Add to owners tracking - if (!DownloadOwners.TryGetValue(info.DownloadId, out var owners)) - { - owners = new HashSet(); - DownloadOwners[info.DownloadId] = owners; - } - owners.Add(ownerId); - - // If already downloading, just add the owner and callback - if (ActiveDownloads.Contains(info.DownloadId)) - { - if (Manager.IsDebugEnabled) - BetterContentLoadingMod.Logger.Msg($"Already downloading {info.DownloadId}, added owner {ownerId}"); - return; - } - - DownloadInfo downloadInfo = info; - var existingIndex = Queue.FindIndex(x => x.Info.DownloadId == downloadInfo.DownloadId); - if (existingIndex >= 0) - { - // Update priority if needed based on new owner - var newPriority = RecalculatePriority(info.DownloadId); - Queue[existingIndex] = new QueueItem(info, newPriority, onComplete); - SortQueue(); - return; - } - - Queue.Add(new QueueItem(info, priority, onComplete)); - SortQueue(); - TryStartNextDownload(); - } - - public void RemoveOwner(string downloadId, string ownerId) - { - if (!DownloadOwners.TryGetValue(downloadId, out var owners)) - return; - - owners.Remove(ownerId); - - if (owners.Count == 0) - { - // No more owners, cancel the download - DownloadOwners.Remove(downloadId); - CancelDownload(downloadId); - } - else if (!ActiveDownloads.Contains(downloadId)) - { - // Still has owners and is queued, recalculate priority - var existingIndex = Queue.FindIndex(x => x.Info.DownloadId == downloadId); - if (existingIndex >= 0) - { - var item = Queue[existingIndex]; - var newPriority = RecalculatePriority(downloadId); - Queue[existingIndex] = new QueueItem(item.Info, newPriority, item.OnComplete); - SortQueue(); - } - } - } - - protected virtual async void TryStartNextDownload() - { - try - { - if (Queue.Count == 0) return; - - await DownloadSemaphore.WaitAsync(); - - if (Queue.Count > 0) - { - var item = Queue[0]; - Queue.RemoveAt(0); - - // Double check we still have owners before starting download - if (!DownloadOwners.TryGetValue(item.Info.DownloadId, out var owners) || owners.Count == 0) - { - DownloadSemaphore.Release(); - TryStartNextDownload(); - return; - } - - ActiveDownloads.Add(item.Info.DownloadId); - - try - { - await ProcessDownload(item.Info); - BetterContentLoadingMod.Logger.Msg($"Download completed for {item.Info.DownloadId}"); - - // Notify all owners of completion - if (DownloadOwners.TryGetValue(item.Info.DownloadId, out owners)) - { - foreach (var owner in owners) - { - item.OnComplete?.Invoke(item.Info.DownloadId, owner); - } - } - } - catch (Exception ex) - { - if (Manager.IsDebugEnabled) - BetterContentLoadingMod.Logger.Error($"Download failed for {item.Info.DownloadId}: {ex}"); - } - finally - { - ActiveDownloads.Remove(item.Info.DownloadId); - DownloadSemaphore.Release(); - TryStartNextDownload(); - } - } - else - { - DownloadSemaphore.Release(); - } - } - catch (Exception e) - { - BetterContentLoadingMod.Logger.Error($"Error in TryStartNextDownload: {e}"); - } - } - - protected virtual async Task ProcessDownload(DownloadInfo info) - { - bool success = await Manager.ProcessDownload(info); - - if (!success) - throw new Exception($"Failed to download {info.AssetId}"); - } - - protected abstract void OnDownloadProgress(string downloadId, float progress); - - protected abstract float RecalculatePriority(string downloadId); - - protected virtual void SortQueue() - { - Queue.Sort((a, b) => a.Priority.CompareTo(b.Priority)); - } - - protected virtual void CancelDownload(string downloadId) - { - Queue.RemoveAll(x => x.Info.DownloadId == downloadId); - if (ActiveDownloads.Remove(downloadId)) DownloadSemaphore.Release(); - } -} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/DownloadQueue/PropDownloadQueue.cs b/BetterContentLoading/BetterContentLoading/DownloadQueue/PropDownloadQueue.cs deleted file mode 100644 index f100e0b..0000000 --- a/BetterContentLoading/BetterContentLoading/DownloadQueue/PropDownloadQueue.cs +++ /dev/null @@ -1,81 +0,0 @@ -using ABI_RC.Core.Util; - -namespace NAK.BetterContentLoading.Queue; - -public class PropDownloadQueue : ContentDownloadQueueBase -{ - private readonly Dictionary _ownerToSpawner = new(); // InstanceId -> SpawnerId - - public PropDownloadQueue(BetterDownloadManager manager) : base(manager, 2) { } - - public void QueueDownload(in DownloadInfo info, string instanceId, string spawnerId, Action onComplete = null) - { - _ownerToSpawner[instanceId] = spawnerId; - float priority = CalculatePropPriority(in info, instanceId, spawnerId); - QueueDownload(in info, instanceId, priority, onComplete); - } - - protected override async Task ProcessDownload(DownloadInfo info) - { - await base.ProcessDownload(info); - } - - protected override void OnDownloadProgress(string downloadId, float progress) - { - if (DownloadOwners.TryGetValue(downloadId, out var owners)) - { - foreach (var instanceId in owners) - { - if (BetterDownloadManager.TryGetPropData(instanceId, out CVRSyncHelper.PropData prop)) - { - BetterContentLoadingMod.Logger.Msg($"Progress for {prop.InstanceId}: {progress:P}"); - } - } - } - } - - protected override float RecalculatePriority(string downloadId) - { - if (!DownloadOwners.TryGetValue(downloadId, out var owners)) - return float.MaxValue; - - float lowestPriority = float.MaxValue; - DownloadInfo? downloadInfo = null; - - // Find the queue item to get the DownloadInfo - var queueItem = Queue.Find(x => x.Info.DownloadId == downloadId); - if (queueItem.Info.AssetId != null) - downloadInfo = queueItem.Info; - - if (downloadInfo == null) - return lowestPriority; - - // Calculate priority for each owner and use the lowest (highest priority) value - foreach (var instanceId in owners) - { - if (_ownerToSpawner.TryGetValue(instanceId, out var spawnerId)) - { - var priority = CalculatePropPriority(downloadInfo.Value, instanceId, spawnerId); - lowestPriority = Math.Min(lowestPriority, priority); - } - } - - return lowestPriority; - } - - private float CalculatePropPriority(in DownloadInfo info, string instanceId, string spawnerId) - { - float priority = info.FileSize; - - if (!BetterDownloadManager.TryGetPropData(instanceId, out var prop)) - return priority; - - if (Manager.PrioritizeFriends && BetterDownloadManager.IsPlayerFriend(spawnerId)) - priority *= 0.5f; - - if (Manager.PrioritizeDistance && Manager.IsPropWithinPriorityDistance(prop)) - priority *= 0.75f; - - return priority; - } -} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/DownloadQueue/WorldDownloadQueue.cs b/BetterContentLoading/BetterContentLoading/DownloadQueue/WorldDownloadQueue.cs deleted file mode 100644 index 1cea689..0000000 --- a/BetterContentLoading/BetterContentLoading/DownloadQueue/WorldDownloadQueue.cs +++ /dev/null @@ -1,66 +0,0 @@ -namespace NAK.BetterContentLoading.Queue; - -public class WorldDownloadQueue : ContentDownloadQueueBase -{ - private readonly Queue<(DownloadInfo Info, bool JoinOnComplete, bool IsHomeRequest)> _backgroundQueue = new(); - private bool _isProcessingPriorityDownload; - - public WorldDownloadQueue(BetterDownloadManager manager) : base(manager, 1) { } - - public void QueueDownload(in DownloadInfo info, bool joinOnComplete, bool isHomeRequest, Action onComplete = null) - { - if (joinOnComplete || isHomeRequest) - { - // Priority download - clear queue and download immediately - Queue.Clear(); - _isProcessingPriorityDownload = true; - QueueDownload(in info, info.DownloadId, 0f, onComplete); - } - else - { - // Background download - add to background queue - _backgroundQueue.Enqueue((info, false, false)); - if (!_isProcessingPriorityDownload) - ProcessBackgroundQueue(); - } - } - - protected override async Task ProcessDownload(DownloadInfo info) - { - await base.ProcessDownload(info); - - if (_isProcessingPriorityDownload) - { - _isProcessingPriorityDownload = false; - ProcessBackgroundQueue(); - } - } - - protected override void OnDownloadProgress(string downloadId, float progress) - { - BetterContentLoadingMod.Logger.Msg($"World download progress: {progress:P}"); - } - - protected override float RecalculatePriority(string downloadId) - { - // For worlds, priority is based on whether it's a priority download and file size - var queueItem = Queue.Find(x => x.Info.DownloadId == downloadId); - return queueItem.Priority; - } - - private void ProcessBackgroundQueue() - { - while (_backgroundQueue.Count > 0) - { - (DownloadInfo info, var join, var home) = _backgroundQueue.Dequeue(); - QueueDownload(in info, info.DownloadId, info.FileSize, null); - } - } - - protected override void CancelDownload(string downloadId) - { - base.CancelDownload(downloadId); - _backgroundQueue.Clear(); - _isProcessingPriorityDownload = false; - } -} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/DownloadState.cs b/BetterContentLoading/BetterContentLoading/DownloadState.cs deleted file mode 100644 index 785396b..0000000 --- a/BetterContentLoading/BetterContentLoading/DownloadState.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace NAK.BetterContentLoading; - -public readonly struct DownloadState -{ - public readonly string DownloadId; - public readonly long BytesRead; - public readonly long TotalBytes; - public readonly int ProgressPercent; - public readonly float BytesPerSecond; - - public DownloadState(string downloadId, long bytesRead, long totalBytes, float bytesPerSecond) - { - DownloadId = downloadId; - BytesRead = bytesRead; - TotalBytes = totalBytes; - BytesPerSecond = bytesPerSecond; - ProgressPercent = (int)(((float)bytesRead / totalBytes) * 100f); - } -} - -public interface IDownloadMonitor -{ - void OnDownloadProgress(DownloadState state); - void OnDownloadStarted(string downloadId); - void OnDownloadCompleted(string downloadId, bool success); -} \ No newline at end of file diff --git a/BetterContentLoading/BetterContentLoading/Util/ThreadingHelper.cs b/BetterContentLoading/BetterContentLoading/Util/ThreadingHelper.cs deleted file mode 100644 index 280aeb2..0000000 --- a/BetterContentLoading/BetterContentLoading/Util/ThreadingHelper.cs +++ /dev/null @@ -1,109 +0,0 @@ -using JetBrains.Annotations; -using UnityEngine; - -namespace NAK.BetterContentLoading.Util; - -[PublicAPI] -public static class ThreadingHelper -{ - private static readonly SynchronizationContext _mainThreadContext; - - static ThreadingHelper() - { - _mainThreadContext = SynchronizationContext.Current; - } - - public static bool IsMainThread => SynchronizationContext.Current == _mainThreadContext; - - /// - /// Runs an action on the main thread. Optionally waits for its completion. - /// - public static void RunOnMainThread(Action action, bool waitForCompletion = true, Action onError = null) - { - if (SynchronizationContext.Current == _mainThreadContext) - { - // Already on the main thread - TryExecute(action, onError); - } - else - { - if (waitForCompletion) - { - ManualResetEvent done = new(false); - _mainThreadContext.Post(_ => - { - TryExecute(action, onError); - done.Set(); - }, null); - done.WaitOne(50000); // Block until action is completed - } - else - { - // Fire and forget (don't wait for the action to complete) - _mainThreadContext.Post(_ => TryExecute(action, onError), null); - } - } - } - - /// - /// Runs an action asynchronously on the main thread and returns a Task. - /// - public static Task RunOnMainThreadAsync(Action action, Action onError = null) - { - if (SynchronizationContext.Current == _mainThreadContext) - { - // Already on the main thread - TryExecute(action, onError); - return Task.CompletedTask; - } - - var tcs = new TaskCompletionSource(); - _mainThreadContext.Post(_ => - { - try - { - TryExecute(action, onError); - tcs.SetResult(true); - } - catch (Exception ex) - { - tcs.SetException(ex); - } - }, null); - return tcs.Task; - } - - /// - /// Runs a task on a background thread with cancellation support. - /// - public static async Task RunOffMainThreadAsync(Action action, CancellationToken cancellationToken, Action onError = null) - { - try - { - await Task.Run(() => - { - cancellationToken.ThrowIfCancellationRequested(); - TryExecute(action, onError); - }, cancellationToken); - } - catch (OperationCanceledException) - { - Debug.LogWarning("Task was canceled."); - } - } - - /// - /// Helper method for error handling. - /// - private static void TryExecute(Action action, Action onError) - { - try - { - action(); - } - catch (Exception ex) - { - onError?.Invoke(ex); - } - } -} diff --git a/BetterContentLoading/DownloadManager/DownloadManager.Core.cs b/BetterContentLoading/DownloadManager/DownloadManager.Core.cs deleted file mode 100644 index ce484cd..0000000 --- a/BetterContentLoading/DownloadManager/DownloadManager.Core.cs +++ /dev/null @@ -1,237 +0,0 @@ -using ABI_RC.Core.InteractionSystem; -using ABI_RC.Core.Networking.API.Responses; -using ABI_RC.Core.Networking.IO.Social; -using ABI_RC.Core.Savior; - -namespace NAK.BetterContentLoading; - -public partial class DownloadManager -{ - #region Singleton - private static DownloadManager _instance; - public static DownloadManager Instance => _instance ??= new DownloadManager(); - #endregion - - private DownloadManager() - { - - } - - #region Settings - public bool IsDebugEnabled { get; set; } = true; - public bool PrioritizeFriends { get; set; } = true; - public bool PrioritizeDistance { get; set; } = true; - public float PriorityDownloadDistance { get; set; } = 25f; - public int MaxConcurrentDownloads { get; set; } = 3; - public int MaxDownloadBandwidth { get; set; } = 100 * 1024 * 1024; // 100MB default - private const int THROTTLE_THRESHOLD = 25 * 1024 * 1024; // 25MB threshold for throttling - - public long MaxAvatarDownloadSize { get; set; } = 25 * 1024 * 1024; // 25MB default - public long MaxPropDownloadSize { get; set; } = 25 * 1024 * 1024; // 25MB default - - #endregion Settings - - #region State - - // priority -> downloadtask - private readonly SortedList _downloadQueue = new(); - - // downloadId -> downloadtask - private readonly Dictionary _cachedDownloads = new(); - - #endregion State - - #region Public Queue Methods - - public void QueueAvatarDownload( - in DownloadInfo info, - string playerId, - CVRLoadingAvatarController loadingController) - { - if (IsDebugEnabled) - { - BetterContentLoadingMod.Logger.Msg( - $"Queuing Avatar Download:\n{info.GetLogString()}\n" + - $"PlayerId: {playerId}\n" + - $"LoadingController: {loadingController}"); - } - - if (!ShouldQueueAvatarDownload(info, playerId)) - { - if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Avatar Download not eligible: {info.DownloadId}"); - return; - } - - if (_cachedDownloads.TryGetValue(info.DownloadId, out DownloadTask cachedDownload)) - { - if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Avatar Download already queued: {info.DownloadId}"); - cachedDownload.AddInstantiationTarget(playerId); - cachedDownload.BasePriority = CalculatePriority(cachedDownload); - return; - } - - DownloadTask task = new() - { - Info = info, - Type = DownloadTaskType.Avatar - }; - task.AddInstantiationTarget(playerId); - task.BasePriority = CalculatePriority(task); - } - - private bool ShouldQueueAvatarDownload( - in DownloadInfo info, - string playerId) - { - // Check if content is incompatible or banned - if (info.TagsData.Incompatible || info.TagsData.AdminBanned) - { - if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Avatar is incompatible or banned"); - return false; - } - - // Check if player is blocked - if (MetaPort.Instance.blockedUserIds.Contains(playerId)) - { - if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Player is blocked: {playerId}"); - return false; - } - - // Check if mature content is disabled - UgcTagsData tags = info.TagsData; - if (!MetaPort.Instance.matureContentAllowed && (tags.Gore || tags.Nudity)) - { - if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Mature content is disabled"); - return false; - } - - // Check file size - if (info.FileSize > MaxAvatarDownloadSize) - { - if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Avatar Download too large: {info.FileSize} > {MaxAvatarDownloadSize}"); - return false; - } - - // Get visibility status for the avatar - // ForceHidden means player avatar or avatar itself is forced off. - // ForceShown will bypass all checks and return true. - MetaPort.Instance.SelfModerationManager.GetAvatarVisibility(playerId, info.AssetId, - out bool wasForceHidden, out bool wasForceShown); - - if (!wasForceHidden) - { - if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Avatar is not visible either because player avatar or avatar itself is forced off"); - return false; - } - - if (!wasForceShown) - { - // Check content filter settings if not force shown - CVRSettings settings = MetaPort.Instance.settings; - bool isLocalPlayer = playerId == MetaPort.Instance.ownerId; - bool isFriend = Friends.FriendsWith(playerId); - bool CheckFilterSettings(string settingName) - { - int settingVal = settings.GetSettingInt(settingName); - switch (settingVal) - { - // Only Self - case 0 when !isLocalPlayer: - // Only Friends - case 1 when !isFriend: - return false; - } - return true; - } - - if (!CheckFilterSettings("ContentFilterVisibility")) return false; - if (!CheckFilterSettings("ContentFilterNudity")) return false; - if (!CheckFilterSettings("ContentFilterGore")) return false; - if (!CheckFilterSettings("ContentFilterSuggestive")) return false; - if (!CheckFilterSettings("ContentFilterFlashingColors")) return false; - if (!CheckFilterSettings("ContentFilterFlashingLights")) return false; - if (!CheckFilterSettings("ContentFilterScreenEffects")) return false; - if (!CheckFilterSettings("ContentFilterExtremelyBright")) return false; - if (!CheckFilterSettings("ContentFilterViolence")) return false; - if (!CheckFilterSettings("ContentFilterJumpscare")) return false; - if (!CheckFilterSettings("ContentFilterExcessivelyHuge")) return false; - if (!CheckFilterSettings("ContentFilterExcessivelySmall")) return false; - } - - // All eligibility checks passed - return true; - } - - /// - /// Queues a prop download. - /// - /// The download info. - /// The instance ID for the prop. - /// The user who spawned the prop. - public void QueuePropDownload( - in DownloadInfo info, - string instanceId, - string spawnerId) - { - if (IsDebugEnabled) - { - BetterContentLoadingMod.Logger.Msg( - $"Queuing Prop Download:\n{info.GetLogString()}\n" + - $"InstanceId: {instanceId}\n" + - $"SpawnerId: {spawnerId}"); - } - - if (_cachedDownloads.TryGetValue(info.DownloadId, out DownloadTask cachedDownload)) - { - if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"Prop Download already queued: {info.DownloadId}"); - cachedDownload.AddInstantiationTarget(instanceId); - cachedDownload.BasePriority = CalculatePriority(cachedDownload); - return; - } - - DownloadTask task = new() - { - Info = info, - Type = DownloadTaskType.Prop - }; - task.AddInstantiationTarget(instanceId); - task.BasePriority = CalculatePriority(task); - } - - /// - /// Queues a world download. - /// - /// Download info. - /// Whether to load into this world once downloaded. - /// Whether the home world is requested. - public void QueueWorldDownload( - in DownloadInfo info, - bool joinOnComplete, - bool isHomeRequested) - { - if (IsDebugEnabled) - { - BetterContentLoadingMod.Logger.Msg( - $"Queuing World Download:\n{info.GetLogString()}\n" + - $"JoinOnComplete: {joinOnComplete}\n" + - $"IsHomeRequested: {isHomeRequested}"); - } - - if (_cachedDownloads.TryGetValue(info.DownloadId, out DownloadTask cachedDownload)) - { - if (IsDebugEnabled) BetterContentLoadingMod.Logger.Msg($"World Download already queued: {info.DownloadId}"); - cachedDownload.BasePriority = CalculatePriority(cachedDownload); - return; - } - - DownloadTask task = new() - { - Info = info, - Type = DownloadTaskType.World - }; - task.BasePriority = CalculatePriority(task); - } - - #endregion Public Queue Methods - -} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager/DownloadManager.Helpers.cs b/BetterContentLoading/DownloadManager/DownloadManager.Helpers.cs deleted file mode 100644 index 3664ed4..0000000 --- a/BetterContentLoading/DownloadManager/DownloadManager.Helpers.cs +++ /dev/null @@ -1,58 +0,0 @@ -using ABI_RC.Core.Networking.IO.Social; -using ABI_RC.Core.Player; -using ABI_RC.Core.Savior; -using ABI_RC.Core.Util; -using UnityEngine; - -namespace NAK.BetterContentLoading; - -public partial class DownloadManager -{ - internal static bool TryGetPlayerEntity(string playerId, out CVRPlayerEntity playerEntity) - { - CVRPlayerEntity player = CVRPlayerManager.Instance.NetworkPlayers.Find(p => p.Uuid == playerId); - if (player == null) - { - // BetterContentLoadingMod.Logger.Error($"Player entity not found for ID: {playerId}"); - playerEntity = null; - return false; - } - playerEntity = player; - return true; - } - - internal static bool TryGetPropData(string instanceId, out CVRSyncHelper.PropData propData) - { - CVRSyncHelper.PropData prop = CVRSyncHelper.Props.Find(p => p.InstanceId == instanceId); - if (prop == null) - { - // BetterContentLoadingMod.Logger.Error($"Prop data not found for ID: {instanceId}"); - propData = null; - return false; - } - propData = prop; - return true; - } - - private static bool IsPlayerLocal(string playerId) - { - return playerId == MetaPort.Instance.ownerId; - } - - private static bool IsPlayerFriend(string playerId) - { - return Friends.FriendsWith(playerId); - } - - private bool IsPlayerWithinPriorityDistance(CVRPlayerEntity player) - { - if (player.PuppetMaster == null) return false; - return player.PuppetMaster.animatorManager.DistanceTo < PriorityDownloadDistance; - } - - internal bool IsPropWithinPriorityDistance(CVRSyncHelper.PropData prop) - { - Vector3 propPosition = new(prop.PositionX, prop.PositionY, prop.PositionZ); - return Vector3.Distance(propPosition, PlayerSetup.Instance.GetPlayerPosition()) < PriorityDownloadDistance; - } -} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager/DownloadManager.Priority.cs b/BetterContentLoading/DownloadManager/DownloadManager.Priority.cs deleted file mode 100644 index ae28cbc..0000000 --- a/BetterContentLoading/DownloadManager/DownloadManager.Priority.cs +++ /dev/null @@ -1,38 +0,0 @@ -using ABI_RC.Core.Player; - -namespace NAK.BetterContentLoading; - -public partial class DownloadManager -{ - private float CalculatePriority(DownloadTask task) - { - return task.Type switch - { - DownloadTaskType.Avatar => CalculateAvatarPriority(task), - // DownloadTaskType.Prop => CalculatePropPriority(task2), - // DownloadTaskType.World => CalculateWorldPriority(task2), - _ => task.Info.FileSize - }; - } - - private float CalculateAvatarPriority(DownloadTask task) - { - float priority = task.Info.FileSize; - - foreach (string target in task.InstantiationTargets) - { - if (IsPlayerLocal(target)) return 0f; - - if (!TryGetPlayerEntity(target, out CVRPlayerEntity player)) - return priority; - - if (PrioritizeFriends && IsPlayerFriend(target)) - priority *= 0.5f; - - if (PrioritizeDistance && IsPlayerWithinPriorityDistance(player)) - priority *= 0.75f; - } - - return priority; - } -} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager/DownloadTask.Main.cs b/BetterContentLoading/DownloadManager/DownloadTask.Main.cs deleted file mode 100644 index 5397cf7..0000000 --- a/BetterContentLoading/DownloadManager/DownloadTask.Main.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace NAK.BetterContentLoading; - -public partial class DownloadTask -{ - public DownloadInfo Info { get; set; } - public DownloadTaskStatus Status { get; set; } - public DownloadTaskType Type { get; set; } - - public float BasePriority { get; set; } - public float CurrentPriority => BasePriority * (1 + Progress / 100f); - - public long BytesRead { get; set; } - public int Progress { get; set; } - - /// The avatar/prop instances that wish to utilize this bundle. - public List InstantiationTargets { get; } = new(); - - public void AddInstantiationTarget(string target) - { - if (InstantiationTargets.Contains(target)) - return; - - InstantiationTargets.Add(target); - } - - public void RemoveInstantiationTarget(string target) - { - if (!InstantiationTargets.Contains(target)) - return; - - InstantiationTargets.Remove(target); - } -} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager/DownloadTask.Priority.cs b/BetterContentLoading/DownloadManager/DownloadTask.Priority.cs deleted file mode 100644 index f697a5e..0000000 --- a/BetterContentLoading/DownloadManager/DownloadTask.Priority.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace NAK.BetterContentLoading; - -public partial class DownloadTask -{ - -} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/ConcurrentPriorityQueue.cs b/BetterContentLoading/DownloadManager2/ConcurrentPriorityQueue.cs deleted file mode 100644 index df844d5..0000000 --- a/BetterContentLoading/DownloadManager2/ConcurrentPriorityQueue.cs +++ /dev/null @@ -1,43 +0,0 @@ -namespace NAK.BetterContentLoading; - -public class ConcurrentPriorityQueue where TPriority : IComparable -{ - private readonly object _lock = new(); - private readonly SortedDictionary> _queues = new(); - - public void Enqueue(TElement item, TPriority priority) - { - lock (_lock) - { - if (!_queues.TryGetValue(priority, out var queue)) - { - queue = new Queue(); - _queues[priority] = queue; - } - queue.Enqueue(item); - } - } - - public bool TryDequeue(out TElement item, out TPriority priority) - { - lock (_lock) - { - if (_queues.Count == 0) - { - item = default; - priority = default; - return false; - } - - var firstQueue = _queues.First(); - priority = firstQueue.Key; - var queue = firstQueue.Value; - item = queue.Dequeue(); - - if (queue.Count == 0) - _queues.Remove(priority); - - return true; - } - } -} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/DownloadManager.Bandwidth.cs b/BetterContentLoading/DownloadManager2/DownloadManager.Bandwidth.cs deleted file mode 100644 index 54d5792..0000000 --- a/BetterContentLoading/DownloadManager2/DownloadManager.Bandwidth.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace NAK.BetterContentLoading; - -public partial class DownloadManager2 -{ - private void StartBandwidthMonitor() - { - Task.Run(async () => - { - while (true) - { - await Task.Delay(1000); - Interlocked.Exchange(ref _bytesReadLastSecond, 0); - Interlocked.Exchange(ref _completedDownloads, 0); - } - }); - } - - private int ComputeUsableBandwidthPerDownload() - { - var activeCount = _activeDownloads.Count; - if (activeCount == 0) return MaxDownloadBandwidth; - return MaxDownloadBandwidth / activeCount; - } -} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/DownloadManager.Core.cs b/BetterContentLoading/DownloadManager2/DownloadManager.Core.cs deleted file mode 100644 index 63fd4c2..0000000 --- a/BetterContentLoading/DownloadManager2/DownloadManager.Core.cs +++ /dev/null @@ -1,126 +0,0 @@ -using System.Collections.Concurrent; -using ABI_RC.Core; -using ABI_RC.Core.IO; -using ABI_RC.Core.IO.AssetManagement; - -namespace NAK.BetterContentLoading; - -public partial class DownloadManager2 -{ - #region Singleton - private static DownloadManager2 _instance; - public static DownloadManager2 Instance => _instance ??= new DownloadManager2(); - #endregion - - #region Settings - public bool IsDebugEnabled { get; set; } = true; - public bool PrioritizeFriends { get; set; } = true; - public bool PrioritizeDistance { get; set; } = true; - public float PriorityDownloadDistance { get; set; } = 25f; - public int MaxConcurrentDownloads { get; set; } = 5; - public int MaxDownloadBandwidth { get; set; } // 100MB default - private const int THROTTLE_THRESHOLD = 25 * 1024 * 1024; // 25MB threshold for throttling - #endregion - - #region State - private readonly ConcurrentDictionary _activeDownloads; - private readonly ConcurrentPriorityQueue _queuedDownloads; - private readonly ConcurrentDictionary _completedDownloads; - private readonly object _downloadLock = new(); - private long _bytesReadLastSecond; - #endregion - - private DownloadManager2() - { - _activeDownloads = new ConcurrentDictionary(); - _queuedDownloads = new ConcurrentPriorityQueue(); - MaxDownloadBandwidth = 100 * 1024 * 1024; - StartBandwidthMonitor(); - } - - public async Task QueueAvatarDownload(DownloadInfo info, string playerId) - { - if (await ValidateAndCheckCache(info)) - return true; - - DownloadTask2 task2 = GetOrCreateDownloadTask(info, DownloadTaskType.Avatar); - task2.AddTarget(playerId); - QueueDownload(task2); - return false; - } - - public async Task QueuePropDownload(DownloadInfo info, string instanceId, string spawnerId) - { - if (await ValidateAndCheckCache(info)) - return true; - - DownloadTask2 task2 = GetOrCreateDownloadTask(info, DownloadTaskType.Prop); - task2.AddTarget(instanceId, spawnerId); - QueueDownload(task2); - return false; - } - - public async Task QueueWorldDownload(DownloadInfo info, bool loadOnComplete) - { - if (await ValidateAndCheckCache(info)) - return true; - - DownloadTask2 task2 = GetOrCreateDownloadTask(info, DownloadTaskType.World, loadOnComplete); - QueueDownload(task2); - return false; - } - - private async Task ValidateAndCheckCache(DownloadInfo info) - { - // Check if already cached and up to date - if (await CacheManager.Instance.IsCachedFileUpToDate( - info.AssetId, - info.FileId, - info.FileHash)) - { - return true; - } - - // Validate disk space - var filePath = CacheManager.Instance.GetCachePath(info.AssetId, info.FileId); - if (!CVRTools.HasEnoughDiskSpace(filePath, info.FileSize)) - { - BetterContentLoadingMod.Logger.Error($"Not enough disk space to download {info.AssetId}"); - return false; - } - - // Ensure cache directory exists - CacheManager.Instance.EnsureCacheDirectoryExists(info.AssetId); - return false; - } - - private DownloadTask2 GetOrCreateDownloadTask(DownloadInfo info, DownloadTaskType type, bool loadOnComplete = false) - { - // Check if task already exists in active downloads - if (_activeDownloads.TryGetValue(info.DownloadId, out var activeTask)) - return activeTask; - - // Check if task exists in queued downloads - var queuedTask = _queuedDownloads.TryFind(t => t.Info.DownloadId == info.DownloadId); - if (queuedTask != null) - return queuedTask; - - // Create new task - var cachePath = CacheManager.Instance.GetCachePath(info.AssetId, info.FileId); - return new DownloadTask2(info, cachePath, type, loadOnComplete); - } - - public bool TryFindTask(string downloadId, out DownloadTask2 task2) - { - return _activeDownloads.TryGetValue(downloadId, out task2) || - _completedDownloads.TryGetValue(downloadId, out task2) || - TryFindQueuedTask(downloadId, out task2); - } - - private bool TryFindQueuedTask(string downloadId, out DownloadTask2 task2) - { - task2 = _queuedDownloads.UnorderedItems - .FirstOrDefault(x => x.Element.Info.DownloadId == downloadId).Element; - return task2 != null; - } -} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/DownloadManager.Helpers.cs b/BetterContentLoading/DownloadManager2/DownloadManager.Helpers.cs deleted file mode 100644 index 2dd205d..0000000 --- a/BetterContentLoading/DownloadManager2/DownloadManager.Helpers.cs +++ /dev/null @@ -1,58 +0,0 @@ -using ABI_RC.Core.Networking.IO.Social; -using ABI_RC.Core.Player; -using ABI_RC.Core.Savior; -using ABI_RC.Core.Util; -using UnityEngine; - -namespace NAK.BetterContentLoading; - -public partial class DownloadManager2 -{ - internal static bool TryGetPlayerEntity(string playerId, out CVRPlayerEntity playerEntity) - { - CVRPlayerEntity player = CVRPlayerManager.Instance.NetworkPlayers.Find(p => p.Uuid == playerId); - if (player == null) - { - // BetterContentLoadingMod.Logger.Error($"Player entity not found for ID: {playerId}"); - playerEntity = null; - return false; - } - playerEntity = player; - return true; - } - - internal static bool TryGetPropData(string instanceId, out CVRSyncHelper.PropData propData) - { - CVRSyncHelper.PropData prop = CVRSyncHelper.Props.Find(p => p.InstanceId == instanceId); - if (prop == null) - { - // BetterContentLoadingMod.Logger.Error($"Prop data not found for ID: {instanceId}"); - propData = null; - return false; - } - propData = prop; - return true; - } - - private static bool IsPlayerLocal(string playerId) - { - return playerId == MetaPort.Instance.ownerId; - } - - private static bool IsPlayerFriend(string playerId) - { - return Friends.FriendsWith(playerId); - } - - private bool IsPlayerWithinPriorityDistance(CVRPlayerEntity player) - { - if (player.PuppetMaster == null) return false; - return player.PuppetMaster.animatorManager.DistanceTo < PriorityDownloadDistance; - } - - internal bool IsPropWithinPriorityDistance(CVRSyncHelper.PropData prop) - { - Vector3 propPosition = new(prop.PositionX, prop.PositionY, prop.PositionZ); - return Vector3.Distance(propPosition, PlayerSetup.Instance.GetPlayerPosition()) < PriorityDownloadDistance; - } -} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/DownloadManager.Priority.cs b/BetterContentLoading/DownloadManager2/DownloadManager.Priority.cs deleted file mode 100644 index 1132b8e..0000000 --- a/BetterContentLoading/DownloadManager2/DownloadManager.Priority.cs +++ /dev/null @@ -1,47 +0,0 @@ -using ABI_RC.Core.IO; - -namespace NAK.BetterContentLoading; - -public partial class DownloadManager2 -{ - private float CalculatePriority(DownloadTask2 task2) - { - return task2.Type switch - { - DownloadTaskType.Avatar => CalculateAvatarPriority(task2), - DownloadTaskType.Prop => CalculatePropPriority(task2), - DownloadTaskType.World => CalculateWorldPriority(task2), - _ => task2.Info.FileSize - }; - } - - private float CalculateAvatarPriority(DownloadTask2 task2) - { - float priority = task2.Info.FileSize; - - if (IsPlayerLocal(task2.PlayerId)) - return 0f; - - if (!TryGetPlayerEntity(task2.PlayerId, out var player)) - return priority; - - if (PrioritizeFriends && IsPlayerFriend(task2.PlayerId)) - priority *= 0.5f; - - if (PrioritizeDistance && IsPlayerWithinPriorityDistance(player)) - priority *= 0.75f; - - // Factor in download progress - priority *= (1 + task2.Progress / 100f); - - return priority; - } - - private float CalculatePropPriority(DownloadTask2 task2) - { - float priority = task2.Info.FileSize; - - if (IsPlayerLocal(task2.PlayerId)) - return 0f; - } -} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/DownloadManager.Processing.cs b/BetterContentLoading/DownloadManager2/DownloadManager.Processing.cs deleted file mode 100644 index 698ac06..0000000 --- a/BetterContentLoading/DownloadManager2/DownloadManager.Processing.cs +++ /dev/null @@ -1,144 +0,0 @@ -using System.Diagnostics; -using System.Net.Http.Headers; -using ABI_RC.Core.IO; - -namespace NAK.BetterContentLoading; - -public partial class DownloadManager2 -{ - private async Task ProcessDownload(DownloadTask2 task2) - { - using var client = new HttpClient(); - - // Set up resume headers if we have a resume token - if (!string.IsNullOrEmpty(task2.ResumeToken)) - { - client.DefaultRequestHeaders.Range = new RangeHeaderValue(task2.BytesRead, null); - } - - using var response = await client.GetAsync(task2.Info.AssetUrl, HttpCompletionOption.ResponseHeadersRead); - using var dataStream = await response.Content.ReadAsStreamAsync(); - - // Open file in append mode if resuming, otherwise create new - using var fileStream = new FileStream( - task2.TargetPath, - string.IsNullOrEmpty(task2.ResumeToken) ? FileMode.Create : FileMode.Append, - FileAccess.Write); - - bool isEligibleForThrottle = task2.Info.FileSize > THROTTLE_THRESHOLD; - var stopwatch = new Stopwatch(); - - int bytesRead; - do - { - if (task2.Status == DownloadTaskStatus.Paused) - { - task2.ResumeToken = GenerateResumeToken(task2); - await fileStream.FlushAsync(); - return; - } - - if (task2.Status != DownloadTaskStatus.Downloading) - { - HandleCancellation(task2, dataStream, fileStream); - return; - } - - stopwatch.Restart(); - var lengthToRead = isEligibleForThrottle ? - ComputeUsableBandwidthPerDownload() : - 16384; - - var buffer = new byte[lengthToRead]; - bytesRead = await dataStream.ReadAsync(buffer, 0, lengthToRead); - - if (isEligibleForThrottle) - Interlocked.Add(ref _bytesReadLastSecond, bytesRead); - - await fileStream.WriteAsync(buffer, 0, bytesRead); - UpdateProgress(task2, bytesRead); - - } while (bytesRead > 0); - - CompleteDownload(task2); - } - - private string GenerateResumeToken(DownloadTask2 task2) - { - // Generate a unique token that includes file position and hash - return $"{task2.BytesRead}:{DateTime.UtcNow.Ticks}"; - } - - private async Task FinalizeDownload(DownloadTask2 task2) - { - var tempPath = task2.CachePath + ".tmp"; - - try - { - // Decrypt the file if needed - if (task2.Info.EncryptionAlgorithm != 0) - { - await DecryptFile(tempPath, task2.CachePath, task2.Info); - File.Delete(tempPath); - } - else - { - File.Move(tempPath, task2.CachePath); - } - - CompleteDownload(task2); - } - catch (Exception ex) - { - // _logger.Error($"Failed to finalize download for {task.Info.AssetId}: {ex.Message}"); - task2.Status = DownloadTaskStatus.Failed; - File.Delete(tempPath); - _activeDownloads.TryRemove(task2.Info.DownloadId, out _); - } - } - - private async Task DecryptFile(string sourcePath, string targetPath, DownloadInfo info) - { - // Implementation of file decryption based on EncryptionAlgorithm - // This would use the FileKey from the DownloadInfo - throw new NotImplementedException("File decryption not implemented"); - } - - private void HandleCancellation(DownloadTask2 task2, Stream dataStream, Stream fileStream) - { - if (task2.Status != DownloadTaskStatus.Failed) - task2.Status = DownloadTaskStatus.Cancelled; - - dataStream.Close(); - fileStream.Close(); - - task2.Progress = 0; - task2.BytesRead = 0; - - _activeDownloads.TryRemove(task2.Info.DownloadId, out _); - } - - private void UpdateProgress(DownloadTask2 task2, int bytesRead) - { - task2.BytesRead += bytesRead; - task2.Progress = Math.Clamp( - (int)(((float)task2.BytesRead / task2.Info.FileSize) * 100f), - 0, 100); - } - - private void CompleteDownload(DownloadTask2 task2) - { - task2.Status = DownloadTaskStatus.Complete; - task2.Progress = 100; - _activeDownloads.TryRemove(task2.Info.DownloadId, out _); - _completedDownloads.TryAdd(task2.Info.DownloadId, task2); - - lock (_downloadLock) - { - if (_queuedDownloads.TryDequeue(out var nextTask, out _)) - { - StartDownload(nextTask); - } - } - } -} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/DownloadManager.Queue.cs b/BetterContentLoading/DownloadManager2/DownloadManager.Queue.cs deleted file mode 100644 index e8a580a..0000000 --- a/BetterContentLoading/DownloadManager2/DownloadManager.Queue.cs +++ /dev/null @@ -1,80 +0,0 @@ -using ABI_RC.Core.IO; - -namespace NAK.BetterContentLoading; - -public partial class DownloadManager2 -{ - public void QueueDownload(DownloadTask2 newTask2) - { - if (_completedDownloads.TryGetValue(newTask2.Info.DownloadId, out var completedTask)) - { - completedTask.AddPlayer(newTask2.PlayerIds.FirstOrDefault()); - return; - } - - if (TryFindTask(newTask2.Info.DownloadId, out var existingTask)) - { - existingTask.AddPlayer(newTask2.PlayerIds.FirstOrDefault()); - RecalculatePriority(existingTask); - return; - } - - float priority = CalculatePriority(newTask2); - newTask2.CurrentPriority = priority; - - lock (_downloadLock) - { - if (_activeDownloads.Count < MaxConcurrentDownloads) - { - StartDownload(newTask2); - return; - } - - var lowestPriorityTask = _activeDownloads.Values - .OrderByDescending(t => t.CurrentPriority * (1 + t.Progress / 100f)) - .LastOrDefault(); - - if (lowestPriorityTask != null && priority < lowestPriorityTask.CurrentPriority) - { - PauseDownload(lowestPriorityTask); - StartDownload(newTask2); - } - else - { - _queuedDownloads.Enqueue(newTask2, priority); - } - } - } - - private void StartDownload(DownloadTask2 task2) - { - task2.Status = DownloadTaskStatus.Downloading; - _activeDownloads.TryAdd(task2.Info.DownloadId, task2); - Task.Run(() => ProcessDownload(task2)); - } - - private void PauseDownload(DownloadTask2 task2) - { - task2.Status = DownloadTaskStatus.Queued; - _activeDownloads.TryRemove(task2.Info.DownloadId, out _); - _queuedDownloads.Enqueue(task2, task2.CurrentPriority); - } - - - - - private void RecalculatePriority(DownloadTask2 task2) - { - var newPriority = CalculatePriority(task2); - if (Math.Abs(newPriority - task2.CurrentPriority) < float.Epsilon) - return; - - task2.CurrentPriority = newPriority; - - if (task2.Status == DownloadTaskStatus.Queued || task2.Status == DownloadTaskStatus.Paused) - { - // Re-enqueue with new priority - _queuedDownloads.UpdatePriority(task2, newPriority); - } - } -} \ No newline at end of file diff --git a/BetterContentLoading/DownloadManager2/DownloadTask2.cs b/BetterContentLoading/DownloadManager2/DownloadTask2.cs deleted file mode 100644 index 0c531f6..0000000 --- a/BetterContentLoading/DownloadManager2/DownloadTask2.cs +++ /dev/null @@ -1,62 +0,0 @@ -namespace NAK.BetterContentLoading; - -public class DownloadTask2 -{ - public DownloadInfo Info { get; } - public DownloadTaskStatus Status { get; set; } - public DownloadTaskType Type { get; } - - public float BasePriority { get; set; } - public float CurrentPriority => BasePriority * (1 + Progress / 100f); - - public long BytesRead { get; set; } - public int Progress { get; set; } - - public string CachePath { get; } - public Dictionary Targets { get; } // Key: targetId (playerId/instanceId), Value: spawnerId - public bool LoadOnComplete { get; } // For worlds only - - public DownloadTask2( - DownloadInfo info, - string cachePath, - DownloadTaskType type, - bool loadOnComplete = false) - { - Info = info; - CachePath = cachePath; - Type = type; - LoadOnComplete = loadOnComplete; - Targets = new Dictionary(); - Status = DownloadTaskStatus.Queued; - } - - public void AddTarget(string targetId, string spawnerId = null) - { - if (Type == DownloadTaskType.World && Targets.Count > 0) - throw new InvalidOperationException("World downloads cannot have multiple targets"); - - Targets[targetId] = spawnerId; - } - - public void RemoveTarget(string targetId) - { - Targets.Remove(targetId); - } -} - -public enum DownloadTaskType -{ - Avatar, - Prop, - World -} - -public enum DownloadTaskStatus -{ - Queued, - Downloading, - Paused, - Complete, - Failed, - Cancelled -} \ No newline at end of file diff --git a/BetterContentLoading/Main.cs b/BetterContentLoading/Main.cs deleted file mode 100644 index 5b5d812..0000000 --- a/BetterContentLoading/Main.cs +++ /dev/null @@ -1,37 +0,0 @@ -using MelonLoader; -using NAK.BetterContentLoading.Patches; - -namespace NAK.BetterContentLoading; - -public class BetterContentLoadingMod : MelonMod -{ - internal static MelonLogger.Instance Logger; - - #region Melon Events - - public override void OnInitializeMelon() - { - Logger = LoggerInstance; - - ApplyPatches(typeof(CVRDownloadManager_Patches)); - } - - #endregion Melon Events - - #region Melon Mod Utilities - - private void ApplyPatches(Type type) - { - try - { - HarmonyInstance.PatchAll(type); - } - catch (Exception e) - { - LoggerInstance.Msg($"Failed while patching {type.Name}!"); - LoggerInstance.Error(e); - } - } - - #endregion Melon Mod Utilities -} \ No newline at end of file diff --git a/BetterContentLoading/ModSettings.cs b/BetterContentLoading/ModSettings.cs deleted file mode 100644 index f07436c..0000000 --- a/BetterContentLoading/ModSettings.cs +++ /dev/null @@ -1,31 +0,0 @@ -using MelonLoader; - -namespace NAK.RCCVirtualSteeringWheel; - -internal static class ModSettings -{ - #region Constants - - private const string ModName = nameof(RCCVirtualSteeringWheel); - - #endregion Constants - - #region Melon Preferences - - private static readonly MelonPreferences_Category Category = - MelonPreferences.CreateCategory(ModName); - - internal static readonly MelonPreferences_Entry EntryOverrideSteeringRange = - Category.CreateEntry("override_steering_range", false, - "Override Steering Range", description: "Should the steering wheel use a custom steering range instead of the vehicle's default?"); - - internal static readonly MelonPreferences_Entry EntryCustomSteeringRange = - Category.CreateEntry("custom_steering_range", 60f, - "Custom Steering Range", description: "The custom steering range in degrees when override is enabled (default: 60)"); - - internal static readonly MelonPreferences_Entry EntryInvertSteering = - Category.CreateEntry("invert_steering", false, - "Invert Steering", description: "Inverts the steering direction"); - - #endregion Melon Preferences -} \ No newline at end of file diff --git a/BetterContentLoading/Patches.cs b/BetterContentLoading/Patches.cs deleted file mode 100644 index d3c452b..0000000 --- a/BetterContentLoading/Patches.cs +++ /dev/null @@ -1,71 +0,0 @@ -using ABI_RC.Core.InteractionSystem; -using ABI_RC.Core.IO; -using ABI_RC.Core.Networking.API; -using ABI_RC.Core.Networking.API.Responses; -using HarmonyLib; -using NAK.BetterContentLoading.Util; - -namespace NAK.BetterContentLoading.Patches; - -internal static class CVRDownloadManager_Patches -{ - [HarmonyPrefix] - [HarmonyPatch(typeof(CVRDownloadManager), nameof(CVRDownloadManager.QueueTask))] - private static bool Prefix_CVRDownloadManager_QueueTask( - string assetId, - DownloadTask2.ObjectType type, - string assetUrl, - string fileId, - long fileSize, - string fileKey, - string toAttach, - string fileHash = null, - UgcTagsData tagsData = null, - CVRLoadingAvatarController loadingAvatarController = null, - bool joinOnComplete = false, - bool isHomeRequested = false, - int compatibilityVersion = 0, - int encryptionAlgorithm = 0, - string spawnerId = null) - { - DownloadInfo info; - - switch (type) - { - case DownloadTask2.ObjectType.Avatar: - info = new DownloadInfo( - assetId, assetUrl, fileId, fileSize, fileKey, fileHash, - compatibilityVersion, encryptionAlgorithm, tagsData); - BetterDownloadManager.Instance.QueueAvatarDownload(in info, toAttach, loadingAvatarController); - return true; - case DownloadTask2.ObjectType.Prop: - info = new DownloadInfo( - assetId, assetUrl, fileId, fileSize, fileKey, fileHash, - compatibilityVersion, encryptionAlgorithm, tagsData); - BetterDownloadManager.Instance.QueuePropDownload(in info, toAttach, spawnerId); - return true; - case DownloadTask2.ObjectType.World: - _ = ThreadingHelper.RunOffMainThreadAsync(() => - { - var response = ApiConnection.MakeRequest( - ApiConnection.ApiOperation.WorldMeta, - new { worldID = assetId } - ); - - if (response?.Result.Data == null) - return; - - info = new DownloadInfo( - assetId, response.Result.Data.FileLocation, response.Result.Data.FileId, - response.Result.Data.FileSize, response.Result.Data.FileKey, response.Result.Data.FileHash, - (int)response.Result.Data.CompatibilityVersion, (int)response.Result.Data.EncryptionAlgorithm, - null); - - BetterDownloadManager.Instance.QueueWorldDownload(in info, joinOnComplete, isHomeRequested); - }, CancellationToken.None); - return true; - default: - return true; - } - } -} \ No newline at end of file diff --git a/BetterContentLoading/Properties/AssemblyInfo.cs b/BetterContentLoading/Properties/AssemblyInfo.cs deleted file mode 100644 index 9ab241d..0000000 --- a/BetterContentLoading/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Reflection; -using MelonLoader; -using NAK.BetterContentLoading; -using NAK.BetterContentLoading.Properties; - -[assembly: AssemblyVersion(AssemblyInfoParams.Version)] -[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] -[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] -[assembly: AssemblyTitle(nameof(NAK.BetterContentLoading))] -[assembly: AssemblyCompany(AssemblyInfoParams.Author)] -[assembly: AssemblyProduct(nameof(NAK.BetterContentLoading))] - -[assembly: MelonInfo( - typeof(BetterContentLoadingMod), - nameof(NAK.BetterContentLoading), - AssemblyInfoParams.Version, - AssemblyInfoParams.Author, - downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/BetterContentLoading" -)] - -[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] -[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] -[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] -[assembly: MelonColor(255, 246, 25, 99)] // red-pink -[assembly: MelonAuthorColor(255, 158, 21, 32)] // red -[assembly: HarmonyDontPatchAll] - -namespace NAK.BetterContentLoading.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/BetterContentLoading/README.md b/BetterContentLoading/README.md deleted file mode 100644 index 8d9f529..0000000 --- a/BetterContentLoading/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# RCCVirtualSteeringWheel - -Allows you to physically grab rigged RCC steering wheels in VR to provide steering input. No explicit setup required other than defining the Steering Wheel transform within the RCC component. - ---- - -Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. -https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games - -> This mod is an independent creation 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.~~~~ \ No newline at end of file diff --git a/BetterContentLoading/format.json b/BetterContentLoading/format.json deleted file mode 100644 index f565d36..0000000 --- a/BetterContentLoading/format.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "_id": -1, - "name": "RCCVirtualSteeringWheel", - "modversion": "1.0.1", - "gameversion": "2024r177", - "loaderversion": "0.6.1", - "modtype": "Mod", - "author": "NotAKidoS", - "description": "Allows you to physically grab rigged RCC steering wheels in VR to provide steering input. No explicit setup required other than defining the Steering Wheel transform within the RCC component.\n", - "searchtags": [ - "rcc", - "steering", - "vehicle", - "car" - ], - "requirements": [ - "None" - ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r44/RCCVirtualSteeringWheel.dll", - "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/RCCVirtualSteeringWheel/", - "changelog": "- Initial release", - "embedcolor": "#f61963" -} \ No newline at end of file diff --git a/PlayerColorsAPI/Main.cs b/PlayerColorsAPI/Main.cs deleted file mode 100644 index 9e5634d..0000000 --- a/PlayerColorsAPI/Main.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using MelonLoader; - -namespace NAK.VisualCloneFix; - -public class VisualCloneFixMod : MelonMod -{ - #region Melon Preferences - - private static readonly MelonPreferences_Category Category = - MelonPreferences.CreateCategory(nameof(VisualCloneFix)); - - internal static readonly MelonPreferences_Entry EntryUseVisualClone = - Category.CreateEntry("use_visual_clone", true, - "Use Visual Clone", description: "Uses the potentially faster Visual Clone setup for the local avatar."); - - #endregion Melon Preferences - - #region Melon Events - - public override void OnInitializeMelon() - { - ApplyPatches(typeof(Patches)); // slapped together a fix cause HarmonyInstance.Patch was null ref for no reason? - } - - #endregion Melon Events - - #region Melon Mod Utilities - - private void ApplyPatches(Type type) - { - try - { - HarmonyInstance.PatchAll(type); - } - catch (Exception e) - { - LoggerInstance.Msg($"Failed while patching {type.Name}!"); - LoggerInstance.Error(e); - } - } - - #endregion Melon Mod Utilities -} \ No newline at end of file diff --git a/PlayerColorsAPI/Patches.cs b/PlayerColorsAPI/Patches.cs deleted file mode 100644 index 2fc9a14..0000000 --- a/PlayerColorsAPI/Patches.cs +++ /dev/null @@ -1,159 +0,0 @@ -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using ABI_RC.Core.Player.LocalClone; -using ABI_RC.Core.Player.TransformHider; -using ABI.CCK.Components; -using HarmonyLib; -using UnityEngine; -using Debug = UnityEngine.Debug; - -namespace NAK.VisualCloneFix; - -public static class Patches -{ - [HarmonyPrefix] - [HarmonyPatch(typeof(TransformHiderUtils), nameof(TransformHiderUtils.SetupAvatar))] - private static bool OnSetupAvatar(GameObject avatar) - { - if (!VisualCloneFixMod.EntryUseVisualClone.Value) - return true; - - LocalCloneHelper.SetupAvatar(avatar); - return false; - } - - [HarmonyPrefix] - [HarmonyPatch(typeof(LocalCloneHelper), nameof(LocalCloneHelper.CollectTransformToExclusionMap))] - private static bool CollectTransformToExclusionMap( - Component root, Transform headBone, - ref Dictionary __result) - { - // add an fpr exclusion to the head bone - if (!headBone.TryGetComponent(out FPRExclusion headExclusion)) - { - headExclusion = headBone.gameObject.AddComponent(); - headExclusion.isShown = false; // default to hidden - headExclusion.target = headBone; - } - - MeshHiderExclusion headExclusionBehaviour = new(); - headExclusion.behaviour = headExclusionBehaviour; - headExclusionBehaviour.id = 1; // head bone is always 1 - - // get all FPRExclusions - var fprExclusions = root.GetComponentsInChildren(true); - - // get all valid exclusion targets, and destroy invalid exclusions - Dictionary exclusionTargets = new(); - - int nextId = 2; - foreach (FPRExclusion exclusion in fprExclusions) - { - if (exclusion.target == null - || exclusionTargets.ContainsKey(exclusion.target) - || !exclusion.target.gameObject.scene.IsValid()) - continue; // invalid exclusion - - if (exclusion.behaviour == null) // head exclusion is already created - { - MeshHiderExclusion meshHiderExclusion = new(); - exclusion.behaviour = meshHiderExclusion; - meshHiderExclusion.id = nextId++; - } - - // first to add wins - exclusionTargets.TryAdd(exclusion.target, exclusion); - } - - // process each FPRExclusion (recursive) - int exclusionCount = exclusionTargets.Values.Count; - for (var index = 0; index < exclusionCount; index++) - { - FPRExclusion exclusion = exclusionTargets.Values.ElementAt(index); - ProcessExclusion(exclusion, exclusion.target); - exclusion.UpdateExclusions(); // initial state - } - - __result = exclusionTargets; - return false; - - void ProcessExclusion(FPRExclusion exclusion, Transform transform) - { - if (exclusionTargets.ContainsKey(transform) - && exclusionTargets[transform] != exclusion) return; // found other exclusion root - - exclusionTargets.TryAdd(transform, exclusion); // add to the dictionary (yes its wasteful) - foreach (Transform child in transform) - ProcessExclusion(exclusion, child); // process children - } - } - - [HarmonyPrefix] - [HarmonyPatch(typeof(SkinnedLocalClone), nameof(SkinnedLocalClone.FindExclusionVertList))] - private static bool FindExclusionVertList( - SkinnedMeshRenderer renderer, IReadOnlyDictionary exclusions, - ref int[] __result) - { - // Start the stopwatch - Stopwatch stopwatch = new(); - stopwatch.Start(); - - var boneWeights = renderer.sharedMesh.boneWeights; - var bones = renderer.bones; - int boneCount = bones.Length; - - bool[] boneHasExclusion = new bool[boneCount]; - - // Populate the weights array - for (int i = 0; i < boneCount; i++) - { - Transform bone = bones[i]; - if (bone == null) continue; - if (exclusions.ContainsKey(bone)) - boneHasExclusion[i] = true; - } - - const float minWeightThreshold = 0.2f; - - int[] vertexIndices = new int[renderer.sharedMesh.vertexCount]; - - // Check bone weights and add vertex to exclusion list if needed - for (int i = 0; i < boneWeights.Length; i++) - { - BoneWeight weight = boneWeights[i]; - Transform bone; - - if (boneHasExclusion[weight.boneIndex0] && weight.weight0 > minWeightThreshold) - bone = bones[weight.boneIndex0]; - else if (boneHasExclusion[weight.boneIndex1] && weight.weight1 > minWeightThreshold) - bone = bones[weight.boneIndex1]; - else if (boneHasExclusion[weight.boneIndex2] && weight.weight2 > minWeightThreshold) - bone = bones[weight.boneIndex2]; - else if (boneHasExclusion[weight.boneIndex3] && weight.weight3 > minWeightThreshold) - bone = bones[weight.boneIndex3]; - else continue; - - if (exclusions.TryGetValue(bone, out FPRExclusion exclusion)) - vertexIndices[i] = ((MeshHiderExclusion)(exclusion.behaviour)).id; - } - - // Stop the stopwatch - stopwatch.Stop(); - - // Log the execution time - Debug.Log($"FindExclusionVertList execution time: {stopwatch.ElapsedMilliseconds} ms"); - - __result = vertexIndices; - return false; - } - - [HarmonyPrefix] - [HarmonyPatch(typeof(MeshHiderExclusion), nameof(MeshHiderExclusion.UpdateExclusions))] - private static bool OnUpdateExclusions(bool isShown, bool shrinkToZero, ref int ___id) - { - if (isShown) LocalCloneManager.cullingMask &= ~(1 << ___id); - else LocalCloneManager.cullingMask |= 1 << ___id; - return false; - } -} \ No newline at end of file diff --git a/PlayerColorsAPI/PlayerColorsAPI.csproj b/PlayerColorsAPI/PlayerColorsAPI.csproj deleted file mode 100644 index 8dc4bcd..0000000 --- a/PlayerColorsAPI/PlayerColorsAPI.csproj +++ /dev/null @@ -1,6 +0,0 @@ - - - - LocalCloneFix - - diff --git a/PlayerColorsAPI/Properties/AssemblyInfo.cs b/PlayerColorsAPI/Properties/AssemblyInfo.cs deleted file mode 100644 index 10b75bb..0000000 --- a/PlayerColorsAPI/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,32 +0,0 @@ -using MelonLoader; -using NAK.VisualCloneFix.Properties; -using System.Reflection; - -[assembly: AssemblyVersion(AssemblyInfoParams.Version)] -[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] -[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] -[assembly: AssemblyTitle(nameof(NAK.VisualCloneFix))] -[assembly: AssemblyCompany(AssemblyInfoParams.Author)] -[assembly: AssemblyProduct(nameof(NAK.VisualCloneFix))] - -[assembly: MelonInfo( - typeof(NAK.VisualCloneFix.VisualCloneFixMod), - nameof(NAK.VisualCloneFix), - AssemblyInfoParams.Version, - AssemblyInfoParams.Author, - downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/VisualCloneFix" -)] - -[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] -[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] -[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] -[assembly: MelonColor(255, 246, 25, 99)] // red-pink -[assembly: MelonAuthorColor(255, 158, 21, 32)] // red -[assembly: HarmonyDontPatchAll] - -namespace NAK.VisualCloneFix.Properties; -internal static class AssemblyInfoParams -{ - public const string Version = "1.0.1"; - public const string Author = "NotAKidoS"; -} \ No newline at end of file diff --git a/PlayerColorsAPI/README.md b/PlayerColorsAPI/README.md deleted file mode 100644 index cc12a9c..0000000 --- a/PlayerColorsAPI/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# VisualCloneFix - -Fixes the Visual Clone system and allows you to use it again. - -Using the Visual Clone should be faster than the default Head Hiding & Shadow Clones, but will add a longer hitch on initial avatar load. - -**NOTE:** The Visual Clone is still an experimental feature that was temporarily removed in [ChilloutVR 2024r175 Hotfix 1](https://abinteractive.net/blog/chilloutvr_2024r175_hotfix_1), so there may be bugs or issues with it. - ---- - -Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. -https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games - -> This mod is an independent creation 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/PlayerColorsAPI/format.json b/PlayerColorsAPI/format.json deleted file mode 100644 index 6634e9f..0000000 --- a/PlayerColorsAPI/format.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "_id": 221, - "name": "VisualCloneFix", - "modversion": "1.0.1", - "gameversion": "2024r175", - "loaderversion": "0.6.1", - "modtype": "Mod", - "author": "NotAKidoS", - "description": "Fixes the Visual Clone system and allows you to use it again.\n\nUsing the Visual Clone should be faster than the default Head Hiding & Shadow Clones, but will add a longer hitch on initial avatar load.\n\n**NOTE:** The Visual Clone is still an experimental feature that was temporarily removed in [ChilloutVR 2024r175 Hotfix 1](https://abinteractive.net/blog/chilloutvr_2024r175_hotfix_1), so there may be bugs or issues with it.", - "searchtags": [ - "visual", - "clone", - "head", - "hiding" - ], - "requirements": [ - "None" - ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r36/VisualCloneFix.dll", - "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/VisualCloneFix/", - "changelog": "- Fixed FPRExclusions IsShown state being inverted when toggled.\n- Fixed head FPRExclusion generation not checking for existing exclusion.\n- Sped up FindExclusionVertList by 100x by not being an idiot. This heavily reduces avatar hitch with Visual Clone active.", - "embedcolor": "#f61963" -} \ No newline at end of file From 7ad549b0bb1a408b90a0f20ab764a553edbcaa9b Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 03:08:25 -0500 Subject: [PATCH 011/119] dead --- .../CameraExperiments.csproj | 6 - .Deprecated/CameraExperiments/Main.cs | 170 ------------------ .../Properties/AssemblyInfo.cs | 32 ---- .Deprecated/CameraExperiments/README.md | 14 -- .Deprecated/CameraExperiments/format.json | 23 --- 5 files changed, 245 deletions(-) delete mode 100644 .Deprecated/CameraExperiments/CameraExperiments.csproj delete mode 100644 .Deprecated/CameraExperiments/Main.cs delete mode 100644 .Deprecated/CameraExperiments/Properties/AssemblyInfo.cs delete mode 100644 .Deprecated/CameraExperiments/README.md delete mode 100644 .Deprecated/CameraExperiments/format.json diff --git a/.Deprecated/CameraExperiments/CameraExperiments.csproj b/.Deprecated/CameraExperiments/CameraExperiments.csproj deleted file mode 100644 index 728edb7..0000000 --- a/.Deprecated/CameraExperiments/CameraExperiments.csproj +++ /dev/null @@ -1,6 +0,0 @@ - - - - net48 - - diff --git a/.Deprecated/CameraExperiments/Main.cs b/.Deprecated/CameraExperiments/Main.cs deleted file mode 100644 index 51035fd..0000000 --- a/.Deprecated/CameraExperiments/Main.cs +++ /dev/null @@ -1,170 +0,0 @@ -using ABI_RC.Core; -using ABI_RC.Core.InteractionSystem; -using ABI_RC.Core.Player; -using HarmonyLib; -using MagicaCloth2; -using MelonLoader; -using Unity.Burst; -using Unity.Collections; -using Unity.Jobs; -using UnityEngine; - -namespace NAK.WhereAmIPointing; - -public class WhereAmIPointingMod : MelonMod -{ - #region Melon Preferences - - // cannot disable because then id need extra logic to reset the alpha :) - // private const string SettingsCategory = nameof(WhereAmIPointingMod); - // - // private static readonly MelonPreferences_Category Category = - // MelonPreferences.CreateCategory(SettingsCategory); - // - // private static readonly MelonPreferences_Entry Entry_Enabled = - // Category.CreateEntry("enabled", true, display_name: "Enabled",description: "Toggle WhereAmIPointingMod entirely."); - - #endregion Melon Preferences - - public override void OnInitializeMelon() - { - ApplyPatches(typeof(TransformManager_Patches)); - } - - private void ApplyPatches(Type type) - { - try - { - HarmonyInstance.PatchAll(type); - } - catch (Exception e) - { - LoggerInstance.Msg($"Failed while patching {type.Name}!"); - LoggerInstance.Error(e); - } - } - - internal static class TransformManager_Patches - { - // Patch for EnableTransform(DataChunk, bool) - [HarmonyPrefix] - [HarmonyPatch(typeof(TransformManager), nameof(TransformManager.EnableTransform), new[] { typeof(DataChunk), typeof(bool) })] - private static bool OnEnableTransformChunk(TransformManager __instance, DataChunk c, bool sw, ref NativeArray ___flagArray) - { - try - { - // Enhanced validation - if (!__instance.IsValid()) - return false; - - if (___flagArray == null || !___flagArray.IsCreated) - { - Debug.LogWarning("[MagicaCloth2] EnableTransform failed: Flag array is invalid or disposed"); - return false; - } - - if (!c.IsValid || c.startIndex < 0 || c.startIndex + c.dataLength > ___flagArray.Length) - { - Debug.LogWarning($"[MagicaCloth2] EnableTransform failed: Invalid chunk parameters. Start: {c.startIndex}, Length: {c.dataLength}, Array Length: {___flagArray.Length}"); - return false; - } - - // Create and run the job with additional safety - SafeEnableTransformJob job = new() - { - chunk = c, - sw = sw, - flagList = ___flagArray, - maxLength = ___flagArray.Length - }; - - try - { - job.Run(); - } - catch (Exception ex) - { - Debug.LogError($"[MagicaCloth2] Error in EnableTransform job execution: {ex.Message}"); - return false; - } - - return false; // Prevent original method execution - } - catch (Exception ex) - { - Debug.LogError($"[MagicaCloth2] Critical error in EnableTransform patch: {ex.Message}"); - return false; - } - } - - // Patch for EnableTransform(int, bool) - [HarmonyPrefix] - [HarmonyPatch(typeof(TransformManager), nameof(TransformManager.EnableTransform), new[] { typeof(int), typeof(bool) })] - private static bool OnEnableTransformIndex(TransformManager __instance, int index, bool sw, ref NativeArray ___flagArray) - { - try - { - // Enhanced validation - if (!__instance.IsValid()) - return false; - - if (___flagArray == null || !___flagArray.IsCreated) - { - Debug.LogWarning("[MagicaCloth2] EnableTransform failed: Flag array is invalid or disposed"); - return false; - } - - if (index < 0 || index >= ___flagArray.Length) - { - Debug.LogWarning($"[MagicaCloth2] EnableTransform failed: Index {index} out of range [0, {___flagArray.Length})"); - return false; - } - - // Safely modify the flag - var flag = ___flagArray[index]; - if (flag.Value == 0) - return false; - - flag.SetFlag(TransformManager.Flag_Enable, sw); - ___flagArray[index] = flag; - - return false; // Prevent original method execution - } - catch (Exception ex) - { - Debug.LogError($"[MagicaCloth2] Critical error in EnableTransform patch: {ex.Message}"); - return false; - } - } - - [BurstCompile] - private struct SafeEnableTransformJob : IJob - { - public DataChunk chunk; - public bool sw; - public NativeArray flagList; - [ReadOnly] public int maxLength; - - public void Execute() - { - // Additional bounds checking - if (chunk.startIndex < 0 || chunk.startIndex + chunk.dataLength > maxLength) - return; - - for (int i = 0; i < chunk.dataLength; i++) - { - int index = chunk.startIndex + i; - if (index >= maxLength) - break; - - ExBitFlag8 flag = flagList[index]; - if (flag.Value == 0) - continue; - - flag.SetFlag(TransformManager.Flag_Enable, sw); - flagList[index] = flag; - } - } - } - } -} \ No newline at end of file diff --git a/.Deprecated/CameraExperiments/Properties/AssemblyInfo.cs b/.Deprecated/CameraExperiments/Properties/AssemblyInfo.cs deleted file mode 100644 index 48c359f..0000000 --- a/.Deprecated/CameraExperiments/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,32 +0,0 @@ -using NAK.WhereAmIPointing.Properties; -using MelonLoader; -using System.Reflection; - -[assembly: AssemblyVersion(AssemblyInfoParams.Version)] -[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] -[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] -[assembly: AssemblyTitle(nameof(NAK.WhereAmIPointing))] -[assembly: AssemblyCompany(AssemblyInfoParams.Author)] -[assembly: AssemblyProduct(nameof(NAK.WhereAmIPointing))] - -[assembly: MelonInfo( - typeof(NAK.WhereAmIPointing.WhereAmIPointingMod), - nameof(NAK.WhereAmIPointing), - AssemblyInfoParams.Version, - AssemblyInfoParams.Author, - downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/WhereAmIPointing" -)] - -[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] -[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] -[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] -[assembly: MelonColor(255, 246, 25, 99)] // red-pink -[assembly: MelonAuthorColor(255, 158, 21, 32)] // red -[assembly: HarmonyDontPatchAll] - -namespace NAK.WhereAmIPointing.Properties; -internal static class AssemblyInfoParams -{ - public const string Version = "1.0.1"; - public const string Author = "NotAKidoS"; -} \ No newline at end of file diff --git a/.Deprecated/CameraExperiments/README.md b/.Deprecated/CameraExperiments/README.md deleted file mode 100644 index c78a56a..0000000 --- a/.Deprecated/CameraExperiments/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# WhereAmIPointing - -Simple mod that makes your controller rays always visible when the menus are open. Useful for when you're trying to aim at something in the distance. Also visualizes which ray is being used for menu interaction. - ---- - -Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. -https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games - -> This mod is an independent creation 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/.Deprecated/CameraExperiments/format.json b/.Deprecated/CameraExperiments/format.json deleted file mode 100644 index 654911a..0000000 --- a/.Deprecated/CameraExperiments/format.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "_id": 234, - "name": "WhereAmIPointing", - "modversion": "1.0.1", - "gameversion": "2024r175", - "loaderversion": "0.6.1", - "modtype": "Mod", - "author": "NotAKidoS", - "description": "Simple mod that makes your controller rays always visible when the menus are open. Useful for when you're trying to aim at something in the distance. Also visualizes which ray is being used for menu interaction.", - "searchtags": [ - "controller", - "ray", - "line", - "tomato" - ], - "requirements": [ - "None" - ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r40/WhereAmIPointing.dll", - "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/WhereAmIPointing/", - "changelog": "- Fixed line renderer alpha not being reset when the menu is closed.", - "embedcolor": "#f61963" -} \ No newline at end of file From 8cffe8a5be5fd9529bda723edbef8abd8c4b2c25 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 03:16:00 -0500 Subject: [PATCH 012/119] [NAK_CVR_Mods] Update solution --- NAK_CVR_Mods.sln | 654 +++++++++++++++++++---------------------- References.Items.props | 20 ++ 2 files changed, 319 insertions(+), 355 deletions(-) diff --git a/NAK_CVR_Mods.sln b/NAK_CVR_Mods.sln index 082aeae..5cc9493 100644 --- a/NAK_CVR_Mods.sln +++ b/NAK_CVR_Mods.sln @@ -1,355 +1,299 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.2.32630.192 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CVRGizmos", "CVRGizmos\CVRGizmos.csproj", "{CF9BC79E-4FB6-429A-8C19-DF31F040BD4A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FuckToes", "FuckToes\FuckToes.csproj", "{79B2A7C4-348D-4A8E-94D1-BA22FDD5FEED}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GestureLock", "GestureLock\GestureLock.csproj", "{45A65AEB-4BFC-4E47-B181-BBB43BD81283}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PathCamDisabler", "PathCamDisabler\PathCamDisabler.csproj", "{98169FD2-5CEB-46D1-A320-D7E06F82C9E0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PortableCameraAdditions", "PortableCameraAdditions\PortableCameraAdditions.csproj", "{C4DAFE9D-C79B-4417-9B7D-B7327999DA4C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PropUndoButton", "PropUndoButton\PropUndoButton.csproj", "{FBFDB717-F81E-4C06-ACF9-A0F3FFDCDE00}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThirdPerson", "ThirdPerson\ThirdPerson.csproj", "{675CEC0E-3E8A-4970-98EA-9B79277A7252}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FOVAdjustment", "FOVAdjustment\FOVAdjustment.csproj", "{EE552804-30B1-49CF-BBDE-3B312895AFF7}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MuteSFX", "MuteSFX\MuteSFX.csproj", "{77D222FC-4AEC-4672-A87A-B860B4C39E17}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChatBoxExtensions", "ChatBoxExtensions\ChatBoxExtensions.csproj", "{0E1DD746-33A1-4179-AE70-8FB83AC40ABC}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhysicsGunMod", "PhysicsGunMod\PhysicsGunMod.csproj", "{F94DDB73-9041-4F5C-AD43-6960701E8417}" -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}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StopClosingMyMenuOnWorldLoad", "StopClosingMyMenuOnWorldLoad\StopClosingMyMenuOnWorldLoad.csproj", "{9FA83514-13F8-412C-9790-C2B750E0E7E7}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RelativeSync", "RelativeSync\RelativeSync.csproj", "{B48C8F19-9451-4EE2-999F-82C0033CDE2C}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptingSpoofer", "ScriptingSpoofer\ScriptingSpoofer.csproj", "{6B4396C7-B451-4FFD-87B6-3ED8377AC308}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuaTTS", "LuaTTS\LuaTTS.csproj", "{24A069F4-4D69-4ABD-AA16-77765469245B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LazyPrune", "LazyPrune\LazyPrune.csproj", "{8FA6D481-5801-4E4C-822E-DE561155D22B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReconnectionSystemFix", "ReconnectionSystemFix\ReconnectionSystemFix.csproj", "{05C427DD-1261-4AAD-B316-A551FC126F2C}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AASDefaultProfileFix", "AASDefaultProfileFix\AASDefaultProfileFix.csproj", "{C6794B18-E785-4F91-A517-3A2A8006E008}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OriginShift", "OriginShift\OriginShift.csproj", "{F381F604-9C16-4870-AD49-4BD7CA3F36DC}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScrollFlight", "ScrollFlight\ScrollFlight.csproj", "{1B5D7DCB-01A4-4988-8B25-211948AEED76}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Portals", "Portals\Portals.csproj", "{BE9629C2-8461-481C-B267-1B8A1805DCD7}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PropLoadingHexagon", "PropLoadingHexagon\PropLoadingHexagon.csproj", "{642A2BC7-C027-4F8F-969C-EF0F867936FD}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IKSimulatedRootAngleFix", "IKSimulatedRootAngleFix\IKSimulatedRootAngleFix.csproj", "{D11214B0-94FE-4008-8D1B-3DC8614466B3}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DropPropTweak", "DropPropTweak\DropPropTweak.csproj", "{2CC1F7C6-A953-4008-8C10-C7592EB401E8}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualCloneFix", "VisualCloneFix\VisualCloneFix.csproj", "{39915C4C-B555-4CB9-890F-26DE1388BC2E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InteractionTest", "InteractionTest\InteractionTest.csproj", "{7C675E64-0A2D-4B34-B6D1-5D6AA369A520}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeepVelocityOnExitFlight", "KeepVelocityOnExitFlight\KeepVelocityOnExitFlight.csproj", "{0BB3D187-BBBA-4C58-B246-102342BE5E8C}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ASTExtension", "ASTExtension\ASTExtension.csproj", "{6580AA87-6A95-438E-A5D3-70E583CCD77B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AvatarQueueSystemTweaks", "AvatarQueueSystemTweaks\AvatarQueueSystemTweaks.csproj", "{D178E422-283B-4FB3-89A6-AA4FB9F87E2F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomSpawnPoint", "CustomSpawnPoint\CustomSpawnPoint.csproj", "{51CA34CA-7684-4819-AC9E-89DFAD63E9AB}" -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}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartReticle", "SmartReticle\SmartReticle.csproj", "{3C992D0C-9729-438E-800C-496B7EFFFB25}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WhereAmIPointing", "WhereAmIPointing\WhereAmIPointing.csproj", "{E285BCC9-D953-4066-8FA2-97EA28EB348E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AvatarScaleMod", "AvatarScaleMod\AvatarScaleMod.csproj", "{A38E687F-8B6B-499E-ABC9-BD95C53DD391}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmootherRay", "SmootherRay\SmootherRay.csproj", "{99F9D60D-9A2D-4DBE-AA52-13D8A0838696}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuaNetworkVariables", "LuaNetworkVariables\LuaNetworkVariables.csproj", "{A3D97D1A-3099-49C5-85AD-D8C79CC5FDE3}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SearchWithSpacesFix", "SearchWithSpacesFix\SearchWithSpacesFix.csproj", "{0640B2BF-1EF5-4FFE-A144-0368748FC48B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ComponentMonitor", "ComponentMonitor\ComponentMonitor.csproj", "{FC91FFFE-1E0A-4F59-8802-BFF99152AD07}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShareBubbles", "ShareBubbles\ShareBubbles.csproj", "{ADD6205B-67A4-4BA8-8BED-DF7D0E857A6A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MutualMute", "MutualMute\MutualMute.csproj", "{6E315182-CC9F-4F62-8385-5E26EFA3B98A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BullshitWatcher", "BullshitWatcher\BullshitWatcher.csproj", "{09238300-4583-45C6-A997-025CBDC44C24}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LegacyContentMitigation", "LegacyContentMitigation\LegacyContentMitigation.csproj", "{21FDAB94-5014-488D-86C7-A366F1902B24}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RCCVirtualSteeringWheel", "RCCVirtualSteeringWheel\RCCVirtualSteeringWheel.csproj", "{4A378F81-3805-41E8-9565-A8A89A8C00D6}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BetterContentLoading", "BetterContentLoading\BetterContentLoading.csproj", "{FFCF6FA8-4F38-415E-AC2D-B576FFD5FED5}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CameraExperiments", "CameraExperiments\CameraExperiments.csproj", "{71CBD7CC-C787-4796-B05E-4F3BC3C28B48}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RemoteAvatarDisablingCameraOnFirstFrameFix", "RemoteAvatarDisablingCameraOnFirstFrameFix\RemoteAvatarDisablingCameraOnFirstFrameFix.csproj", "{42E626F7-9A7E-4F55-B02C-16EB56E2B540}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AvatarCloneTest", "AvatarCloneTest\AvatarCloneTest.csproj", "{8BF2CBBF-6DAB-4D7A-87E0-AE643D6019AB}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FuckOffUICamera", "FuckOffUICamera\FuckOffUICamera.csproj", "{262A8AE0-E610-405F-B4EC-DB714FB54C00}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomRichPresence", "CustomRichPresence\CustomRichPresence.csproj", "{E5F07862-5715-470D-B324-19BDEBB2AA4D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FuckMagicaCloth2", "FuckMagicaCloth2\FuckMagicaCloth2.csproj", "{21B591A0-F6E5-4645-BF2D-4E71F47394A7}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperAwesomeMod", "SuperAwesomeMod\SuperAwesomeMod.csproj", "{F093BDE5-1824-459E-B86E-B9F79B548E58}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlToUnlockMouse", "ControlToUnlockMouse\ControlToUnlockMouse.csproj", "{EDA96974-0BEA-404B-8EED-F19CCA2C95A8}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EzCurls", ".DepricatedMods\EzCurls\EzCurls.csproj", "{ED2CAA2D-4E49-4636-86C4-367D0CDC3572}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {CF9BC79E-4FB6-429A-8C19-DF31F040BD4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CF9BC79E-4FB6-429A-8C19-DF31F040BD4A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CF9BC79E-4FB6-429A-8C19-DF31F040BD4A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CF9BC79E-4FB6-429A-8C19-DF31F040BD4A}.Release|Any CPU.Build.0 = Release|Any CPU - {79B2A7C4-348D-4A8E-94D1-BA22FDD5FEED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {79B2A7C4-348D-4A8E-94D1-BA22FDD5FEED}.Debug|Any CPU.Build.0 = Debug|Any CPU - {79B2A7C4-348D-4A8E-94D1-BA22FDD5FEED}.Release|Any CPU.ActiveCfg = Release|Any CPU - {79B2A7C4-348D-4A8E-94D1-BA22FDD5FEED}.Release|Any CPU.Build.0 = Release|Any CPU - {45A65AEB-4BFC-4E47-B181-BBB43BD81283}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {45A65AEB-4BFC-4E47-B181-BBB43BD81283}.Debug|Any CPU.Build.0 = Debug|Any CPU - {45A65AEB-4BFC-4E47-B181-BBB43BD81283}.Release|Any CPU.ActiveCfg = Release|Any CPU - {45A65AEB-4BFC-4E47-B181-BBB43BD81283}.Release|Any CPU.Build.0 = Release|Any CPU - {98169FD2-5CEB-46D1-A320-D7E06F82C9E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {98169FD2-5CEB-46D1-A320-D7E06F82C9E0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {98169FD2-5CEB-46D1-A320-D7E06F82C9E0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {98169FD2-5CEB-46D1-A320-D7E06F82C9E0}.Release|Any CPU.Build.0 = Release|Any CPU - {C4DAFE9D-C79B-4417-9B7D-B7327999DA4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C4DAFE9D-C79B-4417-9B7D-B7327999DA4C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C4DAFE9D-C79B-4417-9B7D-B7327999DA4C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C4DAFE9D-C79B-4417-9B7D-B7327999DA4C}.Release|Any CPU.Build.0 = Release|Any CPU - {FBFDB717-F81E-4C06-ACF9-A0F3FFDCDE00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FBFDB717-F81E-4C06-ACF9-A0F3FFDCDE00}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FBFDB717-F81E-4C06-ACF9-A0F3FFDCDE00}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FBFDB717-F81E-4C06-ACF9-A0F3FFDCDE00}.Release|Any CPU.Build.0 = Release|Any CPU - {675CEC0E-3E8A-4970-98EA-9B79277A7252}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {675CEC0E-3E8A-4970-98EA-9B79277A7252}.Debug|Any CPU.Build.0 = Debug|Any CPU - {675CEC0E-3E8A-4970-98EA-9B79277A7252}.Release|Any CPU.ActiveCfg = Release|Any CPU - {675CEC0E-3E8A-4970-98EA-9B79277A7252}.Release|Any CPU.Build.0 = Release|Any CPU - {EE552804-30B1-49CF-BBDE-3B312895AFF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EE552804-30B1-49CF-BBDE-3B312895AFF7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EE552804-30B1-49CF-BBDE-3B312895AFF7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EE552804-30B1-49CF-BBDE-3B312895AFF7}.Release|Any CPU.Build.0 = Release|Any CPU - {77D222FC-4AEC-4672-A87A-B860B4C39E17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {77D222FC-4AEC-4672-A87A-B860B4C39E17}.Debug|Any CPU.Build.0 = Debug|Any CPU - {77D222FC-4AEC-4672-A87A-B860B4C39E17}.Release|Any CPU.ActiveCfg = Release|Any CPU - {77D222FC-4AEC-4672-A87A-B860B4C39E17}.Release|Any CPU.Build.0 = Release|Any CPU - {0E1DD746-33A1-4179-AE70-8FB83AC40ABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0E1DD746-33A1-4179-AE70-8FB83AC40ABC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0E1DD746-33A1-4179-AE70-8FB83AC40ABC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0E1DD746-33A1-4179-AE70-8FB83AC40ABC}.Release|Any CPU.Build.0 = Release|Any CPU - {F94DDB73-9041-4F5C-AD43-6960701E8417}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {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 - {AC4857DD-F6D9-436D-A3EE-D148A518E642}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AC4857DD-F6D9-436D-A3EE-D148A518E642}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AC4857DD-F6D9-436D-A3EE-D148A518E642}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AC4857DD-F6D9-436D-A3EE-D148A518E642}.Release|Any CPU.Build.0 = Release|Any CPU - {69AF3C10-1BB1-4746-B697-B5A81D78C8D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {69AF3C10-1BB1-4746-B697-B5A81D78C8D9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {69AF3C10-1BB1-4746-B697-B5A81D78C8D9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {69AF3C10-1BB1-4746-B697-B5A81D78C8D9}.Release|Any CPU.Build.0 = Release|Any CPU - {9FA83514-13F8-412C-9790-C2B750E0E7E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9FA83514-13F8-412C-9790-C2B750E0E7E7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9FA83514-13F8-412C-9790-C2B750E0E7E7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9FA83514-13F8-412C-9790-C2B750E0E7E7}.Release|Any CPU.Build.0 = Release|Any CPU - {B48C8F19-9451-4EE2-999F-82C0033CDE2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B48C8F19-9451-4EE2-999F-82C0033CDE2C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B48C8F19-9451-4EE2-999F-82C0033CDE2C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B48C8F19-9451-4EE2-999F-82C0033CDE2C}.Release|Any CPU.Build.0 = Release|Any CPU - {6B4396C7-B451-4FFD-87B6-3ED8377AC308}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6B4396C7-B451-4FFD-87B6-3ED8377AC308}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6B4396C7-B451-4FFD-87B6-3ED8377AC308}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6B4396C7-B451-4FFD-87B6-3ED8377AC308}.Release|Any CPU.Build.0 = Release|Any CPU - {24A069F4-4D69-4ABD-AA16-77765469245B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {24A069F4-4D69-4ABD-AA16-77765469245B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {24A069F4-4D69-4ABD-AA16-77765469245B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {24A069F4-4D69-4ABD-AA16-77765469245B}.Release|Any CPU.Build.0 = Release|Any CPU - {8FA6D481-5801-4E4C-822E-DE561155D22B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8FA6D481-5801-4E4C-822E-DE561155D22B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8FA6D481-5801-4E4C-822E-DE561155D22B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8FA6D481-5801-4E4C-822E-DE561155D22B}.Release|Any CPU.Build.0 = Release|Any CPU - {05C427DD-1261-4AAD-B316-A551FC126F2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {05C427DD-1261-4AAD-B316-A551FC126F2C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {05C427DD-1261-4AAD-B316-A551FC126F2C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {05C427DD-1261-4AAD-B316-A551FC126F2C}.Release|Any CPU.Build.0 = Release|Any CPU - {C6794B18-E785-4F91-A517-3A2A8006E008}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C6794B18-E785-4F91-A517-3A2A8006E008}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C6794B18-E785-4F91-A517-3A2A8006E008}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C6794B18-E785-4F91-A517-3A2A8006E008}.Release|Any CPU.Build.0 = Release|Any CPU - {F381F604-9C16-4870-AD49-4BD7CA3F36DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F381F604-9C16-4870-AD49-4BD7CA3F36DC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F381F604-9C16-4870-AD49-4BD7CA3F36DC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F381F604-9C16-4870-AD49-4BD7CA3F36DC}.Release|Any CPU.Build.0 = Release|Any CPU - {1B5D7DCB-01A4-4988-8B25-211948AEED76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1B5D7DCB-01A4-4988-8B25-211948AEED76}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1B5D7DCB-01A4-4988-8B25-211948AEED76}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1B5D7DCB-01A4-4988-8B25-211948AEED76}.Release|Any CPU.Build.0 = Release|Any CPU - {BE9629C2-8461-481C-B267-1B8A1805DCD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BE9629C2-8461-481C-B267-1B8A1805DCD7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BE9629C2-8461-481C-B267-1B8A1805DCD7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BE9629C2-8461-481C-B267-1B8A1805DCD7}.Release|Any CPU.Build.0 = Release|Any CPU - {642A2BC7-C027-4F8F-969C-EF0F867936FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {642A2BC7-C027-4F8F-969C-EF0F867936FD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {642A2BC7-C027-4F8F-969C-EF0F867936FD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {642A2BC7-C027-4F8F-969C-EF0F867936FD}.Release|Any CPU.Build.0 = Release|Any CPU - {D11214B0-94FE-4008-8D1B-3DC8614466B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D11214B0-94FE-4008-8D1B-3DC8614466B3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D11214B0-94FE-4008-8D1B-3DC8614466B3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D11214B0-94FE-4008-8D1B-3DC8614466B3}.Release|Any CPU.Build.0 = Release|Any CPU - {2CC1F7C6-A953-4008-8C10-C7592EB401E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2CC1F7C6-A953-4008-8C10-C7592EB401E8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2CC1F7C6-A953-4008-8C10-C7592EB401E8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2CC1F7C6-A953-4008-8C10-C7592EB401E8}.Release|Any CPU.Build.0 = Release|Any CPU - {39915C4C-B555-4CB9-890F-26DE1388BC2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {39915C4C-B555-4CB9-890F-26DE1388BC2E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {39915C4C-B555-4CB9-890F-26DE1388BC2E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {39915C4C-B555-4CB9-890F-26DE1388BC2E}.Release|Any CPU.Build.0 = Release|Any CPU - {7C675E64-0A2D-4B34-B6D1-5D6AA369A520}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7C675E64-0A2D-4B34-B6D1-5D6AA369A520}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7C675E64-0A2D-4B34-B6D1-5D6AA369A520}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7C675E64-0A2D-4B34-B6D1-5D6AA369A520}.Release|Any CPU.Build.0 = Release|Any CPU - {0BB3D187-BBBA-4C58-B246-102342BE5E8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0BB3D187-BBBA-4C58-B246-102342BE5E8C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0BB3D187-BBBA-4C58-B246-102342BE5E8C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0BB3D187-BBBA-4C58-B246-102342BE5E8C}.Release|Any CPU.Build.0 = Release|Any CPU - {6580AA87-6A95-438E-A5D3-70E583CCD77B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6580AA87-6A95-438E-A5D3-70E583CCD77B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6580AA87-6A95-438E-A5D3-70E583CCD77B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6580AA87-6A95-438E-A5D3-70E583CCD77B}.Release|Any CPU.Build.0 = Release|Any CPU - {D178E422-283B-4FB3-89A6-AA4FB9F87E2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D178E422-283B-4FB3-89A6-AA4FB9F87E2F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D178E422-283B-4FB3-89A6-AA4FB9F87E2F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D178E422-283B-4FB3-89A6-AA4FB9F87E2F}.Release|Any CPU.Build.0 = Release|Any CPU - {51CA34CA-7684-4819-AC9E-89DFAD63E9AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {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 - {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 - {FE6BA6EC-2C11-49E1-A2FB-13F2A1C9E7F9}.Release|Any CPU.Build.0 = Release|Any CPU - {E5F54B3E-A676-4DD5-A6DB-73AFA54BEC5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E5F54B3E-A676-4DD5-A6DB-73AFA54BEC5E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E5F54B3E-A676-4DD5-A6DB-73AFA54BEC5E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E5F54B3E-A676-4DD5-A6DB-73AFA54BEC5E}.Release|Any CPU.Build.0 = Release|Any CPU - {3C992D0C-9729-438E-800C-496B7EFFFB25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3C992D0C-9729-438E-800C-496B7EFFFB25}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3C992D0C-9729-438E-800C-496B7EFFFB25}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3C992D0C-9729-438E-800C-496B7EFFFB25}.Release|Any CPU.Build.0 = Release|Any CPU - {E285BCC9-D953-4066-8FA2-97EA28EB348E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E285BCC9-D953-4066-8FA2-97EA28EB348E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E285BCC9-D953-4066-8FA2-97EA28EB348E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E285BCC9-D953-4066-8FA2-97EA28EB348E}.Release|Any CPU.Build.0 = Release|Any CPU - {A38E687F-8B6B-499E-ABC9-BD95C53DD391}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A38E687F-8B6B-499E-ABC9-BD95C53DD391}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A38E687F-8B6B-499E-ABC9-BD95C53DD391}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A38E687F-8B6B-499E-ABC9-BD95C53DD391}.Release|Any CPU.Build.0 = Release|Any CPU - {99F9D60D-9A2D-4DBE-AA52-13D8A0838696}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {99F9D60D-9A2D-4DBE-AA52-13D8A0838696}.Debug|Any CPU.Build.0 = Debug|Any CPU - {99F9D60D-9A2D-4DBE-AA52-13D8A0838696}.Release|Any CPU.ActiveCfg = Release|Any CPU - {99F9D60D-9A2D-4DBE-AA52-13D8A0838696}.Release|Any CPU.Build.0 = Release|Any CPU - {A3D97D1A-3099-49C5-85AD-D8C79CC5FDE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A3D97D1A-3099-49C5-85AD-D8C79CC5FDE3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A3D97D1A-3099-49C5-85AD-D8C79CC5FDE3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A3D97D1A-3099-49C5-85AD-D8C79CC5FDE3}.Release|Any CPU.Build.0 = Release|Any CPU - {0640B2BF-1EF5-4FFE-A144-0368748FC48B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0640B2BF-1EF5-4FFE-A144-0368748FC48B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0640B2BF-1EF5-4FFE-A144-0368748FC48B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0640B2BF-1EF5-4FFE-A144-0368748FC48B}.Release|Any CPU.Build.0 = Release|Any CPU - {FC91FFFE-1E0A-4F59-8802-BFF99152AD07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FC91FFFE-1E0A-4F59-8802-BFF99152AD07}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FC91FFFE-1E0A-4F59-8802-BFF99152AD07}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FC91FFFE-1E0A-4F59-8802-BFF99152AD07}.Release|Any CPU.Build.0 = Release|Any CPU - {ADD6205B-67A4-4BA8-8BED-DF7D0E857A6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ADD6205B-67A4-4BA8-8BED-DF7D0E857A6A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ADD6205B-67A4-4BA8-8BED-DF7D0E857A6A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ADD6205B-67A4-4BA8-8BED-DF7D0E857A6A}.Release|Any CPU.Build.0 = Release|Any CPU - {6E315182-CC9F-4F62-8385-5E26EFA3B98A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6E315182-CC9F-4F62-8385-5E26EFA3B98A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6E315182-CC9F-4F62-8385-5E26EFA3B98A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6E315182-CC9F-4F62-8385-5E26EFA3B98A}.Release|Any CPU.Build.0 = Release|Any CPU - {09238300-4583-45C6-A997-025CBDC44C24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {09238300-4583-45C6-A997-025CBDC44C24}.Debug|Any CPU.Build.0 = Debug|Any CPU - {09238300-4583-45C6-A997-025CBDC44C24}.Release|Any CPU.ActiveCfg = Release|Any CPU - {09238300-4583-45C6-A997-025CBDC44C24}.Release|Any CPU.Build.0 = Release|Any CPU - {21FDAB94-5014-488D-86C7-A366F1902B24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {21FDAB94-5014-488D-86C7-A366F1902B24}.Debug|Any CPU.Build.0 = Debug|Any CPU - {21FDAB94-5014-488D-86C7-A366F1902B24}.Release|Any CPU.ActiveCfg = Release|Any CPU - {21FDAB94-5014-488D-86C7-A366F1902B24}.Release|Any CPU.Build.0 = Release|Any CPU - {4A378F81-3805-41E8-9565-A8A89A8C00D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4A378F81-3805-41E8-9565-A8A89A8C00D6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4A378F81-3805-41E8-9565-A8A89A8C00D6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4A378F81-3805-41E8-9565-A8A89A8C00D6}.Release|Any CPU.Build.0 = Release|Any CPU - {FFCF6FA8-4F38-415E-AC2D-B576FFD5FED5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FFCF6FA8-4F38-415E-AC2D-B576FFD5FED5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FFCF6FA8-4F38-415E-AC2D-B576FFD5FED5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FFCF6FA8-4F38-415E-AC2D-B576FFD5FED5}.Release|Any CPU.Build.0 = Release|Any CPU - {71CBD7CC-C787-4796-B05E-4F3BC3C28B48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {71CBD7CC-C787-4796-B05E-4F3BC3C28B48}.Debug|Any CPU.Build.0 = Debug|Any CPU - {71CBD7CC-C787-4796-B05E-4F3BC3C28B48}.Release|Any CPU.ActiveCfg = Release|Any CPU - {71CBD7CC-C787-4796-B05E-4F3BC3C28B48}.Release|Any CPU.Build.0 = Release|Any CPU - {42E626F7-9A7E-4F55-B02C-16EB56E2B540}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {42E626F7-9A7E-4F55-B02C-16EB56E2B540}.Debug|Any CPU.Build.0 = Debug|Any CPU - {42E626F7-9A7E-4F55-B02C-16EB56E2B540}.Release|Any CPU.ActiveCfg = Release|Any CPU - {42E626F7-9A7E-4F55-B02C-16EB56E2B540}.Release|Any CPU.Build.0 = Release|Any CPU - {8BF2CBBF-6DAB-4D7A-87E0-AE643D6019AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8BF2CBBF-6DAB-4D7A-87E0-AE643D6019AB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8BF2CBBF-6DAB-4D7A-87E0-AE643D6019AB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8BF2CBBF-6DAB-4D7A-87E0-AE643D6019AB}.Release|Any CPU.Build.0 = Release|Any CPU - {262A8AE0-E610-405F-B4EC-DB714FB54C00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {262A8AE0-E610-405F-B4EC-DB714FB54C00}.Debug|Any CPU.Build.0 = Debug|Any CPU - {262A8AE0-E610-405F-B4EC-DB714FB54C00}.Release|Any CPU.ActiveCfg = Release|Any CPU - {262A8AE0-E610-405F-B4EC-DB714FB54C00}.Release|Any CPU.Build.0 = Release|Any CPU - {E5F07862-5715-470D-B324-19BDEBB2AA4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E5F07862-5715-470D-B324-19BDEBB2AA4D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E5F07862-5715-470D-B324-19BDEBB2AA4D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E5F07862-5715-470D-B324-19BDEBB2AA4D}.Release|Any CPU.Build.0 = Release|Any CPU - {21B591A0-F6E5-4645-BF2D-4E71F47394A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {21B591A0-F6E5-4645-BF2D-4E71F47394A7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {21B591A0-F6E5-4645-BF2D-4E71F47394A7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {21B591A0-F6E5-4645-BF2D-4E71F47394A7}.Release|Any CPU.Build.0 = Release|Any CPU - {F093BDE5-1824-459E-B86E-B9F79B548E58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F093BDE5-1824-459E-B86E-B9F79B548E58}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F093BDE5-1824-459E-B86E-B9F79B548E58}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F093BDE5-1824-459E-B86E-B9F79B548E58}.Release|Any CPU.Build.0 = Release|Any CPU - {EDA96974-0BEA-404B-8EED-F19CCA2C95A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EDA96974-0BEA-404B-8EED-F19CCA2C95A8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EDA96974-0BEA-404B-8EED-F19CCA2C95A8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EDA96974-0BEA-404B-8EED-F19CCA2C95A8}.Release|Any CPU.Build.0 = Release|Any CPU - {ED2CAA2D-4E49-4636-86C4-367D0CDC3572}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ED2CAA2D-4E49-4636-86C4-367D0CDC3572}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ED2CAA2D-4E49-4636-86C4-367D0CDC3572}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ED2CAA2D-4E49-4636-86C4-367D0CDC3572}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {CD7DECEC-F4A0-4EEF-978B-72748414D52A} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32630.192 +MinimumVisualStudioVersion = 10.0.40219.1 +EndProject +EndProject +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PathCamDisabler", "PathCamDisabler\PathCamDisabler.csproj", "{98169FD2-5CEB-46D1-A320-D7E06F82C9E0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PortableCameraAdditions", "PortableCameraAdditions\PortableCameraAdditions.csproj", "{C4DAFE9D-C79B-4417-9B7D-B7327999DA4C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PropUndoButton", "PropUndoButton\PropUndoButton.csproj", "{FBFDB717-F81E-4C06-ACF9-A0F3FFDCDE00}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThirdPerson", "ThirdPerson\ThirdPerson.csproj", "{675CEC0E-3E8A-4970-98EA-9B79277A7252}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MuteSFX", "MuteSFX\MuteSFX.csproj", "{77D222FC-4AEC-4672-A87A-B860B4C39E17}" +EndProject +EndProject +EndProject +EndProject +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RelativeSync", "RelativeSync\RelativeSync.csproj", "{B48C8F19-9451-4EE2-999F-82C0033CDE2C}" +EndProject +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LazyPrune", "LazyPrune\LazyPrune.csproj", "{8FA6D481-5801-4E4C-822E-DE561155D22B}" +EndProject +EndProject +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScrollFlight", "ScrollFlight\ScrollFlight.csproj", "{1B5D7DCB-01A4-4988-8B25-211948AEED76}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PropLoadingHexagon", "PropLoadingHexagon\PropLoadingHexagon.csproj", "{642A2BC7-C027-4F8F-969C-EF0F867936FD}" +EndProject +EndProject +EndProject +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeepVelocityOnExitFlight", "KeepVelocityOnExitFlight\KeepVelocityOnExitFlight.csproj", "{0BB3D187-BBBA-4C58-B246-102342BE5E8C}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ASTExtension", "ASTExtension\ASTExtension.csproj", "{6580AA87-6A95-438E-A5D3-70E583CCD77B}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AvatarQueueSystemTweaks", "AvatarQueueSystemTweaks\AvatarQueueSystemTweaks.csproj", "{D178E422-283B-4FB3-89A6-AA4FB9F87E2F}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomSpawnPoint", "CustomSpawnPoint\CustomSpawnPoint.csproj", "{51CA34CA-7684-4819-AC9E-89DFAD63E9AB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stickers", "Stickers\Stickers.csproj", "{E5F54B3E-A676-4DD5-A6DB-73AFA54BEC5E}" +EndProject +EndProject +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmootherRay", "SmootherRay\SmootherRay.csproj", "{99F9D60D-9A2D-4DBE-AA52-13D8A0838696}" +EndProject +EndProject +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShareBubbles", "ShareBubbles\ShareBubbles.csproj", "{ADD6205B-67A4-4BA8-8BED-DF7D0E857A6A}" +EndProject +EndProject +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RCCVirtualSteeringWheel", "RCCVirtualSteeringWheel\RCCVirtualSteeringWheel.csproj", "{4A378F81-3805-41E8-9565-A8A89A8C00D6}" +EndProject +EndProject +EndProject +EndProject +EndProject +EndProject +EndProject +EndProject +EndProject +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CF9BC79E-4FB6-429A-8C19-DF31F040BD4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CF9BC79E-4FB6-429A-8C19-DF31F040BD4A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CF9BC79E-4FB6-429A-8C19-DF31F040BD4A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CF9BC79E-4FB6-429A-8C19-DF31F040BD4A}.Release|Any CPU.Build.0 = Release|Any CPU + {79B2A7C4-348D-4A8E-94D1-BA22FDD5FEED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {79B2A7C4-348D-4A8E-94D1-BA22FDD5FEED}.Debug|Any CPU.Build.0 = Debug|Any CPU + {79B2A7C4-348D-4A8E-94D1-BA22FDD5FEED}.Release|Any CPU.ActiveCfg = Release|Any CPU + {79B2A7C4-348D-4A8E-94D1-BA22FDD5FEED}.Release|Any CPU.Build.0 = Release|Any CPU + {45A65AEB-4BFC-4E47-B181-BBB43BD81283}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {45A65AEB-4BFC-4E47-B181-BBB43BD81283}.Debug|Any CPU.Build.0 = Debug|Any CPU + {45A65AEB-4BFC-4E47-B181-BBB43BD81283}.Release|Any CPU.ActiveCfg = Release|Any CPU + {45A65AEB-4BFC-4E47-B181-BBB43BD81283}.Release|Any CPU.Build.0 = Release|Any CPU + {98169FD2-5CEB-46D1-A320-D7E06F82C9E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {98169FD2-5CEB-46D1-A320-D7E06F82C9E0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {98169FD2-5CEB-46D1-A320-D7E06F82C9E0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {98169FD2-5CEB-46D1-A320-D7E06F82C9E0}.Release|Any CPU.Build.0 = Release|Any CPU + {C4DAFE9D-C79B-4417-9B7D-B7327999DA4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C4DAFE9D-C79B-4417-9B7D-B7327999DA4C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C4DAFE9D-C79B-4417-9B7D-B7327999DA4C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C4DAFE9D-C79B-4417-9B7D-B7327999DA4C}.Release|Any CPU.Build.0 = Release|Any CPU + {FBFDB717-F81E-4C06-ACF9-A0F3FFDCDE00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FBFDB717-F81E-4C06-ACF9-A0F3FFDCDE00}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FBFDB717-F81E-4C06-ACF9-A0F3FFDCDE00}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FBFDB717-F81E-4C06-ACF9-A0F3FFDCDE00}.Release|Any CPU.Build.0 = Release|Any CPU + {675CEC0E-3E8A-4970-98EA-9B79277A7252}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {675CEC0E-3E8A-4970-98EA-9B79277A7252}.Debug|Any CPU.Build.0 = Debug|Any CPU + {675CEC0E-3E8A-4970-98EA-9B79277A7252}.Release|Any CPU.ActiveCfg = Release|Any CPU + {675CEC0E-3E8A-4970-98EA-9B79277A7252}.Release|Any CPU.Build.0 = Release|Any CPU + {EE552804-30B1-49CF-BBDE-3B312895AFF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EE552804-30B1-49CF-BBDE-3B312895AFF7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EE552804-30B1-49CF-BBDE-3B312895AFF7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EE552804-30B1-49CF-BBDE-3B312895AFF7}.Release|Any CPU.Build.0 = Release|Any CPU + {77D222FC-4AEC-4672-A87A-B860B4C39E17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {77D222FC-4AEC-4672-A87A-B860B4C39E17}.Debug|Any CPU.Build.0 = Debug|Any CPU + {77D222FC-4AEC-4672-A87A-B860B4C39E17}.Release|Any CPU.ActiveCfg = Release|Any CPU + {77D222FC-4AEC-4672-A87A-B860B4C39E17}.Release|Any CPU.Build.0 = Release|Any CPU + {0E1DD746-33A1-4179-AE70-8FB83AC40ABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0E1DD746-33A1-4179-AE70-8FB83AC40ABC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0E1DD746-33A1-4179-AE70-8FB83AC40ABC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0E1DD746-33A1-4179-AE70-8FB83AC40ABC}.Release|Any CPU.Build.0 = Release|Any CPU + {F94DDB73-9041-4F5C-AD43-6960701E8417}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {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 + {AC4857DD-F6D9-436D-A3EE-D148A518E642}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AC4857DD-F6D9-436D-A3EE-D148A518E642}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AC4857DD-F6D9-436D-A3EE-D148A518E642}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AC4857DD-F6D9-436D-A3EE-D148A518E642}.Release|Any CPU.Build.0 = Release|Any CPU + {69AF3C10-1BB1-4746-B697-B5A81D78C8D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {69AF3C10-1BB1-4746-B697-B5A81D78C8D9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {69AF3C10-1BB1-4746-B697-B5A81D78C8D9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {69AF3C10-1BB1-4746-B697-B5A81D78C8D9}.Release|Any CPU.Build.0 = Release|Any CPU + {9FA83514-13F8-412C-9790-C2B750E0E7E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9FA83514-13F8-412C-9790-C2B750E0E7E7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9FA83514-13F8-412C-9790-C2B750E0E7E7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9FA83514-13F8-412C-9790-C2B750E0E7E7}.Release|Any CPU.Build.0 = Release|Any CPU + {B48C8F19-9451-4EE2-999F-82C0033CDE2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B48C8F19-9451-4EE2-999F-82C0033CDE2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B48C8F19-9451-4EE2-999F-82C0033CDE2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B48C8F19-9451-4EE2-999F-82C0033CDE2C}.Release|Any CPU.Build.0 = Release|Any CPU + {6B4396C7-B451-4FFD-87B6-3ED8377AC308}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6B4396C7-B451-4FFD-87B6-3ED8377AC308}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6B4396C7-B451-4FFD-87B6-3ED8377AC308}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6B4396C7-B451-4FFD-87B6-3ED8377AC308}.Release|Any CPU.Build.0 = Release|Any CPU + {24A069F4-4D69-4ABD-AA16-77765469245B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {24A069F4-4D69-4ABD-AA16-77765469245B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {24A069F4-4D69-4ABD-AA16-77765469245B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {24A069F4-4D69-4ABD-AA16-77765469245B}.Release|Any CPU.Build.0 = Release|Any CPU + {8FA6D481-5801-4E4C-822E-DE561155D22B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8FA6D481-5801-4E4C-822E-DE561155D22B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8FA6D481-5801-4E4C-822E-DE561155D22B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8FA6D481-5801-4E4C-822E-DE561155D22B}.Release|Any CPU.Build.0 = Release|Any CPU + {05C427DD-1261-4AAD-B316-A551FC126F2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {05C427DD-1261-4AAD-B316-A551FC126F2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {05C427DD-1261-4AAD-B316-A551FC126F2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {05C427DD-1261-4AAD-B316-A551FC126F2C}.Release|Any CPU.Build.0 = Release|Any CPU + {C6794B18-E785-4F91-A517-3A2A8006E008}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6794B18-E785-4F91-A517-3A2A8006E008}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6794B18-E785-4F91-A517-3A2A8006E008}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6794B18-E785-4F91-A517-3A2A8006E008}.Release|Any CPU.Build.0 = Release|Any CPU + {F381F604-9C16-4870-AD49-4BD7CA3F36DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F381F604-9C16-4870-AD49-4BD7CA3F36DC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F381F604-9C16-4870-AD49-4BD7CA3F36DC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F381F604-9C16-4870-AD49-4BD7CA3F36DC}.Release|Any CPU.Build.0 = Release|Any CPU + {1B5D7DCB-01A4-4988-8B25-211948AEED76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1B5D7DCB-01A4-4988-8B25-211948AEED76}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1B5D7DCB-01A4-4988-8B25-211948AEED76}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1B5D7DCB-01A4-4988-8B25-211948AEED76}.Release|Any CPU.Build.0 = Release|Any CPU + {BE9629C2-8461-481C-B267-1B8A1805DCD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BE9629C2-8461-481C-B267-1B8A1805DCD7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BE9629C2-8461-481C-B267-1B8A1805DCD7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BE9629C2-8461-481C-B267-1B8A1805DCD7}.Release|Any CPU.Build.0 = Release|Any CPU + {642A2BC7-C027-4F8F-969C-EF0F867936FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {642A2BC7-C027-4F8F-969C-EF0F867936FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {642A2BC7-C027-4F8F-969C-EF0F867936FD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {642A2BC7-C027-4F8F-969C-EF0F867936FD}.Release|Any CPU.Build.0 = Release|Any CPU + {D11214B0-94FE-4008-8D1B-3DC8614466B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D11214B0-94FE-4008-8D1B-3DC8614466B3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D11214B0-94FE-4008-8D1B-3DC8614466B3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D11214B0-94FE-4008-8D1B-3DC8614466B3}.Release|Any CPU.Build.0 = Release|Any CPU + {2CC1F7C6-A953-4008-8C10-C7592EB401E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2CC1F7C6-A953-4008-8C10-C7592EB401E8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2CC1F7C6-A953-4008-8C10-C7592EB401E8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2CC1F7C6-A953-4008-8C10-C7592EB401E8}.Release|Any CPU.Build.0 = Release|Any CPU + {39915C4C-B555-4CB9-890F-26DE1388BC2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39915C4C-B555-4CB9-890F-26DE1388BC2E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39915C4C-B555-4CB9-890F-26DE1388BC2E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39915C4C-B555-4CB9-890F-26DE1388BC2E}.Release|Any CPU.Build.0 = Release|Any CPU + {7C675E64-0A2D-4B34-B6D1-5D6AA369A520}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7C675E64-0A2D-4B34-B6D1-5D6AA369A520}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7C675E64-0A2D-4B34-B6D1-5D6AA369A520}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7C675E64-0A2D-4B34-B6D1-5D6AA369A520}.Release|Any CPU.Build.0 = Release|Any CPU + {0BB3D187-BBBA-4C58-B246-102342BE5E8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0BB3D187-BBBA-4C58-B246-102342BE5E8C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0BB3D187-BBBA-4C58-B246-102342BE5E8C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0BB3D187-BBBA-4C58-B246-102342BE5E8C}.Release|Any CPU.Build.0 = Release|Any CPU + {6580AA87-6A95-438E-A5D3-70E583CCD77B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6580AA87-6A95-438E-A5D3-70E583CCD77B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6580AA87-6A95-438E-A5D3-70E583CCD77B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6580AA87-6A95-438E-A5D3-70E583CCD77B}.Release|Any CPU.Build.0 = Release|Any CPU + {D178E422-283B-4FB3-89A6-AA4FB9F87E2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D178E422-283B-4FB3-89A6-AA4FB9F87E2F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D178E422-283B-4FB3-89A6-AA4FB9F87E2F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D178E422-283B-4FB3-89A6-AA4FB9F87E2F}.Release|Any CPU.Build.0 = Release|Any CPU + {51CA34CA-7684-4819-AC9E-89DFAD63E9AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {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 + {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 + {FE6BA6EC-2C11-49E1-A2FB-13F2A1C9E7F9}.Release|Any CPU.Build.0 = Release|Any CPU + {E5F54B3E-A676-4DD5-A6DB-73AFA54BEC5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E5F54B3E-A676-4DD5-A6DB-73AFA54BEC5E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E5F54B3E-A676-4DD5-A6DB-73AFA54BEC5E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E5F54B3E-A676-4DD5-A6DB-73AFA54BEC5E}.Release|Any CPU.Build.0 = Release|Any CPU + {3C992D0C-9729-438E-800C-496B7EFFFB25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3C992D0C-9729-438E-800C-496B7EFFFB25}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3C992D0C-9729-438E-800C-496B7EFFFB25}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3C992D0C-9729-438E-800C-496B7EFFFB25}.Release|Any CPU.Build.0 = Release|Any CPU + {E285BCC9-D953-4066-8FA2-97EA28EB348E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E285BCC9-D953-4066-8FA2-97EA28EB348E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E285BCC9-D953-4066-8FA2-97EA28EB348E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E285BCC9-D953-4066-8FA2-97EA28EB348E}.Release|Any CPU.Build.0 = Release|Any CPU + {A38E687F-8B6B-499E-ABC9-BD95C53DD391}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A38E687F-8B6B-499E-ABC9-BD95C53DD391}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A38E687F-8B6B-499E-ABC9-BD95C53DD391}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A38E687F-8B6B-499E-ABC9-BD95C53DD391}.Release|Any CPU.Build.0 = Release|Any CPU + {99F9D60D-9A2D-4DBE-AA52-13D8A0838696}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {99F9D60D-9A2D-4DBE-AA52-13D8A0838696}.Debug|Any CPU.Build.0 = Debug|Any CPU + {99F9D60D-9A2D-4DBE-AA52-13D8A0838696}.Release|Any CPU.ActiveCfg = Release|Any CPU + {99F9D60D-9A2D-4DBE-AA52-13D8A0838696}.Release|Any CPU.Build.0 = Release|Any CPU + {A3D97D1A-3099-49C5-85AD-D8C79CC5FDE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A3D97D1A-3099-49C5-85AD-D8C79CC5FDE3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A3D97D1A-3099-49C5-85AD-D8C79CC5FDE3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A3D97D1A-3099-49C5-85AD-D8C79CC5FDE3}.Release|Any CPU.Build.0 = Release|Any CPU + {0640B2BF-1EF5-4FFE-A144-0368748FC48B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0640B2BF-1EF5-4FFE-A144-0368748FC48B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0640B2BF-1EF5-4FFE-A144-0368748FC48B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0640B2BF-1EF5-4FFE-A144-0368748FC48B}.Release|Any CPU.Build.0 = Release|Any CPU + {FC91FFFE-1E0A-4F59-8802-BFF99152AD07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FC91FFFE-1E0A-4F59-8802-BFF99152AD07}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FC91FFFE-1E0A-4F59-8802-BFF99152AD07}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FC91FFFE-1E0A-4F59-8802-BFF99152AD07}.Release|Any CPU.Build.0 = Release|Any CPU + {ADD6205B-67A4-4BA8-8BED-DF7D0E857A6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ADD6205B-67A4-4BA8-8BED-DF7D0E857A6A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ADD6205B-67A4-4BA8-8BED-DF7D0E857A6A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ADD6205B-67A4-4BA8-8BED-DF7D0E857A6A}.Release|Any CPU.Build.0 = Release|Any CPU + {6E315182-CC9F-4F62-8385-5E26EFA3B98A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6E315182-CC9F-4F62-8385-5E26EFA3B98A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6E315182-CC9F-4F62-8385-5E26EFA3B98A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6E315182-CC9F-4F62-8385-5E26EFA3B98A}.Release|Any CPU.Build.0 = Release|Any CPU + {09238300-4583-45C6-A997-025CBDC44C24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {09238300-4583-45C6-A997-025CBDC44C24}.Debug|Any CPU.Build.0 = Debug|Any CPU + {09238300-4583-45C6-A997-025CBDC44C24}.Release|Any CPU.ActiveCfg = Release|Any CPU + {09238300-4583-45C6-A997-025CBDC44C24}.Release|Any CPU.Build.0 = Release|Any CPU + {21FDAB94-5014-488D-86C7-A366F1902B24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {21FDAB94-5014-488D-86C7-A366F1902B24}.Debug|Any CPU.Build.0 = Debug|Any CPU + {21FDAB94-5014-488D-86C7-A366F1902B24}.Release|Any CPU.ActiveCfg = Release|Any CPU + {21FDAB94-5014-488D-86C7-A366F1902B24}.Release|Any CPU.Build.0 = Release|Any CPU + {4A378F81-3805-41E8-9565-A8A89A8C00D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4A378F81-3805-41E8-9565-A8A89A8C00D6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4A378F81-3805-41E8-9565-A8A89A8C00D6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4A378F81-3805-41E8-9565-A8A89A8C00D6}.Release|Any CPU.Build.0 = Release|Any CPU + {FFCF6FA8-4F38-415E-AC2D-B576FFD5FED5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FFCF6FA8-4F38-415E-AC2D-B576FFD5FED5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FFCF6FA8-4F38-415E-AC2D-B576FFD5FED5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FFCF6FA8-4F38-415E-AC2D-B576FFD5FED5}.Release|Any CPU.Build.0 = Release|Any CPU + {71CBD7CC-C787-4796-B05E-4F3BC3C28B48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {71CBD7CC-C787-4796-B05E-4F3BC3C28B48}.Debug|Any CPU.Build.0 = Debug|Any CPU + {71CBD7CC-C787-4796-B05E-4F3BC3C28B48}.Release|Any CPU.ActiveCfg = Release|Any CPU + {71CBD7CC-C787-4796-B05E-4F3BC3C28B48}.Release|Any CPU.Build.0 = Release|Any CPU + {42E626F7-9A7E-4F55-B02C-16EB56E2B540}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {42E626F7-9A7E-4F55-B02C-16EB56E2B540}.Debug|Any CPU.Build.0 = Debug|Any CPU + {42E626F7-9A7E-4F55-B02C-16EB56E2B540}.Release|Any CPU.ActiveCfg = Release|Any CPU + {42E626F7-9A7E-4F55-B02C-16EB56E2B540}.Release|Any CPU.Build.0 = Release|Any CPU + {8BF2CBBF-6DAB-4D7A-87E0-AE643D6019AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8BF2CBBF-6DAB-4D7A-87E0-AE643D6019AB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8BF2CBBF-6DAB-4D7A-87E0-AE643D6019AB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8BF2CBBF-6DAB-4D7A-87E0-AE643D6019AB}.Release|Any CPU.Build.0 = Release|Any CPU + {262A8AE0-E610-405F-B4EC-DB714FB54C00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {262A8AE0-E610-405F-B4EC-DB714FB54C00}.Debug|Any CPU.Build.0 = Debug|Any CPU + {262A8AE0-E610-405F-B4EC-DB714FB54C00}.Release|Any CPU.ActiveCfg = Release|Any CPU + {262A8AE0-E610-405F-B4EC-DB714FB54C00}.Release|Any CPU.Build.0 = Release|Any CPU + {E5F07862-5715-470D-B324-19BDEBB2AA4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E5F07862-5715-470D-B324-19BDEBB2AA4D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E5F07862-5715-470D-B324-19BDEBB2AA4D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E5F07862-5715-470D-B324-19BDEBB2AA4D}.Release|Any CPU.Build.0 = Release|Any CPU + {21B591A0-F6E5-4645-BF2D-4E71F47394A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {21B591A0-F6E5-4645-BF2D-4E71F47394A7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {21B591A0-F6E5-4645-BF2D-4E71F47394A7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {21B591A0-F6E5-4645-BF2D-4E71F47394A7}.Release|Any CPU.Build.0 = Release|Any CPU + {F093BDE5-1824-459E-B86E-B9F79B548E58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F093BDE5-1824-459E-B86E-B9F79B548E58}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F093BDE5-1824-459E-B86E-B9F79B548E58}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F093BDE5-1824-459E-B86E-B9F79B548E58}.Release|Any CPU.Build.0 = Release|Any CPU + {EDA96974-0BEA-404B-8EED-F19CCA2C95A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EDA96974-0BEA-404B-8EED-F19CCA2C95A8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EDA96974-0BEA-404B-8EED-F19CCA2C95A8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EDA96974-0BEA-404B-8EED-F19CCA2C95A8}.Release|Any CPU.Build.0 = Release|Any CPU + {ED2CAA2D-4E49-4636-86C4-367D0CDC3572}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ED2CAA2D-4E49-4636-86C4-367D0CDC3572}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ED2CAA2D-4E49-4636-86C4-367D0CDC3572}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ED2CAA2D-4E49-4636-86C4-367D0CDC3572}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {CD7DECEC-F4A0-4EEF-978B-72748414D52A} + EndGlobalSection +EndGlobal diff --git a/References.Items.props b/References.Items.props index 275c721..69164f3 100644 --- a/References.Items.props +++ b/References.Items.props @@ -52,6 +52,10 @@ $(MsBuildThisFileDirectory)\.ManagedLibs\Bhaptics.Tact.dll False + + $(MsBuildThisFileDirectory)\.ManagedLibs\BouncyCastle.Crypto.dll + False + $(MsBuildThisFileDirectory)\.ManagedLibs\Boxophobic.TheVehetationEngine.Runtime.dll False @@ -96,6 +100,10 @@ $(MsBuildThisFileDirectory)\.ManagedLibs\DarkRift.dll False + + $(MsBuildThisFileDirectory)\.ManagedLibs\DTLS.Net.dll + False + $(MsBuildThisFileDirectory)\.ManagedLibs\ECM2.dll False @@ -304,6 +312,10 @@ $(MsBuildThisFileDirectory)\.ManagedLibs\System.Runtime.Serialization.dll False + + $(MsBuildThisFileDirectory)\.ManagedLibs\System.Security.Cryptography.Cng.dll + False + $(MsBuildThisFileDirectory)\.ManagedLibs\System.Security.dll False @@ -364,6 +376,10 @@ $(MsBuildThisFileDirectory)\.ManagedLibs\UniTask.TextMeshPro.dll False + + $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.2D.Common.Runtime.dll + False + $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.AI.Navigation.dll False @@ -412,6 +428,10 @@ $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.InputSystem.ForUI.dll False + + $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.InternalAPIEngineBridge.001.dll + False + $(MsBuildThisFileDirectory)\.ManagedLibs\Unity.InternalAPIEngineBridge.002.dll False From 915253972dff2a72c9ef73dc1271331df2e7636a Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 03:31:01 -0500 Subject: [PATCH 013/119] [MuteSFX] Deprecate because functionality is doable native --- .../MuteSFX}/AudioModuleManager.cs | 0 {MuteSFX => .Deprecated/MuteSFX}/Main.cs | 0 {MuteSFX => .Deprecated/MuteSFX}/MuteSFX.csproj | 4 ++-- .../MuteSFX}/Properties/AssemblyInfo.cs | 2 +- {MuteSFX => .Deprecated/MuteSFX}/README.md | 0 {MuteSFX => .Deprecated/MuteSFX}/SFX/sfx_mute.wav | Bin {MuteSFX => .Deprecated/MuteSFX}/SFX/sfx_unmute.wav | Bin {MuteSFX => .Deprecated/MuteSFX}/format.json | 2 +- 8 files changed, 4 insertions(+), 4 deletions(-) rename {MuteSFX => .Deprecated/MuteSFX}/AudioModuleManager.cs (100%) rename {MuteSFX => .Deprecated/MuteSFX}/Main.cs (100%) rename {MuteSFX => .Deprecated/MuteSFX}/MuteSFX.csproj (67%) rename {MuteSFX => .Deprecated/MuteSFX}/Properties/AssemblyInfo.cs (96%) rename {MuteSFX => .Deprecated/MuteSFX}/README.md (100%) rename {MuteSFX => .Deprecated/MuteSFX}/SFX/sfx_mute.wav (100%) rename {MuteSFX => .Deprecated/MuteSFX}/SFX/sfx_unmute.wav (100%) rename {MuteSFX => .Deprecated/MuteSFX}/format.json (96%) diff --git a/MuteSFX/AudioModuleManager.cs b/.Deprecated/MuteSFX/AudioModuleManager.cs similarity index 100% rename from MuteSFX/AudioModuleManager.cs rename to .Deprecated/MuteSFX/AudioModuleManager.cs diff --git a/MuteSFX/Main.cs b/.Deprecated/MuteSFX/Main.cs similarity index 100% rename from MuteSFX/Main.cs rename to .Deprecated/MuteSFX/Main.cs diff --git a/MuteSFX/MuteSFX.csproj b/.Deprecated/MuteSFX/MuteSFX.csproj similarity index 67% rename from MuteSFX/MuteSFX.csproj rename to .Deprecated/MuteSFX/MuteSFX.csproj index 21b218c..5eba218 100644 --- a/MuteSFX/MuteSFX.csproj +++ b/.Deprecated/MuteSFX/MuteSFX.csproj @@ -5,7 +5,7 @@ - - + + diff --git a/MuteSFX/Properties/AssemblyInfo.cs b/.Deprecated/MuteSFX/Properties/AssemblyInfo.cs similarity index 96% rename from MuteSFX/Properties/AssemblyInfo.cs rename to .Deprecated/MuteSFX/Properties/AssemblyInfo.cs index 75cb9f3..452c973 100644 --- a/MuteSFX/Properties/AssemblyInfo.cs +++ b/.Deprecated/MuteSFX/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.MuteSFX.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.2"; + public const string Version = "1.0.3"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/MuteSFX/README.md b/.Deprecated/MuteSFX/README.md similarity index 100% rename from MuteSFX/README.md rename to .Deprecated/MuteSFX/README.md diff --git a/MuteSFX/SFX/sfx_mute.wav b/.Deprecated/MuteSFX/SFX/sfx_mute.wav similarity index 100% rename from MuteSFX/SFX/sfx_mute.wav rename to .Deprecated/MuteSFX/SFX/sfx_mute.wav diff --git a/MuteSFX/SFX/sfx_unmute.wav b/.Deprecated/MuteSFX/SFX/sfx_unmute.wav similarity index 100% rename from MuteSFX/SFX/sfx_unmute.wav rename to .Deprecated/MuteSFX/SFX/sfx_unmute.wav diff --git a/MuteSFX/format.json b/.Deprecated/MuteSFX/format.json similarity index 96% rename from MuteSFX/format.json rename to .Deprecated/MuteSFX/format.json index 3601dd3..877e3e0 100644 --- a/MuteSFX/format.json +++ b/.Deprecated/MuteSFX/format.json @@ -1,7 +1,7 @@ { "_id": 172, "name": "MuteSFX", - "modversion": "1.0.2", + "modversion": "1.0.3", "gameversion": "2023r171", "loaderversion": "0.6.1", "modtype": "Mod", From 61f56b2f846defae784310483ee4fddd6da43527 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 03:58:34 -0500 Subject: [PATCH 014/119] [ASTExtension] bump version --- ASTExtension/Properties/AssemblyInfo.cs | 2 +- ASTExtension/format.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ASTExtension/Properties/AssemblyInfo.cs b/ASTExtension/Properties/AssemblyInfo.cs index 5c617e2..0200119 100644 --- a/ASTExtension/Properties/AssemblyInfo.cs +++ b/ASTExtension/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.ASTExtension.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.2"; + public const string Version = "1.0.3"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/ASTExtension/format.json b/ASTExtension/format.json index 5ad14ea..934110a 100644 --- a/ASTExtension/format.json +++ b/ASTExtension/format.json @@ -1,8 +1,8 @@ { "_id": 223, "name": "ASTExtension", - "modversion": "1.0.2", - "gameversion": "2025r178", + "modversion": "1.0.3", + "gameversion": "2025r179", "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS", @@ -17,8 +17,8 @@ "requirements": [ "BTKUILib" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r45/ASTExtension.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ASTExtension.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ASTExtension/", - "changelog": "- Fixes for 2025r178", + "changelog": "- Recompiled for 2025r179", "embedcolor": "#f61963" } \ No newline at end of file From 736dc71eeca981a51994c266515b4f3ece2622b9 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 03:58:46 -0500 Subject: [PATCH 015/119] [AvatarQueueSystemTweaks] bump version --- AvatarQueueSystemTweaks/Properties/AssemblyInfo.cs | 2 +- AvatarQueueSystemTweaks/format.json | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/AvatarQueueSystemTweaks/Properties/AssemblyInfo.cs b/AvatarQueueSystemTweaks/Properties/AssemblyInfo.cs index 1273c2c..821459b 100644 --- a/AvatarQueueSystemTweaks/Properties/AssemblyInfo.cs +++ b/AvatarQueueSystemTweaks/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.AvatarQueueSystemTweaks.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.0"; + public const string Version = "1.0.1"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/AvatarQueueSystemTweaks/format.json b/AvatarQueueSystemTweaks/format.json index bb6a269..84dadfc 100644 --- a/AvatarQueueSystemTweaks/format.json +++ b/AvatarQueueSystemTweaks/format.json @@ -1,8 +1,8 @@ { - "_id": -1, + "_id": 226, "name": "AvatarQueueSystemTweaks", - "modversion": "1.0.0", - "gameversion": "2024r175", + "modversion": "1.0.1", + "gameversion": "2025r179", "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS", @@ -17,8 +17,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r36/AvatarQueueSystemTweaks.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/AvatarQueueSystemTweaks.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/AvatarQueueSystemTweaks/", - "changelog": "- Initial Release", + "changelog": "- Recompiled for 2025r179", "embedcolor": "#f61963" } \ No newline at end of file From c0ba230fa59d94f530d8f974faedf4f9f256b12f Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 03:58:57 -0500 Subject: [PATCH 016/119] [CustomSpawnPoint] bump version --- CustomSpawnPoint/Properties/AssemblyInfo.cs | 2 +- CustomSpawnPoint/format.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CustomSpawnPoint/Properties/AssemblyInfo.cs b/CustomSpawnPoint/Properties/AssemblyInfo.cs index 480612c..3676fa0 100644 --- a/CustomSpawnPoint/Properties/AssemblyInfo.cs +++ b/CustomSpawnPoint/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.CustomSpawnPoint.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.1"; + public const string Version = "1.0.2"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/CustomSpawnPoint/format.json b/CustomSpawnPoint/format.json index 57d83fd..98f22da 100644 --- a/CustomSpawnPoint/format.json +++ b/CustomSpawnPoint/format.json @@ -1,8 +1,8 @@ { "_id": 228, "name": "CustomSpawnPoint", - "modversion": "1.0.1", - "gameversion": "2024r175", + "modversion": "1.0.2", + "gameversion": "2025r179", "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS", @@ -17,8 +17,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r40/CustomSpawnPoint.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/CustomSpawnPoint.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/CustomSpawnPoint/", - "changelog": "- Removed unneeded logging when opening a World Details page.", + "changelog": "- Recompiled for 2025r179", "embedcolor": "#f61963" } \ No newline at end of file From 4b5c19676d18b2479317973e7561fae4e6c171df Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 03:59:10 -0500 Subject: [PATCH 017/119] [KeepVelocityOnExitFlight] bump version --- KeepVelocityOnExitFlight/Properties/AssemblyInfo.cs | 2 +- KeepVelocityOnExitFlight/format.json | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/KeepVelocityOnExitFlight/Properties/AssemblyInfo.cs b/KeepVelocityOnExitFlight/Properties/AssemblyInfo.cs index 9ad16f8..e51a838 100644 --- a/KeepVelocityOnExitFlight/Properties/AssemblyInfo.cs +++ b/KeepVelocityOnExitFlight/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.KeepVelocityOnExitFlight.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.0"; + public const string Version = "1.0.1"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/KeepVelocityOnExitFlight/format.json b/KeepVelocityOnExitFlight/format.json index ae56509..94d3b8a 100644 --- a/KeepVelocityOnExitFlight/format.json +++ b/KeepVelocityOnExitFlight/format.json @@ -1,8 +1,8 @@ { - "_id": -1, + "_id": 222, "name": "KeepVelocityOnExitFlight", - "modversion": "1.0.0", - "gameversion": "2024r175", + "modversion": "1.0.1", + "gameversion": "2025r179", "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS", @@ -17,8 +17,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r34/KeepVelocityOnExitFlight.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/KeepVelocityOnExitFlight.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/KeepVelocityOnExitFlight/", - "changelog": "- Initial release", + "changelog": "- Recompiled for 2025r179", "embedcolor": "#f61963" } \ No newline at end of file From 200e174b3f315fc85471775980fe564db59f0fad Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 03:59:19 -0500 Subject: [PATCH 018/119] [LazyPrune] bump version --- LazyPrune/Properties/AssemblyInfo.cs | 4 +++- LazyPrune/format.json | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/LazyPrune/Properties/AssemblyInfo.cs b/LazyPrune/Properties/AssemblyInfo.cs index 48fb1ee..169f34e 100644 --- a/LazyPrune/Properties/AssemblyInfo.cs +++ b/LazyPrune/Properties/AssemblyInfo.cs @@ -20,11 +20,13 @@ using System.Reflection; [assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red [assembly: HarmonyDontPatchAll] namespace NAK.LazyPrune.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.2"; + public const string Version = "1.0.3"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/LazyPrune/format.json b/LazyPrune/format.json index d954f95..5125073 100644 --- a/LazyPrune/format.json +++ b/LazyPrune/format.json @@ -1,8 +1,8 @@ { "_id": 214, "name": "LazyPrune", - "modversion": "1.0.2", - "gameversion": "2024r175", + "modversion": "1.0.3", + "gameversion": "2025r179", "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS", @@ -17,8 +17,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r32/LazyPrune.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/LazyPrune.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/LazyPrune/", - "changelog": "- Fixed killtime check, would needlessly check known non-eligible objects for pruning.\n- Moved away from using GameEventSystem as it proved unreliable for tracking remote Avatar destruction, now patching Object Loader directly as loadedObject is not assigned when object wrappers are enabled.\n- Fixed scheduled prune job being nuked as it was created before initial scene load.\n- Patched two race conditions in the game that would cause the object loader to lock up.", + "changelog": "- Recompiled for 2025r179", "embedcolor": "#1c75f1" } \ No newline at end of file From ef3ecde55311d4f96f7e57c371d9c4e5a0b99cd8 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 03:59:29 -0500 Subject: [PATCH 019/119] [PathCamDisabler] bump version --- PathCamDisabler/Properties/AssemblyInfo.cs | 6 +++--- PathCamDisabler/format.json | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/PathCamDisabler/Properties/AssemblyInfo.cs b/PathCamDisabler/Properties/AssemblyInfo.cs index 75cb1f5..8e01437 100644 --- a/PathCamDisabler/Properties/AssemblyInfo.cs +++ b/PathCamDisabler/Properties/AssemblyInfo.cs @@ -20,13 +20,13 @@ using System.Reflection; [assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] -[assembly: MelonColor(255, 155, 89, 182)] -[assembly: MelonAuthorColor(255, 158, 21, 32)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red [assembly: HarmonyDontPatchAll] namespace NAK.PathCamDisabler.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.2"; + public const string Version = "1.0.3"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/PathCamDisabler/format.json b/PathCamDisabler/format.json index 0be5676..6a8d8df 100644 --- a/PathCamDisabler/format.json +++ b/PathCamDisabler/format.json @@ -1,8 +1,8 @@ { "_id": 110, "name": "PathCamDisabler", - "modversion": "1.0.2", - "gameversion": "2023r171", + "modversion": "1.0.3", + "gameversion": "2025r179", "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r16/PathCamDisabler.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/PathCamDisabler.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/PathCamDisabler/", - "changelog": "- Fixes for 2023r171.", - "embedcolor": "#9b59b6" + "changelog": "- Recompiled for 2025r179", + "embedcolor": "#f61963" } \ No newline at end of file From d0504fef91f4c49c20c9205977827dfed9ca0914 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 03:59:40 -0500 Subject: [PATCH 020/119] [PortableCameraAdditions] bump version --- PortableCameraAdditions/Properties/AssemblyInfo.cs | 6 +++--- PortableCameraAdditions/format.json | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/PortableCameraAdditions/Properties/AssemblyInfo.cs b/PortableCameraAdditions/Properties/AssemblyInfo.cs index 44b24ae..841c286 100644 --- a/PortableCameraAdditions/Properties/AssemblyInfo.cs +++ b/PortableCameraAdditions/Properties/AssemblyInfo.cs @@ -20,13 +20,13 @@ using System.Reflection; [assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] -[assembly: MelonColor(255, 255, 217, 106)] -[assembly: MelonAuthorColor(255, 158, 21, 32)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red [assembly: HarmonyDontPatchAll] namespace NAK.PortableCameraAdditions.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.5"; + public const string Version = "1.0.6"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/PortableCameraAdditions/format.json b/PortableCameraAdditions/format.json index b9b8f25..957110c 100644 --- a/PortableCameraAdditions/format.json +++ b/PortableCameraAdditions/format.json @@ -1,8 +1,8 @@ { "_id": 123, "name": "PortableCameraAdditions", - "modversion": "1.0.5", - "gameversion": "2023r173", + "modversion": "1.0.6", + "gameversion": "2025r179", "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS", @@ -18,8 +18,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r22/PortableCameraAdditions.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/PortableCameraAdditions.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/PortableCameraAdditions/", - "changelog": "- Fixes for 2023r173.", + "changelog": "- Recompiled for 2025r179", "embedcolor": "#ffd96a" } \ No newline at end of file From e24eae5a22cb0ca381ffc01a783cd5b97383d6bc Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:00:08 -0500 Subject: [PATCH 021/119] [PropLoadingHexagon] bump version, fix for 2025r179 --- PropLoadingHexagon/Main.cs | 6 +++--- PropLoadingHexagon/Properties/AssemblyInfo.cs | 3 +-- PropLoadingHexagon/format.json | 8 ++++---- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/PropLoadingHexagon/Main.cs b/PropLoadingHexagon/Main.cs index aecb7df..eac818f 100644 --- a/PropLoadingHexagon/Main.cs +++ b/PropLoadingHexagon/Main.cs @@ -50,9 +50,9 @@ public class PropLoadingHexagonMod : MelonMod ); HarmonyInstance.Patch( // delete mode on prop placeholder - typeof(ControllerRay).GetMethod(nameof(ControllerRay.DeleteSpawnable), + typeof(ControllerRay).GetMethod(nameof(ControllerRay.HandleSpawnableClicked), BindingFlags.NonPublic | BindingFlags.Instance), - prefix: new HarmonyMethod(typeof(PropLoadingHexagonMod).GetMethod(nameof(OnDeleteSpawnableCheck), + prefix: new HarmonyMethod(typeof(PropLoadingHexagonMod).GetMethod(nameof(OnHandleSpawnableClicked), BindingFlags.NonPublic | BindingFlags.Static)) ); @@ -185,7 +185,7 @@ public class PropLoadingHexagonMod : MelonMod Loading_Hex_List.Add(loadingHex); } - private static void OnDeleteSpawnableCheck(ref ControllerRay __instance) + private static void OnHandleSpawnableClicked(ref ControllerRay __instance) { if (!__instance._interactDown) return; // not interacted, no need to check diff --git a/PropLoadingHexagon/Properties/AssemblyInfo.cs b/PropLoadingHexagon/Properties/AssemblyInfo.cs index a423d48..35e50f1 100644 --- a/PropLoadingHexagon/Properties/AssemblyInfo.cs +++ b/PropLoadingHexagon/Properties/AssemblyInfo.cs @@ -22,12 +22,11 @@ using System.Reflection; [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] [assembly: MelonColor(255, 246, 25, 99)] // red-pink [assembly: MelonAuthorColor(255, 158, 21, 32)] // red -[assembly: MelonOptionalDependencies("TheClapper")] [assembly: HarmonyDontPatchAll] namespace NAK.PropLoadingHexagon.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.0"; + public const string Version = "1.0.1"; public const string Author = "Exterrata & NotAKidoS"; } \ No newline at end of file diff --git a/PropLoadingHexagon/format.json b/PropLoadingHexagon/format.json index 541cd73..4d12613 100644 --- a/PropLoadingHexagon/format.json +++ b/PropLoadingHexagon/format.json @@ -1,8 +1,8 @@ { "_id": 220, "name": "PropLoadingHexagon", - "modversion": "1.0.0", - "gameversion": "2024r175", + "modversion": "1.0.1", + "gameversion": "2025r179", "loaderversion": "0.6.1", "modtype": "Mod", "author": "Exterrata & NotAKidoS", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r34/PropLoadingHexagon.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/PropLoadingHexagon.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/PropLoadingHexagon/", - "changelog": "- Initial release", + "changelog": "- Fixes for 2025r179", "embedcolor": "#f61963" } \ No newline at end of file From bddc21ec08ca3823217c2fa82fc380faaf2c1778 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:00:19 -0500 Subject: [PATCH 022/119] [PropUndoButton] bump version --- PropUndoButton/Properties/AssemblyInfo.cs | 4 +++- PropUndoButton/format.json | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/PropUndoButton/Properties/AssemblyInfo.cs b/PropUndoButton/Properties/AssemblyInfo.cs index 424a9d7..ca45627 100644 --- a/PropUndoButton/Properties/AssemblyInfo.cs +++ b/PropUndoButton/Properties/AssemblyInfo.cs @@ -20,11 +20,13 @@ using System.Reflection; [assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red [assembly: HarmonyDontPatchAll] namespace NAK.PropUndoButton.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.2"; + public const string Version = "1.0.3"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/PropUndoButton/format.json b/PropUndoButton/format.json index 9f6f07a..32227a9 100644 --- a/PropUndoButton/format.json +++ b/PropUndoButton/format.json @@ -1,8 +1,8 @@ { "_id": 147, "name": "PropUndoButton", - "modversion": "1.0.2", - "gameversion": "2024r175", + "modversion": "1.0.3", + "gameversion": "2025r179", "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r25/PropUndoButton.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/PropUndoButton.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/PropUndoButton/", - "changelog": "- Recompiled for 2024r175", + "changelog": "- Recompiled for 2025r179", "embedcolor": "#00FFFF" } \ No newline at end of file From 9d2c3ed244b1cf3ecf24bdb8288625a1d4bf17a9 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:00:35 -0500 Subject: [PATCH 023/119] [RCCVirtualSteeringWheel] bump version --- RCCVirtualSteeringWheel/Properties/AssemblyInfo.cs | 2 +- RCCVirtualSteeringWheel/format.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/RCCVirtualSteeringWheel/Properties/AssemblyInfo.cs b/RCCVirtualSteeringWheel/Properties/AssemblyInfo.cs index 616aa81..38d7ecc 100644 --- a/RCCVirtualSteeringWheel/Properties/AssemblyInfo.cs +++ b/RCCVirtualSteeringWheel/Properties/AssemblyInfo.cs @@ -28,6 +28,6 @@ using NAK.RCCVirtualSteeringWheel.Properties; namespace NAK.RCCVirtualSteeringWheel.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.3"; + public const string Version = "1.0.4"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/RCCVirtualSteeringWheel/format.json b/RCCVirtualSteeringWheel/format.json index 438f31f..4a5ad1a 100644 --- a/RCCVirtualSteeringWheel/format.json +++ b/RCCVirtualSteeringWheel/format.json @@ -1,8 +1,8 @@ { "_id": 248, "name": "RCCVirtualSteeringWheel", - "modversion": "1.0.3", - "gameversion": "2025r178", + "modversion": "1.0.4", + "gameversion": "2025r179", "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r45/RCCVirtualSteeringWheel.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/RCCVirtualSteeringWheel.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/RCCVirtualSteeringWheel/", - "changelog": "- Fixes for 2025r178", + "changelog": "- Recompiled for 2025r179\n- Fixed steering wheel pickup colliders not being set to isTrigger", "embedcolor": "#f61963" } \ No newline at end of file From 75de6d33a0923d9c8d5f6a311c6374b6e161dec3 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:00:42 -0500 Subject: [PATCH 024/119] [RelativeSync] bump version --- RelativeSync/Properties/AssemblyInfo.cs | 2 +- RelativeSync/format.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/RelativeSync/Properties/AssemblyInfo.cs b/RelativeSync/Properties/AssemblyInfo.cs index f014b61..ef60248 100644 --- a/RelativeSync/Properties/AssemblyInfo.cs +++ b/RelativeSync/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.RelativeSync.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.4"; + public const string Version = "1.0.5"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/RelativeSync/format.json b/RelativeSync/format.json index 7b5c456..2df6da2 100644 --- a/RelativeSync/format.json +++ b/RelativeSync/format.json @@ -1,8 +1,8 @@ { "_id": 211, "name": "RelativeSync", - "modversion": "1.0.4", - "gameversion": "2024r175", + "modversion": "1.0.5", + "gameversion": "2025r179", "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r34/RelativeSync.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/RelativeSync.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/RelativeSync/", - "changelog": "- Fixed log spam when receiving relative sync data from a blocked user (thanks Mod Network for still forwarding that data -_-)\n- Adjusted execution order to apply relative sync before Totally Wholesomes LineController\n- Adjusted Relative Sync to still apply to avatar distance-hidden users\n- Adjusted Relative Sync to not apply if the CVRSeat or Movement Parent is disabled on receiving client", + "changelog": "- Recompiled for 2025r179", "embedcolor": "#f61963" } \ No newline at end of file From 73d76010bc2f7d5d8bb0056c9d3368a2cbc89502 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:00:48 -0500 Subject: [PATCH 025/119] [ScrollFlight] bump version --- ScrollFlight/Main.cs | 6 +++--- ScrollFlight/format.json | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ScrollFlight/Main.cs b/ScrollFlight/Main.cs index 98fdabd..f2180b8 100644 --- a/ScrollFlight/Main.cs +++ b/ScrollFlight/Main.cs @@ -42,8 +42,8 @@ public class ScrollFlightMod : MelonMod { CVRWorld.GameRulesUpdated += OnApplyMovementSettings; // thank you kafe for using actions } - - bool wasFlying = false; + + private bool wasFlying; // stole from LucMod :3 public override void OnUpdate() @@ -66,7 +66,7 @@ public class ScrollFlightMod : MelonMod wasFlying = isFlying; if (!isFlying - || Input.GetKey(KeyCode.Mouse2) // scroll zoom + || Input.GetKey(KeyCode.Mouse2) // scroll zoom (TODO: Use CVRInputManager.zoom, but requires fixing zoom toggle mode on client) || Input.GetKey(KeyCode.LeftControl) // third person / better interact desktop || Cursor.lockState != CursorLockMode.Locked) // unity explorer / in menu return; diff --git a/ScrollFlight/format.json b/ScrollFlight/format.json index 3981ee1..ddcf1de 100644 --- a/ScrollFlight/format.json +++ b/ScrollFlight/format.json @@ -1,8 +1,8 @@ { - "_id": -1, + "_id": 219, "name": "ScrollFlight", - "modversion": "1.0.0", - "gameversion": "2024r175", + "modversion": "1.0.3", + "gameversion": "2025r179", "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r34/ScrollFlight.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ScrollFlight.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ScrollFlight/", - "changelog": "- Initial release", + "changelog": "- Recompiled for 2025r179", "embedcolor": "#f61963" } \ No newline at end of file From 940777d9e5224b424ed712b2f8825fc044468df5 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:00:56 -0500 Subject: [PATCH 026/119] [ScrollFlight] bump version --- ScrollFlight/Properties/AssemblyInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ScrollFlight/Properties/AssemblyInfo.cs b/ScrollFlight/Properties/AssemblyInfo.cs index 3aeb6cb..64e0133 100644 --- a/ScrollFlight/Properties/AssemblyInfo.cs +++ b/ScrollFlight/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.ScrollFlight.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.1"; + public const string Version = "1.0.3"; public const string Author = "NotAKidoS"; } \ No newline at end of file From 697ad77f5f554b798fb5b930ee761713d3b434c5 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:01:15 -0500 Subject: [PATCH 027/119] [ShareBubbles] bump version, fixes for 2025r179 --- ShareBubbles/Patches.cs | 2 +- ShareBubbles/Properties/AssemblyInfo.cs | 2 +- ShareBubbles/format.json | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ShareBubbles/Patches.cs b/ShareBubbles/Patches.cs index 162c75b..5f95231 100644 --- a/ShareBubbles/Patches.cs +++ b/ShareBubbles/Patches.cs @@ -35,7 +35,7 @@ internal static class PlayerSetup_Patches internal static class ControllerRay_Patches { [HarmonyPostfix] - [HarmonyPatch(typeof(ControllerRay), nameof(ControllerRay.DeleteSpawnable))] + [HarmonyPatch(typeof(ControllerRay), nameof(ControllerRay.HandleSpawnableClicked))] public static void Postfix_ControllerRay_DeleteSpawnable(ref ControllerRay __instance) { if (!__instance._interactDown) diff --git a/ShareBubbles/Properties/AssemblyInfo.cs b/ShareBubbles/Properties/AssemblyInfo.cs index 07120d8..ce8f183 100644 --- a/ShareBubbles/Properties/AssemblyInfo.cs +++ b/ShareBubbles/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using NAK.ShareBubbles.Properties; namespace NAK.ShareBubbles.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.4"; + public const string Version = "1.0.5"; public const string Author = "NotAKidoS, Exterrata, Noachi, RaidShadowLily, Tejler"; } \ No newline at end of file diff --git a/ShareBubbles/format.json b/ShareBubbles/format.json index be28ae9..ce31103 100644 --- a/ShareBubbles/format.json +++ b/ShareBubbles/format.json @@ -1,8 +1,8 @@ { "_id": 244, "name": "ShareBubbles", - "modversion": "1.0.4", - "gameversion": "2025r178", + "modversion": "1.0.5", + "gameversion": "2025r179", "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS, Exterrata, Noachi, RaidShadowLily, Tejler, Luc", @@ -17,8 +17,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r45/ShareBubbles.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ShareBubbles.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ShareBubbles/", - "changelog": "- Fixes for 2025r178", + "changelog": "- Fixes for 2025r179", "embedcolor": "#f61963" } \ No newline at end of file From cdcb70a4b13742b92c17f2ea691550bf77238ed4 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:01:22 -0500 Subject: [PATCH 028/119] [SmootherRay] bump version, fixes for 2025r179 --- SmootherRay/Main.cs | 8 ++++---- SmootherRay/Properties/AssemblyInfo.cs | 3 +-- SmootherRay/format.json | 8 ++++---- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/SmootherRay/Main.cs b/SmootherRay/Main.cs index eb6c36a..1d6d3f4 100644 --- a/SmootherRay/Main.cs +++ b/SmootherRay/Main.cs @@ -51,7 +51,7 @@ public class SmootherRayMod : MelonMod { Logger = LoggerInstance; ApplyPatches(typeof(PlayerSetup_Patches)); - ApplyPatches(typeof(ControllerRay_Patches)); + ApplyPatches(typeof(ControllerSmoothing_Patches)); } private void ApplyPatches(Type type) @@ -82,12 +82,12 @@ public class SmootherRayMod : MelonMod } } - internal static class ControllerRay_Patches + internal static class ControllerSmoothing_Patches { // SmootherRay [HarmonyPrefix] - [HarmonyPatch(typeof(ControllerRay), nameof(ControllerRay.SmoothRay))] - private static bool Prefix_ControllerRay_SmoothRay(ref ControllerRay __instance) + [HarmonyPatch(typeof(ControllerSmoothing), nameof(ControllerSmoothing.OnAppliedPoses))] + private static bool Prefix_ControllerSmoothing_OnAppliedPoses(ref ControllerSmoothing __instance) => !EntryEnabled.Value; // SmootherRay method enforces identity local pos when disabled, so we skip it } diff --git a/SmootherRay/Properties/AssemblyInfo.cs b/SmootherRay/Properties/AssemblyInfo.cs index d7f1704..c47196d 100644 --- a/SmootherRay/Properties/AssemblyInfo.cs +++ b/SmootherRay/Properties/AssemblyInfo.cs @@ -25,9 +25,8 @@ using System.Reflection; [assembly: HarmonyDontPatchAll] namespace NAK.SmootherRay.Properties; - internal static class AssemblyInfoParams { - public const string Version = "1.0.6"; + public const string Version = "1.0.7"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/SmootherRay/format.json b/SmootherRay/format.json index a627013..18f38c3 100644 --- a/SmootherRay/format.json +++ b/SmootherRay/format.json @@ -1,8 +1,8 @@ { "_id": 162, "name": "SmootherRay", - "modversion": "1.0.5", - "gameversion": "2024r176", + "modversion": "1.0.6", + "gameversion": "2025r177", "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r40/SmootherRay.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/SmootherRay.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/SmootherRay/", - "changelog": "- Fixed for 2024r176.\n- Rebranded to SmootherRayer due to native implementation now existing and sucking.", + "changelog": "- Fixes for 2025r179", "embedcolor": "#f61963" } \ No newline at end of file From bf89ee24f597af1eaf3505c1ae67c5ccac183983 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:01:28 -0500 Subject: [PATCH 029/119] [Stickers] bump version, fixes for 2025r179 --- Stickers/Properties/AssemblyInfo.cs | 2 +- Stickers/format.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Stickers/Properties/AssemblyInfo.cs b/Stickers/Properties/AssemblyInfo.cs index 5107aed..db9f15b 100644 --- a/Stickers/Properties/AssemblyInfo.cs +++ b/Stickers/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.Stickers.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.8"; + public const string Version = "1.0.9"; public const string Author = "NotAKidoS, SketchFoxsky"; } \ No newline at end of file diff --git a/Stickers/format.json b/Stickers/format.json index 5c28daa..fd49c43 100644 --- a/Stickers/format.json +++ b/Stickers/format.json @@ -1,8 +1,8 @@ { "_id": 232, "name": "Stickers", - "modversion": "1.0.8", - "gameversion": "2024r177", + "modversion": "1.0.9", + "gameversion": "2025r179", "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS, SketchFoxsky", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r41/Stickers.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/Stickers.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/Stickers/", - "changelog": "- Added world restriction via `[DisableStickers]` GameObject (thx Sketch).\n- Added sticker placement preview.\n- Fixed stickers being hit by VR switch shader replacement.\n- Fixed Desktop Sticker placement bind firing when a text field was focused.\n- **This version is not backwards compatible with previous versions over network.**", + "changelog": "- Fixes for 2025r179", "embedcolor": "#f61963" } \ No newline at end of file From 16fb070e8b2b5d7e82530a16fb29855a67e94ce1 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:01:37 -0500 Subject: [PATCH 030/119] [ThirdPerson] bump version --- ThirdPerson/Patches.cs | 1 - ThirdPerson/Properties/AssemblyInfo.cs | 6 +++--- ThirdPerson/format.json | 8 ++++---- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/ThirdPerson/Patches.cs b/ThirdPerson/Patches.cs index 60dc4dd..131b45b 100644 --- a/ThirdPerson/Patches.cs +++ b/ThirdPerson/Patches.cs @@ -4,7 +4,6 @@ using MelonLoader; using System.Reflection; using static NAK.ThirdPerson.CameraLogic; using ABI_RC.Core; -using ABI_RC.Core.Player.TransformHider; namespace NAK.ThirdPerson; diff --git a/ThirdPerson/Properties/AssemblyInfo.cs b/ThirdPerson/Properties/AssemblyInfo.cs index 6c055d1..c2c7701 100644 --- a/ThirdPerson/Properties/AssemblyInfo.cs +++ b/ThirdPerson/Properties/AssemblyInfo.cs @@ -20,13 +20,13 @@ using System.Reflection; [assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] -[assembly: MelonColor(255, 246, 25, 97)] -[assembly: MelonAuthorColor(255, 158, 21, 32)] +[assembly: MelonColor(255, 246, 25, 97)] // do not change color, originally chosen by Davi +[assembly: MelonAuthorColor(255, 158, 21, 32)] // do not change color, originally chosen by Davi [assembly: HarmonyDontPatchAll] namespace NAK.ThirdPerson.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.1.0"; + public const string Version = "1.1.1"; public const string Author = "Davi & NotAKidoS"; } \ No newline at end of file diff --git a/ThirdPerson/format.json b/ThirdPerson/format.json index 52c0017..4cdca3e 100644 --- a/ThirdPerson/format.json +++ b/ThirdPerson/format.json @@ -2,8 +2,8 @@ { "_id": 16, "name": "ThirdPerson", - "modversion": "1.0.9", - "gameversion": "2024r175", + "modversion": "1.1.1", + "gameversion": "2025r179", "loaderversion": "0.6.1", "modtype": "Mod", "author": "Davi & NotAKidoS", @@ -14,9 +14,9 @@ "third person" ], "requirements": [], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r26/ThirdPerson.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ThirdPerson.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ThirdPerson", - "changelog": "- Fixed an issue where VR Switching without using ThirdPerson prior would incorrectly set the Desktop camera culling mask to 0\n- Fixed an NRE when checking CVRWorld zoom rule when no CVRWorld instance was found\n- Prevented head hiding from persisting into third person while Avatar Overrender Ui is enabled", + "changelog": "- Recompiled for 2025r179", "embedcolor": "#F61961" } ] \ No newline at end of file From c35d03b1ec166d5034e3e99f2d4c60c76603055f Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:01:50 -0500 Subject: [PATCH 031/119] [NAK_CVR_Mods] update sln --- NAK_CVR_Mods.sln | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/NAK_CVR_Mods.sln b/NAK_CVR_Mods.sln index 5cc9493..976736f 100644 --- a/NAK_CVR_Mods.sln +++ b/NAK_CVR_Mods.sln @@ -7,11 +7,12 @@ EndProject EndProject EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PathCamDisabler", "PathCamDisabler\PathCamDisabler.csproj", "{98169FD2-5CEB-46D1-A320-D7E06F82C9E0}" -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PortableCameraAdditions", "PortableCameraAdditions\PortableCameraAdditions.csproj", "{C4DAFE9D-C79B-4417-9B7D-B7327999DA4C}" -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PropUndoButton", "PropUndoButton\PropUndoButton.csproj", "{FBFDB717-F81E-4C06-ACF9-A0F3FFDCDE00}" -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThirdPerson", "ThirdPerson\ThirdPerson.csproj", "{675CEC0E-3E8A-4970-98EA-9B79277A7252}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MuteSFX", "MuteSFX\MuteSFX.csproj", "{77D222FC-4AEC-4672-A87A-B860B4C39E17}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PortableCameraAdditions", "PortableCameraAdditions\PortableCameraAdditions.csproj", "{C4DAFE9D-C79B-4417-9B7D-B7327999DA4C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PropUndoButton", "PropUndoButton\PropUndoButton.csproj", "{FBFDB717-F81E-4C06-ACF9-A0F3FFDCDE00}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThirdPerson", "ThirdPerson\ThirdPerson.csproj", "{675CEC0E-3E8A-4970-98EA-9B79277A7252}" EndProject EndProject EndProject @@ -32,8 +33,11 @@ EndProject EndProject EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeepVelocityOnExitFlight", "KeepVelocityOnExitFlight\KeepVelocityOnExitFlight.csproj", "{0BB3D187-BBBA-4C58-B246-102342BE5E8C}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ASTExtension", "ASTExtension\ASTExtension.csproj", "{6580AA87-6A95-438E-A5D3-70E583CCD77B}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AvatarQueueSystemTweaks", "AvatarQueueSystemTweaks\AvatarQueueSystemTweaks.csproj", "{D178E422-283B-4FB3-89A6-AA4FB9F87E2F}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomSpawnPoint", "CustomSpawnPoint\CustomSpawnPoint.csproj", "{51CA34CA-7684-4819-AC9E-89DFAD63E9AB}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stickers", "Stickers\Stickers.csproj", "{E5F54B3E-A676-4DD5-A6DB-73AFA54BEC5E}" @@ -97,10 +101,6 @@ Global {EE552804-30B1-49CF-BBDE-3B312895AFF7}.Debug|Any CPU.Build.0 = Debug|Any CPU {EE552804-30B1-49CF-BBDE-3B312895AFF7}.Release|Any CPU.ActiveCfg = Release|Any CPU {EE552804-30B1-49CF-BBDE-3B312895AFF7}.Release|Any CPU.Build.0 = Release|Any CPU - {77D222FC-4AEC-4672-A87A-B860B4C39E17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {77D222FC-4AEC-4672-A87A-B860B4C39E17}.Debug|Any CPU.Build.0 = Debug|Any CPU - {77D222FC-4AEC-4672-A87A-B860B4C39E17}.Release|Any CPU.ActiveCfg = Release|Any CPU - {77D222FC-4AEC-4672-A87A-B860B4C39E17}.Release|Any CPU.Build.0 = Release|Any CPU {0E1DD746-33A1-4179-AE70-8FB83AC40ABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0E1DD746-33A1-4179-AE70-8FB83AC40ABC}.Debug|Any CPU.Build.0 = Debug|Any CPU {0E1DD746-33A1-4179-AE70-8FB83AC40ABC}.Release|Any CPU.ActiveCfg = Release|Any CPU From f99a22499c68ef1b8d7cfd078930ab569c9f2c6e Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:02:58 -0500 Subject: [PATCH 032/119] [Stickers] Fixed placing stickers when Cohtml text input fields were focused --- Stickers/Main.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Stickers/Main.cs b/Stickers/Main.cs index 80ebd6b..022559b 100644 --- a/Stickers/Main.cs +++ b/Stickers/Main.cs @@ -1,4 +1,5 @@ using ABI_RC.Core; +using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.Player; using ABI_RC.Core.Savior; using ABI_RC.Systems.InputManagement; @@ -51,7 +52,8 @@ public class StickerMod : MelonMod if (!Input.GetKeyDown((KeyCode)ModSettings.Entry_PlaceBinding.Value)) return; - if (CVRInputManager.Instance.textInputFocused) + if (CVRInputManager.Instance.textInputFocused + || ViewManager.Instance.textInputFocused) // BRUH return; // prevent placing stickers while typing StickerSystem.Instance.PlaceStickerFromControllerRay(PlayerSetup.Instance.activeCam.transform); From a9cebb85e95943cd8dc601c403603340bef7f308 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:04:14 -0500 Subject: [PATCH 033/119] [Stickers] Fixed scrolling cycling selected sticker slot despite not being in placement mode --- Stickers/Main.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Stickers/Main.cs b/Stickers/Main.cs index 022559b..1234f10 100644 --- a/Stickers/Main.cs +++ b/Stickers/Main.cs @@ -39,12 +39,15 @@ public class StickerMod : MelonMod if (StickerSystem.Instance == null) return; - if (Input.mouseScrollDelta.y != 0f - && Cursor.lockState == CursorLockMode.Locked // prevent scrolling while in menus - && !CVRInputManager.Instance.zoom) // prevent scrolling while using scroll zoom - StickerSystem.Instance.SelectedStickerSlot += (int)Input.mouseScrollDelta.y; + if (StickerSystem.Instance.IsInStickerMode) + { + if (Input.mouseScrollDelta.y != 0f + && Cursor.lockState == CursorLockMode.Locked // prevent scrolling while in menus + && !CVRInputManager.Instance.zoom) // prevent scrolling while using scroll zoom + StickerSystem.Instance.SelectedStickerSlot += (int)Input.mouseScrollDelta.y; - StickerSystem.Instance.UpdateStickerPreview(); // flashy flash + StickerSystem.Instance.UpdateStickerPreview(); // flashy flash + } if (!ModSettings.Entry_UsePlaceBinding.Value) return; From aad4276f889b13aaaa0398976e4360ef8f534c92 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:05:24 -0500 Subject: [PATCH 034/119] [Stickers] Update format.json --- Stickers/format.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Stickers/format.json b/Stickers/format.json index fd49c43..2d2cab5 100644 --- a/Stickers/format.json +++ b/Stickers/format.json @@ -18,6 +18,6 @@ ], "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/Stickers.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/Stickers/", - "changelog": "- Fixes for 2025r179", + "changelog": "- Fixes for 2025r179\n- Fixed placing stickers when Cohtml text input fields were focused\n- Fixed scrolling cycling selected sticker slot despite not being in placement mode", "embedcolor": "#f61963" } \ No newline at end of file From 138c9a9856c49fa984443a56ca214b2c916dafeb Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:06:43 -0500 Subject: [PATCH 035/119] [RCCVirtualSteeringWheel] Fixed generated steering wheel pickup collider not being marked isTrigger --- .../RCCVirtualSteeringWheel/Components/SteeringWheelRoot.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/RCCVirtualSteeringWheel/RCCVirtualSteeringWheel/Components/SteeringWheelRoot.cs b/RCCVirtualSteeringWheel/RCCVirtualSteeringWheel/Components/SteeringWheelRoot.cs index 0154bd5..088752d 100644 --- a/RCCVirtualSteeringWheel/RCCVirtualSteeringWheel/Components/SteeringWheelRoot.cs +++ b/RCCVirtualSteeringWheel/RCCVirtualSteeringWheel/Components/SteeringWheelRoot.cs @@ -53,6 +53,7 @@ public class SteeringWheelRoot : MonoBehaviour BoxCollider collider = pickup.AddComponent(); collider.size = steeringWheelBounds.size; collider.center = steeringWheelBounds.center; + collider.isTrigger = true; wheelPickup = pickup.AddComponent(); wheelPickup.root = wheel; From 018112d6b9eac08197809e66b64fcdc2f8cd85a8 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:11:40 -0500 Subject: [PATCH 036/119] [RCCVirtualSteeringWheel] Fixed error spam when sitting in a CVRSeat with lockControls, but no RCC component in parent --- RCCVirtualSteeringWheel/Patches.cs | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/RCCVirtualSteeringWheel/Patches.cs b/RCCVirtualSteeringWheel/Patches.cs index b9745d9..1ef3064 100644 --- a/RCCVirtualSteeringWheel/Patches.cs +++ b/RCCVirtualSteeringWheel/Patches.cs @@ -1,4 +1,5 @@ -using ABI_RC.Systems.InputManagement; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Systems.InputManagement; using ABI_RC.Systems.Movement; using HarmonyLib; using NAK.RCCVirtualSteeringWheel.Util; @@ -39,12 +40,20 @@ internal static class CVRInputManager_Patches [HarmonyPatch(typeof(CVRInputManager), nameof(CVRInputManager.UpdateInput))] private static void Postfix_CVRInputManager_UpdateInput(ref CVRInputManager __instance) { - // Steering input is clamped in RCC component - if (BetterBetterCharacterController.Instance.IsSittingOnControlSeat() - && SteeringWheelRoot.TryGetWheelInput( - BetterBetterCharacterController.Instance._lastCvrSeat._carController, out float steeringValue)) - { + BetterBetterCharacterController characterController = BetterBetterCharacterController.Instance; + if (!characterController._isSitting) + return; // Must be sitting + + CVRSeat cvrSeat = characterController._lastCvrSeat; + if (!cvrSeat + || !cvrSeat.lockControls) + return; // Must be a driver seat + + RCC_CarControllerV3 carController = characterController._lastCvrSeat._carController; + if (!carController) + return; // Specific to RCC + + if (SteeringWheelRoot.TryGetWheelInput(carController, out float steeringValue)) __instance.steering = steeringValue; - } } } \ No newline at end of file From e540628db15559a4e73e192136d91939900c30ae Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:12:04 -0500 Subject: [PATCH 037/119] [RCCVirtualSteeringWheel] Updated format.json --- RCCVirtualSteeringWheel/format.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RCCVirtualSteeringWheel/format.json b/RCCVirtualSteeringWheel/format.json index 4a5ad1a..c1c44c8 100644 --- a/RCCVirtualSteeringWheel/format.json +++ b/RCCVirtualSteeringWheel/format.json @@ -18,6 +18,6 @@ ], "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/RCCVirtualSteeringWheel.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/RCCVirtualSteeringWheel/", - "changelog": "- Recompiled for 2025r179\n- Fixed steering wheel pickup colliders not being set to isTrigger", + "changelog": "- Recompiled for 2025r179\n- Fixed generated steering wheel pickup collider not being marked isTrigger\n- Fixed error spam when sitting in a CVRSeat with lockControls, but no RCC component in parent", "embedcolor": "#f61963" } \ No newline at end of file From 72b690365b5d2e0cc214b8231778dac6d0e6e3c5 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:15:11 -0500 Subject: [PATCH 038/119] [ShareBubbles] Fixed Public/Private text on bubble not being correct, Fixed bubble displaying as locked or not claimed despite being shared the content if it was private and not owned by you --- .../API/PedestalInfoBatchProcessor.cs | 17 +++++++++-------- .../PedestalInfoResponse_ButCorrect.cs | 10 ---------- .../Implementation/AvatarBubbleImpl.cs | 6 ++---- .../Implementation/SpawnableBubbleImpl.cs | 6 ++---- 4 files changed, 13 insertions(+), 26 deletions(-) delete mode 100644 ShareBubbles/ShareBubbles/API/Responses/PedestalInfoResponse_ButCorrect.cs diff --git a/ShareBubbles/ShareBubbles/API/PedestalInfoBatchProcessor.cs b/ShareBubbles/ShareBubbles/API/PedestalInfoBatchProcessor.cs index 00b9f41..967734b 100644 --- a/ShareBubbles/ShareBubbles/API/PedestalInfoBatchProcessor.cs +++ b/ShareBubbles/ShareBubbles/API/PedestalInfoBatchProcessor.cs @@ -1,4 +1,5 @@ using ABI_RC.Core.Networking.API; +using ABI_RC.Core.Networking.API.Responses; using NAK.ShareBubbles.API.Responses; namespace NAK.ShareBubbles.API; @@ -19,11 +20,11 @@ public enum PedestalType /// public static class PedestalInfoBatchProcessor { - private static readonly Dictionary>> _pendingRequests + private static readonly Dictionary>> _pendingRequests = new() { - { PedestalType.Avatar, new Dictionary>() }, - { PedestalType.Prop, new Dictionary>() } + { PedestalType.Avatar, new Dictionary>() }, + { PedestalType.Prop, new Dictionary>() } }; private static readonly Dictionary _isBatchProcessing @@ -36,9 +37,9 @@ public static class PedestalInfoBatchProcessor private static readonly object _lock = new(); private const float BATCH_DELAY = 2f; - public static Task QueuePedestalInfoRequest(PedestalType type, string contentId) + public static Task QueuePedestalInfoRequest(PedestalType type, string contentId) { - var tcs = new TaskCompletionSource(); + var tcs = new TaskCompletionSource(); lock (_lock) { @@ -62,12 +63,12 @@ public static class PedestalInfoBatchProcessor await Task.Delay(TimeSpan.FromSeconds(BATCH_DELAY)); List contentIds; - Dictionary> requestBatch; + Dictionary> requestBatch; lock (_lock) { contentIds = _pendingRequests[type].Keys.ToList(); - requestBatch = new Dictionary>(_pendingRequests[type]); + requestBatch = new Dictionary>(_pendingRequests[type]); _pendingRequests[type].Clear(); _isBatchProcessing[type] = false; //ShareBubblesMod.Logger.Msg($"Processing {type} pedestal info batch with {contentIds.Count} items"); @@ -82,7 +83,7 @@ public static class PedestalInfoBatchProcessor _ => throw new ArgumentException($"Unsupported pedestal type: {type}") }; - var response = await ApiConnection.MakeRequest>(operation, contentIds); + var response = await ApiConnection.MakeRequest>(operation, contentIds); if (response?.Data != null) { diff --git a/ShareBubbles/ShareBubbles/API/Responses/PedestalInfoResponse_ButCorrect.cs b/ShareBubbles/ShareBubbles/API/Responses/PedestalInfoResponse_ButCorrect.cs deleted file mode 100644 index 4741a34..0000000 --- a/ShareBubbles/ShareBubbles/API/Responses/PedestalInfoResponse_ButCorrect.cs +++ /dev/null @@ -1,10 +0,0 @@ -using ABI_RC.Core.Networking.API.Responses; - -namespace NAK.ShareBubbles.API.Responses; - -[Serializable] -public class PedestalInfoResponse_ButCorrect : UgcResponse -{ - public UserDetails User { get; set; } - public bool Published { get; set; } // Client mislabelled this as Permitted, but it's actually Published -} \ No newline at end of file diff --git a/ShareBubbles/ShareBubbles/Implementation/AvatarBubbleImpl.cs b/ShareBubbles/ShareBubbles/Implementation/AvatarBubbleImpl.cs index 60dc79d..b79f0c8 100644 --- a/ShareBubbles/ShareBubbles/Implementation/AvatarBubbleImpl.cs +++ b/ShareBubbles/ShareBubbles/Implementation/AvatarBubbleImpl.cs @@ -39,10 +39,8 @@ namespace NAK.ShareBubbles.Impl Name = infoResponse.Name, ImageUrl = infoResponse.ImageUrl, AuthorId = infoResponse.User.Id, - IsPublic = infoResponse.Published, - - // Permit access if Public, Owned, or (CANNOT DO PRIVATE & SHARED CAUSE API DOESNT GIVE) - IsPermitted = infoResponse.Published || infoResponse.User.Id == MetaPort.Instance.ownerId, + IsPublic = infoResponse.IsPublished, + IsPermitted = infoResponse.Permitted, }; downloadedTexture = await ImageCache.GetImageAsync(details.ImageUrl); diff --git a/ShareBubbles/ShareBubbles/Implementation/SpawnableBubbleImpl.cs b/ShareBubbles/ShareBubbles/Implementation/SpawnableBubbleImpl.cs index fc29336..813222c 100644 --- a/ShareBubbles/ShareBubbles/Implementation/SpawnableBubbleImpl.cs +++ b/ShareBubbles/ShareBubbles/Implementation/SpawnableBubbleImpl.cs @@ -39,10 +39,8 @@ namespace NAK.ShareBubbles.Impl Name = infoResponse.Name, ImageUrl = infoResponse.ImageUrl, AuthorId = infoResponse.User.Id, - IsPublic = infoResponse.Published, - - // Permit access if Public, Owned, or (CANNOT DO PRIVATE & SHARED CAUSE API DOESNT GIVE) - IsPermitted = infoResponse.Published || infoResponse.User.Id == MetaPort.Instance.ownerId, + IsPublic = infoResponse.IsPublished, + IsPermitted = infoResponse.Permitted, }; downloadedTexture = await ImageCache.GetImageAsync(details.ImageUrl); From 0fdbcdec34275cb044508e2cc597b53887aeb4bf Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:16:01 -0500 Subject: [PATCH 039/119] [ShareBubbles] Updated format.json --- ShareBubbles/format.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ShareBubbles/format.json b/ShareBubbles/format.json index ce31103..d2028d6 100644 --- a/ShareBubbles/format.json +++ b/ShareBubbles/format.json @@ -19,6 +19,6 @@ ], "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ShareBubbles.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ShareBubbles/", - "changelog": "- Fixes for 2025r179", + "changelog": "- Fixes for 2025r179\n- Fixed Public/Private text on bubble not being correct\n- Fixed bubble displaying as locked or not claimed despite being shared the content if it was private and not owned by you", "embedcolor": "#f61963" } \ No newline at end of file From 84dcf3536277b5a31ebf08c409222e8d72ac6fc9 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:19:17 -0500 Subject: [PATCH 040/119] [ScrollFlight] Update format.json --- ScrollFlight/format.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ScrollFlight/format.json b/ScrollFlight/format.json index ddcf1de..3cc60bd 100644 --- a/ScrollFlight/format.json +++ b/ScrollFlight/format.json @@ -18,6 +18,6 @@ ], "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ScrollFlight.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ScrollFlight/", - "changelog": "- Recompiled for 2025r179", + "changelog": "- Recompiled for 2025r179\n- Added an option to reset flight speed to default on exit flight", "embedcolor": "#f61963" } \ No newline at end of file From 9133c6b16154f0b0ad051d5bec9d174618b582e2 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:34:30 -0500 Subject: [PATCH 041/119] [ShareBubbles] Remove todo notes --- ShareBubbles/ShareBubbles/DataTypes/BubblePedestalInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ShareBubbles/ShareBubbles/DataTypes/BubblePedestalInfo.cs b/ShareBubbles/ShareBubbles/DataTypes/BubblePedestalInfo.cs index 932fa6c..87699e4 100644 --- a/ShareBubbles/ShareBubbles/DataTypes/BubblePedestalInfo.cs +++ b/ShareBubbles/ShareBubbles/DataTypes/BubblePedestalInfo.cs @@ -5,6 +5,6 @@ public class BubblePedestalInfo public string Name; public string ImageUrl; public string AuthorId; - public bool IsPermitted; // TODO: awaiting luc to fix not being true for private shared (only true for public) - public bool IsPublic; // TODO: awaiting luc to add + public bool IsPermitted; + public bool IsPublic; } \ No newline at end of file From 063669e8a60f6cca4352efaa479abd1a5224c34b Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:40:20 -0500 Subject: [PATCH 042/119] [SmootherRay] Update format.json --- SmootherRay/format.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SmootherRay/format.json b/SmootherRay/format.json index 18f38c3..5e49dd0 100644 --- a/SmootherRay/format.json +++ b/SmootherRay/format.json @@ -6,7 +6,7 @@ "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS", - "description": "Smoothes your controller while the raycast lines are visible.\nThis is a CVR adaptation of a Beat Saber mod: [BeatSaber_SmoothedController](https://github.com/kinsi55/BeatSaber_SmoothedController)\n\n- An option is provided to only smooth when aiming at menus.\n- Smoothing characteristics are completely configurable, but the defaults are basically perfect.\n- Pairs well with the [WhereAmIPointing](https://discord.com/channels/1001388809184870441/1002058238545641542/1282798820073406556) mod.\n\n**Only supports OpenVR, not OpenXR.**\n\n-# NOTE: This disables the shitty built-in Smooth Ray setting when the mod is enabled. Compare both & you'll see why.", + "description": "Smoothes your controller while the raycast lines are visible.\nThis is a CVR adaptation of a Beat Saber mod: [BeatSaber_SmoothedController](https://github.com/kinsi55/BeatSaber_SmoothedController)\n\n- An option is provided to only smooth when aiming at menus.\n- Smoothing characteristics are completely configurable, but the defaults are basically perfect.\n\n**Only supports OpenVR, not OpenXR.**\n\n-# NOTE: This disables the shitty built-in Smooth Ray setting when the mod is enabled. Compare both & you'll see why.", "searchtags": [ "vr", "ray", From ea5a9eef970fe60d2b341492bd8880424c0cc88a Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 05:08:25 -0500 Subject: [PATCH 043/119] [RelativeSync] Fixed execution order of RelativeSyncController & PuppetMaster.ProcessAvatarVisibility, so moving at high speeds with passengers does not disrupt voice or avatar distance hider --- RelativeSync/Main.cs | 8 +-- RelativeSync/ModSettings.cs | 7 +-- RelativeSync/Patches.cs | 54 ++++++++++--------- .../Components/RelativeSyncController.cs | 17 +++++- .../RelativeSync/RelativeSyncManager.cs | 1 + 5 files changed, 52 insertions(+), 35 deletions(-) diff --git a/RelativeSync/Main.cs b/RelativeSync/Main.cs index 83ec331..0a50472 100644 --- a/RelativeSync/Main.cs +++ b/RelativeSync/Main.cs @@ -17,10 +17,7 @@ public class RelativeSyncMod : MelonMod // Experimental sync hack ApplyPatches(typeof(CVRSpawnablePatches)); - - // Experimental no interpolation on Better Better Character Controller - ApplyPatches(typeof(BetterBetterCharacterControllerPatches)); - + // Send relative sync update after network root data update ApplyPatches(typeof(NetworkRootDataUpdatePatches)); @@ -31,6 +28,9 @@ public class RelativeSyncMod : MelonMod // Add components if missing (for relative sync markers) ApplyPatches(typeof(CVRSeatPatches)); ApplyPatches(typeof(CVRMovementParentPatches)); + + // So we run after the client moves the remote player + ApplyPatches(typeof(NetIKController_Patches)); } private void ApplyPatches(Type type) diff --git a/RelativeSync/ModSettings.cs b/RelativeSync/ModSettings.cs index 91a60a7..f8567ad 100644 --- a/RelativeSync/ModSettings.cs +++ b/RelativeSync/ModSettings.cs @@ -23,11 +23,7 @@ internal static class ModSettings private static readonly MelonPreferences_Entry ExpSyncedObjectHack = Category.CreateEntry("ExpSyncedObjectHack", true, "Exp Spawnable Sync Fix", description: "Forces CVRSpawnable to update position in FixedUpdate. May help reduce local jitter on synced movement parents."); - - private static readonly MelonPreferences_Entry ExpNoInterpolationOnBBCC = - Category.CreateEntry("ExpNoInterpolationOnBBCC", true, - "Exp Disable Interpolation on BBCC", description: "Disable interpolation on Better Better Character Controller. May help reduce local jitter on synced movement parents."); - + #endregion Melon Preferences internal static void Initialize() @@ -43,6 +39,5 @@ internal static class ModSettings ModNetwork.Debug_NetworkInbound = DebugLogInbound.Value; ModNetwork.Debug_NetworkOutbound = DebugLogOutbound.Value; Patches.CVRSpawnablePatches.UseHack = ExpSyncedObjectHack.Value; - Patches.BetterBetterCharacterControllerPatches.NoInterpolation = ExpNoInterpolationOnBBCC.Value; } } \ No newline at end of file diff --git a/RelativeSync/Patches.cs b/RelativeSync/Patches.cs index 71d4ec8..43937dd 100644 --- a/RelativeSync/Patches.cs +++ b/RelativeSync/Patches.cs @@ -2,12 +2,10 @@ using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.Networking.Jobs; using ABI_RC.Core.Player; -using ABI_RC.Systems.Movement; using ABI.CCK.Components; using HarmonyLib; using NAK.RelativeSync.Components; using NAK.RelativeSync.Networking; -using UnityEngine; namespace NAK.RelativeSync.Patches; @@ -19,7 +17,6 @@ internal static class PlayerSetupPatches { __instance.AddComponentIfMissing(); } - } internal static class PuppetMasterPatches @@ -30,6 +27,20 @@ internal static class PuppetMasterPatches { __instance.AddComponentIfMissing(); } + + private static bool ShouldProcessAvatarVisibility { get; set; } + + [HarmonyPrefix] + [HarmonyPatch(typeof(PuppetMaster), nameof(PuppetMaster.ProcessAvatarVisibility))] + private static bool Prefix_PuppetMaster_ProcessAvatarVisibility() + => ShouldProcessAvatarVisibility; + + public static void ForceProcessAvatarVisibility(PuppetMaster puppetMaster) + { + ShouldProcessAvatarVisibility = true; + puppetMaster.ProcessAvatarVisibility(); + ShouldProcessAvatarVisibility = false; + } } internal static class CVRSeatPatches @@ -85,29 +96,24 @@ internal static class CVRSpawnablePatches } } -internal static class BetterBetterCharacterControllerPatches +internal static class NetIKController_Patches { - private static bool _noInterpolation; - internal static bool NoInterpolation - { - get => _noInterpolation; - set - { - _noInterpolation = value; - if (_rigidbody == null) return; - _rigidbody.interpolation = value ? RigidbodyInterpolation.None : _initialInterpolation; - } - } - - private static Rigidbody _rigidbody; - private static RigidbodyInterpolation _initialInterpolation; - [HarmonyPostfix] - [HarmonyPatch(typeof(BetterBetterCharacterController), nameof(BetterBetterCharacterController.Start))] - private static void Postfix_BetterBetterCharacterController_Update(ref BetterBetterCharacterController __instance) + [HarmonyPatch(typeof(NetIKController), nameof(NetIKController.LateUpdate))] + private static void Postfix_NetIKController_LateUpdate(ref NetIKController __instance) { - _rigidbody = __instance.GetComponent(); - _initialInterpolation = _rigidbody.interpolation; - NoInterpolation = _noInterpolation; // get initial value as patch runs later than settings init + if (!RelativeSyncManager.NetIkControllersToRelativeSyncControllers.TryGetValue(__instance, + out RelativeSyncController syncController)) + { + // Process visibility only after applying network IK + PuppetMasterPatches.ForceProcessAvatarVisibility(__instance._puppetMaster); + return; + } + + // Apply relative sync after the network IK has been applied + syncController.OnPostNetIkControllerLateUpdate(); + + // Process visibility after we have moved the remote player + PuppetMasterPatches.ForceProcessAvatarVisibility(__instance._puppetMaster); } } \ No newline at end of file diff --git a/RelativeSync/RelativeSync/Components/RelativeSyncController.cs b/RelativeSync/RelativeSync/Components/RelativeSyncController.cs index 2e11301..66af2c7 100644 --- a/RelativeSync/RelativeSync/Components/RelativeSyncController.cs +++ b/RelativeSync/RelativeSync/Components/RelativeSyncController.cs @@ -26,14 +26,29 @@ public class RelativeSyncController : MonoBehaviour _userId = puppetMaster._playerDescriptor.ownerId; RelativeSyncManager.RelativeSyncControllers.Add(_userId, this); + RelativeSyncManager.NetIkControllersToRelativeSyncControllers.Add(puppetMaster.netIkController, this); } private void OnDestroy() { RelativeSyncManager.RelativeSyncControllers.Remove(_userId); + + if (puppetMaster == null + || puppetMaster.netIkController == null) + { + // remove by value ? + foreach (var kvp in RelativeSyncManager.NetIkControllersToRelativeSyncControllers) + { + if (kvp.Value != this) continue; + RelativeSyncManager.NetIkControllersToRelativeSyncControllers.Remove(kvp.Key); + break; + } + return; + } + RelativeSyncManager.NetIkControllersToRelativeSyncControllers.Remove(puppetMaster.netIkController); } - private void LateUpdate() + internal void OnPostNetIkControllerLateUpdate() { // if (puppetMaster._isHidden) // return; diff --git a/RelativeSync/RelativeSync/RelativeSyncManager.cs b/RelativeSync/RelativeSync/RelativeSyncManager.cs index 9a532f4..052ca3c 100644 --- a/RelativeSync/RelativeSync/RelativeSyncManager.cs +++ b/RelativeSync/RelativeSync/RelativeSyncManager.cs @@ -11,6 +11,7 @@ public static class RelativeSyncManager public static readonly Dictionary RelativeSyncTransforms = new(); public static readonly Dictionary RelativeSyncControllers = new(); + public static readonly Dictionary NetIkControllersToRelativeSyncControllers = new(); public static void ApplyRelativeSync(string userId, int target, Vector3 position, Vector3 rotation) { From 6249696efaa00151708201b07259ea5cd5284e4d Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 05:08:57 -0500 Subject: [PATCH 044/119] [RelativeSync] Updated format.json --- RelativeSync/format.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RelativeSync/format.json b/RelativeSync/format.json index 2df6da2..b917a7d 100644 --- a/RelativeSync/format.json +++ b/RelativeSync/format.json @@ -18,6 +18,6 @@ ], "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/RelativeSync.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/RelativeSync/", - "changelog": "- Recompiled for 2025r179", + "changelog": "- Recompiled for 2025r179\n- Fixed execution order of RelativeSyncController & PuppetMaster.ProcessAvatarVisibility, so moving at high speeds with passengers does not disrupt voice or avatar distance hider", "embedcolor": "#f61963" } \ No newline at end of file From fea10ac221b9ada48e145242c721bacc6d5562df Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 05:24:48 -0500 Subject: [PATCH 045/119] [RelativeSync] actually fixed distance hider --- RelativeSync/Patches.cs | 31 ++++++------------- .../Components/RelativeSyncController.cs | 8 ++++- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/RelativeSync/Patches.cs b/RelativeSync/Patches.cs index 43937dd..10acf15 100644 --- a/RelativeSync/Patches.cs +++ b/RelativeSync/Patches.cs @@ -6,6 +6,7 @@ using ABI.CCK.Components; using HarmonyLib; using NAK.RelativeSync.Components; using NAK.RelativeSync.Networking; +using UnityEngine; namespace NAK.RelativeSync.Patches; @@ -27,20 +28,6 @@ internal static class PuppetMasterPatches { __instance.AddComponentIfMissing(); } - - private static bool ShouldProcessAvatarVisibility { get; set; } - - [HarmonyPrefix] - [HarmonyPatch(typeof(PuppetMaster), nameof(PuppetMaster.ProcessAvatarVisibility))] - private static bool Prefix_PuppetMaster_ProcessAvatarVisibility() - => ShouldProcessAvatarVisibility; - - public static void ForceProcessAvatarVisibility(PuppetMaster puppetMaster) - { - ShouldProcessAvatarVisibility = true; - puppetMaster.ProcessAvatarVisibility(); - ShouldProcessAvatarVisibility = false; - } } internal static class CVRSeatPatches @@ -104,16 +91,18 @@ internal static class NetIKController_Patches { if (!RelativeSyncManager.NetIkControllersToRelativeSyncControllers.TryGetValue(__instance, out RelativeSyncController syncController)) - { - // Process visibility only after applying network IK - PuppetMasterPatches.ForceProcessAvatarVisibility(__instance._puppetMaster); return; - } // Apply relative sync after the network IK has been applied syncController.OnPostNetIkControllerLateUpdate(); - - // Process visibility after we have moved the remote player - PuppetMasterPatches.ForceProcessAvatarVisibility(__instance._puppetMaster); + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(NetIKController), nameof(NetIKController.GetLocalPlayerPosition))] + private static bool Prefix_NetIKController_GetLocalPlayerPosition(ref NetIKController __instance, ref Vector3 __result) + { + // why is the original method so bad + __result = PlayerSetup.Instance.activeCam.transform.position; + return false; } } \ No newline at end of file diff --git a/RelativeSync/RelativeSync/Components/RelativeSyncController.cs b/RelativeSync/RelativeSync/Components/RelativeSyncController.cs index 66af2c7..a94cde0 100644 --- a/RelativeSync/RelativeSync/Components/RelativeSyncController.cs +++ b/RelativeSync/RelativeSync/Components/RelativeSyncController.cs @@ -1,4 +1,5 @@ using ABI_RC.Core.Player; +using ABI_RC.Systems.Movement; using UnityEngine; namespace NAK.RelativeSync.Components; @@ -62,7 +63,7 @@ public class RelativeSyncController : MonoBehaviour Animator animator = puppetMaster._animator; if (animator == null) return; - + Transform avatarTransform = animator.transform; Transform hipTrans = (animator.avatar != null && animator.isHuman) ? animator.GetBoneTransform(HumanBodyBones.Hips) : null; @@ -97,6 +98,11 @@ public class RelativeSyncController : MonoBehaviour hipTrans.position = transform.position + transform.rotation * relativeHipPos; hipTrans.rotation = transform.rotation * relativeHipRot; } + + // Reprocess the root distance so we don't fuck avatar distance hider + NetIKController netIkController = puppetMaster.netIkController; + netIkController._rootDistance = Vector3.Distance((netIkController._collider.transform.position + netIkController._collider.center), + netIkController.GetLocalPlayerPosition()) - (netIkController._collider.radius + BetterBetterCharacterController.Instance.Radius); } private void ApplyRelativeRotation(Transform avatarTransform, Transform hipTransform, float lerp) From 364de89b30037b6fc6587cb80a16a8142338eae2 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 3 Apr 2025 05:25:37 -0500 Subject: [PATCH 046/119] [RelativeSync] Updated format.json --- RelativeSync/format.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RelativeSync/format.json b/RelativeSync/format.json index b917a7d..a5346fa 100644 --- a/RelativeSync/format.json +++ b/RelativeSync/format.json @@ -18,6 +18,6 @@ ], "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/RelativeSync.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/RelativeSync/", - "changelog": "- Recompiled for 2025r179\n- Fixed execution order of RelativeSyncController & PuppetMaster.ProcessAvatarVisibility, so moving at high speeds with passengers does not disrupt voice or avatar distance hider", + "changelog": "- Recompiled for 2025r179\n- Fixed execution order of RelativeSyncController so moving at high speeds with passengers does not disrupt voice or avatar distance hider", "embedcolor": "#f61963" } \ No newline at end of file From 7030ed865087be4a0fa41c02eac777b71edb6da5 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Wed, 9 Apr 2025 15:49:27 -0500 Subject: [PATCH 047/119] [NAK_CVR_Mods] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 76c86ad..5fa34df 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ ## NotAKids ChilloutVR Mods + + ## Released Mods | Mod Name | README | Download | Description | @@ -37,6 +39,8 @@ | VisualCloneFix | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/VisualCloneFix) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/VisualCloneFix.dll) | Fixes the Visual Clone system. | | WhereAmIPointing | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/WhereAmIPointing) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/WhereAmIPointing.dll) | Makes your controller rays always visible when the menus are open. | + + # How To Install The majority of modifications found in this repository are reviewed and made available through the [ChilloutVR Modding Group](https://discord.gg/dndGPM3bxu). From 0564de3ebfade2fed62d134f6ad94b5465db74ab Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Wed, 9 Apr 2025 15:52:32 -0500 Subject: [PATCH 048/119] [NAK_CVR_Mods] Experiment --- .github/scripts/update-modlist.js | 55 ++++++++++++++++++++++++++++ .github/workflows/update-modlist.yml | 34 +++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 .github/scripts/update-modlist.js create mode 100644 .github/workflows/update-modlist.yml diff --git a/.github/scripts/update-modlist.js b/.github/scripts/update-modlist.js new file mode 100644 index 0000000..2e5c55d --- /dev/null +++ b/.github/scripts/update-modlist.js @@ -0,0 +1,55 @@ +const fs = require('fs'); +const path = require('path'); + +const ROOT = '.'; +const EXPERIMENTAL = '.Experimental'; +const README_PATH = 'README.md'; +const MARKER_START = ''; +const MARKER_END = ''; + +function getModFolders(baseDir) { + const entries = fs.readdirSync(baseDir, { withFileTypes: true }); + return entries + .filter(entry => entry.isDirectory()) + .map(entry => path.join(baseDir, entry.name)) + .filter(dir => fs.existsSync(path.join(dir, 'README.md'))); +} + +function formatTable(mods, baseDir) { + if (mods.length === 0) return ''; + + let rows = mods.map(modPath => { + const modName = path.basename(modPath); + const readmeLink = path.join(modPath, 'README.md'); + const zipLink = path.join(modPath, `${modName}.zip`); + return `| [${modName}](${readmeLink}) | [Download](${zipLink}) |`; + }); + + return [ + `### ${baseDir === EXPERIMENTAL ? 'Experimental Mods' : 'Released Mods'}`, + '', + '| Name | Download |', + '|------|----------|', + ...rows, + '' + ].join('\n'); +} + +function updateReadme(modListSection) { + const readme = fs.readFileSync(README_PATH, 'utf8'); + const before = readme.split(MARKER_START)[0]; + const after = readme.split(MARKER_END)[1]; + + const newReadme = `${before}${MARKER_START}\n\n${modListSection}\n${MARKER_END}${after}`; + fs.writeFileSync(README_PATH, newReadme); +} + +const mainMods = getModFolders(ROOT).filter(dir => !dir.startsWith(EXPERIMENTAL)); +const experimentalMods = getModFolders(EXPERIMENTAL); + +const tableContent = [ + formatTable(mainMods, ROOT), + formatTable(experimentalMods, EXPERIMENTAL) +].join('\n'); + +updateReadme(tableContent); \ No newline at end of file diff --git a/.github/workflows/update-modlist.yml b/.github/workflows/update-modlist.yml new file mode 100644 index 0000000..73d8919 --- /dev/null +++ b/.github/workflows/update-modlist.yml @@ -0,0 +1,34 @@ +name: Update Mod List in README + +on: + push: + paths: + - '**/README.md' + - '.github/workflows/update-modlist.yml' + workflow_dispatch: + +jobs: + update-readme: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: '20' + + - name: Install dependencies + run: npm install gray-matter + + - name: Generate mod list + run: node .github/scripts/update-modlist.js + + - name: Commit changes + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add README.md + git commit -m "[NAK_CVR_Mods] Update mod list in README" || echo "No changes to commit" + git push From 68d7c22b7c54430ec9e54573cee97e11da3eb66f Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Wed, 9 Apr 2025 16:02:53 -0500 Subject: [PATCH 049/119] [NAK_CVR_Mods] Experiment 2 --- .github/workflows/update-modlist.yml | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/.github/workflows/update-modlist.yml b/.github/workflows/update-modlist.yml index 73d8919..2b117fb 100644 --- a/.github/workflows/update-modlist.yml +++ b/.github/workflows/update-modlist.yml @@ -1,34 +1,35 @@ -name: Update Mod List in README +name: Update Mod List on: push: paths: - - '**/README.md' + - 'scripts/update_modlist.py' - '.github/workflows/update-modlist.yml' + - 'README.md' + - '**/README.md' workflow_dispatch: jobs: - update-readme: + update-modlist: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - name: Checkout repo + uses: actions/checkout@v4 - - name: Set up Node.js - uses: actions/setup-node@v3 + - name: Set up Python + uses: actions/setup-python@v5 with: - node-version: '20' + python-version: '3.x' - - name: Install dependencies - run: npm install gray-matter + - name: Run mod list updater + run: python scripts/update_modlist.py - - name: Generate mod list - run: node .github/scripts/update-modlist.js - - - name: Commit changes + - name: Commit and push changes run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" + git remote set-url origin https://x-access-token:${{ secrets.GH_TOKEN }}@github.com/${{ github.repository }} git add README.md git commit -m "[NAK_CVR_Mods] Update mod list in README" || echo "No changes to commit" git push From dafff6a9a2d31d7c54e36d3e89a6ccd5d661913f Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Wed, 9 Apr 2025 16:05:01 -0500 Subject: [PATCH 050/119] [NAK_CVR_Mods] trust --- .github/workflows/update-modlist.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/update-modlist.yml b/.github/workflows/update-modlist.yml index 2b117fb..3376080 100644 --- a/.github/workflows/update-modlist.yml +++ b/.github/workflows/update-modlist.yml @@ -3,7 +3,7 @@ name: Update Mod List on: push: paths: - - 'scripts/update_modlist.py' + - 'update-modlist.js' - '.github/workflows/update-modlist.yml' - 'README.md' - '**/README.md' @@ -17,13 +17,13 @@ jobs: - name: Checkout repo uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v5 + - name: Set up Node.js + uses: actions/setup-node@v3 with: - python-version: '3.x' + node-version: '20' - name: Run mod list updater - run: python scripts/update_modlist.py + run: node update-modlist.js - name: Commit and push changes run: | From 02be4ec4453ad2516497462e7fd1003160c4cb60 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Wed, 9 Apr 2025 16:07:44 -0500 Subject: [PATCH 051/119] [NAK_CVR_Mods] trust 2 --- .github/workflows/update-modlist.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/update-modlist.yml b/.github/workflows/update-modlist.yml index 3376080..69c4426 100644 --- a/.github/workflows/update-modlist.yml +++ b/.github/workflows/update-modlist.yml @@ -3,7 +3,7 @@ name: Update Mod List on: push: paths: - - 'update-modlist.js' + - '.github/scripts/update-modlist.js' - '.github/workflows/update-modlist.yml' - 'README.md' - '**/README.md' @@ -23,7 +23,7 @@ jobs: node-version: '20' - name: Run mod list updater - run: node update-modlist.js + run: node .github/scripts/update-modlist.js - name: Commit and push changes run: | @@ -32,4 +32,4 @@ jobs: git remote set-url origin https://x-access-token:${{ secrets.GH_TOKEN }}@github.com/${{ github.repository }} git add README.md git commit -m "[NAK_CVR_Mods] Update mod list in README" || echo "No changes to commit" - git push + git push \ No newline at end of file From 21aa6463590381c17beeb87bcd769c6920326d5a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 9 Apr 2025 21:23:54 +0000 Subject: [PATCH 052/119] [NAK_CVR_Mods] Update mod list in README --- README.md | 62 ++++++++++++++++++++++++------------------------------- 1 file changed, 27 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 5fa34df..c84f23e 100644 --- a/README.md +++ b/README.md @@ -2,42 +2,34 @@ -## Released Mods +### Released Mods -| Mod Name | README | Download | Description | -|------------------------------|--------------------------------------------------------|-----------------------------------------------------------------------------------------------------|--------------------------------------------------------------------| -| AASDefaultProfileFix | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/AASDefaultProfileFix) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/AASDefaultProfileFix.dll) | Fixes the Default AAS profile not being applied. | -| ASTExtension | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/ASTExtension) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/ASTExtension.dll) | Avatar scaling gesture & persistance on existing avatars. | -| AvatarQueueSystemTweaks | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/AvatarQueueSystemTweaks) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/AvatarQueueSystemTweaks.dll) | Tweaks to improve the avatar queuing system. | -| ChatBoxExtensions | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/ChatBoxExtensions) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/ChatBoxExtensions.dll) | Adds some chat commands to the ChatBox mod. | -| CustomSpawnPoint | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/CustomSpawnPoint) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/CustomSpawnPoint.dll) | Allows setting custom spawn points in worlds. | -| CVRGizmos | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/CVRGizmos) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/CVRGizmos.dll) | Adds runtime gizmos to common CCK components. | -| DropPropTweak | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/DropPropTweak) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/DropPropTweak.dll) | Allows you to drop props in the air. | -| FOVAdjustment | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/FOVAdjustment) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/FOVAdjustment.dll) | Makes CVR_DesktopCameraController default FOV configurable. | -| HeadLookLockingInputFix | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/HeadLookLockingInputFix) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/HeadLookLockingInputFix.dll) | Fixes head look locking input issues. | -| IKAdjustments | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/IKAdjustments) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/IKAdjustments.dll) | Allows grabbing IK points for manual adjustment. | -| IKSimulatedRootAngleFix | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/IKSimulatedRootAngleFix) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/IKSimulatedRootAngleFix.dll) | Fixes Desktop & HalfBody root angle issues. | -| KeepVelocityOnExitFlight | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/KeepVelocityOnExitFlight) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/KeepVelocityOnExitFlight.dll) | Keeps the player's velocity when exiting flight mode. | -| LazyPrune | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/LazyPrune) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/LazyPrune.dll) | Prevents loaded objects from immediately unloading. | -| LuaTTS | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/LuaTTS) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/LuaTTS.dll) | Adds Text-to-Speech (TTS) functionality through Lua. | -| MoreMenuOptions | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/MoreMenuOptions) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/MoreMenuOptions.dll) | Exposes some menu placement configuration options. | -| MuteSFX | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/MuteSFX) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/MuteSFX.dll) | Adds an audio cue for muting and unmuting. | -| OriginShift | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/OriginShift) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/OriginShift.dll) | Shifts the world origin to avoid precision issues. | -| PathCamDisabler | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/PathCamDisabler) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/PathCamDisabler.dll) | Adds option to disable the Path Camera Controller keybinds. | -| PortableCameraAdditions | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/PortableCameraAdditions) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/PortableCameraAdditions.dll) | Adds a few basic settings to the Portable Camera. | -| PropLoadingHexagon | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/PropLoadingHexagon) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/PropLoadingHexagon.dll) | Adds a hexagon indicator to downloading props. | -| PropUndoButton | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/PropUndoButton) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/PropUndoButton.dll) | CTRL+Z to undo latest spawned prop. | -| ReconnectionSystemFix | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/ReconnectionSystemFix) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/ReconnectionSystemFix.dll) | Prevents recreating and reloading all remote players. | -| RelativeSync | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/RelativeSync) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/RelativeSync.dll) | Relative sync for Movement Parent & Chairs. | -| ScrollFlight | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/ScrollFlight) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/ScrollFlight.dll) | Scroll-wheel to adjust flight speed in Desktop. | -| ShadowCloneFallback | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/ShadowCloneFallback) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/ShadowCloneFallback.dll) | Exposes a toggle for the Fallback Shadow Clone. | -| SmartReticle | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/SmartReticle) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/SmartReticle.dll) | Makes the reticle only appear when hovering interactables. | -| Stickers | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/Stickers) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/Stickers.dll) | Allows you to place small images on any surface. | -| StopClosingMyMenuOnWorldLoad | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/StopClosingMyMenuOnWorldLoad)| [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/StopClosingMyMenuOnWorldLoad.dll) | Prevents your menu from being closed when a world is loaded. | -| SwitchToDesktopOnSteamVRExit | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/SwitchToDesktopOnSteamVRExit)| [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/SwitchToDesktopOnSteamVRExit.dll) | Initiates a VR Switch to Desktop when SteamVR is exited. | -| ThirdPerson | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/ThirdPerson) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/ThirdPerson.dll) | Allows you to go into third person view. | -| VisualCloneFix | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/VisualCloneFix) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/VisualCloneFix.dll) | Fixes the Visual Clone system. | -| WhereAmIPointing | [README](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/WhereAmIPointing) | [Download](https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/latest/download/WhereAmIPointing.dll) | Makes your controller rays always visible when the menus are open. | +| Name | Download | +|------|----------| +| [ASTExtension](ASTExtension/README.md) | [Download](ASTExtension/ASTExtension.zip) | +| [AvatarQueueSystemTweaks](AvatarQueueSystemTweaks/README.md) | [Download](AvatarQueueSystemTweaks/AvatarQueueSystemTweaks.zip) | +| [CustomRichPresence](CustomRichPresence/README.md) | [Download](CustomRichPresence/CustomRichPresence.zip) | +| [CustomSpawnPoint](CustomSpawnPoint/README.md) | [Download](CustomSpawnPoint/CustomSpawnPoint.zip) | +| [FuckToes](FuckToes/README.md) | [Download](FuckToes/FuckToes.zip) | +| [KeepVelocityOnExitFlight](KeepVelocityOnExitFlight/README.md) | [Download](KeepVelocityOnExitFlight/KeepVelocityOnExitFlight.zip) | +| [LazyPrune](LazyPrune/README.md) | [Download](LazyPrune/LazyPrune.zip) | +| [PropLoadingHexagon](PropLoadingHexagon/README.md) | [Download](PropLoadingHexagon/PropLoadingHexagon.zip) | +| [RCCVirtualSteeringWheel](RCCVirtualSteeringWheel/README.md) | [Download](RCCVirtualSteeringWheel/RCCVirtualSteeringWheel.zip) | +| [RelativeSync](RelativeSync/README.md) | [Download](RelativeSync/RelativeSync.zip) | +| [ShareBubbles](ShareBubbles/README.md) | [Download](ShareBubbles/ShareBubbles.zip) | +| [SmootherRay](SmootherRay/README.md) | [Download](SmootherRay/SmootherRay.zip) | +| [Stickers](Stickers/README.md) | [Download](Stickers/Stickers.zip) | +| [ThirdPerson](ThirdPerson/README.md) | [Download](ThirdPerson/ThirdPerson.zip) | + +### Experimental Mods + +| Name | Download | +|------|----------| +| [CVRLuaToolsExtension](.Experimental/CVRLuaToolsExtension/README.md) | [Download](.Experimental/CVRLuaToolsExtension/CVRLuaToolsExtension.zip) | +| [LuaNetworkVariables](.Experimental/LuaNetworkVariables/README.md) | [Download](.Experimental/LuaNetworkVariables/LuaNetworkVariables.zip) | +| [LuaTTS](.Experimental/LuaTTS/README.md) | [Download](.Experimental/LuaTTS/LuaTTS.zip) | +| [OriginShift](.Experimental/OriginShift/README.md) | [Download](.Experimental/OriginShift/OriginShift.zip) | +| [ScriptingSpoofer](.Experimental/ScriptingSpoofer/README.md) | [Download](.Experimental/ScriptingSpoofer/ScriptingSpoofer.zip) | From d5480e32b49ea6a86491fde7952345be19c9340f Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Wed, 9 Apr 2025 16:29:13 -0500 Subject: [PATCH 053/119] [NAK_CVR_Mods] test --- .github/scripts/update-modlist.js | 36 ++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/.github/scripts/update-modlist.js b/.github/scripts/update-modlist.js index 2e5c55d..7045224 100644 --- a/.github/scripts/update-modlist.js +++ b/.github/scripts/update-modlist.js @@ -15,6 +15,33 @@ function getModFolders(baseDir) { .filter(dir => fs.existsSync(path.join(dir, 'README.md'))); } +function extractDescription(readmePath) { + try { + const content = fs.readFileSync(readmePath, 'utf8'); + const lines = content.split('\n'); + + // Find the first header (# something) + let headerIndex = -1; + for (let i = 0; i < lines.length; i++) { + if (lines[i].trim().startsWith('# ')) { + headerIndex = i; + break; + } + } + + // If we found a header, try to get the third line after it + if (headerIndex !== -1 && headerIndex + 2 < lines.length) { + const description = lines[headerIndex + 2].trim(); + return description || 'No description available'; + } + + return 'No description available'; + } catch (error) { + console.error(`Error reading ${readmePath}:`, error); + return 'No description available'; + } +} + function formatTable(mods, baseDir) { if (mods.length === 0) return ''; @@ -22,14 +49,17 @@ function formatTable(mods, baseDir) { const modName = path.basename(modPath); const readmeLink = path.join(modPath, 'README.md'); const zipLink = path.join(modPath, `${modName}.zip`); - return `| [${modName}](${readmeLink}) | [Download](${zipLink}) |`; + const readmePath = path.join(modPath, 'README.md'); + const description = extractDescription(readmePath); + + return `| [${modName}](${readmeLink}) | ${description} | [Download](${zipLink}) |`; }); return [ `### ${baseDir === EXPERIMENTAL ? 'Experimental Mods' : 'Released Mods'}`, '', - '| Name | Download |', - '|------|----------|', + '| Name | Description | Download |', + '|------|-------------|----------|', ...rows, '' ].join('\n'); From e67d5719711963dcee86a5f3e9f3a8e622c460cb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 9 Apr 2025 21:29:34 +0000 Subject: [PATCH 054/119] [NAK_CVR_Mods] Update mod list in README --- README.md | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index c84f23e..dde9417 100644 --- a/README.md +++ b/README.md @@ -4,32 +4,32 @@ ### Released Mods -| Name | Download | -|------|----------| -| [ASTExtension](ASTExtension/README.md) | [Download](ASTExtension/ASTExtension.zip) | -| [AvatarQueueSystemTweaks](AvatarQueueSystemTweaks/README.md) | [Download](AvatarQueueSystemTweaks/AvatarQueueSystemTweaks.zip) | -| [CustomRichPresence](CustomRichPresence/README.md) | [Download](CustomRichPresence/CustomRichPresence.zip) | -| [CustomSpawnPoint](CustomSpawnPoint/README.md) | [Download](CustomSpawnPoint/CustomSpawnPoint.zip) | -| [FuckToes](FuckToes/README.md) | [Download](FuckToes/FuckToes.zip) | -| [KeepVelocityOnExitFlight](KeepVelocityOnExitFlight/README.md) | [Download](KeepVelocityOnExitFlight/KeepVelocityOnExitFlight.zip) | -| [LazyPrune](LazyPrune/README.md) | [Download](LazyPrune/LazyPrune.zip) | -| [PropLoadingHexagon](PropLoadingHexagon/README.md) | [Download](PropLoadingHexagon/PropLoadingHexagon.zip) | -| [RCCVirtualSteeringWheel](RCCVirtualSteeringWheel/README.md) | [Download](RCCVirtualSteeringWheel/RCCVirtualSteeringWheel.zip) | -| [RelativeSync](RelativeSync/README.md) | [Download](RelativeSync/RelativeSync.zip) | -| [ShareBubbles](ShareBubbles/README.md) | [Download](ShareBubbles/ShareBubbles.zip) | -| [SmootherRay](SmootherRay/README.md) | [Download](SmootherRay/SmootherRay.zip) | -| [Stickers](Stickers/README.md) | [Download](Stickers/Stickers.zip) | -| [ThirdPerson](ThirdPerson/README.md) | [Download](ThirdPerson/ThirdPerson.zip) | +| Name | Description | Download | +|------|-------------|----------| +| [ASTExtension](ASTExtension/README.md) | Extension mod for [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool): | [Download](ASTExtension/ASTExtension.zip) | +| [AvatarQueueSystemTweaks](AvatarQueueSystemTweaks/README.md) | Small tweaks to the Avatar Queue System. | [Download](AvatarQueueSystemTweaks/AvatarQueueSystemTweaks.zip) | +| [CustomRichPresence](CustomRichPresence/README.md) | Gives the Drop Prop button more utility by allowing you to drop props in the air. | [Download](CustomRichPresence/CustomRichPresence.zip) | +| [CustomSpawnPoint](CustomSpawnPoint/README.md) | Replaces the unused Images button in the World Details page with a button to set a custom spawn point. | [Download](CustomSpawnPoint/CustomSpawnPoint.zip) | +| [FuckToes](FuckToes/README.md) | No description available | [Download](FuckToes/FuckToes.zip) | +| [KeepVelocityOnExitFlight](KeepVelocityOnExitFlight/README.md) | Keeps the player's velocity when exiting flight mode. Makes it possible to fling yourself like in Garry's Mod. | [Download](KeepVelocityOnExitFlight/KeepVelocityOnExitFlight.zip) | +| [LazyPrune](LazyPrune/README.md) | Prevents loaded objects from immediately unloading on destruction. Should prevent needlessly unloading & reloading all avatars/props on world rejoin or GS reconnection. | [Download](LazyPrune/LazyPrune.zip) | +| [PropLoadingHexagon](PropLoadingHexagon/README.md) | https://github.com/NotAKidoS/NAK_CVR_Mods/assets/37721153/a892c765-71c1-47f3-a781-bdb9b60ba117 | [Download](PropLoadingHexagon/PropLoadingHexagon.zip) | +| [RCCVirtualSteeringWheel](RCCVirtualSteeringWheel/README.md) | Allows you to physically grab rigged RCC steering wheels in VR to provide steering input. No explicit setup required other than defining the Steering Wheel transform within the RCC component. | [Download](RCCVirtualSteeringWheel/RCCVirtualSteeringWheel.zip) | +| [RelativeSync](RelativeSync/README.md) | Relative sync for Movement Parent & Chairs. Requires both users to have the mod installed. Synced over Mod Network. | [Download](RelativeSync/RelativeSync.zip) | +| [ShareBubbles](ShareBubbles/README.md) | Share Bubbles! Allows you to drop down bubbles containing Avatars & Props. Requires both users to have the mod installed. Synced over Mod Network. | [Download](ShareBubbles/ShareBubbles.zip) | +| [SmootherRay](SmootherRay/README.md) | Smoothes your controller while the raycast lines are visible. | [Download](SmootherRay/SmootherRay.zip) | +| [Stickers](Stickers/README.md) | Stickers! Allows you to place small images on any surface. Requires both users to have the mod installed. Synced over Mod Network. | [Download](Stickers/Stickers.zip) | +| [ThirdPerson](ThirdPerson/README.md) | Original repo: https://github.com/oestradiol/CVR-Mods | [Download](ThirdPerson/ThirdPerson.zip) | ### Experimental Mods -| Name | Download | -|------|----------| -| [CVRLuaToolsExtension](.Experimental/CVRLuaToolsExtension/README.md) | [Download](.Experimental/CVRLuaToolsExtension/CVRLuaToolsExtension.zip) | -| [LuaNetworkVariables](.Experimental/LuaNetworkVariables/README.md) | [Download](.Experimental/LuaNetworkVariables/LuaNetworkVariables.zip) | -| [LuaTTS](.Experimental/LuaTTS/README.md) | [Download](.Experimental/LuaTTS/LuaTTS.zip) | -| [OriginShift](.Experimental/OriginShift/README.md) | [Download](.Experimental/OriginShift/OriginShift.zip) | -| [ScriptingSpoofer](.Experimental/ScriptingSpoofer/README.md) | [Download](.Experimental/ScriptingSpoofer/ScriptingSpoofer.zip) | +| Name | Description | Download | +|------|-------------|----------| +| [CVRLuaToolsExtension](.Experimental/CVRLuaToolsExtension/README.md) | Extension mod for [CVRLuaTools](https://github.com/NotAKidoS/CVRLuaTools) Hot Reload functionality. | [Download](.Experimental/CVRLuaToolsExtension/CVRLuaToolsExtension.zip) | +| [LuaNetworkVariables](.Experimental/LuaNetworkVariables/README.md) | Simple mod that makes your controller rays always visible when the menus are open. Useful for when you're trying to aim at something in the distance. Also visualizes which ray is being used for menu interaction. | [Download](.Experimental/LuaNetworkVariables/LuaNetworkVariables.zip) | +| [LuaTTS](.Experimental/LuaTTS/README.md) | Provides access to the built-in text-to-speech (TTS) functionality to lua scripts. Allows you to make the local player speak. | [Download](.Experimental/LuaTTS/LuaTTS.zip) | +| [OriginShift](.Experimental/OriginShift/README.md) | Experimental mod that allows world origin to be shifted to prevent floating point precision issues. | [Download](.Experimental/OriginShift/OriginShift.zip) | +| [ScriptingSpoofer](.Experimental/ScriptingSpoofer/README.md) | Prevents **local** scripts from accessing your Username or UserID by spoofing them with random values each session. | [Download](.Experimental/ScriptingSpoofer/ScriptingSpoofer.zip) | From ef6ad34a4eb3c6cccc3868fd9c1be320560fb28d Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Wed, 9 Apr 2025 16:32:15 -0500 Subject: [PATCH 055/119] [NAK_CVR_Mods] Fixed finding description for FuckToes --- .github/scripts/update-modlist.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/scripts/update-modlist.js b/.github/scripts/update-modlist.js index 7045224..b404561 100644 --- a/.github/scripts/update-modlist.js +++ b/.github/scripts/update-modlist.js @@ -29,10 +29,14 @@ function extractDescription(readmePath) { } } - // If we found a header, try to get the third line after it - if (headerIndex !== -1 && headerIndex + 2 < lines.length) { - const description = lines[headerIndex + 2].trim(); - return description || 'No description available'; + // If we found a header, look for the first non-empty line after it + if (headerIndex !== -1) { + for (let i = headerIndex + 1; i < lines.length; i++) { + const line = lines[i].trim(); + if (line && !line.startsWith('#')) { + return line; + } + } } return 'No description available'; From c13e48638c96ff9da9c321374b754065ca25a2f5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 9 Apr 2025 21:32:36 +0000 Subject: [PATCH 056/119] [NAK_CVR_Mods] Update mod list in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dde9417..0a11162 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ | [AvatarQueueSystemTweaks](AvatarQueueSystemTweaks/README.md) | Small tweaks to the Avatar Queue System. | [Download](AvatarQueueSystemTweaks/AvatarQueueSystemTweaks.zip) | | [CustomRichPresence](CustomRichPresence/README.md) | Gives the Drop Prop button more utility by allowing you to drop props in the air. | [Download](CustomRichPresence/CustomRichPresence.zip) | | [CustomSpawnPoint](CustomSpawnPoint/README.md) | Replaces the unused Images button in the World Details page with a button to set a custom spawn point. | [Download](CustomSpawnPoint/CustomSpawnPoint.zip) | -| [FuckToes](FuckToes/README.md) | No description available | [Download](FuckToes/FuckToes.zip) | +| [FuckToes](FuckToes/README.md) | Prevents VRIK from autodetecting toes in HalfbodyIK. | [Download](FuckToes/FuckToes.zip) | | [KeepVelocityOnExitFlight](KeepVelocityOnExitFlight/README.md) | Keeps the player's velocity when exiting flight mode. Makes it possible to fling yourself like in Garry's Mod. | [Download](KeepVelocityOnExitFlight/KeepVelocityOnExitFlight.zip) | | [LazyPrune](LazyPrune/README.md) | Prevents loaded objects from immediately unloading on destruction. Should prevent needlessly unloading & reloading all avatars/props on world rejoin or GS reconnection. | [Download](LazyPrune/LazyPrune.zip) | | [PropLoadingHexagon](PropLoadingHexagon/README.md) | https://github.com/NotAKidoS/NAK_CVR_Mods/assets/37721153/a892c765-71c1-47f3-a781-bdb9b60ba117 | [Download](PropLoadingHexagon/PropLoadingHexagon.zip) | From ba26a1faae0c5f3f76ccef66a6bbe0d57faceac2 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Fri, 11 Apr 2025 07:39:16 -0500 Subject: [PATCH 057/119] [CustomRichPresence] Move to .Experimental folder --- .../CustomRichPresence}/CustomRichPresence.csproj | 0 {CustomRichPresence => .Experimental/CustomRichPresence}/Main.cs | 0 .../CustomRichPresence}/Properties/AssemblyInfo.cs | 0 .../CustomRichPresence}/README.md | 0 .../CustomRichPresence}/format.json | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename {CustomRichPresence => .Experimental/CustomRichPresence}/CustomRichPresence.csproj (100%) rename {CustomRichPresence => .Experimental/CustomRichPresence}/Main.cs (100%) rename {CustomRichPresence => .Experimental/CustomRichPresence}/Properties/AssemblyInfo.cs (100%) rename {CustomRichPresence => .Experimental/CustomRichPresence}/README.md (100%) rename {CustomRichPresence => .Experimental/CustomRichPresence}/format.json (100%) diff --git a/CustomRichPresence/CustomRichPresence.csproj b/.Experimental/CustomRichPresence/CustomRichPresence.csproj similarity index 100% rename from CustomRichPresence/CustomRichPresence.csproj rename to .Experimental/CustomRichPresence/CustomRichPresence.csproj diff --git a/CustomRichPresence/Main.cs b/.Experimental/CustomRichPresence/Main.cs similarity index 100% rename from CustomRichPresence/Main.cs rename to .Experimental/CustomRichPresence/Main.cs diff --git a/CustomRichPresence/Properties/AssemblyInfo.cs b/.Experimental/CustomRichPresence/Properties/AssemblyInfo.cs similarity index 100% rename from CustomRichPresence/Properties/AssemblyInfo.cs rename to .Experimental/CustomRichPresence/Properties/AssemblyInfo.cs diff --git a/CustomRichPresence/README.md b/.Experimental/CustomRichPresence/README.md similarity index 100% rename from CustomRichPresence/README.md rename to .Experimental/CustomRichPresence/README.md diff --git a/CustomRichPresence/format.json b/.Experimental/CustomRichPresence/format.json similarity index 100% rename from CustomRichPresence/format.json rename to .Experimental/CustomRichPresence/format.json From 392390cde7a097f851f94f984bf0a130b7c8d342 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Fri, 11 Apr 2025 07:39:32 -0500 Subject: [PATCH 058/119] [YouAreMyPropNowWeAreHavingSoftTacosLater] Initial push --- NAK_CVR_Mods.sln | 6 + .../Main.cs | 479 ++++++++++++++++++ .../Properties/AssemblyInfo.cs | 32 ++ .../README.md | 19 + ...eMyPropNowWeAreHavingSoftTacosLater.csproj | 6 + .../format.json | 23 + 6 files changed, 565 insertions(+) create mode 100644 YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs create mode 100644 YouAreMyPropNowWeAreHavingSoftTacosLater/Properties/AssemblyInfo.cs create mode 100644 YouAreMyPropNowWeAreHavingSoftTacosLater/README.md create mode 100644 YouAreMyPropNowWeAreHavingSoftTacosLater/YouAreMyPropNowWeAreHavingSoftTacosLater.csproj create mode 100644 YouAreMyPropNowWeAreHavingSoftTacosLater/format.json diff --git a/NAK_CVR_Mods.sln b/NAK_CVR_Mods.sln index 976736f..26deacd 100644 --- a/NAK_CVR_Mods.sln +++ b/NAK_CVR_Mods.sln @@ -54,6 +54,8 @@ EndProject EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RCCVirtualSteeringWheel", "RCCVirtualSteeringWheel\RCCVirtualSteeringWheel.csproj", "{4A378F81-3805-41E8-9565-A8A89A8C00D6}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YouAreMyPropNowWeAreHavingSoftTacosLater", "YouAreMyPropNowWeAreHavingSoftTacosLater\YouAreMyPropNowWeAreHavingSoftTacosLater.csproj", "{8DA821CC-F911-4FCB-8C29-5EF3D76A5F76}" +EndProject EndProject EndProject EndProject @@ -289,6 +291,10 @@ Global {ED2CAA2D-4E49-4636-86C4-367D0CDC3572}.Debug|Any CPU.Build.0 = Debug|Any CPU {ED2CAA2D-4E49-4636-86C4-367D0CDC3572}.Release|Any CPU.ActiveCfg = Release|Any CPU {ED2CAA2D-4E49-4636-86C4-367D0CDC3572}.Release|Any CPU.Build.0 = Release|Any CPU + {8DA821CC-F911-4FCB-8C29-5EF3D76A5F76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8DA821CC-F911-4FCB-8C29-5EF3D76A5F76}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8DA821CC-F911-4FCB-8C29-5EF3D76A5F76}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8DA821CC-F911-4FCB-8C29-5EF3D76A5F76}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs b/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs new file mode 100644 index 0000000..645f7c0 --- /dev/null +++ b/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs @@ -0,0 +1,479 @@ +using System.Collections; +using System.Reflection; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.IO; +using ABI_RC.Core.Networking; +using ABI_RC.Core.Networking.API.Responses; +using ABI_RC.Core.Player; +using ABI_RC.Core.Util; +using ABI_RC.Systems.GameEventSystem; +using ABI_RC.Systems.Movement; +using ABI.CCK.Components; +using DarkRift; +using HarmonyLib; +using MelonLoader; +using UnityEngine; +using UnityEngine.SceneManagement; +using Object = UnityEngine.Object; +using Random = UnityEngine.Random; + +namespace NAK.YouAreMyPropNowWeAreHavingSoftTacosLater; + +public class YouAreMyPropNowWeAreHavingSoftTacosLaterMod : MelonMod +{ + #region Melon Events + + public override void OnInitializeMelon() + { + #region CVRPickupObject Patches + + HarmonyInstance.Patch( + typeof(CVRPickupObject).GetMethod(nameof(CVRPickupObject.OnGrab), + BindingFlags.NonPublic | BindingFlags.Instance), + postfix: new HarmonyMethod(typeof(YouAreMyPropNowWeAreHavingSoftTacosLaterMod).GetMethod(nameof(OnCVRPickupObjectOnGrab), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + HarmonyInstance.Patch( + typeof(CVRPickupObject).GetMethod(nameof(CVRPickupObject.OnDrop), BindingFlags.NonPublic | BindingFlags.Instance), + postfix: new HarmonyMethod(typeof(YouAreMyPropNowWeAreHavingSoftTacosLaterMod).GetMethod(nameof(OnCVRPickupObjectOnDrop), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + #endregion CVRPickupObject Patches + + #region CVRAttachment Patches + + HarmonyInstance.Patch( // Cannot compile when using nameof + typeof(CVRAttachment).GetMethod("\u003CAttachInternal\u003Eg__DoAttachmentSetup\u007C43_0", + BindingFlags.NonPublic | BindingFlags.Instance), + postfix: new HarmonyMethod(typeof(YouAreMyPropNowWeAreHavingSoftTacosLaterMod).GetMethod(nameof(OnCVRAttachmentAttachInternal), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + HarmonyInstance.Patch( + typeof(CVRAttachment).GetMethod(nameof(CVRAttachment.DeAttach)), + prefix: new HarmonyMethod(typeof(YouAreMyPropNowWeAreHavingSoftTacosLaterMod).GetMethod(nameof(OnCVRAttachmentDeAttach), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + #endregion CVRAttachment Patches + + #region CVRSyncHelper Patches + + HarmonyInstance.Patch( // Replaces method, original needlessly ToArray??? + typeof(CVRSyncHelper).GetMethod(nameof(CVRSyncHelper.ClearProps), + BindingFlags.Public | BindingFlags.Static), + prefix: new HarmonyMethod(typeof(YouAreMyPropNowWeAreHavingSoftTacosLaterMod).GetMethod(nameof(OnCVRSyncHelperClearProps), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + #endregion CVRSyncHelper Patches + + #region CVRDownloadManager Patches + + HarmonyInstance.Patch( + typeof(CVRDownloadManager).GetMethod(nameof(CVRDownloadManager.QueueTask), + BindingFlags.Public | BindingFlags.Instance), + prefix: new HarmonyMethod(typeof(YouAreMyPropNowWeAreHavingSoftTacosLaterMod).GetMethod(nameof(OnCVRDownloadManagerQueueTask), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + #endregion CVRDownloadManager Patches + + #region BetterBetterCharacterController Patches + + HarmonyInstance.Patch( + typeof(BetterBetterCharacterController).GetMethod(nameof(BetterBetterCharacterController.SetSitting), + BindingFlags.Public | BindingFlags.Instance), + prefix: new HarmonyMethod(typeof(YouAreMyPropNowWeAreHavingSoftTacosLaterMod).GetMethod(nameof(OnBetterBetterCharacterControllerSetSitting), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + #endregion BetterBetterCharacterController Patches + + #region CVRWorld Game Events + + CVRGameEventSystem.World.OnLoad.AddListener(OnWorldLoad); + CVRGameEventSystem.World.OnUnload.AddListener(OnWorldUnload); + + #endregion CVRWorld Game Events + + #region Instances Game Events + + CVRGameEventSystem.Instance.OnConnected.AddListener(OnInstanceConnected); + + #endregion Instances Game Events + } + + #endregion Melon Events + + #region Harmony Patches + + private static readonly List _heldPropData = new(); + private static GameObject _persistantPropsContainer; + private static GameObject GetOrCreatePropsContainer() + { + if (_persistantPropsContainer != null) return _persistantPropsContainer; + _persistantPropsContainer = new("[NAK] PersistantProps"); + _persistantPropsContainer.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity); + _persistantPropsContainer.transform.localScale = Vector3.one; + Object.DontDestroyOnLoad(_persistantPropsContainer); + return _persistantPropsContainer; + } + + private static readonly Dictionary _keyToPropData = new(); + private static readonly Stack _spawnablePositionStack = new(); + private static bool _ignoreNextSeatExit; + private static float _heightOffset; + + private static void OnCVRPickupObjectOnGrab(CVRPickupObject __instance) + { + if (!GetPropData(__instance.GetComponentInParent(true), out CVRSyncHelper.PropData propData)) return; + if (!_heldPropData.Contains(propData)) _heldPropData.Add(propData); + } + + private static void OnCVRPickupObjectOnDrop(CVRPickupObject __instance) + { + if (!GetPropData(__instance.GetComponentInParent(true), out CVRSyncHelper.PropData propData)) return; + if (_heldPropData.Contains(propData)) _heldPropData.Remove(propData); + } + + private static void OnCVRAttachmentAttachInternal(CVRAttachment __instance) + { + if (!GetPropData(__instance.GetComponentInParent(true), out CVRSyncHelper.PropData propData)) return; + if (!_heldPropData.Contains(propData)) _heldPropData.Add(propData); + } + + private static void OnCVRAttachmentDeAttach(CVRAttachment __instance) + { + if (!__instance._isAttached) return; // Can invoke DeAttach without being attached + if (!GetPropData(__instance.GetComponentInParent(true), out CVRSyncHelper.PropData propData)) return; + if (_heldPropData.Contains(propData)) _heldPropData.Remove(propData); + } + + // ReSharper disable UnusedParameter.Local + private static bool OnCVRDownloadManagerQueueTask(string assetId, DownloadTask.ObjectType type, string assetUrl, string fileId, long fileSize, string fileKey, string toAttach, + string fileHash = null, UgcTagsData tagsData = null, CVRLoadingAvatarController loadingAvatarController = null, + bool joinOnComplete = false, bool isHomeRequested = false, int compatibilityVersion = 0, int encryptionAlgorithm = 0, + string spawnerId = null) + { + if (type != DownloadTask.ObjectType.Prop) return true; // Only care about props + + // toAttach is our instanceId, lets find the propData + if (!GetPropDataById(toAttach, out CVRSyncHelper.PropData newPropData)) return true; + + // Check if this is a prop we requested to spawn + Vector3 identity = GetIdentityKeyFromPropData(newPropData); + if (!_keyToPropData.Remove(identity, out CVRSyncHelper.PropData originalPropData)) return true; + + // Remove original prop data from held + if (_heldPropData.Contains(originalPropData)) _heldPropData.Remove(originalPropData); + + // If original prop data is null spawn a new prop i guess :( + if (originalPropData.Spawnable == null) return true; + + // Add the new prop data to our held props in place of the old one + if (!_heldPropData.Contains(newPropData)) _heldPropData.Add(newPropData); + + // Apply new prop data to the spawnable + newPropData.Spawnable = originalPropData.Spawnable; + newPropData.Wrapper = originalPropData.Wrapper; + newPropData.Wrapper.name = $"p+{newPropData.ObjectId}~{newPropData.InstanceId}"; + + // Copy sync values + Array.Copy(newPropData.CustomFloats, originalPropData.CustomFloats, newPropData.CustomFloatsAmount); + + CVRSyncHelper.ApplyPropValuesSpawn(newPropData); + + // Place the prop in the additive content scene + PlacePropInAdditiveContentScene(newPropData.Spawnable); + + // Clear old data so Recycle() doesn't delete our prop + originalPropData.Spawnable = null; + originalPropData.Wrapper = null; + originalPropData.Recycle(); + + return false; + } + + private static bool OnCVRSyncHelperClearProps() // Prevent deleting of our held props on scene load + { + for (var index = CVRSyncHelper.Props.Count - 1; index >= 0; index--) + { + CVRSyncHelper.PropData prop = CVRSyncHelper.Props[index]; + if (prop.Spawnable != null && _heldPropData.Contains(prop)) + continue; // Do not recycle props that are valid & held + + DeleteOrRecycleProp(prop); + } + + CVRSyncHelper.MySpawnedPropInstanceIds.Clear(); + return false; + } + + private static bool OnBetterBetterCharacterControllerSetSitting(bool isSitting, CVRSeat cvrSeat = null, bool callExitSeat = true) + { + if (!_ignoreNextSeatExit) return true; + _ignoreNextSeatExit = false; + if (BetterBetterCharacterController.Instance._lastCvrSeat == null) return true; // run original + return false; // dont run if there is a chair & we skipped it + } + + #endregion Harmony Patches + + #region Game Events + + private object _worldLoadTimer; + + private void OnWorldLoad(string _) + { + CVRWorld worldInstance = CVRWorld.Instance; + if (worldInstance != null && !worldInstance.allowSpawnables) + { + foreach (CVRSyncHelper.PropData prop in _heldPropData) DeleteOrRecycleProp(prop); // Delete all props we kept + return; + } + + for (var index = _heldPropData.Count - 1; index >= 0; index--) + { + CVRSyncHelper.PropData prop = _heldPropData[index]; + if (prop.Spawnable == null) + { + DeleteOrRecycleProp(prop); + return; + } + + // apply positions + int stackCount = _spawnablePositionStack.Count; + for (int i = stackCount - 1; i >= 0; i--) _spawnablePositionStack.Pop().ReapplyOffsets(); + } + + // Start a timer, and anything that did not load within 3 seconds will be destroyed + if (_worldLoadTimer != null) + { + MelonCoroutines.Stop(_worldLoadTimer); + _worldLoadTimer = null; + } + _worldLoadTimer = MelonCoroutines.Start(DestroyPersistantPropContainerInFive()); + _ignoreNextSeatExit = true; // just in case we are in a car / vehicle + } + + private IEnumerator DestroyPersistantPropContainerInFive() + { + yield return new WaitForSeconds(3f); + _worldLoadTimer = null; + Object.Destroy(_persistantPropsContainer); + _persistantPropsContainer = null; + _keyToPropData.Clear(); // no more chances + } + + private static void OnWorldUnload(string _) + { + // Prevent deleting of our held props on scene destruction + foreach (CVRSyncHelper.PropData prop in _heldPropData) + { + if (prop.Spawnable == null) continue; + PlacePropInPersistantPropsContainer(prop.Spawnable); + _spawnablePositionStack.Push(new SpawnablePositionContainer(prop.Spawnable)); + } + + // Likely in a vehicle + _heightOffset = BetterBetterCharacterController.Instance._lastCvrSeat != null + ? GetHeightOffsetFromPlayer() + : 0f; + } + + private static void OnInstanceConnected(string _) + { + // Request the server to respawn our props by GUID, and add a secret key to the propData to identify it + + foreach (CVRSyncHelper.PropData prop in _heldPropData) + { + if (prop.Spawnable == null) continue; + + // Generate a new identity key for the prop (this is used to identify the prop when we respawn it) + Vector3 identityKey = new(Random.Range(0, 1000), Random.Range(0, 1000), Random.Range(0, 1000)); + _keyToPropData.Add(identityKey, prop); + + SpawnPropFromGuid(prop.ObjectId, + new Vector3(prop.PositionX, prop.PositionY, prop.PositionZ), + new Vector3(prop.RotationX, prop.RotationY, prop.RotationZ), + identityKey); + } + } + + #endregion Game Events + + #region Util + + private static bool GetPropData(CVRSpawnable spawnable, out CVRSyncHelper.PropData propData) + { + if (spawnable == null) + { + propData = null; + return false; + } + foreach (CVRSyncHelper.PropData data in CVRSyncHelper.Props) + { + if (data.InstanceId != spawnable.instanceId) continue; + propData = data; + return true; + } + propData = null; + return false; + } + + private static bool GetPropDataById(string instanceId, out CVRSyncHelper.PropData propData) + { + foreach (CVRSyncHelper.PropData data in CVRSyncHelper.Props) + { + if (data.InstanceId != instanceId) continue; + propData = data; + return true; + } + propData = null; + return false; + } + + private static void PlacePropInAdditiveContentScene(CVRSpawnable spawnable) + { + spawnable.transform.parent.SetParent(null); // Unparent from the prop container + SceneManager.MoveGameObjectToScene(spawnable.transform.parent.gameObject, + SceneManager.GetSceneByName(CVRObjectLoader.AdditiveContentSceneName)); + } + + private static void PlacePropInPersistantPropsContainer(CVRSpawnable spawnable) + { + spawnable.transform.parent.SetParent(GetOrCreatePropsContainer().transform); + } + + private static void DeleteOrRecycleProp(CVRSyncHelper.PropData prop) + { + if (prop.Spawnable == null) prop.Recycle(); + else prop.Spawnable.Delete(); + if (_heldPropData.Contains(prop)) _heldPropData.Remove(prop); + } + + private static void SpawnPropFromGuid(string propGuid, Vector3 position, Vector3 rotation, Vector3 identityKey) + { + using DarkRiftWriter darkRiftWriter = DarkRiftWriter.Create(); + darkRiftWriter.Write(propGuid); + darkRiftWriter.Write(position.x); + darkRiftWriter.Write(position.y); + darkRiftWriter.Write(position.z); + darkRiftWriter.Write(rotation.x); + darkRiftWriter.Write(rotation.y); + darkRiftWriter.Write(rotation.z); + darkRiftWriter.Write(identityKey.x); // for scale, but unused by CVR + darkRiftWriter.Write(identityKey.y); // we will use this to identify our prop + darkRiftWriter.Write(identityKey.z); // and recycle existing instance if it exists + darkRiftWriter.Write(0f); // if not zero, prop spawn will be rejected by gs + using Message message = Message.Create(10050, darkRiftWriter); + NetworkManager.Instance.GameNetwork.SendMessage(message, SendMode.Reliable); + } + + private static Vector3 GetIdentityKeyFromPropData(CVRSyncHelper.PropData propData) + => new(propData.ScaleX, propData.ScaleY, propData.ScaleZ); + + private const int WORLD_RAYCAST_LAYER_MASK = + (1 << 0) | // Default + (1 << 16) | (1 << 17) | (1 << 18) | (1 << 19) | + (1 << 20) | (1 << 21) | (1 << 22) | (1 << 23) | + (1 << 24) | (1 << 25) | (1 << 26) | (1 << 27) | + (1 << 28) | (1 << 29) | (1 << 30) | (1 << 31); + + private static float GetHeightOffsetFromPlayer() + { + Vector3 playerPos = PlayerSetup.Instance.GetPlayerPosition(); + Ray ray = new(playerPos, Vector3.down); + + // ReSharper disable once Unity.PreferNonAllocApi + RaycastHit[] hits = Physics.RaycastAll(ray, 1000f, WORLD_RAYCAST_LAYER_MASK, QueryTriggerInteraction.Ignore); + Scene baseScene = SceneManager.GetActiveScene(); + + float closestDist = float.MaxValue; + Vector3 closestPoint = Vector3.zero; + bool foundValidHit = false; + + foreach (RaycastHit hit in hits) + { + if (hit.collider.gameObject.scene != baseScene) continue; // Ignore objects not in the world scene + if (!(hit.distance < closestDist)) continue; + closestDist = hit.distance; + closestPoint = hit.point; + foundValidHit = true; + } + + if (!foundValidHit) return 0f; // TODO: idk if i should do this + float offset = playerPos.y - closestPoint.y; + return Mathf.Clamp(offset, 0f, 20f); + } + + #endregion Util + + #region Helper Classes + + private readonly struct SpawnablePositionContainer + { + private readonly CVRSpawnable _spawnable; + private readonly Vector3[] _posOffsets; + private readonly Quaternion[] _rotOffsets; + + public SpawnablePositionContainer(CVRSpawnable spawnable) + { + _spawnable = spawnable; + + int syncedTransforms = 1 + _spawnable.subSyncs.Count; // root + subSyncs + + _posOffsets = new Vector3[syncedTransforms]; + _rotOffsets = new Quaternion[syncedTransforms]; + + Transform playerTransform = PlayerSetup.Instance.transform; + + // Save root offset relative to player + Transform _spawnableTransform = _spawnable.transform; + _posOffsets[0] = playerTransform.InverseTransformPoint(_spawnableTransform.position); + _rotOffsets[0] = Quaternion.Inverse(playerTransform.rotation) * _spawnableTransform.rotation; + + // Save subSync offsets relative to player + for (int i = 0; i < _spawnable.subSyncs.Count; i++) + { + Transform subSyncTransform = _spawnable.subSyncs[i].transform; + if (subSyncTransform == null) continue; + _posOffsets[i + 1] = playerTransform.InverseTransformPoint(subSyncTransform.position); + _rotOffsets[i + 1] = Quaternion.Inverse(playerTransform.rotation) * subSyncTransform.rotation; + } + } + + public void ReapplyOffsets() + { + Transform playerTransform = PlayerSetup.Instance.transform; + + // Reapply to root + Vector3 rootWorldPos = playerTransform.TransformPoint(_posOffsets[0]); + rootWorldPos.y += _heightOffset; + _spawnable.transform.position = rootWorldPos; + _spawnable.transform.rotation = playerTransform.rotation * _rotOffsets[0]; + + // Reapply to subSyncs + for (int i = 0; i < _spawnable.subSyncs.Count; i++) + { + Transform subSyncTransform = _spawnable.subSyncs[i].transform; + if (subSyncTransform == null) continue; + + Vector3 subWorldPos = playerTransform.TransformPoint(_posOffsets[i + 1]); + subWorldPos.y += _heightOffset; + subSyncTransform.position = subWorldPos; + subSyncTransform.rotation = playerTransform.rotation * _rotOffsets[i + 1]; + } + + // hack + _spawnable.needsUpdate = true; + _spawnable.UpdateSubSyncValues(); + _spawnable.sendUpdate(); + } + } + + #endregion Helper Classes +} \ No newline at end of file diff --git a/YouAreMyPropNowWeAreHavingSoftTacosLater/Properties/AssemblyInfo.cs b/YouAreMyPropNowWeAreHavingSoftTacosLater/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..bfc0a13 --- /dev/null +++ b/YouAreMyPropNowWeAreHavingSoftTacosLater/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using MelonLoader; +using NAK.YouAreMyPropNowWeAreHavingSoftTacosLater.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.YouAreMyPropNowWeAreHavingSoftTacosLater))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.YouAreMyPropNowWeAreHavingSoftTacosLater))] + +[assembly: MelonInfo( + typeof(NAK.YouAreMyPropNowWeAreHavingSoftTacosLater.YouAreMyPropNowWeAreHavingSoftTacosLaterMod), + nameof(NAK.YouAreMyPropNowWeAreHavingSoftTacosLater), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/YouAreMyPropNowWeAreHavingSoftTacosLater" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red +[assembly: HarmonyDontPatchAll] + +namespace NAK.YouAreMyPropNowWeAreHavingSoftTacosLater.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/YouAreMyPropNowWeAreHavingSoftTacosLater/README.md b/YouAreMyPropNowWeAreHavingSoftTacosLater/README.md new file mode 100644 index 0000000..9ddff99 --- /dev/null +++ b/YouAreMyPropNowWeAreHavingSoftTacosLater/README.md @@ -0,0 +1,19 @@ +# YouAreMyPropNowWeAreHavingSoftTacosLater + +Lets you bring held & attached props through world loads. + +https://youtu.be/9P6Jeh-VN58?si=eXTPGyKB_0wq1gZO + +## Examples +https://fixupx.com/NotAKidoS/status/1910545346922422675 + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation 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/YouAreMyPropNowWeAreHavingSoftTacosLater/YouAreMyPropNowWeAreHavingSoftTacosLater.csproj b/YouAreMyPropNowWeAreHavingSoftTacosLater/YouAreMyPropNowWeAreHavingSoftTacosLater.csproj new file mode 100644 index 0000000..5a8badc --- /dev/null +++ b/YouAreMyPropNowWeAreHavingSoftTacosLater/YouAreMyPropNowWeAreHavingSoftTacosLater.csproj @@ -0,0 +1,6 @@ + + + + YouAreMineNow + + diff --git a/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json b/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json new file mode 100644 index 0000000..78c5bbc --- /dev/null +++ b/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json @@ -0,0 +1,23 @@ +{ + "_id": -1, + "name": "YouAreMyPropNowWeAreHavingSoftTacosLater", + "modversion": "1.0.0", + "gameversion": "2025r179", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Lets you bring held & attached props through world loads.\nhttps://youtu.be/9P6Jeh-VN58?si=eXTPGyKB_0wq1gZO", + "searchtags": [ + "prop", + "spawn", + "friend", + "load" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/YouAreMyPropNowWeAreHavingSoftTacosLater.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/YouAreMyPropNowWeAreHavingSoftTacosLater/", + "changelog": "- Initial Release", + "embedcolor": "#00FFFF" +} \ No newline at end of file From 0cde9ecb21676ed05b5b74dff1d82aea8e658f30 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 11 Apr 2025 12:39:51 +0000 Subject: [PATCH 059/119] [NAK_CVR_Mods] Update mod list in README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0a11162..84b53d5 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,6 @@ |------|-------------|----------| | [ASTExtension](ASTExtension/README.md) | Extension mod for [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool): | [Download](ASTExtension/ASTExtension.zip) | | [AvatarQueueSystemTweaks](AvatarQueueSystemTweaks/README.md) | Small tweaks to the Avatar Queue System. | [Download](AvatarQueueSystemTweaks/AvatarQueueSystemTweaks.zip) | -| [CustomRichPresence](CustomRichPresence/README.md) | Gives the Drop Prop button more utility by allowing you to drop props in the air. | [Download](CustomRichPresence/CustomRichPresence.zip) | | [CustomSpawnPoint](CustomSpawnPoint/README.md) | Replaces the unused Images button in the World Details page with a button to set a custom spawn point. | [Download](CustomSpawnPoint/CustomSpawnPoint.zip) | | [FuckToes](FuckToes/README.md) | Prevents VRIK from autodetecting toes in HalfbodyIK. | [Download](FuckToes/FuckToes.zip) | | [KeepVelocityOnExitFlight](KeepVelocityOnExitFlight/README.md) | Keeps the player's velocity when exiting flight mode. Makes it possible to fling yourself like in Garry's Mod. | [Download](KeepVelocityOnExitFlight/KeepVelocityOnExitFlight.zip) | @@ -20,12 +19,14 @@ | [SmootherRay](SmootherRay/README.md) | Smoothes your controller while the raycast lines are visible. | [Download](SmootherRay/SmootherRay.zip) | | [Stickers](Stickers/README.md) | Stickers! Allows you to place small images on any surface. Requires both users to have the mod installed. Synced over Mod Network. | [Download](Stickers/Stickers.zip) | | [ThirdPerson](ThirdPerson/README.md) | Original repo: https://github.com/oestradiol/CVR-Mods | [Download](ThirdPerson/ThirdPerson.zip) | +| [YouAreMyPropNowWeAreHavingSoftTacosLater](YouAreMyPropNowWeAreHavingSoftTacosLater/README.md) | Lets you bring held & attached props through world loads. | [Download](YouAreMyPropNowWeAreHavingSoftTacosLater/YouAreMyPropNowWeAreHavingSoftTacosLater.zip) | ### Experimental Mods | Name | Description | Download | |------|-------------|----------| | [CVRLuaToolsExtension](.Experimental/CVRLuaToolsExtension/README.md) | Extension mod for [CVRLuaTools](https://github.com/NotAKidoS/CVRLuaTools) Hot Reload functionality. | [Download](.Experimental/CVRLuaToolsExtension/CVRLuaToolsExtension.zip) | +| [CustomRichPresence](.Experimental/CustomRichPresence/README.md) | Gives the Drop Prop button more utility by allowing you to drop props in the air. | [Download](.Experimental/CustomRichPresence/CustomRichPresence.zip) | | [LuaNetworkVariables](.Experimental/LuaNetworkVariables/README.md) | Simple mod that makes your controller rays always visible when the menus are open. Useful for when you're trying to aim at something in the distance. Also visualizes which ray is being used for menu interaction. | [Download](.Experimental/LuaNetworkVariables/LuaNetworkVariables.zip) | | [LuaTTS](.Experimental/LuaTTS/README.md) | Provides access to the built-in text-to-speech (TTS) functionality to lua scripts. Allows you to make the local player speak. | [Download](.Experimental/LuaTTS/LuaTTS.zip) | | [OriginShift](.Experimental/OriginShift/README.md) | Experimental mod that allows world origin to be shifted to prevent floating point precision issues. | [Download](.Experimental/OriginShift/OriginShift.zip) | From b246f71e6eac1cbe754a939b87ded0b732302c0e Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Fri, 11 Apr 2025 07:40:53 -0500 Subject: [PATCH 060/119] [CustomRichPresence] fix readme --- .Experimental/CustomRichPresence/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.Experimental/CustomRichPresence/README.md b/.Experimental/CustomRichPresence/README.md index 33bd3fd..1f37b48 100644 --- a/.Experimental/CustomRichPresence/README.md +++ b/.Experimental/CustomRichPresence/README.md @@ -1,6 +1,6 @@ -# DropPropTweak +# Custom Rich Presence -Gives the Drop Prop button more utility by allowing you to drop props in the air. +Lets you customize the Steam & Discord rich presence messages & values. --- From a2aa3b9871ccaab0657967d5e6ada19d3a53d6c1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 11 Apr 2025 12:41:14 +0000 Subject: [PATCH 061/119] [NAK_CVR_Mods] Update mod list in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 84b53d5..b8a81e8 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ | Name | Description | Download | |------|-------------|----------| | [CVRLuaToolsExtension](.Experimental/CVRLuaToolsExtension/README.md) | Extension mod for [CVRLuaTools](https://github.com/NotAKidoS/CVRLuaTools) Hot Reload functionality. | [Download](.Experimental/CVRLuaToolsExtension/CVRLuaToolsExtension.zip) | -| [CustomRichPresence](.Experimental/CustomRichPresence/README.md) | Gives the Drop Prop button more utility by allowing you to drop props in the air. | [Download](.Experimental/CustomRichPresence/CustomRichPresence.zip) | +| [CustomRichPresence](.Experimental/CustomRichPresence/README.md) | Lets you customize the Steam & Discord rich presence messages & values. | [Download](.Experimental/CustomRichPresence/CustomRichPresence.zip) | | [LuaNetworkVariables](.Experimental/LuaNetworkVariables/README.md) | Simple mod that makes your controller rays always visible when the menus are open. Useful for when you're trying to aim at something in the distance. Also visualizes which ray is being used for menu interaction. | [Download](.Experimental/LuaNetworkVariables/LuaNetworkVariables.zip) | | [LuaTTS](.Experimental/LuaTTS/README.md) | Provides access to the built-in text-to-speech (TTS) functionality to lua scripts. Allows you to make the local player speak. | [Download](.Experimental/LuaTTS/LuaTTS.zip) | | [OriginShift](.Experimental/OriginShift/README.md) | Experimental mod that allows world origin to be shifted to prevent floating point precision issues. | [Download](.Experimental/OriginShift/OriginShift.zip) | From 8f8f2ad1fb780126d98d07e34a35850c6e2d62ef Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Fri, 11 Apr 2025 07:45:31 -0500 Subject: [PATCH 062/119] [NAK_CVR_Mods] fixed generated download link in readme --- .github/scripts/update-modlist.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/scripts/update-modlist.js b/.github/scripts/update-modlist.js index b404561..37cf1c5 100644 --- a/.github/scripts/update-modlist.js +++ b/.github/scripts/update-modlist.js @@ -52,11 +52,11 @@ function formatTable(mods, baseDir) { let rows = mods.map(modPath => { const modName = path.basename(modPath); const readmeLink = path.join(modPath, 'README.md'); - const zipLink = path.join(modPath, `${modName}.zip`); + const dllLink = path.join(modPath, `${modName}.dll`); const readmePath = path.join(modPath, 'README.md'); const description = extractDescription(readmePath); - return `| [${modName}](${readmeLink}) | ${description} | [Download](${zipLink}) |`; + return `| [${modName}](${readmeLink}) | ${description} | [Download](${dllLink}) |`; }); return [ From a2e29149e29397d96956a26fe8d32cdb87db77cb Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Fri, 11 Apr 2025 07:46:51 -0500 Subject: [PATCH 063/119] [NAK_CVR_Mods] test --- .github/scripts/update-modlist.js | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/.github/scripts/update-modlist.js b/.github/scripts/update-modlist.js index 37cf1c5..383e275 100644 --- a/.github/scripts/update-modlist.js +++ b/.github/scripts/update-modlist.js @@ -1,6 +1,5 @@ const fs = require('fs'); const path = require('path'); - const ROOT = '.'; const EXPERIMENTAL = '.Experimental'; const README_PATH = 'README.md'; @@ -19,7 +18,7 @@ function extractDescription(readmePath) { try { const content = fs.readFileSync(readmePath, 'utf8'); const lines = content.split('\n'); - + // Find the first header (# something) let headerIndex = -1; for (let i = 0; i < lines.length; i++) { @@ -28,7 +27,7 @@ function extractDescription(readmePath) { break; } } - + // If we found a header, look for the first non-empty line after it if (headerIndex !== -1) { for (let i = headerIndex + 1; i < lines.length; i++) { @@ -38,7 +37,7 @@ function extractDescription(readmePath) { } } } - + return 'No description available'; } catch (error) { console.error(`Error reading ${readmePath}:`, error); @@ -46,19 +45,29 @@ function extractDescription(readmePath) { } } +function checkIfDllExists(modPath, modName) { + const dllPath = path.join(modPath, `${modName}.dll`); + return fs.existsSync(dllPath); +} + function formatTable(mods, baseDir) { if (mods.length === 0) return ''; - + let rows = mods.map(modPath => { const modName = path.basename(modPath); const readmeLink = path.join(modPath, 'README.md'); - const dllLink = path.join(modPath, `${modName}.dll`); const readmePath = path.join(modPath, 'README.md'); const description = extractDescription(readmePath); - return `| [${modName}](${readmeLink}) | ${description} | [Download](${dllLink}) |`; + // Check if DLL exists and format download cell accordingly + const hasDll = checkIfDllExists(modPath, modName); + const downloadCell = hasDll + ? `[Download](${path.join(modPath, `${modName}.dll`)})` + : 'No Download'; + + return `| [${modName}](${readmeLink}) | ${description} | ${downloadCell} |`; }); - + return [ `### ${baseDir === EXPERIMENTAL ? 'Experimental Mods' : 'Released Mods'}`, '', @@ -73,7 +82,6 @@ function updateReadme(modListSection) { const readme = fs.readFileSync(README_PATH, 'utf8'); const before = readme.split(MARKER_START)[0]; const after = readme.split(MARKER_END)[1]; - const newReadme = `${before}${MARKER_START}\n\n${modListSection}\n${MARKER_END}${after}`; fs.writeFileSync(README_PATH, newReadme); } From d5eb9ae1a08553803510dd8efa591b7c61beb074 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 11 Apr 2025 12:47:11 +0000 Subject: [PATCH 064/119] [NAK_CVR_Mods] Update mod list in README --- README.md | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index b8a81e8..017ca92 100644 --- a/README.md +++ b/README.md @@ -6,31 +6,31 @@ | Name | Description | Download | |------|-------------|----------| -| [ASTExtension](ASTExtension/README.md) | Extension mod for [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool): | [Download](ASTExtension/ASTExtension.zip) | -| [AvatarQueueSystemTweaks](AvatarQueueSystemTweaks/README.md) | Small tweaks to the Avatar Queue System. | [Download](AvatarQueueSystemTweaks/AvatarQueueSystemTweaks.zip) | -| [CustomSpawnPoint](CustomSpawnPoint/README.md) | Replaces the unused Images button in the World Details page with a button to set a custom spawn point. | [Download](CustomSpawnPoint/CustomSpawnPoint.zip) | -| [FuckToes](FuckToes/README.md) | Prevents VRIK from autodetecting toes in HalfbodyIK. | [Download](FuckToes/FuckToes.zip) | -| [KeepVelocityOnExitFlight](KeepVelocityOnExitFlight/README.md) | Keeps the player's velocity when exiting flight mode. Makes it possible to fling yourself like in Garry's Mod. | [Download](KeepVelocityOnExitFlight/KeepVelocityOnExitFlight.zip) | -| [LazyPrune](LazyPrune/README.md) | Prevents loaded objects from immediately unloading on destruction. Should prevent needlessly unloading & reloading all avatars/props on world rejoin or GS reconnection. | [Download](LazyPrune/LazyPrune.zip) | -| [PropLoadingHexagon](PropLoadingHexagon/README.md) | https://github.com/NotAKidoS/NAK_CVR_Mods/assets/37721153/a892c765-71c1-47f3-a781-bdb9b60ba117 | [Download](PropLoadingHexagon/PropLoadingHexagon.zip) | -| [RCCVirtualSteeringWheel](RCCVirtualSteeringWheel/README.md) | Allows you to physically grab rigged RCC steering wheels in VR to provide steering input. No explicit setup required other than defining the Steering Wheel transform within the RCC component. | [Download](RCCVirtualSteeringWheel/RCCVirtualSteeringWheel.zip) | -| [RelativeSync](RelativeSync/README.md) | Relative sync for Movement Parent & Chairs. Requires both users to have the mod installed. Synced over Mod Network. | [Download](RelativeSync/RelativeSync.zip) | -| [ShareBubbles](ShareBubbles/README.md) | Share Bubbles! Allows you to drop down bubbles containing Avatars & Props. Requires both users to have the mod installed. Synced over Mod Network. | [Download](ShareBubbles/ShareBubbles.zip) | -| [SmootherRay](SmootherRay/README.md) | Smoothes your controller while the raycast lines are visible. | [Download](SmootherRay/SmootherRay.zip) | -| [Stickers](Stickers/README.md) | Stickers! Allows you to place small images on any surface. Requires both users to have the mod installed. Synced over Mod Network. | [Download](Stickers/Stickers.zip) | -| [ThirdPerson](ThirdPerson/README.md) | Original repo: https://github.com/oestradiol/CVR-Mods | [Download](ThirdPerson/ThirdPerson.zip) | -| [YouAreMyPropNowWeAreHavingSoftTacosLater](YouAreMyPropNowWeAreHavingSoftTacosLater/README.md) | Lets you bring held & attached props through world loads. | [Download](YouAreMyPropNowWeAreHavingSoftTacosLater/YouAreMyPropNowWeAreHavingSoftTacosLater.zip) | +| [ASTExtension](ASTExtension/README.md) | Extension mod for [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool): | No Download | +| [AvatarQueueSystemTweaks](AvatarQueueSystemTweaks/README.md) | Small tweaks to the Avatar Queue System. | No Download | +| [CustomSpawnPoint](CustomSpawnPoint/README.md) | Replaces the unused Images button in the World Details page with a button to set a custom spawn point. | No Download | +| [FuckToes](FuckToes/README.md) | Prevents VRIK from autodetecting toes in HalfbodyIK. | No Download | +| [KeepVelocityOnExitFlight](KeepVelocityOnExitFlight/README.md) | Keeps the player's velocity when exiting flight mode. Makes it possible to fling yourself like in Garry's Mod. | No Download | +| [LazyPrune](LazyPrune/README.md) | Prevents loaded objects from immediately unloading on destruction. Should prevent needlessly unloading & reloading all avatars/props on world rejoin or GS reconnection. | No Download | +| [PropLoadingHexagon](PropLoadingHexagon/README.md) | https://github.com/NotAKidoS/NAK_CVR_Mods/assets/37721153/a892c765-71c1-47f3-a781-bdb9b60ba117 | No Download | +| [RCCVirtualSteeringWheel](RCCVirtualSteeringWheel/README.md) | Allows you to physically grab rigged RCC steering wheels in VR to provide steering input. No explicit setup required other than defining the Steering Wheel transform within the RCC component. | No Download | +| [RelativeSync](RelativeSync/README.md) | Relative sync for Movement Parent & Chairs. Requires both users to have the mod installed. Synced over Mod Network. | No Download | +| [ShareBubbles](ShareBubbles/README.md) | Share Bubbles! Allows you to drop down bubbles containing Avatars & Props. Requires both users to have the mod installed. Synced over Mod Network. | No Download | +| [SmootherRay](SmootherRay/README.md) | Smoothes your controller while the raycast lines are visible. | No Download | +| [Stickers](Stickers/README.md) | Stickers! Allows you to place small images on any surface. Requires both users to have the mod installed. Synced over Mod Network. | No Download | +| [ThirdPerson](ThirdPerson/README.md) | Original repo: https://github.com/oestradiol/CVR-Mods | No Download | +| [YouAreMyPropNowWeAreHavingSoftTacosLater](YouAreMyPropNowWeAreHavingSoftTacosLater/README.md) | Lets you bring held & attached props through world loads. | No Download | ### Experimental Mods | Name | Description | Download | |------|-------------|----------| -| [CVRLuaToolsExtension](.Experimental/CVRLuaToolsExtension/README.md) | Extension mod for [CVRLuaTools](https://github.com/NotAKidoS/CVRLuaTools) Hot Reload functionality. | [Download](.Experimental/CVRLuaToolsExtension/CVRLuaToolsExtension.zip) | -| [CustomRichPresence](.Experimental/CustomRichPresence/README.md) | Lets you customize the Steam & Discord rich presence messages & values. | [Download](.Experimental/CustomRichPresence/CustomRichPresence.zip) | -| [LuaNetworkVariables](.Experimental/LuaNetworkVariables/README.md) | Simple mod that makes your controller rays always visible when the menus are open. Useful for when you're trying to aim at something in the distance. Also visualizes which ray is being used for menu interaction. | [Download](.Experimental/LuaNetworkVariables/LuaNetworkVariables.zip) | -| [LuaTTS](.Experimental/LuaTTS/README.md) | Provides access to the built-in text-to-speech (TTS) functionality to lua scripts. Allows you to make the local player speak. | [Download](.Experimental/LuaTTS/LuaTTS.zip) | -| [OriginShift](.Experimental/OriginShift/README.md) | Experimental mod that allows world origin to be shifted to prevent floating point precision issues. | [Download](.Experimental/OriginShift/OriginShift.zip) | -| [ScriptingSpoofer](.Experimental/ScriptingSpoofer/README.md) | Prevents **local** scripts from accessing your Username or UserID by spoofing them with random values each session. | [Download](.Experimental/ScriptingSpoofer/ScriptingSpoofer.zip) | +| [CVRLuaToolsExtension](.Experimental/CVRLuaToolsExtension/README.md) | Extension mod for [CVRLuaTools](https://github.com/NotAKidoS/CVRLuaTools) Hot Reload functionality. | No Download | +| [CustomRichPresence](.Experimental/CustomRichPresence/README.md) | Lets you customize the Steam & Discord rich presence messages & values. | No Download | +| [LuaNetworkVariables](.Experimental/LuaNetworkVariables/README.md) | Simple mod that makes your controller rays always visible when the menus are open. Useful for when you're trying to aim at something in the distance. Also visualizes which ray is being used for menu interaction. | No Download | +| [LuaTTS](.Experimental/LuaTTS/README.md) | Provides access to the built-in text-to-speech (TTS) functionality to lua scripts. Allows you to make the local player speak. | No Download | +| [OriginShift](.Experimental/OriginShift/README.md) | Experimental mod that allows world origin to be shifted to prevent floating point precision issues. | No Download | +| [ScriptingSpoofer](.Experimental/ScriptingSpoofer/README.md) | Prevents **local** scripts from accessing your Username or UserID by spoofing them with random values each session. | No Download | From 1fbfcd80cdb6b443079df37b825022d3edf61a5b Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Fri, 11 Apr 2025 07:52:15 -0500 Subject: [PATCH 065/119] [NAK_CVR_Mods] 2 --- .github/scripts/update-modlist.js | 160 +++++++++++++++++++++++------- 1 file changed, 124 insertions(+), 36 deletions(-) diff --git a/.github/scripts/update-modlist.js b/.github/scripts/update-modlist.js index 383e275..8ed69bf 100644 --- a/.github/scripts/update-modlist.js +++ b/.github/scripts/update-modlist.js @@ -1,10 +1,56 @@ const fs = require('fs'); const path = require('path'); +const https = require('https'); + +// Configuration const ROOT = '.'; const EXPERIMENTAL = '.Experimental'; const README_PATH = 'README.md'; const MARKER_START = ''; const MARKER_END = ''; +const REPO_OWNER = process.env.REPO_OWNER || 'NotAKidoS'; +const REPO_NAME = process.env.REPO_NAME || 'NAK_CVR_Mods'; + +// Function to get latest release info from GitHub API +async function getLatestRelease() { + return new Promise((resolve, reject) => { + const options = { + hostname: 'api.github.com', + path: `/repos/${REPO_OWNER}/${REPO_NAME}/releases/latest`, + method: 'GET', + headers: { + 'User-Agent': 'Node.js GitHub Release Checker', + 'Accept': 'application/vnd.github.v3+json' + } + }; + + const req = https.request(options, (res) => { + let data = ''; + + res.on('data', (chunk) => { + data += chunk; + }); + + res.on('end', () => { + if (res.statusCode === 200) { + try { + resolve(JSON.parse(data)); + } catch (e) { + reject(new Error(`Failed to parse GitHub API response: ${e.message}`)); + } + } else { + reject(new Error(`GitHub API request failed with status code: ${res.statusCode}`)); + } + }); + }); + + req.on('error', (e) => { + reject(new Error(`GitHub API request error: ${e.message}`)); + }); + + req.end(); + }); +} function getModFolders(baseDir) { const entries = fs.readdirSync(baseDir, { withFileTypes: true }); @@ -45,37 +91,69 @@ function extractDescription(readmePath) { } } -function checkIfDllExists(modPath, modName) { - const dllPath = path.join(modPath, `${modName}.dll`); - return fs.existsSync(dllPath); -} - -function formatTable(mods, baseDir) { +async function formatTable(mods, baseDir) { if (mods.length === 0) return ''; - let rows = mods.map(modPath => { - const modName = path.basename(modPath); - const readmeLink = path.join(modPath, 'README.md'); - const readmePath = path.join(modPath, 'README.md'); - const description = extractDescription(readmePath); + try { + // Get the latest release info from GitHub + const latestRelease = await getLatestRelease(); + const releaseAssets = latestRelease.assets || []; - // Check if DLL exists and format download cell accordingly - const hasDll = checkIfDllExists(modPath, modName); - const downloadCell = hasDll - ? `[Download](${path.join(modPath, `${modName}.dll`)})` - : 'No Download'; - - return `| [${modName}](${readmeLink}) | ${description} | ${downloadCell} |`; - }); - - return [ - `### ${baseDir === EXPERIMENTAL ? 'Experimental Mods' : 'Released Mods'}`, - '', - '| Name | Description | Download |', - '|------|-------------|----------|', - ...rows, - '' - ].join('\n'); + // Create a map of available files in the release + const availableFiles = {}; + releaseAssets.forEach(asset => { + availableFiles[asset.name] = asset.browser_download_url; + }); + + let rows = mods.map(modPath => { + const modName = path.basename(modPath); + const readmeLink = path.join(modPath, 'README.md'); + const readmePath = path.join(modPath, 'README.md'); + const description = extractDescription(readmePath); + + // Check if the DLL exists in the latest release + const dllFilename = `${modName}.dll`; + let downloadSection; + + if (availableFiles[dllFilename]) { + downloadSection = `[Download](${availableFiles[dllFilename]})`; + } else { + downloadSection = 'No Download'; + } + + return `| [${modName}](${readmeLink}) | ${description} | ${downloadSection} |`; + }); + + return [ + `### ${baseDir === EXPERIMENTAL ? 'Experimental Mods' : 'Released Mods'}`, + '', + '| Name | Description | Download |', + '|------|-------------|----------|', + ...rows, + '' + ].join('\n'); + } catch (error) { + console.error('Error fetching release information:', error); + + // Fallback to showing "No Download" for all mods if we can't fetch release info + let rows = mods.map(modPath => { + const modName = path.basename(modPath); + const readmeLink = path.join(modPath, 'README.md'); + const readmePath = path.join(modPath, 'README.md'); + const description = extractDescription(readmePath); + + return `| [${modName}](${readmeLink}) | ${description} | No Download |`; + }); + + return [ + `### ${baseDir === EXPERIMENTAL ? 'Experimental Mods' : 'Released Mods'}`, + '', + '| Name | Description | Download |', + '|------|-------------|----------|', + ...rows, + '' + ].join('\n'); + } } function updateReadme(modListSection) { @@ -86,12 +164,22 @@ function updateReadme(modListSection) { fs.writeFileSync(README_PATH, newReadme); } -const mainMods = getModFolders(ROOT).filter(dir => !dir.startsWith(EXPERIMENTAL)); -const experimentalMods = getModFolders(EXPERIMENTAL); +async function main() { + try { + const mainMods = getModFolders(ROOT).filter(dir => !dir.startsWith(EXPERIMENTAL)); + const experimentalMods = getModFolders(EXPERIMENTAL); + + const mainModsTable = await formatTable(mainMods, ROOT); + const experimentalModsTable = await formatTable(experimentalMods, EXPERIMENTAL); + + const tableContent = [mainModsTable, experimentalModsTable].join('\n'); + updateReadme(tableContent); + + console.log('README.md updated successfully!'); + } catch (error) { + console.error('Error updating README:', error); + process.exit(1); + } +} -const tableContent = [ - formatTable(mainMods, ROOT), - formatTable(experimentalMods, EXPERIMENTAL) -].join('\n'); - -updateReadme(tableContent); \ No newline at end of file +main(); \ No newline at end of file From 2af27cc81d1278b956e2d043cf499b35f002f6b8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 11 Apr 2025 12:52:38 +0000 Subject: [PATCH 066/119] [NAK_CVR_Mods] Update mod list in README --- README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 017ca92..cb01fcb 100644 --- a/README.md +++ b/README.md @@ -6,19 +6,19 @@ | Name | Description | Download | |------|-------------|----------| -| [ASTExtension](ASTExtension/README.md) | Extension mod for [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool): | No Download | -| [AvatarQueueSystemTweaks](AvatarQueueSystemTweaks/README.md) | Small tweaks to the Avatar Queue System. | No Download | -| [CustomSpawnPoint](CustomSpawnPoint/README.md) | Replaces the unused Images button in the World Details page with a button to set a custom spawn point. | No Download | +| [ASTExtension](ASTExtension/README.md) | Extension mod for [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool): | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ASTExtension.dll) | +| [AvatarQueueSystemTweaks](AvatarQueueSystemTweaks/README.md) | Small tweaks to the Avatar Queue System. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/AvatarQueueSystemTweaks.dll) | +| [CustomSpawnPoint](CustomSpawnPoint/README.md) | Replaces the unused Images button in the World Details page with a button to set a custom spawn point. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/CustomSpawnPoint.dll) | | [FuckToes](FuckToes/README.md) | Prevents VRIK from autodetecting toes in HalfbodyIK. | No Download | -| [KeepVelocityOnExitFlight](KeepVelocityOnExitFlight/README.md) | Keeps the player's velocity when exiting flight mode. Makes it possible to fling yourself like in Garry's Mod. | No Download | -| [LazyPrune](LazyPrune/README.md) | Prevents loaded objects from immediately unloading on destruction. Should prevent needlessly unloading & reloading all avatars/props on world rejoin or GS reconnection. | No Download | -| [PropLoadingHexagon](PropLoadingHexagon/README.md) | https://github.com/NotAKidoS/NAK_CVR_Mods/assets/37721153/a892c765-71c1-47f3-a781-bdb9b60ba117 | No Download | -| [RCCVirtualSteeringWheel](RCCVirtualSteeringWheel/README.md) | Allows you to physically grab rigged RCC steering wheels in VR to provide steering input. No explicit setup required other than defining the Steering Wheel transform within the RCC component. | No Download | -| [RelativeSync](RelativeSync/README.md) | Relative sync for Movement Parent & Chairs. Requires both users to have the mod installed. Synced over Mod Network. | No Download | -| [ShareBubbles](ShareBubbles/README.md) | Share Bubbles! Allows you to drop down bubbles containing Avatars & Props. Requires both users to have the mod installed. Synced over Mod Network. | No Download | -| [SmootherRay](SmootherRay/README.md) | Smoothes your controller while the raycast lines are visible. | No Download | -| [Stickers](Stickers/README.md) | Stickers! Allows you to place small images on any surface. Requires both users to have the mod installed. Synced over Mod Network. | No Download | -| [ThirdPerson](ThirdPerson/README.md) | Original repo: https://github.com/oestradiol/CVR-Mods | No Download | +| [KeepVelocityOnExitFlight](KeepVelocityOnExitFlight/README.md) | Keeps the player's velocity when exiting flight mode. Makes it possible to fling yourself like in Garry's Mod. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/KeepVelocityOnExitFlight.dll) | +| [LazyPrune](LazyPrune/README.md) | Prevents loaded objects from immediately unloading on destruction. Should prevent needlessly unloading & reloading all avatars/props on world rejoin or GS reconnection. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/LazyPrune.dll) | +| [PropLoadingHexagon](PropLoadingHexagon/README.md) | https://github.com/NotAKidoS/NAK_CVR_Mods/assets/37721153/a892c765-71c1-47f3-a781-bdb9b60ba117 | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/PropLoadingHexagon.dll) | +| [RCCVirtualSteeringWheel](RCCVirtualSteeringWheel/README.md) | Allows you to physically grab rigged RCC steering wheels in VR to provide steering input. No explicit setup required other than defining the Steering Wheel transform within the RCC component. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/RCCVirtualSteeringWheel.dll) | +| [RelativeSync](RelativeSync/README.md) | Relative sync for Movement Parent & Chairs. Requires both users to have the mod installed. Synced over Mod Network. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/RelativeSync.dll) | +| [ShareBubbles](ShareBubbles/README.md) | Share Bubbles! Allows you to drop down bubbles containing Avatars & Props. Requires both users to have the mod installed. Synced over Mod Network. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ShareBubbles.dll) | +| [SmootherRay](SmootherRay/README.md) | Smoothes your controller while the raycast lines are visible. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/SmootherRay.dll) | +| [Stickers](Stickers/README.md) | Stickers! Allows you to place small images on any surface. Requires both users to have the mod installed. Synced over Mod Network. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/Stickers.dll) | +| [ThirdPerson](ThirdPerson/README.md) | Original repo: https://github.com/oestradiol/CVR-Mods | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ThirdPerson.dll) | | [YouAreMyPropNowWeAreHavingSoftTacosLater](YouAreMyPropNowWeAreHavingSoftTacosLater/README.md) | Lets you bring held & attached props through world loads. | No Download | ### Experimental Mods From a8e0553e53532fe83913f12c7a1a80edbd083dff Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Sat, 12 Apr 2025 02:41:43 -0500 Subject: [PATCH 067/119] [DoubleTapJumpToExitSeat] Initial push --- .../DoubleTapJumpToExitSeat.csproj | 6 + DoubleTapJumpToExitSeat/Main.cs | 103 ++++++++++++++++++ .../Properties/AssemblyInfo.cs | 32 ++++++ DoubleTapJumpToExitSeat/README.md | 14 +++ DoubleTapJumpToExitSeat/format.json | 23 ++++ 5 files changed, 178 insertions(+) create mode 100644 DoubleTapJumpToExitSeat/DoubleTapJumpToExitSeat.csproj create mode 100644 DoubleTapJumpToExitSeat/Main.cs create mode 100644 DoubleTapJumpToExitSeat/Properties/AssemblyInfo.cs create mode 100644 DoubleTapJumpToExitSeat/README.md create mode 100644 DoubleTapJumpToExitSeat/format.json diff --git a/DoubleTapJumpToExitSeat/DoubleTapJumpToExitSeat.csproj b/DoubleTapJumpToExitSeat/DoubleTapJumpToExitSeat.csproj new file mode 100644 index 0000000..5a8badc --- /dev/null +++ b/DoubleTapJumpToExitSeat/DoubleTapJumpToExitSeat.csproj @@ -0,0 +1,6 @@ + + + + YouAreMineNow + + diff --git a/DoubleTapJumpToExitSeat/Main.cs b/DoubleTapJumpToExitSeat/Main.cs new file mode 100644 index 0000000..91c268e --- /dev/null +++ b/DoubleTapJumpToExitSeat/Main.cs @@ -0,0 +1,103 @@ +using System.Reflection; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Savior; +using ABI_RC.Systems.InputManagement; +using ABI_RC.Systems.Movement; +using HarmonyLib; +using MelonLoader; +using UnityEngine; + +namespace NAK.DoubleTapJumpToExitSeat; + +public class DoubleTapJumpToExitSeatMod : MelonMod +{ + #region Melon Preferences + + public static readonly MelonPreferences_Category Category = + MelonPreferences.CreateCategory(nameof(DoubleTapJumpToExitSeatMod)); + + public static readonly MelonPreferences_Entry EntryOnlyInVR = + Category.CreateEntry("only_in_vr", false, display_name: "Only In VR", description: "Should this behaviour only be active in VR?"); + + #endregion Melon Preferences + + #region Melon Events + + public override void OnInitializeMelon() + { + #region CVRSeat Patches + + HarmonyInstance.Patch( + typeof(CVRSeat).GetMethod(nameof(CVRSeat.Update), + BindingFlags.NonPublic | BindingFlags.Instance), + prefix: new HarmonyMethod(typeof(DoubleTapJumpToExitSeatMod).GetMethod(nameof(OnPreCVRSeatUpdate), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + #endregion CVRSeat Patches + + #region ViewManager Patches + + HarmonyInstance.Patch( + typeof(ViewManager).GetMethod(nameof(ViewManager.Update), + BindingFlags.NonPublic | BindingFlags.Instance), + prefix: new HarmonyMethod(typeof(DoubleTapJumpToExitSeatMod).GetMethod(nameof(OnPreViewManagerUpdate), + BindingFlags.NonPublic | BindingFlags.Static)), + postfix: new HarmonyMethod(typeof(DoubleTapJumpToExitSeatMod).GetMethod(nameof(OnPostViewManagerUpdate), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + #endregion ViewManager Patches + } + + #endregion Melon Events + + #region Harmony Patches + + private static float lastJumpTime = -1f; + private static bool wasJumping; + + private static bool OnPreCVRSeatUpdate(CVRSeat __instance) + { + if (!__instance.occupied) return false; + + // Crazy? + bool jumped = CVRInputManager.Instance.jump; + bool justJumped = jumped && !wasJumping; + wasJumping = jumped; + if (justJumped && (!EntryOnlyInVR.Value || MetaPort.Instance.isUsingVr)) + { + float t = Time.time; + if (t - lastJumpTime <= BetterBetterCharacterController.DoubleJumpFlightTimeOut) + { + lastJumpTime = -1f; + __instance.ExitSeat(); + return false; + } + lastJumpTime = t; + } + + // Double update this frame (this ensures Extrapolate / Every Frame Updated objects are seated correctly) + if (__instance.vrSitPosition.position != __instance._lastPosition || __instance.vrSitPosition.rotation != __instance._lastRotation) + __instance.MovePlayerToSeat(__instance.vrSitPositionReady ? __instance.vrSitPosition : __instance.transform); + + // Steal sync + if (__instance.lockControls) + { + if (__instance._spawnable != null) __instance._spawnable.ForceUpdate(4); + if (__instance._objectSync != null) __instance._objectSync.ForceUpdate(4); + } + + return false; // don't call original method + } + + // ReSharper disable once RedundantAssignment + private static void OnPreViewManagerUpdate(ref bool __state) + => (__state, BetterBetterCharacterController.Instance._isSitting) + = (BetterBetterCharacterController.Instance._isSitting, false); + + private static void OnPostViewManagerUpdate(ref bool __state) + => BetterBetterCharacterController.Instance._isSitting = __state; + + #endregion Harmony Patches +} \ No newline at end of file diff --git a/DoubleTapJumpToExitSeat/Properties/AssemblyInfo.cs b/DoubleTapJumpToExitSeat/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..fd30036 --- /dev/null +++ b/DoubleTapJumpToExitSeat/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using MelonLoader; +using NAK.DoubleTapJumpToExitSeat.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.DoubleTapJumpToExitSeat))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.DoubleTapJumpToExitSeat))] + +[assembly: MelonInfo( + typeof(NAK.DoubleTapJumpToExitSeat.DoubleTapJumpToExitSeatMod), + nameof(NAK.DoubleTapJumpToExitSeat), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/DoubleTapJumpToExitSeat" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red +[assembly: HarmonyDontPatchAll] + +namespace NAK.DoubleTapJumpToExitSeat.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/DoubleTapJumpToExitSeat/README.md b/DoubleTapJumpToExitSeat/README.md new file mode 100644 index 0000000..df6f722 --- /dev/null +++ b/DoubleTapJumpToExitSeat/README.md @@ -0,0 +1,14 @@ +# DoubleTapJumpToExitSeat + +Literally the mod name. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation 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/DoubleTapJumpToExitSeat/format.json b/DoubleTapJumpToExitSeat/format.json new file mode 100644 index 0000000..b7fa28e --- /dev/null +++ b/DoubleTapJumpToExitSeat/format.json @@ -0,0 +1,23 @@ +{ + "_id": -1, + "name": "DoubleTapJumpToExitSeat", + "modversion": "1.0.0", + "gameversion": "2025r179", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Literally the mod name.", + "searchtags": [ + "double", + "jump", + "chair", + "seat" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/DoubleTapJumpToExitSeat.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/DoubleTapJumpToExitSeat/", + "changelog": "- Initial Release", + "embedcolor": "#00FFFF" +} \ No newline at end of file From 8764339ac8b462dce73d2617df3260930455120e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 12 Apr 2025 07:41:58 +0000 Subject: [PATCH 068/119] [NAK_CVR_Mods] Update mod list in README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index cb01fcb..56402aa 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ | [ASTExtension](ASTExtension/README.md) | Extension mod for [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool): | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ASTExtension.dll) | | [AvatarQueueSystemTweaks](AvatarQueueSystemTweaks/README.md) | Small tweaks to the Avatar Queue System. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/AvatarQueueSystemTweaks.dll) | | [CustomSpawnPoint](CustomSpawnPoint/README.md) | Replaces the unused Images button in the World Details page with a button to set a custom spawn point. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/CustomSpawnPoint.dll) | +| [DoubleTapJumpToExitSeat](DoubleTapJumpToExitSeat/README.md) | Literally the mod name. | No Download | | [FuckToes](FuckToes/README.md) | Prevents VRIK from autodetecting toes in HalfbodyIK. | No Download | | [KeepVelocityOnExitFlight](KeepVelocityOnExitFlight/README.md) | Keeps the player's velocity when exiting flight mode. Makes it possible to fling yourself like in Garry's Mod. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/KeepVelocityOnExitFlight.dll) | | [LazyPrune](LazyPrune/README.md) | Prevents loaded objects from immediately unloading on destruction. Should prevent needlessly unloading & reloading all avatars/props on world rejoin or GS reconnection. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/LazyPrune.dll) | From 89b8f19288aced61416e7b8ad3cf5ce9baa14c8d Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Sat, 12 Apr 2025 03:33:10 -0500 Subject: [PATCH 069/119] [YouAreMyPropNowWeAreHavingSoftTacosLaterMod] added settingd --- .../Main.cs | 71 +++++++++++++++++-- 1 file changed, 64 insertions(+), 7 deletions(-) diff --git a/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs b/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs index 645f7c0..b4f22de 100644 --- a/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs +++ b/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs @@ -21,6 +21,25 @@ namespace NAK.YouAreMyPropNowWeAreHavingSoftTacosLater; public class YouAreMyPropNowWeAreHavingSoftTacosLaterMod : MelonMod { + #region Melon Preferences + + public static readonly MelonPreferences_Category Category = + MelonPreferences.CreateCategory(nameof(YouAreMyPropNowWeAreHavingSoftTacosLaterMod)); + + public static readonly MelonPreferences_Entry EntryTrackPickups = + Category.CreateEntry("track_pickups", true, display_name: "Track Pickups", description: "Should pickups be tracked?"); + + public static readonly MelonPreferences_Entry EntryTrackAttachments = + Category.CreateEntry("track_attachments", true, display_name: "Track Attachments", description: "Should attachments be tracked?"); + + public static readonly MelonPreferences_Entry EntryTrackSeats = + Category.CreateEntry("track_seats", true, display_name: "Track Seats", description: "Should seats be tracked?"); + + public static readonly MelonPreferences_Entry EntryOnlySpawnedByMe = + Category.CreateEntry("only_spawned_by_me", true, display_name: "Only Spawned By Me", description: "Should only props spawned by me be tracked?"); + + #endregion Melon Preferences + #region Melon Events public override void OnInitializeMelon() @@ -58,6 +77,24 @@ public class YouAreMyPropNowWeAreHavingSoftTacosLaterMod : MelonMod ); #endregion CVRAttachment Patches + + #region CVRSeat Patches + + HarmonyInstance.Patch( + typeof(CVRSeat).GetMethod(nameof(CVRSeat.SitDown), + BindingFlags.Public | BindingFlags.Instance), + postfix: new HarmonyMethod(typeof(YouAreMyPropNowWeAreHavingSoftTacosLaterMod).GetMethod(nameof(OnCVRSeatSitDown), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + HarmonyInstance.Patch( + typeof(CVRSeat).GetMethod(nameof(CVRSeat.ExitSeat), + BindingFlags.Public | BindingFlags.Instance), + postfix: new HarmonyMethod(typeof(YouAreMyPropNowWeAreHavingSoftTacosLaterMod).GetMethod(nameof(OnCVRSeatExitSeat), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + #endregion CVRSeat Patches #region CVRSyncHelper Patches @@ -129,26 +166,41 @@ public class YouAreMyPropNowWeAreHavingSoftTacosLaterMod : MelonMod private static void OnCVRPickupObjectOnGrab(CVRPickupObject __instance) { - if (!GetPropData(__instance.GetComponentInParent(true), out CVRSyncHelper.PropData propData)) return; + if (!EntryTrackPickups.Value) return; + if (!TryGetPropData(__instance.GetComponentInParent(true), out CVRSyncHelper.PropData propData)) return; if (!_heldPropData.Contains(propData)) _heldPropData.Add(propData); } private static void OnCVRPickupObjectOnDrop(CVRPickupObject __instance) { - if (!GetPropData(__instance.GetComponentInParent(true), out CVRSyncHelper.PropData propData)) return; + if (!TryGetPropData(__instance.GetComponentInParent(true), out CVRSyncHelper.PropData propData)) return; if (_heldPropData.Contains(propData)) _heldPropData.Remove(propData); } private static void OnCVRAttachmentAttachInternal(CVRAttachment __instance) { - if (!GetPropData(__instance.GetComponentInParent(true), out CVRSyncHelper.PropData propData)) return; + if (!EntryTrackAttachments.Value) return; + if (!TryGetPropData(__instance.GetComponentInParent(true), out CVRSyncHelper.PropData propData)) return; if (!_heldPropData.Contains(propData)) _heldPropData.Add(propData); } private static void OnCVRAttachmentDeAttach(CVRAttachment __instance) { if (!__instance._isAttached) return; // Can invoke DeAttach without being attached - if (!GetPropData(__instance.GetComponentInParent(true), out CVRSyncHelper.PropData propData)) return; + if (!TryGetPropData(__instance.GetComponentInParent(true), out CVRSyncHelper.PropData propData)) return; + if (_heldPropData.Contains(propData)) _heldPropData.Remove(propData); + } + + private static void OnCVRSeatSitDown(CVRSeat __instance) + { + if (!EntryTrackSeats.Value) return; + if (!TryGetPropData(__instance.GetComponentInParent(true), out CVRSyncHelper.PropData propData)) return; + if (!_heldPropData.Contains(propData)) _heldPropData.Add(propData); + } + + private static void OnCVRSeatExitSeat(CVRSeat __instance) + { + if (!TryGetPropData(__instance.GetComponentInParent(true), out CVRSyncHelper.PropData propData)) return; if (_heldPropData.Contains(propData)) _heldPropData.Remove(propData); } @@ -161,7 +213,7 @@ public class YouAreMyPropNowWeAreHavingSoftTacosLaterMod : MelonMod if (type != DownloadTask.ObjectType.Prop) return true; // Only care about props // toAttach is our instanceId, lets find the propData - if (!GetPropDataById(toAttach, out CVRSyncHelper.PropData newPropData)) return true; + if (!TryGetPropDataById(toAttach, out CVRSyncHelper.PropData newPropData)) return true; // Check if this is a prop we requested to spawn Vector3 identity = GetIdentityKeyFromPropData(newPropData); @@ -307,13 +359,18 @@ public class YouAreMyPropNowWeAreHavingSoftTacosLaterMod : MelonMod #region Util - private static bool GetPropData(CVRSpawnable spawnable, out CVRSyncHelper.PropData propData) + private static bool TryGetPropData(CVRSpawnable spawnable, out CVRSyncHelper.PropData propData) { if (spawnable == null) { propData = null; return false; } + if (EntryOnlySpawnedByMe.Value && !spawnable.IsMine()) + { + propData = null; + return false; + } foreach (CVRSyncHelper.PropData data in CVRSyncHelper.Props) { if (data.InstanceId != spawnable.instanceId) continue; @@ -324,7 +381,7 @@ public class YouAreMyPropNowWeAreHavingSoftTacosLaterMod : MelonMod return false; } - private static bool GetPropDataById(string instanceId, out CVRSyncHelper.PropData propData) + private static bool TryGetPropDataById(string instanceId, out CVRSyncHelper.PropData propData) { foreach (CVRSyncHelper.PropData data in CVRSyncHelper.Props) { From 1f99312c22024bc15f405a674649171d82b4203d Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Sat, 12 Apr 2025 04:05:48 -0500 Subject: [PATCH 070/119] [WindowFocusCheckFix] iniyial push --- WindowFocusCheckFix/Main.cs | 39 +++++++++++++++++++ .../Properties/AssemblyInfo.cs | 32 +++++++++++++++ WindowFocusCheckFix/README.md | 14 +++++++ .../WindowFocusCheckFix.csproj | 6 +++ WindowFocusCheckFix/format.json | 23 +++++++++++ 5 files changed, 114 insertions(+) create mode 100644 WindowFocusCheckFix/Main.cs create mode 100644 WindowFocusCheckFix/Properties/AssemblyInfo.cs create mode 100644 WindowFocusCheckFix/README.md create mode 100644 WindowFocusCheckFix/WindowFocusCheckFix.csproj create mode 100644 WindowFocusCheckFix/format.json diff --git a/WindowFocusCheckFix/Main.cs b/WindowFocusCheckFix/Main.cs new file mode 100644 index 0000000..24d5de5 --- /dev/null +++ b/WindowFocusCheckFix/Main.cs @@ -0,0 +1,39 @@ +using System.Reflection; +using ABI_RC.Core; +using HarmonyLib; +using MelonLoader; +using UnityEngine; + +namespace NAK.WindowFocusCheckFix; + +public class WindowFocusCheckFixMod : MelonMod +{ + #region Melon Events + + public override void OnInitializeMelon() + { + #region WindowFocusManager Patches + + HarmonyInstance.Patch( + typeof(WindowFocusManager).GetMethod(nameof(WindowFocusManager.IsWindowFocused), + BindingFlags.NonPublic | BindingFlags.Static), + prefix: new HarmonyMethod(typeof(WindowFocusCheckFixMod).GetMethod(nameof(OnPreWindowFocusManagerIsWindowFocused), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + #endregion WindowFocusManager Patches + } + + #endregion Melon Events + + #region Harmony Patches + + // ReSharper disable once RedundantAssignment + private static bool OnPreWindowFocusManagerIsWindowFocused(ref bool __result) + { + __result = Application.isFocused; // use Unity method instead + return false; + } + + #endregion Harmony Patches +} \ No newline at end of file diff --git a/WindowFocusCheckFix/Properties/AssemblyInfo.cs b/WindowFocusCheckFix/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..1f95200 --- /dev/null +++ b/WindowFocusCheckFix/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using MelonLoader; +using NAK.WindowFocusCheckFix.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.WindowFocusCheckFix))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.WindowFocusCheckFix))] + +[assembly: MelonInfo( + typeof(NAK.WindowFocusCheckFix.WindowFocusCheckFixMod), + nameof(NAK.WindowFocusCheckFix), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/WindowFocusCheckFix" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red +[assembly: HarmonyDontPatchAll] + +namespace NAK.WindowFocusCheckFix.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/WindowFocusCheckFix/README.md b/WindowFocusCheckFix/README.md new file mode 100644 index 0000000..5c2dbe0 --- /dev/null +++ b/WindowFocusCheckFix/README.md @@ -0,0 +1,14 @@ +# WindowFocusCheckFix + +Fixes window focus check on specific Linux distribution. ????!??!?! + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation 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/WindowFocusCheckFix/WindowFocusCheckFix.csproj b/WindowFocusCheckFix/WindowFocusCheckFix.csproj new file mode 100644 index 0000000..5a8badc --- /dev/null +++ b/WindowFocusCheckFix/WindowFocusCheckFix.csproj @@ -0,0 +1,6 @@ + + + + YouAreMineNow + + diff --git a/WindowFocusCheckFix/format.json b/WindowFocusCheckFix/format.json new file mode 100644 index 0000000..9fe9458 --- /dev/null +++ b/WindowFocusCheckFix/format.json @@ -0,0 +1,23 @@ +{ + "_id": -1, + "name": "WindowFocusCheckFix", + "modversion": "1.0.0", + "gameversion": "2025r179", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Fixes window focus check on specific Linux distribution. ????!??!?!\n", + "searchtags": [ + "prop", + "spawn", + "friend", + "load" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/WindowFocusCheckFix.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/WindowFocusCheckFix/", + "changelog": "- Initial Release", + "embedcolor": "#00FFFF" +} \ No newline at end of file From 446a89f35d0643dcb66e486d7ddbb3fe26f75fab Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 12 Apr 2025 09:06:01 +0000 Subject: [PATCH 071/119] [NAK_CVR_Mods] Update mod list in README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 56402aa..77e26db 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ | [SmootherRay](SmootherRay/README.md) | Smoothes your controller while the raycast lines are visible. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/SmootherRay.dll) | | [Stickers](Stickers/README.md) | Stickers! Allows you to place small images on any surface. Requires both users to have the mod installed. Synced over Mod Network. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/Stickers.dll) | | [ThirdPerson](ThirdPerson/README.md) | Original repo: https://github.com/oestradiol/CVR-Mods | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ThirdPerson.dll) | +| [WindowFocusCheckFix](WindowFocusCheckFix/README.md) | Fixes window focus check on specific Linux distribution. ????!??!?! | No Download | | [YouAreMyPropNowWeAreHavingSoftTacosLater](YouAreMyPropNowWeAreHavingSoftTacosLater/README.md) | Lets you bring held & attached props through world loads. | No Download | ### Experimental Mods From 1f8435edb9fe4f5245b5f13d0437e5b0aa26c38f Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Sat, 12 Apr 2025 04:29:25 -0500 Subject: [PATCH 072/119] nvm --- WindowFocusCheckFix/Main.cs | 39 ------------------- .../Properties/AssemblyInfo.cs | 32 --------------- WindowFocusCheckFix/README.md | 14 ------- .../WindowFocusCheckFix.csproj | 6 --- WindowFocusCheckFix/format.json | 23 ----------- 5 files changed, 114 deletions(-) delete mode 100644 WindowFocusCheckFix/Main.cs delete mode 100644 WindowFocusCheckFix/Properties/AssemblyInfo.cs delete mode 100644 WindowFocusCheckFix/README.md delete mode 100644 WindowFocusCheckFix/WindowFocusCheckFix.csproj delete mode 100644 WindowFocusCheckFix/format.json diff --git a/WindowFocusCheckFix/Main.cs b/WindowFocusCheckFix/Main.cs deleted file mode 100644 index 24d5de5..0000000 --- a/WindowFocusCheckFix/Main.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Reflection; -using ABI_RC.Core; -using HarmonyLib; -using MelonLoader; -using UnityEngine; - -namespace NAK.WindowFocusCheckFix; - -public class WindowFocusCheckFixMod : MelonMod -{ - #region Melon Events - - public override void OnInitializeMelon() - { - #region WindowFocusManager Patches - - HarmonyInstance.Patch( - typeof(WindowFocusManager).GetMethod(nameof(WindowFocusManager.IsWindowFocused), - BindingFlags.NonPublic | BindingFlags.Static), - prefix: new HarmonyMethod(typeof(WindowFocusCheckFixMod).GetMethod(nameof(OnPreWindowFocusManagerIsWindowFocused), - BindingFlags.NonPublic | BindingFlags.Static)) - ); - - #endregion WindowFocusManager Patches - } - - #endregion Melon Events - - #region Harmony Patches - - // ReSharper disable once RedundantAssignment - private static bool OnPreWindowFocusManagerIsWindowFocused(ref bool __result) - { - __result = Application.isFocused; // use Unity method instead - return false; - } - - #endregion Harmony Patches -} \ No newline at end of file diff --git a/WindowFocusCheckFix/Properties/AssemblyInfo.cs b/WindowFocusCheckFix/Properties/AssemblyInfo.cs deleted file mode 100644 index 1f95200..0000000 --- a/WindowFocusCheckFix/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,32 +0,0 @@ -using MelonLoader; -using NAK.WindowFocusCheckFix.Properties; -using System.Reflection; - -[assembly: AssemblyVersion(AssemblyInfoParams.Version)] -[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] -[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] -[assembly: AssemblyTitle(nameof(NAK.WindowFocusCheckFix))] -[assembly: AssemblyCompany(AssemblyInfoParams.Author)] -[assembly: AssemblyProduct(nameof(NAK.WindowFocusCheckFix))] - -[assembly: MelonInfo( - typeof(NAK.WindowFocusCheckFix.WindowFocusCheckFixMod), - nameof(NAK.WindowFocusCheckFix), - AssemblyInfoParams.Version, - AssemblyInfoParams.Author, - downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/WindowFocusCheckFix" -)] - -[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] -[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] -[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] -[assembly: MelonColor(255, 246, 25, 99)] // red-pink -[assembly: MelonAuthorColor(255, 158, 21, 32)] // red -[assembly: HarmonyDontPatchAll] - -namespace NAK.WindowFocusCheckFix.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/WindowFocusCheckFix/README.md b/WindowFocusCheckFix/README.md deleted file mode 100644 index 5c2dbe0..0000000 --- a/WindowFocusCheckFix/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# WindowFocusCheckFix - -Fixes window focus check on specific Linux distribution. ????!??!?! - ---- - -Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. -https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games - -> This mod is an independent creation 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/WindowFocusCheckFix/WindowFocusCheckFix.csproj b/WindowFocusCheckFix/WindowFocusCheckFix.csproj deleted file mode 100644 index 5a8badc..0000000 --- a/WindowFocusCheckFix/WindowFocusCheckFix.csproj +++ /dev/null @@ -1,6 +0,0 @@ - - - - YouAreMineNow - - diff --git a/WindowFocusCheckFix/format.json b/WindowFocusCheckFix/format.json deleted file mode 100644 index 9fe9458..0000000 --- a/WindowFocusCheckFix/format.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "_id": -1, - "name": "WindowFocusCheckFix", - "modversion": "1.0.0", - "gameversion": "2025r179", - "loaderversion": "0.6.1", - "modtype": "Mod", - "author": "NotAKidoS", - "description": "Fixes window focus check on specific Linux distribution. ????!??!?!\n", - "searchtags": [ - "prop", - "spawn", - "friend", - "load" - ], - "requirements": [ - "None" - ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/WindowFocusCheckFix.dll", - "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/WindowFocusCheckFix/", - "changelog": "- Initial Release", - "embedcolor": "#00FFFF" -} \ No newline at end of file From 8ad74b5ef66bfe74c60fce715f7e046ac98dc00b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 12 Apr 2025 09:29:46 +0000 Subject: [PATCH 073/119] [NAK_CVR_Mods] Update mod list in README --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 77e26db..56402aa 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,6 @@ | [SmootherRay](SmootherRay/README.md) | Smoothes your controller while the raycast lines are visible. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/SmootherRay.dll) | | [Stickers](Stickers/README.md) | Stickers! Allows you to place small images on any surface. Requires both users to have the mod installed. Synced over Mod Network. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/Stickers.dll) | | [ThirdPerson](ThirdPerson/README.md) | Original repo: https://github.com/oestradiol/CVR-Mods | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ThirdPerson.dll) | -| [WindowFocusCheckFix](WindowFocusCheckFix/README.md) | Fixes window focus check on specific Linux distribution. ????!??!?! | No Download | | [YouAreMyPropNowWeAreHavingSoftTacosLater](YouAreMyPropNowWeAreHavingSoftTacosLater/README.md) | Lets you bring held & attached props through world loads. | No Download | ### Experimental Mods From 21b791083b0624b01837ec9cb55b1f8f41e7f67d Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Sat, 12 Apr 2025 16:20:22 -0500 Subject: [PATCH 074/119] [DoubleTapJumpToExitSeat] bump for release --- DoubleTapJumpToExitSeat/Main.cs | 27 ++++++++------------------- DoubleTapJumpToExitSeat/README.md | 2 +- DoubleTapJumpToExitSeat/format.json | 2 +- 3 files changed, 10 insertions(+), 21 deletions(-) diff --git a/DoubleTapJumpToExitSeat/Main.cs b/DoubleTapJumpToExitSeat/Main.cs index 91c268e..c3b5a6f 100644 --- a/DoubleTapJumpToExitSeat/Main.cs +++ b/DoubleTapJumpToExitSeat/Main.cs @@ -1,6 +1,5 @@ using System.Reflection; using ABI_RC.Core.InteractionSystem; -using ABI_RC.Core.Savior; using ABI_RC.Systems.InputManagement; using ABI_RC.Systems.Movement; using HarmonyLib; @@ -11,16 +10,6 @@ namespace NAK.DoubleTapJumpToExitSeat; public class DoubleTapJumpToExitSeatMod : MelonMod { - #region Melon Preferences - - public static readonly MelonPreferences_Category Category = - MelonPreferences.CreateCategory(nameof(DoubleTapJumpToExitSeatMod)); - - public static readonly MelonPreferences_Entry EntryOnlyInVR = - Category.CreateEntry("only_in_vr", false, display_name: "Only In VR", description: "Should this behaviour only be active in VR?"); - - #endregion Melon Preferences - #region Melon Events public override void OnInitializeMelon() @@ -54,8 +43,8 @@ public class DoubleTapJumpToExitSeatMod : MelonMod #region Harmony Patches - private static float lastJumpTime = -1f; - private static bool wasJumping; + private static float _lastJumpTime = -1f; + private static bool _wasJumping; private static bool OnPreCVRSeatUpdate(CVRSeat __instance) { @@ -63,18 +52,18 @@ public class DoubleTapJumpToExitSeatMod : MelonMod // Crazy? bool jumped = CVRInputManager.Instance.jump; - bool justJumped = jumped && !wasJumping; - wasJumping = jumped; - if (justJumped && (!EntryOnlyInVR.Value || MetaPort.Instance.isUsingVr)) + bool justJumped = jumped && !_wasJumping; + _wasJumping = jumped; + if (justJumped) { float t = Time.time; - if (t - lastJumpTime <= BetterBetterCharacterController.DoubleJumpFlightTimeOut) + if (t - _lastJumpTime <= BetterBetterCharacterController.DoubleJumpFlightTimeOut) { - lastJumpTime = -1f; + _lastJumpTime = -1f; __instance.ExitSeat(); return false; } - lastJumpTime = t; + _lastJumpTime = t; } // Double update this frame (this ensures Extrapolate / Every Frame Updated objects are seated correctly) diff --git a/DoubleTapJumpToExitSeat/README.md b/DoubleTapJumpToExitSeat/README.md index df6f722..c154674 100644 --- a/DoubleTapJumpToExitSeat/README.md +++ b/DoubleTapJumpToExitSeat/README.md @@ -1,6 +1,6 @@ # DoubleTapJumpToExitSeat -Literally the mod name. +Replaces seat exit controls with a double-tap of the jump button, avoiding accidental exits from joystick drift or opening the menu. --- diff --git a/DoubleTapJumpToExitSeat/format.json b/DoubleTapJumpToExitSeat/format.json index b7fa28e..f09cc1f 100644 --- a/DoubleTapJumpToExitSeat/format.json +++ b/DoubleTapJumpToExitSeat/format.json @@ -6,7 +6,7 @@ "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS", - "description": "Literally the mod name.", + "description": "Replaces seat exit controls with a double-tap of the jump button, avoiding accidental exits from joystick drift or opening the menu.", "searchtags": [ "double", "jump", From 377b365cdcb0fe7ce90129b44a201b490099b200 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Sat, 12 Apr 2025 16:20:37 -0500 Subject: [PATCH 075/119] [YouAreMyPropNowWeAreHavingSoftTacosLater] fix accessors --- YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs b/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs index b4f22de..7ed15f1 100644 --- a/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs +++ b/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs @@ -23,19 +23,19 @@ public class YouAreMyPropNowWeAreHavingSoftTacosLaterMod : MelonMod { #region Melon Preferences - public static readonly MelonPreferences_Category Category = - MelonPreferences.CreateCategory(nameof(YouAreMyPropNowWeAreHavingSoftTacosLaterMod)); + private static readonly MelonPreferences_Category Category = + MelonPreferences.CreateCategory(nameof(YouAreMyPropNowWeAreHavingSoftTacosLater)); - public static readonly MelonPreferences_Entry EntryTrackPickups = + private static readonly MelonPreferences_Entry EntryTrackPickups = Category.CreateEntry("track_pickups", true, display_name: "Track Pickups", description: "Should pickups be tracked?"); - public static readonly MelonPreferences_Entry EntryTrackAttachments = + private static readonly MelonPreferences_Entry EntryTrackAttachments = Category.CreateEntry("track_attachments", true, display_name: "Track Attachments", description: "Should attachments be tracked?"); - public static readonly MelonPreferences_Entry EntryTrackSeats = + private static readonly MelonPreferences_Entry EntryTrackSeats = Category.CreateEntry("track_seats", true, display_name: "Track Seats", description: "Should seats be tracked?"); - public static readonly MelonPreferences_Entry EntryOnlySpawnedByMe = + private static readonly MelonPreferences_Entry EntryOnlySpawnedByMe = Category.CreateEntry("only_spawned_by_me", true, display_name: "Only Spawned By Me", description: "Should only props spawned by me be tracked?"); #endregion Melon Preferences From d5d4e3eddd5895e881f559f93a9752822bb02c80 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 12 Apr 2025 21:20:39 +0000 Subject: [PATCH 076/119] [NAK_CVR_Mods] Update mod list in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 56402aa..5bd6054 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ | [ASTExtension](ASTExtension/README.md) | Extension mod for [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool): | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ASTExtension.dll) | | [AvatarQueueSystemTweaks](AvatarQueueSystemTweaks/README.md) | Small tweaks to the Avatar Queue System. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/AvatarQueueSystemTweaks.dll) | | [CustomSpawnPoint](CustomSpawnPoint/README.md) | Replaces the unused Images button in the World Details page with a button to set a custom spawn point. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/CustomSpawnPoint.dll) | -| [DoubleTapJumpToExitSeat](DoubleTapJumpToExitSeat/README.md) | Literally the mod name. | No Download | +| [DoubleTapJumpToExitSeat](DoubleTapJumpToExitSeat/README.md) | Replaces seat exit controls with a double-tap of the jump button, avoiding accidental exits from joystick drift or opening the menu. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/DoubleTapJumpToExitSeat.dll) | | [FuckToes](FuckToes/README.md) | Prevents VRIK from autodetecting toes in HalfbodyIK. | No Download | | [KeepVelocityOnExitFlight](KeepVelocityOnExitFlight/README.md) | Keeps the player's velocity when exiting flight mode. Makes it possible to fling yourself like in Garry's Mod. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/KeepVelocityOnExitFlight.dll) | | [LazyPrune](LazyPrune/README.md) | Prevents loaded objects from immediately unloading on destruction. Should prevent needlessly unloading & reloading all avatars/props on world rejoin or GS reconnection. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/LazyPrune.dll) | From 9606b10c9d2b731f53f20531718e33fcfea23c42 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Sat, 12 Apr 2025 16:20:56 -0500 Subject: [PATCH 077/119] [NAK_CVR_Mods] update solution --- NAK_CVR_Mods.sln | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/NAK_CVR_Mods.sln b/NAK_CVR_Mods.sln index 26deacd..a85eb63 100644 --- a/NAK_CVR_Mods.sln +++ b/NAK_CVR_Mods.sln @@ -56,6 +56,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RCCVirtualSteeringWheel", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YouAreMyPropNowWeAreHavingSoftTacosLater", "YouAreMyPropNowWeAreHavingSoftTacosLater\YouAreMyPropNowWeAreHavingSoftTacosLater.csproj", "{8DA821CC-F911-4FCB-8C29-5EF3D76A5F76}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DoubleTapJumpToExitSeat", "DoubleTapJumpToExitSeat\DoubleTapJumpToExitSeat.csproj", "{36BF2B8B-F444-4886-AA4C-0EDF7540F1CE}" +EndProject EndProject EndProject EndProject @@ -295,6 +297,10 @@ Global {8DA821CC-F911-4FCB-8C29-5EF3D76A5F76}.Debug|Any CPU.Build.0 = Debug|Any CPU {8DA821CC-F911-4FCB-8C29-5EF3D76A5F76}.Release|Any CPU.ActiveCfg = Release|Any CPU {8DA821CC-F911-4FCB-8C29-5EF3D76A5F76}.Release|Any CPU.Build.0 = Release|Any CPU + {36BF2B8B-F444-4886-AA4C-0EDF7540F1CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {36BF2B8B-F444-4886-AA4C-0EDF7540F1CE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {36BF2B8B-F444-4886-AA4C-0EDF7540F1CE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {36BF2B8B-F444-4886-AA4C-0EDF7540F1CE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From c4ab9cce47649a30930a8ed5ff03d4da01d4ccf5 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Sat, 12 Apr 2025 16:23:00 -0500 Subject: [PATCH 078/119] [DoubleTapJumpToExitSeat] fix format.json --- DoubleTapJumpToExitSeat/format.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DoubleTapJumpToExitSeat/format.json b/DoubleTapJumpToExitSeat/format.json index f09cc1f..ab8e14e 100644 --- a/DoubleTapJumpToExitSeat/format.json +++ b/DoubleTapJumpToExitSeat/format.json @@ -18,6 +18,6 @@ ], "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/DoubleTapJumpToExitSeat.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/DoubleTapJumpToExitSeat/", - "changelog": "- Initial Release", - "embedcolor": "#00FFFF" + "changelog": "- Initial release", + "embedcolor": "#f61963" } \ No newline at end of file From 6e37bcbabb74bba955e415400a67a26c8f392f71 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Sat, 12 Apr 2025 16:38:19 -0500 Subject: [PATCH 079/119] [FuckToes] i guess bring this back --- FuckToes/Main.cs | 20 +++++++++----------- FuckToes/Properties/AssemblyInfo.cs | 2 +- FuckToes/README.md | 6 ++---- FuckToes/format.json | 8 ++++---- NAK_CVR_Mods.sln | 6 ++++++ 5 files changed, 22 insertions(+), 20 deletions(-) diff --git a/FuckToes/Main.cs b/FuckToes/Main.cs index 7e6a936..7fc6892 100644 --- a/FuckToes/Main.cs +++ b/FuckToes/Main.cs @@ -3,23 +3,22 @@ using ABI_RC.Systems.IK; using MelonLoader; using RootMotion.FinalIK; using System.Reflection; +using ABI_RC.Core; namespace NAK.FuckToes; public class FuckToesMod : MelonMod { - private static MelonLogger.Instance Logger; - #region Melon Preferences private static readonly MelonPreferences_Category Category = - MelonPreferences.CreateCategory(nameof(FuckToesMod)); + MelonPreferences.CreateCategory(nameof(FuckToes)); private static readonly MelonPreferences_Entry EntryEnabledVR = - Category.CreateEntry("Enabled in HalfBody", true, description: "Nuke VRIK toes when in Halfbody."); + Category.CreateEntry("use_in_halfbody", true, display_name:"No Toes in Halfbody", description: "Nuke VRIK toes when in Halfbody."); private static readonly MelonPreferences_Entry EntryEnabledFBT = - Category.CreateEntry("Enabled in FBT", true, description: "Nuke VRIK toes when in FBT."); + Category.CreateEntry("use_in_fbt", true, display_name:"No Toes in Fullbody", description: "Nuke VRIK toes when in FBT."); #endregion Melon Preferences @@ -27,10 +26,10 @@ public class FuckToesMod : MelonMod public override void OnInitializeMelon() { - Logger = LoggerInstance; HarmonyInstance.Patch( typeof(VRIK).GetMethod(nameof(VRIK.AutoDetectReferences)), - prefix: new HarmonyLib.HarmonyMethod(typeof(FuckToesMod).GetMethod(nameof(OnVRIKAutoDetectReferences_Prefix), BindingFlags.NonPublic | BindingFlags.Static)) + prefix: new HarmonyLib.HarmonyMethod(typeof(FuckToesMod).GetMethod(nameof(OnVRIKAutoDetectReferences_Prefix), + BindingFlags.NonPublic | BindingFlags.Static)) ); } @@ -43,13 +42,12 @@ public class FuckToesMod : MelonMod try { // Must be PlayerLocal layer and in VR - if (__instance.gameObject.layer != 8 + if (__instance.gameObject.layer != CVRLayers.PlayerLocal || !MetaPort.Instance.isUsingVr) return; switch (IKSystem.Instance.BodySystem.FullBodyActive) { - case false when !EntryEnabledVR.Value: // Not in FBT, and not enabled, perish case true when !EntryEnabledFBT.Value: // In FBT, and not enabled in fbt, perish return; @@ -61,8 +59,8 @@ public class FuckToesMod : MelonMod } catch (Exception e) { - Logger.Error($"Error during the patched method {nameof(OnVRIKAutoDetectReferences_Prefix)}"); - Logger.Error(e); + MelonLogger.Error($"Error during the patched method {nameof(OnVRIKAutoDetectReferences_Prefix)}"); + MelonLogger.Error(e); } } diff --git a/FuckToes/Properties/AssemblyInfo.cs b/FuckToes/Properties/AssemblyInfo.cs index c26d688..c308a51 100644 --- a/FuckToes/Properties/AssemblyInfo.cs +++ b/FuckToes/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.FuckToes.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.3"; + public const string Version = "1.0.4"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/FuckToes/README.md b/FuckToes/README.md index e9b9e4d..6caf1f4 100644 --- a/FuckToes/README.md +++ b/FuckToes/README.md @@ -1,7 +1,6 @@ # FuckToes -Prevents VRIK from autodetecting toes in HalfbodyIK. -Optionally can be applied in FBT, but toes in FBT are nice so you are a monster if so. +Prevents VRIK from autodetecting toes in Halfbody or Fullbody. ![fuckthetoes](https://user-images.githubusercontent.com/37721153/216518012-ae3b1dde-17ea-419a-a875-48d57e13f3dd.png) @@ -14,5 +13,4 @@ https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games > Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use. -> To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive. - +> To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive. \ No newline at end of file diff --git a/FuckToes/format.json b/FuckToes/format.json index c02103b..3bd10a4 100644 --- a/FuckToes/format.json +++ b/FuckToes/format.json @@ -1,8 +1,8 @@ { "_id": 129, "name": "FuckToes", - "modversion": "1.0.3", - "gameversion": "2023r171", + "modversion": "1.0.4", + "gameversion": "2025r179", "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r14/FuckToes.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/FuckToes.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/FuckToes/", - "changelog": "- Fixes for 2023r171.", + "changelog": "- Recompiled for 2025r179", "embedcolor": "#f61963" } \ No newline at end of file diff --git a/NAK_CVR_Mods.sln b/NAK_CVR_Mods.sln index a85eb63..eb7c1a3 100644 --- a/NAK_CVR_Mods.sln +++ b/NAK_CVR_Mods.sln @@ -58,6 +58,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YouAreMyPropNowWeAreHavingS EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DoubleTapJumpToExitSeat", "DoubleTapJumpToExitSeat\DoubleTapJumpToExitSeat.csproj", "{36BF2B8B-F444-4886-AA4C-0EDF7540F1CE}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FuckToes", "FuckToes\FuckToes.csproj", "{751E4140-2F4D-4550-A4A9-65ABA9F7893A}" +EndProject EndProject EndProject EndProject @@ -301,6 +303,10 @@ Global {36BF2B8B-F444-4886-AA4C-0EDF7540F1CE}.Debug|Any CPU.Build.0 = Debug|Any CPU {36BF2B8B-F444-4886-AA4C-0EDF7540F1CE}.Release|Any CPU.ActiveCfg = Release|Any CPU {36BF2B8B-F444-4886-AA4C-0EDF7540F1CE}.Release|Any CPU.Build.0 = Release|Any CPU + {751E4140-2F4D-4550-A4A9-65ABA9F7893A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {751E4140-2F4D-4550-A4A9-65ABA9F7893A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {751E4140-2F4D-4550-A4A9-65ABA9F7893A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {751E4140-2F4D-4550-A4A9-65ABA9F7893A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 8343d6c5bb22e7e10e97d6629855f9f637b91370 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 12 Apr 2025 21:38:33 +0000 Subject: [PATCH 080/119] [NAK_CVR_Mods] Update mod list in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5bd6054..e3217d1 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ | [AvatarQueueSystemTweaks](AvatarQueueSystemTweaks/README.md) | Small tweaks to the Avatar Queue System. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/AvatarQueueSystemTweaks.dll) | | [CustomSpawnPoint](CustomSpawnPoint/README.md) | Replaces the unused Images button in the World Details page with a button to set a custom spawn point. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/CustomSpawnPoint.dll) | | [DoubleTapJumpToExitSeat](DoubleTapJumpToExitSeat/README.md) | Replaces seat exit controls with a double-tap of the jump button, avoiding accidental exits from joystick drift or opening the menu. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/DoubleTapJumpToExitSeat.dll) | -| [FuckToes](FuckToes/README.md) | Prevents VRIK from autodetecting toes in HalfbodyIK. | No Download | +| [FuckToes](FuckToes/README.md) | Prevents VRIK from autodetecting toes in Halfbody or Fullbody. | No Download | | [KeepVelocityOnExitFlight](KeepVelocityOnExitFlight/README.md) | Keeps the player's velocity when exiting flight mode. Makes it possible to fling yourself like in Garry's Mod. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/KeepVelocityOnExitFlight.dll) | | [LazyPrune](LazyPrune/README.md) | Prevents loaded objects from immediately unloading on destruction. Should prevent needlessly unloading & reloading all avatars/props on world rejoin or GS reconnection. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/LazyPrune.dll) | | [PropLoadingHexagon](PropLoadingHexagon/README.md) | https://github.com/NotAKidoS/NAK_CVR_Mods/assets/37721153/a892c765-71c1-47f3-a781-bdb9b60ba117 | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/PropLoadingHexagon.dll) | From f6afea3c4452965480d248bb6d360c3f1f14c32f Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Sat, 12 Apr 2025 16:41:05 -0500 Subject: [PATCH 081/119] [FuckToes] fix format.json --- FuckToes/format.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FuckToes/format.json b/FuckToes/format.json index 3bd10a4..c7c42ee 100644 --- a/FuckToes/format.json +++ b/FuckToes/format.json @@ -6,7 +6,7 @@ "loaderversion": "0.6.1", "modtype": "Mod", "author": "NotAKidoS", - "description": "Prevents VRIK from using toe bones in HalfBody or FBT.\n\nVRIK calculates weird center of mass when toes are mapped, so it is sometimes desired to unmap toes to prevent an avatars feet from resting far back.\n\nPlease see the README for relevant imagery detailing the problem.", + "description": "Prevents VRIK from using toe bones in HalfBody or FBT.\n\nVRIK calculates weird center of mass when toes are mapped, so it is sometimes desired to unmap toes to prevent an avatars feet from resting far back.\n\nPlease see the [README](https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/FuckToes/README.md) for relevant imagery detailing the problem.", "searchtags": [ "toes", "vrik", From 47b69dfbc77524554d8d1c2d8b0c5aaae05cd000 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Sat, 12 Apr 2025 17:01:24 -0500 Subject: [PATCH 082/119] [RelativeSync] add support for YouAreMyPropNowWeAreHavingSoftTacosLaterMod --- .../Components/RelativeSyncMarker.cs | 54 +++++++++++-------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/RelativeSync/RelativeSync/Components/RelativeSyncMarker.cs b/RelativeSync/RelativeSync/Components/RelativeSyncMarker.cs index 0669d81..9627146 100644 --- a/RelativeSync/RelativeSync/Components/RelativeSyncMarker.cs +++ b/RelativeSync/RelativeSync/Components/RelativeSyncMarker.cs @@ -12,18 +12,35 @@ public class RelativeSyncMarker : MonoBehaviour public bool IsComponentActive => _component.isActiveAndEnabled; - + public bool ApplyRelativePosition = true; public bool ApplyRelativeRotation = true; public bool OnlyApplyRelativeHeading; - + private MonoBehaviour _component; - + private void Start() { + RegisterWithManager(); + ConfigureForPotentialMovementParent(); + } + + private void OnDestroy() + { + RelativeSyncManager.RelativeSyncTransforms.Remove(pathHash); + } + + public void OnHavingSoftTacosNow() + => RegisterWithManager(); + + private void RegisterWithManager() + { + // Remove old hash in case this is a re-registration + RelativeSyncManager.RelativeSyncTransforms.Remove(pathHash); + string path = GetGameObjectPath(transform); int hash = path.GetHashCode(); - + // check if it already exists (this **should** only matter in worlds) if (RelativeSyncManager.RelativeSyncTransforms.ContainsKey(hash)) { @@ -34,18 +51,11 @@ public class RelativeSyncMarker : MonoBehaviour return; } } - + pathHash = hash; RelativeSyncManager.RelativeSyncTransforms.Add(hash, this); - - ConfigureForPotentialMovementParent(); } - private void OnDestroy() - { - RelativeSyncManager.RelativeSyncTransforms.Remove(pathHash); - } - private void ConfigureForPotentialMovementParent() { if (!gameObject.TryGetComponent(out CVRMovementParent movementParent)) @@ -54,20 +64,20 @@ public class RelativeSyncMarker : MonoBehaviour return; } _component = movementParent; - + // TODO: a refactor may be needed to handle the orientation mode being animated - + // respect orientation mode & gravity zone ApplyRelativeRotation = movementParent.orientationMode == CVRMovementParent.OrientationMode.RotateWithParent; OnlyApplyRelativeHeading = movementParent.GetComponent() == null; } - + private static string GetGameObjectPath(Transform transform) { // props already have a unique instance identifier at root // worlds uhhhh, dont duplicate the same thing over and over thx // avatars on remote/local client have diff path, we need to account for it -_- - + string path = transform.name; while (transform.parent != null) { @@ -79,22 +89,22 @@ public class RelativeSyncMarker : MonoBehaviour path = MetaPort.Instance.ownerId + "/" + path; break; } // remote player object root is already player guid - + path = transform.name + "/" + path; } - + return path; } - - private bool FindAvailableHash(ref int hash) + + private static bool FindAvailableHash(ref int hash) { for (int i = 0; i < 16; i++) { hash += 1; if (!RelativeSyncManager.RelativeSyncTransforms.ContainsKey(hash)) return true; } - + // failed to find a hash in 16 tries, dont care return false; } -} \ No newline at end of file +} From ece15e0dfc56ff4c982712d86aa016ce9d202250 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Sat, 12 Apr 2025 17:01:33 -0500 Subject: [PATCH 083/119] [YouAreMyPropNowWeAreHavingSoftTacosLater] fix for relative sync --- YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs b/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs index 7ed15f1..02e39c0 100644 --- a/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs +++ b/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs @@ -231,6 +231,7 @@ public class YouAreMyPropNowWeAreHavingSoftTacosLaterMod : MelonMod // Apply new prop data to the spawnable newPropData.Spawnable = originalPropData.Spawnable; newPropData.Wrapper = originalPropData.Wrapper; + newPropData.Wrapper.BroadcastMessage("OnHavingSoftTacosNow", SendMessageOptions.DontRequireReceiver); // support with RelativeSync newPropData.Wrapper.name = $"p+{newPropData.ObjectId}~{newPropData.InstanceId}"; // Copy sync values From e85c1e2f2506446265d10f5a2199d9eb88e13176 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Mon, 14 Apr 2025 18:11:23 -0500 Subject: [PATCH 084/119] [LuaNetworkVariables] Remove exp stuff, fix context properties --- .Experimental/LuaNetworkVariables/Main.cs | 28 +- .../LuaNetworkVariables/NetLuaModule.cs | 22 +- .../NetworkVariables/LuaEventContext.cs | 20 +- .../LuaNetVarController.Base.cs | 32 +- .../LuaNetVarController.Networking.cs | 31 +- .Experimental/LuaNetworkVariables/Patches.cs | 41 +-- .../Properties/AssemblyInfo.cs | 4 +- .../SyncedBehaviour/MNSyncedBehaviour.cs | 326 ------------------ .../SyncedBehaviour/TestSyncedBehaviour.cs | 63 ---- .../SyncedBehaviour/TestSyncedObject.cs | 42 --- 10 files changed, 95 insertions(+), 514 deletions(-) delete mode 100644 .Experimental/LuaNetworkVariables/SyncedBehaviour/MNSyncedBehaviour.cs delete mode 100644 .Experimental/LuaNetworkVariables/SyncedBehaviour/TestSyncedBehaviour.cs delete mode 100644 .Experimental/LuaNetworkVariables/SyncedBehaviour/TestSyncedObject.cs diff --git a/.Experimental/LuaNetworkVariables/Main.cs b/.Experimental/LuaNetworkVariables/Main.cs index d8c5def..2a8b2fb 100644 --- a/.Experimental/LuaNetworkVariables/Main.cs +++ b/.Experimental/LuaNetworkVariables/Main.cs @@ -18,24 +18,22 @@ public class LuaNetVarsMod : MelonMod public override void OnInitializeMelon() { Logger = LoggerInstance; - ApplyPatches(typeof(Patches.LuaScriptFactory_Patches)); - ApplyPatches(typeof(Patches.CVRSyncHelper_Patches)); } - public override void OnUpdate() - { - // if (Input.GetKeyDown(KeyCode.F1)) - // { - // PlayerSetup.Instance.DropProp("be0b5acc-a987-48dc-a28b-62bd912fe3a0"); - // } - // - // if (Input.GetKeyDown(KeyCode.F2)) - // { - // GameObject go = new("TestSyncedObject"); - // go.AddComponent(); - // } - } + // public override void OnUpdate() + // { + // // if (Input.GetKeyDown(KeyCode.F1)) + // // { + // // PlayerSetup.Instance.DropProp("be0b5acc-a987-48dc-a28b-62bd912fe3a0"); + // // } + // // + // // if (Input.GetKeyDown(KeyCode.F2)) + // // { + // // GameObject go = new("TestSyncedObject"); + // // go.AddComponent(); + // // } + // } #endregion Melon Events diff --git a/.Experimental/LuaNetworkVariables/NetLuaModule.cs b/.Experimental/LuaNetworkVariables/NetLuaModule.cs index 319fefa..b13bc9b 100644 --- a/.Experimental/LuaNetworkVariables/NetLuaModule.cs +++ b/.Experimental/LuaNetworkVariables/NetLuaModule.cs @@ -1,12 +1,11 @@ using ABI_RC.Core.Base; using ABI.Scripting.CVRSTL.Common; using JetBrains.Annotations; -using NAK.LuaNetVars; using MoonSharp.Interpreter; namespace NAK.LuaNetVars.Modules; -[PublicAPI] // Indicates that this class is used and should not be considered unused +[PublicAPI] public class LuaNetModule : BaseScriptedStaticWrapper { public const string MODULE_ID = "NetworkModule"; @@ -101,6 +100,25 @@ public class LuaNetModule : BaseScriptedStaticWrapper _controller.SendLuaEvent(eventName, args); } + + /// + /// Sends a Lua event to other clients. + /// + /// The name of the event to send. + /// Optional arguments to send with the event. + public void SendLuaEventToUser(string eventName, string userId, params DynValue[] args) + { + CheckIfCanAccessMethod(nameof(SendLuaEventToUser), false, + CVRLuaEnvironmentContext.CLIENT, CVRLuaObjectContext.ALL_BUT_EVENTS, CVRLuaOwnerContext.ANY); + + if (_controller == null) + { + LuaNetVarsMod.Logger.Error("LuaNetVarController is null."); + return; + } + + _controller.SendLuaEventToUser(eventName, userId, args); + } /// /// Checks if the current client is the owner of the synchronized object. diff --git a/.Experimental/LuaNetworkVariables/NetworkVariables/LuaEventContext.cs b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaEventContext.cs index 01fbdc4..6a3fd57 100644 --- a/.Experimental/LuaNetworkVariables/NetworkVariables/LuaEventContext.cs +++ b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaEventContext.cs @@ -1,6 +1,6 @@ -using MoonSharp.Interpreter; +using ABI_RC.Core.Networking; +using MoonSharp.Interpreter; using ABI_RC.Core.Player; -using ABI_RC.Core.Savior; namespace NAK.LuaNetVars; @@ -12,9 +12,9 @@ public struct LuaEventContext private double TimeSinceLastInvoke { get; set; } private bool IsLocal { get; set; } - public static LuaEventContext Create(string senderId, DateTime lastInvokeTime) + public static LuaEventContext Create(bool isLocal, string senderId, DateTime lastInvokeTime) { - var playerName = CVRPlayerManager.Instance.TryGetPlayerName(senderId); + var playerName = isLocal ? AuthManager.Username : CVRPlayerManager.Instance.TryGetPlayerName(senderId); return new LuaEventContext { @@ -22,7 +22,7 @@ public struct LuaEventContext SenderName = playerName ?? "Unknown", LastInvokeTime = lastInvokeTime, TimeSinceLastInvoke = (DateTime.Now - lastInvokeTime).TotalSeconds, - IsLocal = senderId == MetaPort.Instance.ownerId + IsLocal = isLocal }; } @@ -30,11 +30,11 @@ public struct LuaEventContext { Table table = new(script) { - ["senderId"] = SenderId, - ["senderName"] = SenderName, - ["lastInvokeTime"] = LastInvokeTime.ToUniversalTime().ToString("O"), - ["timeSinceLastInvoke"] = TimeSinceLastInvoke, - ["isLocal"] = IsLocal + ["SenderId"] = SenderId, + ["SenderName"] = SenderName, + ["LastInvokeTime"] = LastInvokeTime.ToUniversalTime().ToString("O"), + ["TimeSinceLastInvoke"] = TimeSinceLastInvoke, + ["IsLocal"] = IsLocal }; return table; } diff --git a/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Base.cs b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Base.cs index 589c405..811fa9b 100644 --- a/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Base.cs +++ b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Base.cs @@ -5,6 +5,7 @@ using ABI.CCK.Components; using ABI.Scripting.CVRSTL.Common; using MoonSharp.Interpreter; using UnityEngine; +using Coroutine = UnityEngine.Coroutine; namespace NAK.LuaNetVars; @@ -26,21 +27,23 @@ public partial class LuaNetVarController : MonoBehaviour private bool _requestInitialSync; private CVRSpawnable _spawnable; private CVRObjectSync _objectSync; - + + private bool _isInitialized; + private Coroutine _syncCoroutine; + #region Unity Events private void Awake() - { - if (!Initialize()) - return; - - // TODO: a manager script should be in charge of this - // TODO: disabling object will kill coroutine - StartCoroutine(SendVariableUpdatesCoroutine()); - } - + => _isInitialized = Initialize(); + private void OnDestroy() => Cleanup(); + + private void OnEnable() + => StartStopVariableUpdatesCoroutine(true); + + private void OnDisable() + => StartStopVariableUpdatesCoroutine(false); #endregion Unity Events @@ -102,9 +105,16 @@ public partial class LuaNetVarController : MonoBehaviour _hashes.Remove(_uniquePathHash); } + private void StartStopVariableUpdatesCoroutine(bool start) + { + if (_syncCoroutine != null) StopCoroutine(_syncCoroutine); + _syncCoroutine = null; + if (start) _syncCoroutine = StartCoroutine(SendVariableUpdatesCoroutine()); + } + private System.Collections.IEnumerator SendVariableUpdatesCoroutine() { - while (true) + while (isActiveAndEnabled) { yield return new WaitForSeconds(0.1f); if (IsSyncOwner()) SendVariableUpdates(); diff --git a/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Networking.cs b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Networking.cs index 47f6415..bed3bb8 100644 --- a/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Networking.cs +++ b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Networking.cs @@ -1,7 +1,6 @@ using ABI_RC.Core.Savior; using ABI_RC.Systems.ModNetwork; using MoonSharp.Interpreter; -using Unity.Services.Authentication.Internal; namespace NAK.LuaNetVars { @@ -66,7 +65,7 @@ namespace NAK.LuaNetVars msg.Read(out int argsCount); DateTime lastInvokeTime = _eventTracker.GetLastInvokeTimeForSender(eventName, senderId); - LuaEventContext context = LuaEventContext.Create(senderId, lastInvokeTime); + LuaEventContext context = LuaEventContext.Create(false, senderId, lastInvokeTime); // Update tracking _eventTracker.UpdateInvokeTime(eventName, senderId); @@ -187,7 +186,7 @@ namespace NAK.LuaNetVars { string senderId = MetaPort.Instance.ownerId; DateTime lastInvokeTime = _eventTracker.GetLastInvokeTimeForSender(eventName, senderId); - LuaEventContext context = LuaEventContext.Create(senderId, lastInvokeTime); + LuaEventContext context = LuaEventContext.Create(true, senderId, lastInvokeTime); // Update tracking _eventTracker.UpdateInvokeTime(eventName, senderId); @@ -209,6 +208,32 @@ namespace NAK.LuaNetVars modMsg.Send(); } + internal void SendLuaEventToUser(string eventName, string userId, DynValue[] args) + { + string senderId = MetaPort.Instance.ownerId; + DateTime lastInvokeTime = _eventTracker.GetLastInvokeTimeForSender(eventName, senderId); + LuaEventContext context = LuaEventContext.Create(true, senderId, lastInvokeTime); + + // Update tracking + _eventTracker.UpdateInvokeTime(eventName, senderId); + + var argsWithContext = new DynValue[args.Length + 1]; + argsWithContext[0] = DynValue.FromObject(_luaClientBehaviour.script, context.ToLuaTable(_luaClientBehaviour.script)); + Array.Copy(args, 0, argsWithContext, 1, args.Length); + + InvokeLuaEvent(eventName, argsWithContext); + + using ModNetworkMessage modMsg = new(ModNetworkID, userId); + modMsg.Write((byte)MessageType.LuaEvent); + modMsg.Write(eventName); + modMsg.Write(args.Length); + + foreach (DynValue arg in args) + SerializeDynValue(modMsg, arg); + + modMsg.Send(); + } + #endregion } } \ No newline at end of file diff --git a/.Experimental/LuaNetworkVariables/Patches.cs b/.Experimental/LuaNetworkVariables/Patches.cs index ce861fe..672e1df 100644 --- a/.Experimental/LuaNetworkVariables/Patches.cs +++ b/.Experimental/LuaNetworkVariables/Patches.cs @@ -1,13 +1,8 @@ -using ABI_RC.Core.Base; -using ABI_RC.Core.Savior; -using ABI_RC.Core.Util; -using ABI.CCK.Components; -using ABI.Scripting.CVRSTL.Client; +using ABI.Scripting.CVRSTL.Client; using ABI.Scripting.CVRSTL.Common; using HarmonyLib; using MoonSharp.Interpreter; using NAK.LuaNetVars.Modules; -using UnityEngine; namespace NAK.LuaNetVars.Patches; @@ -28,38 +23,4 @@ internal static class LuaScriptFactory_Patches __result = LuaNetModule.RegisterUserData(____script, ____context); __instance.RegisteredModules[LuaNetModule.MODULE_ID] = __result; // add module to cache } -} - -internal static class CVRSyncHelper_Patches -{ - [HarmonyPostfix] - [HarmonyPatch(typeof(CVRSyncHelper), nameof(CVRSyncHelper.UpdatePropValues))] - private static void Postfix_CVRSyncHelper_UpdatePropValues( - Vector3 position, Vector3 rotation, Vector3 scale, - float[] syncValues, string guid, string instanceId, - Span subSyncValues, int numSyncValues, int syncType = 0) - { - CVRSyncHelper.PropData propData = CVRSyncHelper.Props.Find(prop => prop.InstanceId == instanceId); - if (propData == null) return; - - // Update locally stored prop data with new values - // as GS does not reply with our own data... - - propData.PositionX = position.x; - propData.PositionY = position.y; - propData.PositionZ = position.z; - propData.RotationX = rotation.x; - propData.RotationY = rotation.y; - propData.RotationZ = rotation.z; - propData.ScaleX = scale.x; - propData.ScaleY = scale.y; - propData.ScaleZ = scale.z; - propData.CustomFloatsAmount = numSyncValues; - for (int i = 0; i < numSyncValues; i++) - propData.CustomFloats[i] = syncValues[i]; - - //propData.SpawnedBy - propData.syncedBy = MetaPort.Instance.ownerId; - propData.syncType = syncType; - } } \ No newline at end of file diff --git a/.Experimental/LuaNetworkVariables/Properties/AssemblyInfo.cs b/.Experimental/LuaNetworkVariables/Properties/AssemblyInfo.cs index 4cc49cf..84217ef 100644 --- a/.Experimental/LuaNetworkVariables/Properties/AssemblyInfo.cs +++ b/.Experimental/LuaNetworkVariables/Properties/AssemblyInfo.cs @@ -14,7 +14,7 @@ using System.Reflection; nameof(NAK.LuaNetVars), AssemblyInfoParams.Version, AssemblyInfoParams.Author, - downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/WhereAmIPointing" + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/LuaNetworkVariables" )] [assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.LuaNetVars.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.0"; + public const string Version = "1.0.1"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/.Experimental/LuaNetworkVariables/SyncedBehaviour/MNSyncedBehaviour.cs b/.Experimental/LuaNetworkVariables/SyncedBehaviour/MNSyncedBehaviour.cs deleted file mode 100644 index 3576155..0000000 --- a/.Experimental/LuaNetworkVariables/SyncedBehaviour/MNSyncedBehaviour.cs +++ /dev/null @@ -1,326 +0,0 @@ -using UnityEngine; -using System; -using System.Collections.Generic; -using System.Threading; -using ABI_RC.Core.Savior; -using ABI_RC.Systems.ModNetwork; - -namespace NAK.LuaNetVars -{ - public abstract class MNSyncedBehaviour : IDisposable - { - // Add static property for clarity - protected static string LocalUserId => MetaPort.Instance.ownerId; - - protected enum MessageType : byte - { - OwnershipRequest, - OwnershipResponse, - OwnershipTransfer, - StateRequest, - StateUpdate, - CustomData - } - - protected enum OwnershipResponse : byte - { - Accepted, - Rejected - } - - protected readonly string networkId; - protected string currentOwnerId; - private readonly bool autoAcceptTransfers; - private readonly Dictionary> pendingRequests; - private bool isInitialized; - private bool disposedValue; - private bool isSoftOwner = false; - private Timer stateRequestTimer; - private const int StateRequestTimeout = 3000; // 3 seconds - - public string CurrentOwnerId => currentOwnerId; - public bool HasOwnership => currentOwnerId == LocalUserId; - - protected MNSyncedBehaviour(string networkId, string currentOwnerId = "", bool autoAcceptTransfers = false) - { - this.networkId = networkId; - this.currentOwnerId = currentOwnerId; - this.autoAcceptTransfers = autoAcceptTransfers; - this.pendingRequests = new Dictionary>(); - - ModNetworkManager.Subscribe(networkId, OnMessageReceived); - - if (!HasOwnership) - RequestInitialState(); - else - isInitialized = true; - } - - private void RequestInitialState() - { - using ModNetworkMessage msg = new(networkId); - msg.Write((byte)MessageType.StateRequest); - msg.Send(); - - stateRequestTimer = new Timer(StateRequestTimeoutCallback, null, StateRequestTimeout, Timeout.Infinite); - } - - private void StateRequestTimeoutCallback(object state) - { - // If isInitialized is still false, we assume soft ownership - if (!isInitialized) - { - currentOwnerId = LocalUserId; - isSoftOwner = true; - isInitialized = true; - OnOwnershipChanged(currentOwnerId); - } - - stateRequestTimer.Dispose(); - stateRequestTimer = null; - } - - public virtual void RequestOwnership(Action callback = null) - { - if (HasOwnership) - { - callback?.Invoke(true); - return; - } - - using (ModNetworkMessage msg = new(networkId)) - { - msg.Write((byte)MessageType.OwnershipRequest); - msg.Send(); - } - - if (callback != null) - { - pendingRequests[LocalUserId] = callback; - } - } - - protected void SendNetworkedData(Action writeData) - { - if (!HasOwnership) - { - Debug.LogWarning($"[MNSyncedBehaviour] Cannot send data without ownership. NetworkId: {networkId}"); - return; - } - - using (ModNetworkMessage msg = new(networkId)) - { - msg.Write((byte)MessageType.CustomData); - writeData(msg); - msg.Send(); - } - } - - protected virtual void OnMessageReceived(ModNetworkMessage message) - { - message.Read(out byte type); - MessageType messageType = (MessageType)type; - - if (!Enum.IsDefined(typeof(MessageType), messageType)) - return; - - switch (messageType) - { - case MessageType.OwnershipRequest: - if (!HasOwnership) break; - HandleOwnershipRequest(message); - break; - - case MessageType.OwnershipResponse: - if (message.Sender != currentOwnerId) break; - HandleOwnershipResponse(message); - break; - - case MessageType.OwnershipTransfer: - if (message.Sender != currentOwnerId) break; - currentOwnerId = message.Sender; - OnOwnershipChanged(currentOwnerId); - break; - - case MessageType.StateRequest: - if (!HasOwnership) break; // this is the only safeguard against ownership hijacking... idk how to prevent it - // TODO: only respond to a StateUpdate if expecting one - HandleStateRequest(message); - break; - - case MessageType.StateUpdate: - // Accept state updates from current owner or if we have soft ownership - if (message.Sender != currentOwnerId && !isSoftOwner) break; - HandleStateUpdate(message); - break; - - case MessageType.CustomData: - if (message.Sender != currentOwnerId) - { - // If we have soft ownership and receive data from real owner, accept it - if (isSoftOwner && message.Sender != LocalUserId) - { - currentOwnerId = message.Sender; - isSoftOwner = false; - OnOwnershipChanged(currentOwnerId); - } - else - { - // Ignore data from non-owner - break; - } - } - HandleCustomData(message); - break; - } - } - - protected virtual void HandleOwnershipRequest(ModNetworkMessage message) - { - if (!HasOwnership) - return; - - string requesterId = message.Sender; - var response = autoAcceptTransfers ? OwnershipResponse.Accepted : - OnOwnershipRequested(requesterId); - - using (ModNetworkMessage responseMsg = new(networkId)) - { - responseMsg.Write((byte)MessageType.OwnershipResponse); - responseMsg.Write((byte)response); - responseMsg.Send(); - } - - if (response == OwnershipResponse.Accepted) - { - TransferOwnership(requesterId); - } - } - - protected virtual void HandleOwnershipResponse(ModNetworkMessage message) - { - message.Read(out byte responseByte); - OwnershipResponse response = (OwnershipResponse)responseByte; - - if (pendingRequests.TryGetValue(LocalUserId, out var callback)) - { - bool accepted = response == OwnershipResponse.Accepted; - callback(accepted); - pendingRequests.Remove(LocalUserId); - - // Update ownership locally only if accepted - if (accepted) - { - currentOwnerId = LocalUserId; - OnOwnershipChanged(currentOwnerId); - } - } - } - - protected virtual void HandleStateRequest(ModNetworkMessage message) - { - if (!HasOwnership) - return; - - using ModNetworkMessage response = new(networkId, message.Sender); - response.Write((byte)MessageType.StateUpdate); - WriteState(response); - response.Send(); - } - - protected virtual void HandleStateUpdate(ModNetworkMessage message) - { - currentOwnerId = message.Sender; - isSoftOwner = false; - ReadState(message); - isInitialized = true; - - // Dispose of the state request timer if it's still running - if (stateRequestTimer != null) - { - stateRequestTimer.Dispose(); - stateRequestTimer = null; - } - } - - protected virtual void HandleCustomData(ModNetworkMessage message) - { - if (!isInitialized) - { - Debug.LogWarning($"[MNSyncedBehaviour] Received custom data before initialization. NetworkId: {networkId}"); - return; - } - - if (message.Sender != currentOwnerId) - { - // If we have soft ownership and receive data from real owner, accept it - if (isSoftOwner && message.Sender != LocalUserId) - { - currentOwnerId = message.Sender; - isSoftOwner = false; - OnOwnershipChanged(currentOwnerId); - } - else - { - // Ignore data from non-owner - return; - } - } - - ReadCustomData(message); - } - - protected virtual void TransferOwnership(string newOwnerId) - { - using (ModNetworkMessage msg = new(networkId)) - { - msg.Write((byte)MessageType.OwnershipTransfer); - msg.Write(newOwnerId); // Include the new owner ID in transfer message - msg.Send(); - } - - currentOwnerId = newOwnerId; - OnOwnershipChanged(newOwnerId); - } - - protected virtual OwnershipResponse OnOwnershipRequested(string requesterId) - { - return OwnershipResponse.Rejected; - } - - protected virtual void OnOwnershipChanged(string newOwnerId) - { - // Override to handle ownership changes - } - - protected virtual void WriteState(ModNetworkMessage message) { } - protected virtual void ReadState(ModNetworkMessage message) { } - protected virtual void ReadCustomData(ModNetworkMessage message) { } - - protected virtual void Dispose(bool disposing) - { - if (disposedValue) - return; - - if (disposing) - { - ModNetworkManager.Unsubscribe(networkId); - pendingRequests.Clear(); - - if (stateRequestTimer != null) - { - stateRequestTimer.Dispose(); - stateRequestTimer = null; - } - } - - disposedValue = true; - } - - public void Dispose() - { - Dispose(disposing: true); - GC.SuppressFinalize(this); - } - } -} \ No newline at end of file diff --git a/.Experimental/LuaNetworkVariables/SyncedBehaviour/TestSyncedBehaviour.cs b/.Experimental/LuaNetworkVariables/SyncedBehaviour/TestSyncedBehaviour.cs deleted file mode 100644 index 4941aaa..0000000 --- a/.Experimental/LuaNetworkVariables/SyncedBehaviour/TestSyncedBehaviour.cs +++ /dev/null @@ -1,63 +0,0 @@ -using ABI_RC.Systems.ModNetwork; -using UnityEngine; - -namespace NAK.LuaNetVars; - - -// Test implementation -public class TestSyncedBehaviour : MNSyncedBehaviour -{ - private readonly System.Random random = new(); - private int testValue; - private int incrementValue; - - public TestSyncedBehaviour(string networkId) : base(networkId, autoAcceptTransfers: true) - { - Debug.Log($"[TestSyncedBehaviour] Initialized. NetworkId: {networkId}"); - } - - public void SendTestMessage() - { - if (!HasOwnership) return; - - SendNetworkedData(msg => { - testValue = random.Next(1000); - incrementValue++; - msg.Write(testValue); - msg.Write(incrementValue); - }); - } - - protected override void WriteState(ModNetworkMessage message) - { - message.Write(testValue); - message.Write(incrementValue); - } - - protected override void ReadState(ModNetworkMessage message) - { - message.Read(out testValue); - message.Read(out incrementValue); - Debug.Log($"[TestSyncedBehaviour] State synchronized. TestValue: {testValue}, IncrementValue: {incrementValue}"); - } - - protected override void ReadCustomData(ModNetworkMessage message) - { - message.Read(out int receivedValue); - message.Read(out int receivedIncrement); - testValue = receivedValue; - incrementValue = receivedIncrement; - Debug.Log($"[TestSyncedBehaviour] Received custom data: TestValue: {testValue}, IncrementValue: {incrementValue}"); - } - - protected override void OnOwnershipChanged(string newOwnerId) - { - Debug.Log($"[TestSyncedBehaviour] Ownership changed to: {newOwnerId}"); - } - - protected override OwnershipResponse OnOwnershipRequested(string requesterId) - { - Debug.Log($"[TestSyncedBehaviour] Ownership requested by: {requesterId}"); - return OwnershipResponse.Accepted; - } -} \ No newline at end of file diff --git a/.Experimental/LuaNetworkVariables/SyncedBehaviour/TestSyncedObject.cs b/.Experimental/LuaNetworkVariables/SyncedBehaviour/TestSyncedObject.cs deleted file mode 100644 index 76d6281..0000000 --- a/.Experimental/LuaNetworkVariables/SyncedBehaviour/TestSyncedObject.cs +++ /dev/null @@ -1,42 +0,0 @@ -using ABI_RC.Core.Savior; -using UnityEngine; - -namespace NAK.LuaNetVars; - -public class TestSyncedObject : MonoBehaviour -{ - private const string TEST_NETWORK_ID = "test.synced.object.1"; - private TestSyncedBehaviour syncBehaviour; - private float messageTimer = 0f; - private const float MESSAGE_INTERVAL = 2f; - - private void Start() - { - syncBehaviour = new TestSyncedBehaviour(TEST_NETWORK_ID); - Debug.Log($"TestSyncedObject started. Local Player ID: {MetaPort.Instance.ownerId}"); - } - - private void Update() - { - // Request ownership on Space key - if (Input.GetKeyDown(KeyCode.Space)) - { - Debug.Log("Requesting ownership..."); - syncBehaviour.RequestOwnership((success) => - { - Debug.Log($"Ownership request {(success ? "accepted" : "rejected")}"); - }); - } - - // If we have ownership, send custom data periodically - if (syncBehaviour.HasOwnership) - { - messageTimer += Time.deltaTime; - if (messageTimer >= MESSAGE_INTERVAL) - { - messageTimer = 0f; - syncBehaviour.SendTestMessage(); - } - } - } -} \ No newline at end of file From 0f6006db832d7877ef8dd3ada24b1f4664c53d89 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 24 Apr 2025 21:14:17 -0500 Subject: [PATCH 085/119] [CVRLuaToolsExtension] kinda fix --- .../Extensions/CVRLuaClientBehaviourExtensions.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.Experimental/CVRLuaToolsExtension/LuaToolsExtension/Extensions/CVRLuaClientBehaviourExtensions.cs b/.Experimental/CVRLuaToolsExtension/LuaToolsExtension/Extensions/CVRLuaClientBehaviourExtensions.cs index 8c07542..5dc7b86 100644 --- a/.Experimental/CVRLuaToolsExtension/LuaToolsExtension/Extensions/CVRLuaClientBehaviourExtensions.cs +++ b/.Experimental/CVRLuaToolsExtension/LuaToolsExtension/Extensions/CVRLuaClientBehaviourExtensions.cs @@ -1,6 +1,7 @@ using ABI.CCK.Components; using ABI.Scripting.CVRSTL.Client; using System.Diagnostics; +using ABI_RC.Scripting.Persistence; using MTJobSystem; using UnityEngine; @@ -108,8 +109,11 @@ public static class CVRLuaClientBehaviourExtensions behaviour._startupMessageQueue.Clear(); // will be repopulated behaviour.LogInfo("[CVRLuaToolsExtension] Resetting script...\n"); + // remove the script from the persistence manager, as the storage needs to be reinitialized + PersistenceManager.HandleUnsubscribe(behaviour.Storage, behaviour.script, behaviour.Context.ParentContent.ContentType, behaviour.Context.AssetID); + behaviour.script = null; - behaviour.script = LuaScriptFactory.ForLuaBehaviour(behaviour, boundObjectEntries, behaviour.gameObject, behaviour.transform, PersistentDataPath); + behaviour.script = LuaScriptFactory.ForLuaBehaviour(behaviour, boundObjectEntries, behaviour.gameObject, behaviour.transform); behaviour.InitTimerIfNeeded(); // only null if crashed prior behaviour.script.AttachDebugger(behaviour.timer); // reattach the debugger From 3521453010d663b473ebaa420a51dd1209964510 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 24 Apr 2025 21:14:35 -0500 Subject: [PATCH 086/119] [ASTExtension] Fix no supported parameter found spam --- ASTExtension/Main.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ASTExtension/Main.cs b/ASTExtension/Main.cs index f7b7115..461dc16 100644 --- a/ASTExtension/Main.cs +++ b/ASTExtension/Main.cs @@ -121,7 +121,8 @@ public class ASTExtensionMod : MelonMod private void OnLocalAvatarLoad() { - if (!FindSupportedParameter(out string parameterName)) + _currentAvatarSupported = FindSupportedParameter(out string parameterName); + if (!_currentAvatarSupported) return; if (!AttemptCalibrateParameter(parameterName, out float minHeight, out float maxHeight, out float modifier)) From da6520beb0ce858788fe0ef03211fc9b8f74e1fc Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 24 Apr 2025 21:14:49 -0500 Subject: [PATCH 087/119] [ConfigureCalibrationPose] initial builds --- .../ConfigureCalibrationPose.csproj | 6 + ConfigureCalibrationPose/Main.cs | 543 ++++++++++++++++++ .../Properties/AssemblyInfo.cs | 32 ++ ConfigureCalibrationPose/README.md | 14 + ConfigureCalibrationPose/format.json | 23 + 5 files changed, 618 insertions(+) create mode 100644 ConfigureCalibrationPose/ConfigureCalibrationPose.csproj create mode 100644 ConfigureCalibrationPose/Main.cs create mode 100644 ConfigureCalibrationPose/Properties/AssemblyInfo.cs create mode 100644 ConfigureCalibrationPose/README.md create mode 100644 ConfigureCalibrationPose/format.json diff --git a/ConfigureCalibrationPose/ConfigureCalibrationPose.csproj b/ConfigureCalibrationPose/ConfigureCalibrationPose.csproj new file mode 100644 index 0000000..5a8badc --- /dev/null +++ b/ConfigureCalibrationPose/ConfigureCalibrationPose.csproj @@ -0,0 +1,6 @@ + + + + YouAreMineNow + + diff --git a/ConfigureCalibrationPose/Main.cs b/ConfigureCalibrationPose/Main.cs new file mode 100644 index 0000000..179f7e4 --- /dev/null +++ b/ConfigureCalibrationPose/Main.cs @@ -0,0 +1,543 @@ +using System.Reflection; +using ABI_RC.Core.Player; +using ABI_RC.Systems.IK; +using ABI_RC.Systems.IK.SubSystems; +using ABI_RC.Systems.InputManagement; +using ABI_RC.Systems.Movement; +using HarmonyLib; +using MelonLoader; +using RootMotion.FinalIK; +using UnityEngine; + +namespace NAK.ConfigureCalibrationPose; + +public class ConfigureCalibrationPoseMod : MelonMod +{ + #region Enums + + private enum CalibrationPose + { + TPose, + APose, + IKPose, + BikePose, + RacushSit, + CCKSitting, + CCKCrouch, + CCKProne, + } + + #endregion Enums + + #region Melon Preferences + + private static readonly MelonPreferences_Category Category = + MelonPreferences.CreateCategory(nameof(ConfigureCalibrationPose)); + + private static readonly MelonPreferences_Entry EntryCalibrationPose = + Category.CreateEntry("calibration_pose", CalibrationPose.APose, display_name: "Calibration Pose", + description: "What pose to use for FBT calibration."); + + #endregion Melon Preferences + + #region Melon Events + + public override void OnInitializeMelon() + { + #region BodySystem Patches + + HarmonyInstance.Patch( + typeof(BodySystem).GetMethod(nameof(BodySystem.MuscleUpdate), + BindingFlags.Public | BindingFlags.Instance), + prefix: new HarmonyMethod(typeof(ConfigureCalibrationPoseMod).GetMethod(nameof(OnPreBodySystemMuscleUpdate), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + #endregion BodySystem Patches + } + + #endregion Melon Events + + #region Harmony Patches + + private static bool OnPreBodySystemMuscleUpdate(ref float[] muscles) + { + PlayerSetup playerSetup = PlayerSetup.Instance; + IKSystem ikSystem = IKSystem.Instance; + ref HumanPose humanPose = ref ikSystem._humanPose; + + if (BodySystem.isCalibrating) + { + switch (EntryCalibrationPose.Value) + { + default: + case CalibrationPose.TPose: + for (int i = 0; i < MusclePoses.TPoseMuscles.Length; i++) + ikSystem.ApplyMuscleValue((MuscleIndex) i, MusclePoses.TPoseMuscles[i], ref muscles); + break; + case CalibrationPose.APose: + for (int i = 0; i < MusclePoses.APoseMuscles.Length; i++) + ikSystem.ApplyMuscleValue((MuscleIndex) i, MusclePoses.APoseMuscles[i], ref muscles); + break; + case CalibrationPose.IKPose: + for (int i = 0; i < MusclePoses.IKPoseMuscles.Length; i++) + ikSystem.ApplyMuscleValue((MuscleIndex) i, MusclePoses.IKPoseMuscles[i], ref muscles); + break; + case CalibrationPose.BikePose: + for (int i = 0; i < MusclePoses.TPoseMuscles.Length; i++) + ikSystem.ApplyMuscleValue((MuscleIndex) i, 0f, ref muscles); + break; + case CalibrationPose.CCKSitting: + for (int i = 0; i < CCKSittingMuscles.Length; i++) + ikSystem.ApplyMuscleValue((MuscleIndex) i, CCKSittingMuscles[i], ref muscles); + break; + case CalibrationPose.CCKCrouch: + for (int i = 0; i < CCKCrouchMuscles.Length; i++) + ikSystem.ApplyMuscleValue((MuscleIndex) i, CCKCrouchMuscles[i], ref muscles); + break; + case CalibrationPose.CCKProne: + for (int i = 0; i < CCKProneMuscles.Length; i++) + ikSystem.ApplyMuscleValue((MuscleIndex) i, CCKProneMuscles[i], ref muscles); + break; + case CalibrationPose.RacushSit: + for (int i = 0; i < RacushSitMuscles.Length; i++) + ikSystem.ApplyMuscleValue((MuscleIndex) i, RacushSitMuscles[i], ref muscles); + break; + } + + humanPose.bodyPosition = Vector3.up; + humanPose.bodyRotation = Quaternion.identity; + } + else if (BodySystem.isCalibratedAsFullBody && BodySystem.TrackingPositionWeight > 0f) + { + BetterBetterCharacterController characterController = playerSetup.CharacterController; + + bool isRunning = characterController.IsMoving(); + bool isGrounded = characterController.IsGrounded(); + bool isFlying = characterController.IsFlying(); + bool isSwimming = characterController.IsSwimming(); + + if ((BodySystem.PlayRunningAnimationInFullBody + && (isRunning || !isGrounded && !isFlying && !isSwimming))) + { + ikSystem.applyOriginalHipPosition = true; + ikSystem.applyOriginalHipRotation = true; + + IKSolverVR solver = IKSystem.vrik.solver; + BodySystem.SetPelvisWeight(solver.spine, 0f); + BodySystem.SetLegWeight(solver.leftLeg, 0f); + BodySystem.SetLegWeight(solver.rightLeg, 0f); + } + else + { + ikSystem.applyOriginalHipPosition = true; + ikSystem.applyOriginalHipRotation = false; + humanPose.bodyRotation = Quaternion.identity; + } + } + + return false; // dont run original + } + + #endregion Harmony Patches + + #region Custom Pose Arrays + + private static readonly float[] CCKSittingMuscles = + [ + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + -0.8000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + -0.8000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + -1.0000f, + 0.0000f, + -0.3000f, + 0.3000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + -1.0000f, + 0.0000f, + -0.3000f, + 0.3000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f + ]; + + private static readonly float[] CCKCrouchMuscles = + [ + -1.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.5000f, + 0.0000f, + 0.0000f, + 0.5000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + -0.6279f, + 0.0000f, + 0.0000f, + -0.8095f, + 0.0000f, + -1.0091f, + 0.0000f, + 0.0000f, + -0.4126f, + 0.0013f, + -0.0860f, + -0.9331f, + -0.0869f, + -1.3586f, + 0.1791f, + 0.0000f, + 0.0000f, + 0.0000f, + -0.1998f, + -0.2300f, + 0.1189f, + 0.3479f, + 0.1364f, + -0.3737f, + 0.0069f, + 0.0000f, + 0.0000f, + -0.1994f, + -0.2301f, + 0.0267f, + 0.7532f, + 0.1922f, + 0.0009f, + -0.0005f, + -1.4747f, + -0.0443f, + -0.3347f, + -0.3062f, + -0.7596f, + -1.2067f, + -0.7329f, + -0.7329f, + -0.5984f, + -2.7162f, + -0.7439f, + -0.7439f, + -0.5812f, + 1.8528f, + -0.7520f, + -0.7520f, + -0.7242f, + 0.5912f, + -0.7632f, + -0.7632f, + -1.4747f, + -0.0443f, + -0.3347f, + -0.3062f, + -0.7596f, + -1.2067f, + -0.7329f, + -0.7329f, + -0.5984f, + -2.7162f, + -0.7439f, + -0.7439f, + -0.5812f, + 1.8528f, + -0.7520f, + 0.8104f, + -0.7242f, + 0.5912f, + -0.7632f, + 0.8105f + ]; + + private static readonly float[] CCKProneMuscles = + [ + 0.6604f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.7083f, + 0.0000f, + 0.0000f, + 0.7083f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.2444f, + -0.0554f, + -0.8192f, + 0.9301f, + 0.5034f, + 1.0274f, + -0.1198f, + 0.5849f, + 0.2360f, + -0.0837f, + -1.1803f, + 0.9676f, + 0.7390f, + 0.9944f, + -0.1717f, + 0.5849f, + 0.0000f, + 0.0000f, + 0.2823f, + -0.6297f, + 0.3200f, + -0.3376f, + 0.0714f, + 0.9260f, + -1.5768f, + 0.0000f, + 0.0000f, + 0.1561f, + -0.6712f, + 0.2997f, + -0.3392f, + 0.0247f, + 0.7672f, + -1.5269f, + -1.1422f, + 0.0392f, + 0.6457f, + 0.0000f, + 0.6185f, + -0.5393f, + 0.8104f, + 0.8104f, + 0.6223f, + -0.8225f, + 0.8104f, + 0.8104f, + 0.6218f, + -0.3961f, + 0.8104f, + 0.8104f, + 0.6160f, + -0.3721f, + 0.8105f, + 0.8105f, + -1.1422f, + 0.0392f, + 0.6457f, + 0.0000f, + 0.6185f, + -0.5393f, + 0.8104f, + 0.8104f, + 0.6223f, + -0.8226f, + 0.8104f, + 0.8104f, + 0.6218f, + -0.3961f, + 0.8104f, + 0.8104f, + 0.6160f, + -0.3721f, + 0.8105f, + 0.8105f + ]; + + private static readonly float[] RacushSitMuscles = + [ + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + -0.7500f, + -0.0002f, + 0.1599f, + -0.1500f, + 0.1000f, + 0.1300f, + -0.0001f, + 0.0000f, + -0.7500f, + -0.0002f, + 0.1599f, + -0.1500f, + 0.1000f, + 0.1300f, + -0.0001f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.3927f, + 0.3114f, + 0.0805f, + 0.9650f, + -0.0536f, + 0.0024f, + 0.0005f, + 0.0000f, + 0.0000f, + 0.3928f, + 0.3114f, + 0.0805f, + 0.9650f, + -0.0536f, + 0.0024f, + 0.0005f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f, + 0.0000f + ]; + + #endregion Custom Pose Arrays +} \ No newline at end of file diff --git a/ConfigureCalibrationPose/Properties/AssemblyInfo.cs b/ConfigureCalibrationPose/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..1fdc09d --- /dev/null +++ b/ConfigureCalibrationPose/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using MelonLoader; +using NAK.ConfigureCalibrationPose.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.ConfigureCalibrationPose))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.ConfigureCalibrationPose))] + +[assembly: MelonInfo( + typeof(NAK.ConfigureCalibrationPose.ConfigureCalibrationPoseMod), + nameof(NAK.ConfigureCalibrationPose), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ConfigureCalibrationPose" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red +[assembly: HarmonyDontPatchAll] + +namespace NAK.ConfigureCalibrationPose.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/ConfigureCalibrationPose/README.md b/ConfigureCalibrationPose/README.md new file mode 100644 index 0000000..f17ba48 --- /dev/null +++ b/ConfigureCalibrationPose/README.md @@ -0,0 +1,14 @@ +# ConfigureCalibrationPose + +Select FBT calibration pose. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation 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/ConfigureCalibrationPose/format.json b/ConfigureCalibrationPose/format.json new file mode 100644 index 0000000..6324d2b --- /dev/null +++ b/ConfigureCalibrationPose/format.json @@ -0,0 +1,23 @@ +{ + "_id": -1, + "name": "ConfigureCalibrationPose", + "modversion": "1.0.0", + "gameversion": "2025r179", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Lets you bring held & attached props through world loads.\nhttps://youtu.be/9P6Jeh-VN58?si=eXTPGyKB_0wq1gZO", + "searchtags": [ + "prop", + "spawn", + "friend", + "load" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ConfigureCalibrationPose.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ConfigureCalibrationPose/", + "changelog": "- Initial Release", + "embedcolor": "#00FFFF" +} \ No newline at end of file From abd7b9d67424348ac2b015077cc06324f9902196 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 25 Apr 2025 02:15:00 +0000 Subject: [PATCH 088/119] [NAK_CVR_Mods] Update mod list in README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e3217d1..39be991 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,10 @@ |------|-------------|----------| | [ASTExtension](ASTExtension/README.md) | Extension mod for [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool): | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ASTExtension.dll) | | [AvatarQueueSystemTweaks](AvatarQueueSystemTweaks/README.md) | Small tweaks to the Avatar Queue System. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/AvatarQueueSystemTweaks.dll) | +| [ConfigureCalibrationPose](ConfigureCalibrationPose/README.md) | Select FBT calibration pose. | No Download | | [CustomSpawnPoint](CustomSpawnPoint/README.md) | Replaces the unused Images button in the World Details page with a button to set a custom spawn point. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/CustomSpawnPoint.dll) | | [DoubleTapJumpToExitSeat](DoubleTapJumpToExitSeat/README.md) | Replaces seat exit controls with a double-tap of the jump button, avoiding accidental exits from joystick drift or opening the menu. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/DoubleTapJumpToExitSeat.dll) | -| [FuckToes](FuckToes/README.md) | Prevents VRIK from autodetecting toes in Halfbody or Fullbody. | No Download | +| [FuckToes](FuckToes/README.md) | Prevents VRIK from autodetecting toes in Halfbody or Fullbody. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/FuckToes.dll) | | [KeepVelocityOnExitFlight](KeepVelocityOnExitFlight/README.md) | Keeps the player's velocity when exiting flight mode. Makes it possible to fling yourself like in Garry's Mod. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/KeepVelocityOnExitFlight.dll) | | [LazyPrune](LazyPrune/README.md) | Prevents loaded objects from immediately unloading on destruction. Should prevent needlessly unloading & reloading all avatars/props on world rejoin or GS reconnection. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/LazyPrune.dll) | | [PropLoadingHexagon](PropLoadingHexagon/README.md) | https://github.com/NotAKidoS/NAK_CVR_Mods/assets/37721153/a892c765-71c1-47f3-a781-bdb9b60ba117 | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/PropLoadingHexagon.dll) | From bdf6b0e51a8a9e73082610c0190b9042cc9f634f Mon Sep 17 00:00:00 2001 From: SketchFoxsky <109103755+SketchFoxsky@users.noreply.github.com> Date: Thu, 24 Apr 2025 23:29:32 -0400 Subject: [PATCH 089/119] updated seated calibration --- ConfigureCalibrationPose/Main.cs | 50 ++++++++++++++++---------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/ConfigureCalibrationPose/Main.cs b/ConfigureCalibrationPose/Main.cs index 179f7e4..df677fd 100644 --- a/ConfigureCalibrationPose/Main.cs +++ b/ConfigureCalibrationPose/Main.cs @@ -101,10 +101,10 @@ public class ConfigureCalibrationPoseMod : MelonMod break; case CalibrationPose.RacushSit: for (int i = 0; i < RacushSitMuscles.Length; i++) - ikSystem.ApplyMuscleValue((MuscleIndex) i, RacushSitMuscles[i], ref muscles); + ikSystem.ApplyMuscleValue((MuscleIndex)i, RacushSitMuscles[i], ref muscles); break; } - + humanPose.bodyPosition = Vector3.up; humanPose.bodyRotation = Quaternion.identity; } @@ -439,8 +439,8 @@ public class ConfigureCalibrationPoseMod : MelonMod 0.8105f, 0.8105f ]; - - private static readonly float[] RacushSitMuscles = + + public static readonly float[] RacushSitMuscles = [ 0.0000f, 0.0000f, @@ -463,40 +463,40 @@ public class ConfigureCalibrationPoseMod : MelonMod 0.0000f, 0.0000f, 0.0000f, - -0.7500f, - -0.0002f, - 0.1599f, - -0.1500f, + -0.7600f, 0.1000f, + 0.0600f, + -0.1800f, + -0.0991f, 0.1300f, - -0.0001f, + 0.0001f, 0.0000f, - -0.7500f, - -0.0002f, - 0.1599f, - -0.1500f, + -0.7600f, 0.1000f, + 0.0600f, + -0.1800f, + -0.0991f, 0.1300f, - -0.0001f, + 0.0001f, 0.0000f, 0.0000f, 0.0000f, 0.3927f, - 0.3114f, - 0.0805f, + 0.3115f, + 0.0931f, 0.9650f, - -0.0536f, - 0.0024f, - 0.0005f, + -0.0662f, + 0.0026f, + 0.0006f, 0.0000f, 0.0000f, - 0.3928f, - 0.3114f, - 0.0805f, + 0.3927f, + 0.3115f, + 0.0931f, 0.9650f, - -0.0536f, - 0.0024f, - 0.0005f, + -0.0662f, + 0.0026f, + 0.0006f, 0.0000f, 0.0000f, 0.0000f, From d54ec06190e0f235fc0ee16770387e90dab3f52a Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Tue, 29 Apr 2025 00:33:43 -0500 Subject: [PATCH 090/119] [ShareBubbles] no send shit if no people --- NAK_CVR_Mods.sln | 24 +++++++++++++++++++ .../ShareBubbles/API/ShareApiHelper.cs | 1 + .../Networking/ModNetwork.Helpers.cs | 5 +++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/NAK_CVR_Mods.sln b/NAK_CVR_Mods.sln index eb7c1a3..1541fc7 100644 --- a/NAK_CVR_Mods.sln +++ b/NAK_CVR_Mods.sln @@ -60,6 +60,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DoubleTapJumpToExitSeat", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FuckToes", "FuckToes\FuckToes.csproj", "{751E4140-2F4D-4550-A4A9-65ABA9F7893A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuaNetworkVariables", ".Experimental\LuaNetworkVariables\LuaNetworkVariables.csproj", "{6E7857D9-07AC-419F-B111-0DB0348D1C92}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TouchySquishy", ".Blackbox\TouchySquishy\TouchySquishy.csproj", "{FF4BF0E7-698D-49A0-96E9-0E2646FEAFFA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CVRLuaToolsExtension", ".Experimental\CVRLuaToolsExtension\CVRLuaToolsExtension.csproj", "{3D221A25-007F-4764-98CD-CEEF2EB92165}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConfigureCalibrationPose", "ConfigureCalibrationPose\ConfigureCalibrationPose.csproj", "{31667A36-D069-4708-9DCA-E3446009941B}" +EndProject EndProject EndProject EndProject @@ -307,6 +315,22 @@ Global {751E4140-2F4D-4550-A4A9-65ABA9F7893A}.Debug|Any CPU.Build.0 = Debug|Any CPU {751E4140-2F4D-4550-A4A9-65ABA9F7893A}.Release|Any CPU.ActiveCfg = Release|Any CPU {751E4140-2F4D-4550-A4A9-65ABA9F7893A}.Release|Any CPU.Build.0 = Release|Any CPU + {6E7857D9-07AC-419F-B111-0DB0348D1C92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6E7857D9-07AC-419F-B111-0DB0348D1C92}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6E7857D9-07AC-419F-B111-0DB0348D1C92}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6E7857D9-07AC-419F-B111-0DB0348D1C92}.Release|Any CPU.Build.0 = Release|Any CPU + {FF4BF0E7-698D-49A0-96E9-0E2646FEAFFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FF4BF0E7-698D-49A0-96E9-0E2646FEAFFA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FF4BF0E7-698D-49A0-96E9-0E2646FEAFFA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FF4BF0E7-698D-49A0-96E9-0E2646FEAFFA}.Release|Any CPU.Build.0 = Release|Any CPU + {3D221A25-007F-4764-98CD-CEEF2EB92165}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3D221A25-007F-4764-98CD-CEEF2EB92165}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3D221A25-007F-4764-98CD-CEEF2EB92165}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3D221A25-007F-4764-98CD-CEEF2EB92165}.Release|Any CPU.Build.0 = Release|Any CPU + {31667A36-D069-4708-9DCA-E3446009941B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {31667A36-D069-4708-9DCA-E3446009941B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {31667A36-D069-4708-9DCA-E3446009941B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {31667A36-D069-4708-9DCA-E3446009941B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ShareBubbles/ShareBubbles/API/ShareApiHelper.cs b/ShareBubbles/ShareBubbles/API/ShareApiHelper.cs index 3200deb..c338930 100644 --- a/ShareBubbles/ShareBubbles/API/ShareApiHelper.cs +++ b/ShareBubbles/ShareBubbles/API/ShareApiHelper.cs @@ -1,4 +1,5 @@ using System.Net; +using System.Net.Http; using System.Text; using System.Web; using ABI_RC.Core.Networking; diff --git a/ShareBubbles/ShareBubbles/Networking/ModNetwork.Helpers.cs b/ShareBubbles/ShareBubbles/Networking/ModNetwork.Helpers.cs index 3ee6e81..e65a178 100644 --- a/ShareBubbles/ShareBubbles/Networking/ModNetwork.Helpers.cs +++ b/ShareBubbles/ShareBubbles/Networking/ModNetwork.Helpers.cs @@ -1,4 +1,5 @@ using ABI_RC.Core.Networking; +using ABI_RC.Core.Player; using DarkRift; using UnityEngine; @@ -9,7 +10,9 @@ public static partial class ModNetwork #region Private Methods private static bool CanSendModNetworkMessage() - => _isSubscribedToModNetwork && IsConnectedToGameNetwork(); + => _isSubscribedToModNetwork + && IsConnectedToGameNetwork() + && CVRPlayerManager.Instance.NetworkPlayers.Count > 0; // No need to send if there are no players private static bool IsConnectedToGameNetwork() { From 0a01534aa4d5226e0f079e02cf59b4c3fb05e07b Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 8 May 2025 17:15:52 -0500 Subject: [PATCH 091/119] [LuaNetworkVariables] rename classes --- .Experimental/LuaNetworkVariables/Main.cs | 4 +- .../LuaNetworkVariables/NetLuaModule.cs | 16 ++-- .../NetworkVariables/LuaEventContext.cs | 2 +- .../NetworkVariables/LuaEventTracker.cs | 2 +- .../LuaNetVarController.Base.cs | 8 +- .../LuaNetVarController.Networking.cs | 16 ++-- .../LuaNetVarController.Registration.cs | 20 ++--- .../LuaNetVarController.Serialization.cs | 6 +- .../LuaNetVarController.Utility.cs | 6 +- .Experimental/LuaNetworkVariables/Patches.cs | 4 +- .../Properties/AssemblyInfo.cs | 14 ++-- .Experimental/LuaNetworkVariables/README.md | 75 ++++++++++++++++++- 12 files changed, 122 insertions(+), 51 deletions(-) diff --git a/.Experimental/LuaNetworkVariables/Main.cs b/.Experimental/LuaNetworkVariables/Main.cs index 2a8b2fb..ce59fa0 100644 --- a/.Experimental/LuaNetworkVariables/Main.cs +++ b/.Experimental/LuaNetworkVariables/Main.cs @@ -2,9 +2,9 @@ using MelonLoader; using UnityEngine; -namespace NAK.LuaNetVars; +namespace NAK.LuaNetworkVariables; -public class LuaNetVarsMod : MelonMod +public class LuaNetworkVariablesMod : MelonMod { internal static MelonLogger.Instance Logger; diff --git a/.Experimental/LuaNetworkVariables/NetLuaModule.cs b/.Experimental/LuaNetworkVariables/NetLuaModule.cs index b13bc9b..23855ed 100644 --- a/.Experimental/LuaNetworkVariables/NetLuaModule.cs +++ b/.Experimental/LuaNetworkVariables/NetLuaModule.cs @@ -3,7 +3,7 @@ using ABI.Scripting.CVRSTL.Common; using JetBrains.Annotations; using MoonSharp.Interpreter; -namespace NAK.LuaNetVars.Modules; +namespace NAK.LuaNetworkVariables.Modules; [PublicAPI] public class LuaNetModule : BaseScriptedStaticWrapper @@ -37,7 +37,7 @@ public class LuaNetModule : BaseScriptedStaticWrapper if (_controller == null) { - LuaNetVarsMod.Logger.Error("LuaNetVarController is null."); + LuaNetworkVariablesMod.Logger.Error("LuaNetVarController is null."); return; } @@ -56,7 +56,7 @@ public class LuaNetModule : BaseScriptedStaticWrapper if (_controller == null) { - LuaNetVarsMod.Logger.Error("LuaNetVarController is null."); + LuaNetworkVariablesMod.Logger.Error("LuaNetVarController is null."); return; } @@ -75,7 +75,7 @@ public class LuaNetModule : BaseScriptedStaticWrapper if (_controller == null) { - LuaNetVarsMod.Logger.Error("LuaNetVarController is null."); + LuaNetworkVariablesMod.Logger.Error("LuaNetVarController is null."); return; } @@ -94,7 +94,7 @@ public class LuaNetModule : BaseScriptedStaticWrapper if (_controller == null) { - LuaNetVarsMod.Logger.Error("LuaNetVarController is null."); + LuaNetworkVariablesMod.Logger.Error("LuaNetVarController is null."); return; } @@ -113,7 +113,7 @@ public class LuaNetModule : BaseScriptedStaticWrapper if (_controller == null) { - LuaNetVarsMod.Logger.Error("LuaNetVarController is null."); + LuaNetworkVariablesMod.Logger.Error("LuaNetVarController is null."); return; } @@ -130,7 +130,7 @@ public class LuaNetModule : BaseScriptedStaticWrapper if (_controller == null) { - LuaNetVarsMod.Logger.Error("LuaNetVarController is null."); + LuaNetworkVariablesMod.Logger.Error("LuaNetVarController is null."); return false; } @@ -144,7 +144,7 @@ public class LuaNetModule : BaseScriptedStaticWrapper if (_controller == null) { - LuaNetVarsMod.Logger.Error("LuaNetVarController is null."); + LuaNetworkVariablesMod.Logger.Error("LuaNetVarController is null."); return string.Empty; } diff --git a/.Experimental/LuaNetworkVariables/NetworkVariables/LuaEventContext.cs b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaEventContext.cs index 6a3fd57..59b385e 100644 --- a/.Experimental/LuaNetworkVariables/NetworkVariables/LuaEventContext.cs +++ b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaEventContext.cs @@ -2,7 +2,7 @@ using MoonSharp.Interpreter; using ABI_RC.Core.Player; -namespace NAK.LuaNetVars; +namespace NAK.LuaNetworkVariables; public struct LuaEventContext { diff --git a/.Experimental/LuaNetworkVariables/NetworkVariables/LuaEventTracker.cs b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaEventTracker.cs index ed60cee..98f6322 100644 --- a/.Experimental/LuaNetworkVariables/NetworkVariables/LuaEventTracker.cs +++ b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaEventTracker.cs @@ -1,4 +1,4 @@ -namespace NAK.LuaNetVars; +namespace NAK.LuaNetworkVariables; internal class LuaEventTracker { diff --git a/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Base.cs b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Base.cs index 811fa9b..51e60e8 100644 --- a/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Base.cs +++ b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Base.cs @@ -7,7 +7,7 @@ using MoonSharp.Interpreter; using UnityEngine; using Coroutine = UnityEngine.Coroutine; -namespace NAK.LuaNetVars; +namespace NAK.LuaNetworkVariables; public partial class LuaNetVarController : MonoBehaviour { @@ -58,13 +58,13 @@ public partial class LuaNetVarController : MonoBehaviour if (ModNetworkID.Length > ModNetworkManager.MaxMessageIdLength) { - LuaNetVarsMod.Logger.Error($"ModNetworkID ({ModNetworkID}) exceeds max length of {ModNetworkManager.MaxMessageIdLength} characters!"); + LuaNetworkVariablesMod.Logger.Error($"ModNetworkID ({ModNetworkID}) exceeds max length of {ModNetworkManager.MaxMessageIdLength} characters!"); return false; } _hashes.Add(_uniquePathHash); ModNetworkManager.Subscribe(ModNetworkID, OnMessageReceived); - LuaNetVarsMod.Logger.Msg($"Registered LuaNetVarController with ModNetworkID: {ModNetworkID}"); + LuaNetworkVariablesMod.Logger.Msg($"Registered LuaNetVarController with ModNetworkID: {ModNetworkID}"); switch (_luaClientBehaviour.Context.objContext) { @@ -101,7 +101,7 @@ public partial class LuaNetVarController : MonoBehaviour return; ModNetworkManager.Unsubscribe(ModNetworkID); - LuaNetVarsMod.Logger.Msg($"Unsubscribed LuaNetVarController with ModNetworkID: {ModNetworkID}"); + LuaNetworkVariablesMod.Logger.Msg($"Unsubscribed LuaNetVarController with ModNetworkID: {ModNetworkID}"); _hashes.Remove(_uniquePathHash); } diff --git a/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Networking.cs b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Networking.cs index bed3bb8..a674987 100644 --- a/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Networking.cs +++ b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Networking.cs @@ -2,7 +2,7 @@ using ABI_RC.Systems.ModNetwork; using MoonSharp.Interpreter; -namespace NAK.LuaNetVars +namespace NAK.LuaNetworkVariables { public partial class LuaNetVarController { @@ -46,7 +46,7 @@ namespace NAK.LuaNetVars msg.Read(out string varName); DynValue newValue = DeserializeDynValue(msg); - LuaNetVarsMod.Logger.Msg($"Received LuaVariable update: {varName} = {newValue}"); + LuaNetworkVariablesMod.Logger.Msg($"Received LuaVariable update: {varName} = {newValue}"); if (_registeredNetworkVars.TryGetValue(varName, out DynValue var)) { @@ -54,7 +54,7 @@ namespace NAK.LuaNetVars } else { - LuaNetVarsMod.Logger.Warning($"Received update for unregistered variable {varName}"); + LuaNetworkVariablesMod.Logger.Warning($"Received update for unregistered variable {varName}"); } } @@ -79,7 +79,7 @@ namespace NAK.LuaNetVars args[i + 1] = DeserializeDynValue(msg); } - LuaNetVarsMod.Logger.Msg($"Received LuaEvent: {eventName} from {context.SenderName} with {argsCount} args"); + LuaNetworkVariablesMod.Logger.Msg($"Received LuaEvent: {eventName} from {context.SenderName} with {argsCount} args"); InvokeLuaEvent(eventName, args); } @@ -98,7 +98,7 @@ namespace NAK.LuaNetVars } else { - LuaNetVarsMod.Logger.Warning($"Received sync for unregistered variable {varName}"); + LuaNetworkVariablesMod.Logger.Warning($"Received sync for unregistered variable {varName}"); } } } @@ -121,7 +121,7 @@ namespace NAK.LuaNetVars } else { - LuaNetVarsMod.Logger.Warning($"No registered callback for event {eventName}"); + LuaNetworkVariablesMod.Logger.Warning($"No registered callback for event {eventName}"); } } @@ -159,7 +159,7 @@ namespace NAK.LuaNetVars } modMsg.Send(); - LuaNetVarsMod.Logger.Msg($"Sent variable sync to {userId}"); + LuaNetworkVariablesMod.Logger.Msg($"Sent variable sync to {userId}"); } private void RequestVariableSync() @@ -167,7 +167,7 @@ namespace NAK.LuaNetVars using ModNetworkMessage modMsg = new(ModNetworkID); modMsg.Write((byte)MessageType.RequestSync); modMsg.Send(); - LuaNetVarsMod.Logger.Msg("Requested variable sync"); + LuaNetworkVariablesMod.Logger.Msg("Requested variable sync"); } // private DynValue SendLuaEventCallback(ScriptExecutionContext context, CallbackArguments args) diff --git a/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Registration.cs b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Registration.cs index e68170f..fde4fdf 100644 --- a/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Registration.cs +++ b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Registration.cs @@ -1,6 +1,6 @@ using MoonSharp.Interpreter; -namespace NAK.LuaNetVars; +namespace NAK.LuaNetworkVariables; public partial class LuaNetVarController { @@ -8,7 +8,7 @@ public partial class LuaNetVarController { if (_registeredNetworkVars.ContainsKey(varName)) { - LuaNetVarsMod.Logger.Warning($"Network variable {varName} already registered!"); + LuaNetworkVariablesMod.Logger.Warning($"Network variable {varName} already registered!"); return; } @@ -18,7 +18,7 @@ public partial class LuaNetVarController RegisterGetterFunction(varName); RegisterSetterFunction(varName); - LuaNetVarsMod.Logger.Msg($"Registered network variable {varName}"); + LuaNetworkVariablesMod.Logger.Msg($"Registered network variable {varName}"); } private void RegisterGetterFunction(string varName) @@ -38,7 +38,7 @@ public partial class LuaNetVarController var newValue = args[0]; if (!IsSupportedDynValue(newValue)) { - LuaNetVarsMod.Logger.Error($"Unsupported DynValue type: {newValue.Type} for variable {varName}"); + LuaNetworkVariablesMod.Logger.Error($"Unsupported DynValue type: {newValue.Type} for variable {varName}"); return DynValue.Nil; } @@ -68,10 +68,10 @@ public partial class LuaNetVarController if (!ValidateCallback(callback) || !ValidateNetworkVar(varName)) return; if (_registeredNotifyCallbacks.ContainsKey(varName)) - LuaNetVarsMod.Logger.Warning($"Overwriting notify callback for {varName}"); + LuaNetworkVariablesMod.Logger.Warning($"Overwriting notify callback for {varName}"); _registeredNotifyCallbacks[varName] = callback; - LuaNetVarsMod.Logger.Msg($"Registered notify callback for {varName}"); + LuaNetworkVariablesMod.Logger.Msg($"Registered notify callback for {varName}"); } internal void RegisterEventCallback(string eventName, DynValue callback) @@ -79,23 +79,23 @@ public partial class LuaNetVarController if (!ValidateCallback(callback)) return; if (_registeredEventCallbacks.ContainsKey(eventName)) - LuaNetVarsMod.Logger.Warning($"Overwriting event callback for {eventName}"); + LuaNetworkVariablesMod.Logger.Warning($"Overwriting event callback for {eventName}"); _registeredEventCallbacks[eventName] = callback; - LuaNetVarsMod.Logger.Msg($"Registered event callback for {eventName}"); + LuaNetworkVariablesMod.Logger.Msg($"Registered event callback for {eventName}"); } private bool ValidateCallback(DynValue callback) { if (callback?.Function != null) return true; - LuaNetVarsMod.Logger.Error("Passed DynValue must be a function"); + LuaNetworkVariablesMod.Logger.Error("Passed DynValue must be a function"); return false; } private bool ValidateNetworkVar(string varName) { if (_registeredNetworkVars.ContainsKey(varName)) return true; - LuaNetVarsMod.Logger.Error($"Attempted to register notify callback for non-registered variable {varName}."); + LuaNetworkVariablesMod.Logger.Error($"Attempted to register notify callback for non-registered variable {varName}."); return false; } } \ No newline at end of file diff --git a/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Serialization.cs b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Serialization.cs index 57221a7..ba20565 100644 --- a/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Serialization.cs +++ b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Serialization.cs @@ -1,7 +1,7 @@ using ABI_RC.Systems.ModNetwork; using MoonSharp.Interpreter; -namespace NAK.LuaNetVars; +namespace NAK.LuaNetworkVariables; public partial class LuaNetVarController { @@ -24,7 +24,7 @@ public partial class LuaNetVarController case DataType.Nil: return DynValue.Nil; default: - LuaNetVarsMod.Logger.Error($"Unsupported data type received: {dataType}"); + LuaNetworkVariablesMod.Logger.Error($"Unsupported data type received: {dataType}"); return DynValue.Nil; } } @@ -49,7 +49,7 @@ public partial class LuaNetVarController msg.Write((byte)DataType.Nil); break; default: - LuaNetVarsMod.Logger.Error($"Unsupported DynValue type: {value.Type}"); + LuaNetworkVariablesMod.Logger.Error($"Unsupported DynValue type: {value.Type}"); msg.Write((byte)DataType.Nil); break; } diff --git a/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Utility.cs b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Utility.cs index 7712781..d52d504 100644 --- a/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Utility.cs +++ b/.Experimental/LuaNetworkVariables/NetworkVariables/LuaNetVarController.Utility.cs @@ -1,7 +1,7 @@ using ABI_RC.Core.Savior; using UnityEngine; -namespace NAK.LuaNetVars; +namespace NAK.LuaNetworkVariables; public partial class LuaNetVarController { @@ -13,10 +13,10 @@ public partial class LuaNetVarController // Check if it already exists (this **should** only matter in worlds) if (_hashes.Contains(hash)) { - LuaNetVarsMod.Logger.Warning($"Duplicate RelativeSyncMarker found at path {path}"); + LuaNetworkVariablesMod.Logger.Warning($"Duplicate RelativeSyncMarker found at path {path}"); if (!FindAvailableHash(ref hash)) // Super lazy fix idfc { - LuaNetVarsMod.Logger.Error($"Failed to find available hash for RelativeSyncMarker after 16 tries! {path}"); + LuaNetworkVariablesMod.Logger.Error($"Failed to find available hash for RelativeSyncMarker after 16 tries! {path}"); return false; } } diff --git a/.Experimental/LuaNetworkVariables/Patches.cs b/.Experimental/LuaNetworkVariables/Patches.cs index 672e1df..a442013 100644 --- a/.Experimental/LuaNetworkVariables/Patches.cs +++ b/.Experimental/LuaNetworkVariables/Patches.cs @@ -2,9 +2,9 @@ using ABI.Scripting.CVRSTL.Common; using HarmonyLib; using MoonSharp.Interpreter; -using NAK.LuaNetVars.Modules; +using NAK.LuaNetworkVariables.Modules; -namespace NAK.LuaNetVars.Patches; +namespace NAK.LuaNetworkVariables.Patches; internal static class LuaScriptFactory_Patches { diff --git a/.Experimental/LuaNetworkVariables/Properties/AssemblyInfo.cs b/.Experimental/LuaNetworkVariables/Properties/AssemblyInfo.cs index 84217ef..66b2858 100644 --- a/.Experimental/LuaNetworkVariables/Properties/AssemblyInfo.cs +++ b/.Experimental/LuaNetworkVariables/Properties/AssemblyInfo.cs @@ -1,17 +1,17 @@ -using NAK.LuaNetVars.Properties; +using NAK.LuaNetworkVariables.Properties; using MelonLoader; using System.Reflection; [assembly: AssemblyVersion(AssemblyInfoParams.Version)] [assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] [assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] -[assembly: AssemblyTitle(nameof(NAK.LuaNetVars))] +[assembly: AssemblyTitle(nameof(NAK.LuaNetworkVariables))] [assembly: AssemblyCompany(AssemblyInfoParams.Author)] -[assembly: AssemblyProduct(nameof(NAK.LuaNetVars))] +[assembly: AssemblyProduct(nameof(NAK.LuaNetworkVariables))] [assembly: MelonInfo( - typeof(NAK.LuaNetVars.LuaNetVarsMod), - nameof(NAK.LuaNetVars), + typeof(NAK.LuaNetworkVariables.LuaNetworkVariablesMod), + nameof(NAK.LuaNetworkVariables), AssemblyInfoParams.Version, AssemblyInfoParams.Author, downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/LuaNetworkVariables" @@ -24,9 +24,9 @@ using System.Reflection; [assembly: MelonAuthorColor(255, 158, 21, 32)] // red [assembly: HarmonyDontPatchAll] -namespace NAK.LuaNetVars.Properties; +namespace NAK.LuaNetworkVariables.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.1"; + public const string Version = "1.0.2"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/.Experimental/LuaNetworkVariables/README.md b/.Experimental/LuaNetworkVariables/README.md index c78a56a..c6ee80c 100644 --- a/.Experimental/LuaNetworkVariables/README.md +++ b/.Experimental/LuaNetworkVariables/README.md @@ -1,6 +1,77 @@ -# WhereAmIPointing +# LuaNetworkVariables -Simple mod that makes your controller rays always visible when the menus are open. Useful for when you're trying to aim at something in the distance. Also visualizes which ray is being used for menu interaction. +Adds a simple module for creating network variables & events *kinda* similar to Garry's Mod. + +Example Usage: +```lua +-- Requires UnityEngine and NetworkModule +UnityEngine = require("UnityEngine") +NetworkModule = require("NetworkModule") + +-- Unity Events -- + +function Start() + + if NetworkModule == nil then + print("NetworkModule did not load.") + return + end + + -- Registers "AvatarHeight" as a network variable + -- This creates Get and Set functions (GetAvatarHeight() and SetAvatarHeight()) + NetworkModule:RegisterNetworkVar("AvatarHeight") + + -- Registers a callback for when "AvatarHeight" is changed. + NetworkModule:RegisterNotifyCallback("AvatarHeight", function(varName, oldValue, newValue) + print(varName .. " changed from " .. tostring(oldValue) .. " to " .. tostring(newValue)) + end) + + -- Registers "ButtonClickedEvent" as a networked event. This provides context alongside the arguments passed. + NetworkModule:RegisterEventCallback("ButtonClickedEvent", function(context, message) + print("ButtonClickedEvent triggered by " .. tostring(context.senderName) .. " with message: " .. tostring(message)) + print("Context details:") + print(" senderId: " .. tostring(context.senderId)) + print(" senderName: " .. tostring(context.senderName)) + print(" lastInvokeTime: " .. tostring(context.lastInvokeTime)) + print(" timeSinceLastInvoke: " .. tostring(context.timeSinceLastInvoke)) + print(" isLocal: " .. tostring(context.isLocal)) + end) + + -- Secondry example + NetworkModule:RegisterEventCallback("CoolEvent", OnCoolEventOccured) +end + +function Update() + if not NetworkModule:IsSyncOwner() then + return + end + + SetAvatarHeight(PlayerAPI.LocalPlayer:GetViewPointPosition().y) +end + +-- Global Functions -- + +function SendClickEvent() + NetworkModule:SendLuaEvent("ButtonClickedEvent", "The button was clicked!") + print("Sent ButtonClickedEvent") +end + +function SendCoolEvent() + NetworkModule:SendLuaEvent("CoolEvent", 1, 2) +end + +-- Listener Functions -- + +function OnCoolEventOccured(context, value, value2) + print("CoolEvent triggered by " .. tostring(context.senderName)) + print("Received values: " .. tostring(value) .. ", " .. tostring(value2)) + print("Context details:") + print(" SenderId: " .. tostring(context.SenderId)) + print(" LastInvokeTime: " .. tostring(context.LastInvokeTime)) + print(" TimeSinceLastInvoke: " .. tostring(context.TimeSinceLastInvoke)) + print(" IsLocal: " .. tostring(context.IsLocal)) +end +``` --- From b75dce1d0222a990af4de65e0f67a5e438c495d2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 8 May 2025 22:16:07 +0000 Subject: [PATCH 092/119] [NAK_CVR_Mods] Update mod list in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 39be991..93d8d1e 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ |------|-------------|----------| | [CVRLuaToolsExtension](.Experimental/CVRLuaToolsExtension/README.md) | Extension mod for [CVRLuaTools](https://github.com/NotAKidoS/CVRLuaTools) Hot Reload functionality. | No Download | | [CustomRichPresence](.Experimental/CustomRichPresence/README.md) | Lets you customize the Steam & Discord rich presence messages & values. | No Download | -| [LuaNetworkVariables](.Experimental/LuaNetworkVariables/README.md) | Simple mod that makes your controller rays always visible when the menus are open. Useful for when you're trying to aim at something in the distance. Also visualizes which ray is being used for menu interaction. | No Download | +| [LuaNetworkVariables](.Experimental/LuaNetworkVariables/README.md) | Adds a simple module for creating network variables & events *kinda* similar to Garry's Mod. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/LuaNetworkVariables.dll) | | [LuaTTS](.Experimental/LuaTTS/README.md) | Provides access to the built-in text-to-speech (TTS) functionality to lua scripts. Allows you to make the local player speak. | No Download | | [OriginShift](.Experimental/OriginShift/README.md) | Experimental mod that allows world origin to be shifted to prevent floating point precision issues. | No Download | | [ScriptingSpoofer](.Experimental/ScriptingSpoofer/README.md) | Prevents **local** scripts from accessing your Username or UserID by spoofing them with random values each session. | No Download | From cc7762293dc43831518a1645b07330090fb44c9d Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Thu, 8 May 2025 17:36:28 -0500 Subject: [PATCH 093/119] [LuaNetworkVariables] fixed readmoe --- .Experimental/LuaNetworkVariables/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.Experimental/LuaNetworkVariables/README.md b/.Experimental/LuaNetworkVariables/README.md index c6ee80c..5ad6ee2 100644 --- a/.Experimental/LuaNetworkVariables/README.md +++ b/.Experimental/LuaNetworkVariables/README.md @@ -28,13 +28,13 @@ function Start() -- Registers "ButtonClickedEvent" as a networked event. This provides context alongside the arguments passed. NetworkModule:RegisterEventCallback("ButtonClickedEvent", function(context, message) - print("ButtonClickedEvent triggered by " .. tostring(context.senderName) .. " with message: " .. tostring(message)) + print("ButtonClickedEvent triggered by " .. tostring(context.SenderName) .. " with message: " .. tostring(message)) print("Context details:") - print(" senderId: " .. tostring(context.senderId)) - print(" senderName: " .. tostring(context.senderName)) - print(" lastInvokeTime: " .. tostring(context.lastInvokeTime)) - print(" timeSinceLastInvoke: " .. tostring(context.timeSinceLastInvoke)) - print(" isLocal: " .. tostring(context.isLocal)) + print(" SenderId: " .. tostring(context.SenderId)) + print(" SenderName: " .. tostring(context.SenderName)) + print(" LastInvokeTime: " .. tostring(context.LastInvokeTime)) + print(" TimeSinceLastInvoke: " .. tostring(context.TimeSinceLastInvoke)) + print(" IsLocal: " .. tostring(context.IsLocal)) end) -- Secondry example @@ -63,7 +63,7 @@ end -- Listener Functions -- function OnCoolEventOccured(context, value, value2) - print("CoolEvent triggered by " .. tostring(context.senderName)) + print("CoolEvent triggered by " .. tostring(context.SenderName)) print("Received values: " .. tostring(value) .. ", " .. tostring(value2)) print("Context details:") print(" SenderId: " .. tostring(context.SenderId)) From e96a0e164df6acd7fcf29ae2b658fa35cf17cf16 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Tue, 15 Jul 2025 21:02:03 -0500 Subject: [PATCH 094/119] [ThirdPerson] Fixed for Stable and Nightly, did some cleanup - Adjusted the local player scaled event patch to work both on Stable and Nightly --- ThirdPerson/CameraLogic.cs | 16 +++++++--------- ThirdPerson/Patches.cs | 2 +- ThirdPerson/Properties/AssemblyInfo.cs | 2 +- ThirdPerson/format.json | 4 ++-- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/ThirdPerson/CameraLogic.cs b/ThirdPerson/CameraLogic.cs index f1b83ef..a0ef565 100644 --- a/ThirdPerson/CameraLogic.cs +++ b/ThirdPerson/CameraLogic.cs @@ -13,7 +13,6 @@ internal static class CameraLogic private static float _dist; private static float _scale = 1f; private static Camera _thirdPersonCam; - private static Camera _uiCam; private static Camera _desktopCam; private static int _storedCamMask; private static CameraFovClone _cameraFovClone; @@ -51,11 +50,10 @@ internal static class CameraLogic _cameraFovClone = _thirdPersonCam.gameObject.AddComponent(); - _desktopCam = PlayerSetup.Instance.desktopCamera.GetComponent(); + _desktopCam = PlayerSetup.Instance.desktopCam; _cameraFovClone.targetCamera = _desktopCam; _thirdPersonCam.transform.SetParent(_desktopCam.transform); - _uiCam = _desktopCam.transform.Find("_UICamera").GetComponent(); RelocateCam(CameraLocation.Default); @@ -66,15 +64,15 @@ internal static class CameraLogic internal static void CopyPlayerCamValues() { - Camera activePlayerCam = PlayerSetup.Instance.GetActiveCamera().GetComponent(); - if (_thirdPersonCam == null || activePlayerCam == null) + Camera activePlayerCam = PlayerSetup.Instance.activeCam; + if (!_thirdPersonCam || !activePlayerCam) return; ThirdPerson.Logger.Msg("Copying active camera settings & components."); - CVRTools.CopyToDestCam(activePlayerCam, _thirdPersonCam, true); + CVRTools.CopyToDestCam(activePlayerCam, _thirdPersonCam); // Remove PlayerClone - _thirdPersonCam.cullingMask &= ~(1 << CVRLayers.PlayerClone); + // _thirdPersonCam.cullingMask &= ~(1 << CVRLayers.PlayerClone); if (!CheckIsRestricted()) return; @@ -116,9 +114,9 @@ internal static class CameraLogic private static void ResetDist() => _dist = 0; internal static void ScrollDist(float sign) { _dist += sign * 0.25f; RelocateCam(CurrentLocation); } - internal static void AdjustScale(float height) { _scale = height; RelocateCam(CurrentLocation); } + internal static void AdjustScale(float avatarScaleRelation) { _scale = avatarScaleRelation; RelocateCam(CurrentLocation); } internal static void CheckVRMode() { if (MetaPort.Instance.isUsingVr) State = false; } private static bool CheckIsRestricted() - => CVRWorld.Instance != null && !CVRWorld.Instance.enableZoom; + => CVRWorld.Instance && !CVRWorld.Instance.enableZoom; } \ No newline at end of file diff --git a/ThirdPerson/Patches.cs b/ThirdPerson/Patches.cs index 131b45b..02a60db 100644 --- a/ThirdPerson/Patches.cs +++ b/ThirdPerson/Patches.cs @@ -32,6 +32,6 @@ internal static class Patches //Copy camera settings & postprocessing components private static void OnPostWorldStart() => CopyPlayerCamValues(); //Adjust camera distance with height as modifier - private static void OnScaleAdjusted(float height) => AdjustScale(height); + private static void OnScaleAdjusted(ref float ____avatarScaleRelation) => AdjustScale(____avatarScaleRelation); private static void OnConfigureHudAffinity() => CheckVRMode(); } \ No newline at end of file diff --git a/ThirdPerson/Properties/AssemblyInfo.cs b/ThirdPerson/Properties/AssemblyInfo.cs index c2c7701..e6254b3 100644 --- a/ThirdPerson/Properties/AssemblyInfo.cs +++ b/ThirdPerson/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.ThirdPerson.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.1.1"; + public const string Version = "1.1.2"; public const string Author = "Davi & NotAKidoS"; } \ No newline at end of file diff --git a/ThirdPerson/format.json b/ThirdPerson/format.json index 4cdca3e..c2536e7 100644 --- a/ThirdPerson/format.json +++ b/ThirdPerson/format.json @@ -2,7 +2,7 @@ { "_id": 16, "name": "ThirdPerson", - "modversion": "1.1.1", + "modversion": "1.1.2", "gameversion": "2025r179", "loaderversion": "0.6.1", "modtype": "Mod", @@ -16,7 +16,7 @@ "requirements": [], "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ThirdPerson.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ThirdPerson", - "changelog": "- Recompiled for 2025r179", + "changelog": "- Adjusted the local player scaled event patch to work both on Stable and Nightly.", "embedcolor": "#F61961" } ] \ No newline at end of file From 0cdef04a53d10ed003324714614fe7e766344e0e Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Tue, 15 Jul 2025 21:02:05 -0500 Subject: [PATCH 095/119] Create DepthCameraFix.cs --- .Deprecated/SuperAwesomeMod/DepthCameraFix.cs | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 .Deprecated/SuperAwesomeMod/DepthCameraFix.cs diff --git a/.Deprecated/SuperAwesomeMod/DepthCameraFix.cs b/.Deprecated/SuperAwesomeMod/DepthCameraFix.cs new file mode 100644 index 0000000..933cfa6 --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/DepthCameraFix.cs @@ -0,0 +1,106 @@ +namespace NAK.SuperAwesomeMod; + +using UnityEngine; +using UnityEngine.Rendering; + +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine; +using UnityEngine.Rendering; + +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine; +using UnityEngine.Rendering; + +[RequireComponent(typeof(Camera))] +public class DepthTextureFix : MonoBehaviour +{ + private Camera cam; + private CommandBuffer beforeCommandBuffer; + private CommandBuffer afterCommandBuffer; + + void Start() + { + cam = GetComponent(); + + // Ensure camera generates depth texture + cam.depthTextureMode |= DepthTextureMode.Depth; + + // Create command buffers + beforeCommandBuffer = new CommandBuffer(); + beforeCommandBuffer.name = "DepthTextureFix_Before"; + + afterCommandBuffer = new CommandBuffer(); + afterCommandBuffer.name = "DepthTextureFix_After"; + + // Add command buffers at the right events + cam.AddCommandBuffer(CameraEvent.BeforeDepthTexture, beforeCommandBuffer); + cam.AddCommandBuffer(CameraEvent.AfterDepthTexture, afterCommandBuffer); + } + + void OnPreRender() + { + // Set up command buffers each frame to handle dynamic changes + SetupCommandBuffers(); + } + + void SetupCommandBuffers() + { + // Get current camera viewport in pixels + Rect pixelRect = cam.pixelRect; + + // Before depth texture: override viewport to full screen + beforeCommandBuffer.Clear(); + beforeCommandBuffer.SetViewport(new Rect(0, 0, Screen.width, Screen.height)); + + // After depth texture: restore original viewport + afterCommandBuffer.Clear(); + afterCommandBuffer.SetViewport(pixelRect); + } + + void OnDestroy() + { + // Clean up + if (cam != null) + { + if (beforeCommandBuffer != null) + { + cam.RemoveCommandBuffer(CameraEvent.BeforeDepthTexture, beforeCommandBuffer); + beforeCommandBuffer.Dispose(); + } + + if (afterCommandBuffer != null) + { + cam.RemoveCommandBuffer(CameraEvent.AfterDepthTexture, afterCommandBuffer); + afterCommandBuffer.Dispose(); + } + } + } + + void OnDisable() + { + if (cam != null) + { + if (beforeCommandBuffer != null) + cam.RemoveCommandBuffer(CameraEvent.BeforeDepthTexture, beforeCommandBuffer); + if (afterCommandBuffer != null) + cam.RemoveCommandBuffer(CameraEvent.AfterDepthTexture, afterCommandBuffer); + } + } + + void OnEnable() + { + if (cam != null && beforeCommandBuffer != null && afterCommandBuffer != null) + { + cam.AddCommandBuffer(CameraEvent.BeforeDepthTexture, beforeCommandBuffer); + cam.AddCommandBuffer(CameraEvent.AfterDepthTexture, afterCommandBuffer); + } + } +} \ No newline at end of file From c455d20f9c22ec85b156ec750618e912af2f4cd7 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Tue, 15 Jul 2025 21:13:55 -0500 Subject: [PATCH 096/119] [ThirdPerson] update format.json --- ThirdPerson/format.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ThirdPerson/format.json b/ThirdPerson/format.json index c2536e7..52d5bc8 100644 --- a/ThirdPerson/format.json +++ b/ThirdPerson/format.json @@ -16,7 +16,7 @@ "requirements": [], "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ThirdPerson.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ThirdPerson", - "changelog": "- Adjusted the local player scaled event patch to work both on Stable and Nightly.", + "changelog": "- Adjusted the local player scaled event patch to work both on Stable and Nightly (r179 & r180)", "embedcolor": "#F61961" } ] \ No newline at end of file From faf9d48fb6a166280c14085b95b1f476befde761 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Tue, 19 Aug 2025 23:30:02 -0500 Subject: [PATCH 097/119] [YouAreMyPropNowWeAreHavingSoftTacosLater] initial release --- .../Main.cs | 104 ++++++++++++------ .../Properties/AssemblyInfo.cs | 2 +- .../format.json | 4 +- 3 files changed, 74 insertions(+), 36 deletions(-) diff --git a/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs b/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs index 02e39c0..ee47977 100644 --- a/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs +++ b/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs @@ -1,11 +1,13 @@ using System.Collections; using System.Reflection; +using ABI_RC.Core.EventSystem; using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.IO; using ABI_RC.Core.Networking; using ABI_RC.Core.Networking.API.Responses; using ABI_RC.Core.Player; using ABI_RC.Core.Util; +using ABI_RC.Core.Util.Encryption; using ABI_RC.Systems.GameEventSystem; using ABI_RC.Systems.Movement; using ABI.CCK.Components; @@ -64,7 +66,7 @@ public class YouAreMyPropNowWeAreHavingSoftTacosLaterMod : MelonMod #region CVRAttachment Patches HarmonyInstance.Patch( // Cannot compile when using nameof - typeof(CVRAttachment).GetMethod("\u003CAttachInternal\u003Eg__DoAttachmentSetup\u007C43_0", + typeof(CVRAttachment).GetMethod(nameof(CVRAttachment.DoAttachmentSetup), BindingFlags.NonPublic | BindingFlags.Instance), postfix: new HarmonyMethod(typeof(YouAreMyPropNowWeAreHavingSoftTacosLaterMod).GetMethod(nameof(OnCVRAttachmentAttachInternal), BindingFlags.NonPublic | BindingFlags.Static)) @@ -96,6 +98,17 @@ public class YouAreMyPropNowWeAreHavingSoftTacosLaterMod : MelonMod #endregion CVRSeat Patches + #region CVRSpawnable Patches + + HarmonyInstance.Patch( + typeof(CVRSpawnable).GetMethod(nameof(CVRSpawnable.OnDestroy), + BindingFlags.Public | BindingFlags.Instance), + prefix: new HarmonyMethod(typeof(YouAreMyPropNowWeAreHavingSoftTacosLaterMod).GetMethod(nameof(OnSpawnableOnDestroy), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + #endregion CVRSpawnable Patches + #region CVRSyncHelper Patches HarmonyInstance.Patch( // Replaces method, original needlessly ToArray??? @@ -147,12 +160,28 @@ public class YouAreMyPropNowWeAreHavingSoftTacosLaterMod : MelonMod #region Harmony Patches - private static readonly List _heldPropData = new(); + [Flags] private enum HeldPropState { None = 0, Pickup = 1, Attachment = 2, Seat = 3 } + + private static readonly Dictionary _heldPropStates = new(); + + private static void AddHeldPropState(CVRSyncHelper.PropData propData, HeldPropState state) + { + if (!_heldPropStates.TryAdd(propData, state)) _heldPropStates[propData] |= state; + } + + private static void RemoveHeldPropState(CVRSyncHelper.PropData propData, HeldPropState state) + { + if (!_heldPropStates.TryGetValue(propData, out HeldPropState currentState)) return; + currentState &= ~state; + if (currentState == HeldPropState.None) _heldPropStates.Remove(propData); + else _heldPropStates[propData] = currentState; + } + private static GameObject _persistantPropsContainer; private static GameObject GetOrCreatePropsContainer() { - if (_persistantPropsContainer != null) return _persistantPropsContainer; - _persistantPropsContainer = new("[NAK] PersistantProps"); + if (_persistantPropsContainer) return _persistantPropsContainer; + _persistantPropsContainer = new("YouAreMyPropNowWeAreHavingSoftTacosLater"); _persistantPropsContainer.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity); _persistantPropsContainer.transform.localScale = Vector3.one; Object.DontDestroyOnLoad(_persistantPropsContainer); @@ -168,47 +197,50 @@ public class YouAreMyPropNowWeAreHavingSoftTacosLaterMod : MelonMod { if (!EntryTrackPickups.Value) return; if (!TryGetPropData(__instance.GetComponentInParent(true), out CVRSyncHelper.PropData propData)) return; - if (!_heldPropData.Contains(propData)) _heldPropData.Add(propData); + AddHeldPropState(propData, HeldPropState.Pickup); } private static void OnCVRPickupObjectOnDrop(CVRPickupObject __instance) { if (!TryGetPropData(__instance.GetComponentInParent(true), out CVRSyncHelper.PropData propData)) return; - if (_heldPropData.Contains(propData)) _heldPropData.Remove(propData); + RemoveHeldPropState(propData, HeldPropState.Pickup); } private static void OnCVRAttachmentAttachInternal(CVRAttachment __instance) { if (!EntryTrackAttachments.Value) return; if (!TryGetPropData(__instance.GetComponentInParent(true), out CVRSyncHelper.PropData propData)) return; - if (!_heldPropData.Contains(propData)) _heldPropData.Add(propData); + AddHeldPropState(propData, HeldPropState.Attachment); } private static void OnCVRAttachmentDeAttach(CVRAttachment __instance) { if (!__instance._isAttached) return; // Can invoke DeAttach without being attached if (!TryGetPropData(__instance.GetComponentInParent(true), out CVRSyncHelper.PropData propData)) return; - if (_heldPropData.Contains(propData)) _heldPropData.Remove(propData); + RemoveHeldPropState(propData, HeldPropState.Attachment); } private static void OnCVRSeatSitDown(CVRSeat __instance) { if (!EntryTrackSeats.Value) return; if (!TryGetPropData(__instance.GetComponentInParent(true), out CVRSyncHelper.PropData propData)) return; - if (!_heldPropData.Contains(propData)) _heldPropData.Add(propData); + AddHeldPropState(propData, HeldPropState.Seat); } private static void OnCVRSeatExitSeat(CVRSeat __instance) { if (!TryGetPropData(__instance.GetComponentInParent(true), out CVRSyncHelper.PropData propData)) return; - if (_heldPropData.Contains(propData)) _heldPropData.Remove(propData); + RemoveHeldPropState(propData, HeldPropState.Seat); + } + + private static void OnSpawnableOnDestroy(CVRSpawnable __instance) + { + if (!TryGetPropData(__instance, out CVRSyncHelper.PropData propData)) return; + _heldPropStates.Remove(propData); } // ReSharper disable UnusedParameter.Local - private static bool OnCVRDownloadManagerQueueTask(string assetId, DownloadTask.ObjectType type, string assetUrl, string fileId, long fileSize, string fileKey, string toAttach, - string fileHash = null, UgcTagsData tagsData = null, CVRLoadingAvatarController loadingAvatarController = null, - bool joinOnComplete = false, bool isHomeRequested = false, int compatibilityVersion = 0, int encryptionAlgorithm = 0, - string spawnerId = null) + private static bool OnCVRDownloadManagerQueueTask(AssetManagement.UgcMetadata metadata, DownloadTask.ObjectType type, string assetUrl, string fileId, string toAttach, CVRLoadingAvatarController loadingAvatarController = null, bool joinOnComplete = false, bool isHomeRequested = false, CompatibilityVersions compatibilityVersion = CompatibilityVersions.NotSpi, CVREncryptionRouter.EncryptionAlgorithm encryptionAlgorithm = CVREncryptionRouter.EncryptionAlgorithm.Gen1, string spawnerId = null) { if (type != DownloadTask.ObjectType.Prop) return true; // Only care about props @@ -219,14 +251,20 @@ public class YouAreMyPropNowWeAreHavingSoftTacosLaterMod : MelonMod Vector3 identity = GetIdentityKeyFromPropData(newPropData); if (!_keyToPropData.Remove(identity, out CVRSyncHelper.PropData originalPropData)) return true; - // Remove original prop data from held - if (_heldPropData.Contains(originalPropData)) _heldPropData.Remove(originalPropData); + // Remove original prop data from held, cache states + HeldPropState heldState = HeldPropState.None; + if (_heldPropStates.ContainsKey(originalPropData)) + { + heldState = _heldPropStates[originalPropData]; + _heldPropStates.Remove(originalPropData); + } // If original prop data is null spawn a new prop i guess :( - if (originalPropData.Spawnable == null) return true; + if (!originalPropData.Spawnable) return true; // Add the new prop data to our held props in place of the old one - if (!_heldPropData.Contains(newPropData)) _heldPropData.Add(newPropData); + // if (!_heldPropData.Contains(newPropData)) _heldPropData.Add(newPropData); + _heldPropStates.TryAdd(newPropData, heldState); // Apply new prop data to the spawnable newPropData.Spawnable = originalPropData.Spawnable; @@ -255,7 +293,7 @@ public class YouAreMyPropNowWeAreHavingSoftTacosLaterMod : MelonMod for (var index = CVRSyncHelper.Props.Count - 1; index >= 0; index--) { CVRSyncHelper.PropData prop = CVRSyncHelper.Props[index]; - if (prop.Spawnable != null && _heldPropData.Contains(prop)) + if (prop.Spawnable && _heldPropStates.ContainsKey(prop)) continue; // Do not recycle props that are valid & held DeleteOrRecycleProp(prop); @@ -269,7 +307,7 @@ public class YouAreMyPropNowWeAreHavingSoftTacosLaterMod : MelonMod { if (!_ignoreNextSeatExit) return true; _ignoreNextSeatExit = false; - if (BetterBetterCharacterController.Instance._lastCvrSeat == null) return true; // run original + if (!BetterBetterCharacterController.Instance._lastCvrSeat) return true; // run original return false; // dont run if there is a chair & we skipped it } @@ -282,16 +320,16 @@ public class YouAreMyPropNowWeAreHavingSoftTacosLaterMod : MelonMod private void OnWorldLoad(string _) { CVRWorld worldInstance = CVRWorld.Instance; - if (worldInstance != null && !worldInstance.allowSpawnables) + if (worldInstance && !worldInstance.allowSpawnables) { - foreach (CVRSyncHelper.PropData prop in _heldPropData) DeleteOrRecycleProp(prop); // Delete all props we kept + foreach (CVRSyncHelper.PropData prop in _heldPropStates.Keys) DeleteOrRecycleProp(prop); // Delete all props we kept return; } - for (var index = _heldPropData.Count - 1; index >= 0; index--) + for (var index = _heldPropStates.Count - 1; index >= 0; index--) { - CVRSyncHelper.PropData prop = _heldPropData[index]; - if (prop.Spawnable == null) + CVRSyncHelper.PropData prop = _heldPropStates.ElementAt(index).Key; + if (!prop.Spawnable) { DeleteOrRecycleProp(prop); return; @@ -324,9 +362,9 @@ public class YouAreMyPropNowWeAreHavingSoftTacosLaterMod : MelonMod private static void OnWorldUnload(string _) { // Prevent deleting of our held props on scene destruction - foreach (CVRSyncHelper.PropData prop in _heldPropData) + foreach (CVRSyncHelper.PropData prop in _heldPropStates.Keys) { - if (prop.Spawnable == null) continue; + if (!prop.Spawnable) continue; PlacePropInPersistantPropsContainer(prop.Spawnable); _spawnablePositionStack.Push(new SpawnablePositionContainer(prop.Spawnable)); } @@ -341,9 +379,9 @@ public class YouAreMyPropNowWeAreHavingSoftTacosLaterMod : MelonMod { // Request the server to respawn our props by GUID, and add a secret key to the propData to identify it - foreach (CVRSyncHelper.PropData prop in _heldPropData) + foreach (CVRSyncHelper.PropData prop in _heldPropStates.Keys) { - if (prop.Spawnable == null) continue; + if (!prop.Spawnable) continue; // Generate a new identity key for the prop (this is used to identify the prop when we respawn it) Vector3 identityKey = new(Random.Range(0, 1000), Random.Range(0, 1000), Random.Range(0, 1000)); @@ -362,7 +400,7 @@ public class YouAreMyPropNowWeAreHavingSoftTacosLaterMod : MelonMod private static bool TryGetPropData(CVRSpawnable spawnable, out CVRSyncHelper.PropData propData) { - if (spawnable == null) + if (!spawnable) { propData = null; return false; @@ -408,9 +446,9 @@ public class YouAreMyPropNowWeAreHavingSoftTacosLaterMod : MelonMod private static void DeleteOrRecycleProp(CVRSyncHelper.PropData prop) { - if (prop.Spawnable == null) prop.Recycle(); + if (!prop.Spawnable) prop.Recycle(); else prop.Spawnable.Delete(); - if (_heldPropData.Contains(prop)) _heldPropData.Remove(prop); + _heldPropStates.Remove(prop); } private static void SpawnPropFromGuid(string propGuid, Vector3 position, Vector3 rotation, Vector3 identityKey) @@ -518,7 +556,7 @@ public class YouAreMyPropNowWeAreHavingSoftTacosLaterMod : MelonMod for (int i = 0; i < _spawnable.subSyncs.Count; i++) { Transform subSyncTransform = _spawnable.subSyncs[i].transform; - if (subSyncTransform == null) continue; + if (!subSyncTransform) continue; Vector3 subWorldPos = playerTransform.TransformPoint(_posOffsets[i + 1]); subWorldPos.y += _heightOffset; diff --git a/YouAreMyPropNowWeAreHavingSoftTacosLater/Properties/AssemblyInfo.cs b/YouAreMyPropNowWeAreHavingSoftTacosLater/Properties/AssemblyInfo.cs index bfc0a13..fa1864b 100644 --- a/YouAreMyPropNowWeAreHavingSoftTacosLater/Properties/AssemblyInfo.cs +++ b/YouAreMyPropNowWeAreHavingSoftTacosLater/Properties/AssemblyInfo.cs @@ -17,7 +17,7 @@ using System.Reflection; downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/YouAreMyPropNowWeAreHavingSoftTacosLater" )] -[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonGame("ChilloutVR", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] [assembly: MelonColor(255, 246, 25, 99)] // red-pink diff --git a/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json b/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json index 78c5bbc..b88a58b 100644 --- a/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json +++ b/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json @@ -2,8 +2,8 @@ "_id": -1, "name": "YouAreMyPropNowWeAreHavingSoftTacosLater", "modversion": "1.0.0", - "gameversion": "2025r179", - "loaderversion": "0.6.1", + "gameversion": "2025r180", + "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS", "description": "Lets you bring held & attached props through world loads.\nhttps://youtu.be/9P6Jeh-VN58?si=eXTPGyKB_0wq1gZO", From ee4df06d2ecd30964f1e98cf8a33d4630d9d0580 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Tue, 19 Aug 2025 23:30:16 -0500 Subject: [PATCH 098/119] [ThirdPerson] Fixes for r180 --- ThirdPerson/CameraLogic.cs | 5 +---- ThirdPerson/Properties/AssemblyInfo.cs | 4 ++-- ThirdPerson/ThirdPerson.cs | 5 +++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/ThirdPerson/CameraLogic.cs b/ThirdPerson/CameraLogic.cs index a0ef565..8f26e68 100644 --- a/ThirdPerson/CameraLogic.cs +++ b/ThirdPerson/CameraLogic.cs @@ -1,7 +1,6 @@ using ABI_RC.Core.Player; using ABI_RC.Core.Savior; using ABI_RC.Core.Util.Object_Behaviour; -using System.Collections; using ABI_RC.Core; using ABI.CCK.Components; using UnityEngine; @@ -42,10 +41,8 @@ internal static class CameraLogic } } - internal static IEnumerator SetupCamera() + internal static void SetupCamera() { - yield return new WaitUntil(() => PlayerSetup.Instance); - _thirdPersonCam = new GameObject("ThirdPersonCameraObj", typeof(Camera)).GetComponent(); _cameraFovClone = _thirdPersonCam.gameObject.AddComponent(); diff --git a/ThirdPerson/Properties/AssemblyInfo.cs b/ThirdPerson/Properties/AssemblyInfo.cs index e6254b3..85d8bfa 100644 --- a/ThirdPerson/Properties/AssemblyInfo.cs +++ b/ThirdPerson/Properties/AssemblyInfo.cs @@ -17,7 +17,7 @@ using System.Reflection; downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ThirdPerson" )] -[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonGame("ChilloutVR", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] [assembly: MelonColor(255, 246, 25, 97)] // do not change color, originally chosen by Davi @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.ThirdPerson.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.1.2"; + public const string Version = "1.1.3"; public const string Author = "Davi & NotAKidoS"; } \ No newline at end of file diff --git a/ThirdPerson/ThirdPerson.cs b/ThirdPerson/ThirdPerson.cs index 21691c4..5147e39 100644 --- a/ThirdPerson/ThirdPerson.cs +++ b/ThirdPerson/ThirdPerson.cs @@ -1,4 +1,5 @@ -using MelonLoader; +using ABI_RC.Systems.GameEventSystem; +using MelonLoader; using UnityEngine; using static NAK.ThirdPerson.CameraLogic; @@ -13,7 +14,7 @@ public class ThirdPerson : MelonMod Logger = LoggerInstance; Patches.Apply(HarmonyInstance); - MelonCoroutines.Start(SetupCamera()); + CVRGameEventSystem.Initialization.OnPlayerSetupStart.AddListener(SetupCamera); } public override void OnUpdate() From 548fcf72bcc6e7d824ba79bd6ae39531712e2535 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Tue, 19 Aug 2025 23:31:07 -0500 Subject: [PATCH 099/119] [ThirdPerson] Updated format.json --- ThirdPerson/format.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ThirdPerson/format.json b/ThirdPerson/format.json index 52d5bc8..780db31 100644 --- a/ThirdPerson/format.json +++ b/ThirdPerson/format.json @@ -2,9 +2,9 @@ { "_id": 16, "name": "ThirdPerson", - "modversion": "1.1.2", - "gameversion": "2025r179", - "loaderversion": "0.6.1", + "modversion": "1.1.3", + "gameversion": "2025r180", + "loaderversion": "0.7.2", "modtype": "Mod", "author": "Davi & NotAKidoS", "description": "Allows you to go into third person view by pressing Ctrl + T to toggle and Ctrl + Y to cycle modes.", @@ -16,7 +16,7 @@ "requirements": [], "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ThirdPerson.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ThirdPerson", - "changelog": "- Adjusted the local player scaled event patch to work both on Stable and Nightly (r179 & r180)", + "changelog": "- Fixes for r180", "embedcolor": "#F61961" } ] \ No newline at end of file From 13e206cd5882585db4560c538b941717e1bec183 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Tue, 19 Aug 2025 23:33:42 -0500 Subject: [PATCH 100/119] [ThirdPerson] Updated format.json --- ThirdPerson/format.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ThirdPerson/format.json b/ThirdPerson/format.json index 780db31..ff4c491 100644 --- a/ThirdPerson/format.json +++ b/ThirdPerson/format.json @@ -14,9 +14,9 @@ "third person" ], "requirements": [], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ThirdPerson.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/ThirdPerson.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ThirdPerson", - "changelog": "- Fixes for r180", + "changelog": "- Fixes for 2025r180", "embedcolor": "#F61961" } ] \ No newline at end of file From a0a859aa868cdf56bd81534404e9d85656e0a808 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Tue, 19 Aug 2025 23:33:53 -0500 Subject: [PATCH 101/119] [ShareBubbles] Fixes for 2025r180 --- ShareBubbles/Main.cs | 2 +- ShareBubbles/Patches.cs | 1631 +---------------- ShareBubbles/Properties/AssemblyInfo.cs | 4 +- .../API/Exceptions/ShareApiExceptions.cs | 66 - .../API/PedestalInfoBatchProcessor.cs | 3 +- .../API/Responses/ActiveSharesResponse.cs | 22 - .../ShareBubbles/API/ShareApiHelper.cs | 237 --- .../Implementation/AvatarBubbleImpl.cs | 4 +- .../Implementation/SpawnableBubbleImpl.cs | 4 +- .../Implementation/TempShareManager.cs | 4 +- .../Networking/ModNetwork.Inbound.cs | 4 +- .../Networking/ModNetwork.Outbound.cs | 4 +- .../ShareBubbles/UI/BubbleInteract.cs | 18 +- ShareBubbles/format.json | 10 +- 14 files changed, 60 insertions(+), 1953 deletions(-) delete mode 100644 ShareBubbles/ShareBubbles/API/Exceptions/ShareApiExceptions.cs delete mode 100644 ShareBubbles/ShareBubbles/API/Responses/ActiveSharesResponse.cs delete mode 100644 ShareBubbles/ShareBubbles/API/ShareApiHelper.cs diff --git a/ShareBubbles/Main.cs b/ShareBubbles/Main.cs index 72f3c3d..802a6be 100644 --- a/ShareBubbles/Main.cs +++ b/ShareBubbles/Main.cs @@ -28,7 +28,7 @@ public class ShareBubblesMod : MelonMod LoadAssetBundle(); } - + public override void OnApplicationQuit() { ModNetwork.Unsubscribe(); diff --git a/ShareBubbles/Patches.cs b/ShareBubbles/Patches.cs index 5f95231..eaf2440 100644 --- a/ShareBubbles/Patches.cs +++ b/ShareBubbles/Patches.cs @@ -1,14 +1,6 @@ using ABI_RC.Core.InteractionSystem; -using ABI_RC.Core.Networking.API.Responses; -using ABI_RC.Core.Networking.API.UserWebsocket; using ABI_RC.Core.Player; -using ABI_RC.Core.Savior; using HarmonyLib; -using MTJobSystem; -using NAK.ShareBubbles.API; -using NAK.ShareBubbles.API.Exceptions; -using NAK.ShareBubbles.API.Responses; -using Newtonsoft.Json; namespace NAK.ShareBubbles.Patches; @@ -68,1419 +60,31 @@ internal static class ControllerRay_Patches internal static class ViewManager_Patches { - -private const string DETAILS_TOOLBAR_PATCHES = """ - -const ContentShareMod = { - debugMode: false, - currentContentData: null, - themeColors: null, - - /* Theme Handling */ - - getThemeColors: function() { - if (this.themeColors) return this.themeColors; - - // Default fallback colors - const defaultColors = { - background: '#373021', - border: '#59885d' - }; - - // Try to get colors from favorite category element - const favoriteCategoryElement = document.querySelector('.favorite-category-selection'); - if (!favoriteCategoryElement) return defaultColors; - - const computedStyle = window.getComputedStyle(favoriteCategoryElement); - this.themeColors = { - background: computedStyle.backgroundColor || defaultColors.background, - border: computedStyle.borderColor || defaultColors.border - }; - - return this.themeColors; - }, - - applyThemeToDialog: function(dialog) { - const colors = this.getThemeColors(); - dialog.style.backgroundColor = colors.background; - dialog.style.borderColor = colors.border; - - // Update any close or page buttons to match theme - const buttons = dialog.querySelectorAll('.close-btn, .page-btn'); - buttons.forEach(button => { - button.style.borderColor = colors.border; - }); - - return colors; - }, - - /* Core Initialization */ - - init: function() { - const styles = [ - this.getSharedStyles(), - this.ShareBubble.initStyles(), - this.ShareSelect.initStyles(), - this.DirectShare.initStyles(), - this.Unshare.initStyles() - ].join('\n'); - - const styleElement = document.createElement('style'); - styleElement.type = 'text/css'; - styleElement.innerHTML = styles; - document.head.appendChild(styleElement); - - this.shareBubbleDialog = this.ShareBubble.createDialog(); - this.shareSelectDialog = this.ShareSelect.createDialog(); - this.directShareDialog = this.DirectShare.createDialog(); - this.unshareDialog = this.Unshare.createDialog(); - - this.initializeToolbars(); - this.bindEvents(); - }, - - getSharedStyles: function() { - return ` - .content-sharing-base-dialog { - position: fixed; - background-color: #373021; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 800px; - min-width: 500px; - border: 3px solid #59885d; - padding: 20px; - z-index: 100000; - opacity: 0; - transition: opacity 0.2s linear; - } - - .content-sharing-base-dialog.in { - opacity: 1; - } - - .content-sharing-base-dialog.out { - opacity: 0; - } - - .content-sharing-base-dialog.hidden { - display: none; - } - - .content-sharing-base-dialog h2, - .content-sharing-base-dialog h3 { - margin-top: 0; - margin-bottom: 0.5em; - text-align: left; - } - - .content-sharing-base-dialog .description { - margin-bottom: 1em; - text-align: left; - font-size: 0.9em; - color: #aaa; - } - - .content-sharing-base-dialog .close-btn { - position: absolute; - top: 1%; - right: 1%; - border-radius: 0.25em; - border: 3px solid #59885d; - padding: 0.5em; - width: 8em; - text-align: center; - } - - .page-btn { - border-radius: 0.25em; - border: 3px solid #59885d; - padding: 0.5em; - width: 8em; - text-align: center; - } - - .page-btn:disabled { - opacity: 0.5; - cursor: not-allowed; - } - - .inp-hidden { - display: none; - } - `; - }, - - /* Feature Modules */ - - ShareBubble: { - initStyles: function() { - return ` - .share-bubble-dialog { - max-width: 800px; - transform: translate(-50%, -60%); - } - - .share-bubble-dialog .content-btn { - position: relative; - margin-bottom: 0.5em; - } - - .share-bubble-dialog .btn-group { - display: flex; - margin-bottom: 1em; - } - - .share-bubble-dialog .option-select { - flex: 1 1 0; - min-width: 0; - background-color: inherit; - text-align: center; - padding: 0.5em; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - border: 1px solid inherit; - } - - .share-bubble-dialog .option-select + .option-select { - margin-left: -1px; - } - - .share-bubble-dialog .option-select.active, - .share-bubble-dialog .option-select:hover { - background-color: rgba(27, 80, 55, 1); - } - - .share-bubble-dialog .action-buttons { - margin-top: 1em; - display: flex; - justify-content: space-between; - } - - .share-bubble-dialog .action-btn { - flex: 1; - text-align: center; - padding: 0.5em; - border-radius: 0.25em; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - margin-right: 0.5em; - } - - .share-bubble-dialog .action-btn:last-child { - margin-right: 0; - } - `; - }, - - createDialog: function() { - const dialog = document.createElement('div'); - dialog.id = 'content-share-bubble-dialog'; - dialog.className = 'content-sharing-base-dialog share-bubble-dialog hidden'; - dialog.innerHTML = ` -

Share Bubble

-
Close
- -

Visibility

-

Choose who can see your Sharing Bubble.

-
-
Everyone
-
Friends Only
-
- -

Lifetime

-

How long the Sharing Bubble lasts. You can delete it at any time.

-
-
2 Minutes
-
For Session
-
- -
-

Access Control

-
- - -

- Users cannot access your Private Content through this share. -

-
-
-
Keep
-
Instance Only
-
None
-
-
- - - - - - - -
-
Drop
-
Select
-
- `; - document.body.appendChild(dialog); - return dialog; - }, - - show: function(contentDetails) { - const dialog = ContentShareMod.shareBubbleDialog; - const colors = ContentShareMod.applyThemeToDialog(dialog); - - // Additional ShareBubble-specific theming - const optionSelects = dialog.querySelectorAll('.option-select'); - optionSelects.forEach(element => { - element.style.borderColor = colors.border; - }); - - const grantAccessSection = dialog.querySelector('.grant-access-section'); - const noAccessControlMessage = dialog.querySelector('.no-access-control-message'); - const showGrantAccess = contentDetails.IsMine && !contentDetails.IsPublic; - - if (grantAccessSection && noAccessControlMessage) { - grantAccessSection.style.display = showGrantAccess ? '' : 'none'; - noAccessControlMessage.style.display = showGrantAccess ? 'none' : ''; - } - - dialog.classList.remove('hidden', 'out'); - setTimeout(() => dialog.classList.add('in'), 50); - - ContentShareMod.currentContentData = contentDetails; - }, - - hide: function() { - const dialog = ContentShareMod.shareBubbleDialog; - dialog.classList.remove('in'); - dialog.classList.add('out'); - setTimeout(() => { - dialog.classList.add('hidden'); - dialog.classList.remove('out'); - }, 200); - }, - - changeVisibility: function(element) { - document.getElementById('share-visibility').value = element.dataset.visibilityValue; - const buttons = ContentShareMod.shareBubbleDialog.querySelectorAll('.visibility-btn'); - buttons.forEach(btn => btn.classList.remove('active')); - element.classList.add('active'); - }, - - changeDuration: function(element) { - document.getElementById('share-duration').value = element.dataset.durationValue; - const buttons = ContentShareMod.shareBubbleDialog.querySelectorAll('.duration-btn'); - buttons.forEach(btn => btn.classList.remove('active')); - element.classList.add('active'); - }, - - changeAccess: function(element) { - document.getElementById('share-access').value = element.dataset.accessValue; - const buttons = ContentShareMod.shareBubbleDialog.querySelectorAll('.access-btn'); - buttons.forEach(btn => btn.classList.remove('active')); - element.classList.add('active'); - - const descriptions = ContentShareMod.shareBubbleDialog.querySelectorAll('.access-desc'); - descriptions.forEach(desc => { - desc.style.display = desc.dataset.accessType === element.dataset.accessValue ? '' : 'none'; - }); - }, - - submit: function(action) { - const contentDetails = ContentShareMod.currentContentData; - let bubbleImpl, bubbleContent, contentImage, contentName; - - if (contentDetails.AvatarId) { - bubbleImpl = 'Avatar'; - bubbleContent = contentDetails.AvatarId; - contentImage = contentDetails.AvatarImageCoui; - contentName = contentDetails.AvatarName; - } else if (contentDetails.SpawnableId) { - bubbleImpl = 'Spawnable'; - bubbleContent = contentDetails.SpawnableId; - contentImage = contentDetails.SpawnableImageCoui; - contentName = contentDetails.SpawnableName; - } else if (contentDetails.WorldId) { - bubbleImpl = 'World'; - bubbleContent = contentDetails.WorldId; - contentImage = contentDetails.WorldImageCoui; - contentName = contentDetails.WorldName; - } else if (contentDetails.UserId) { - bubbleImpl = 'User'; - bubbleContent = contentDetails.UserId; - contentImage = contentDetails.UserImageCoui; - contentName = contentDetails.UserName; - } else { - console.error('No valid content ID found'); - return; - } - - const visibility = document.getElementById('share-visibility').value; - const duration = document.getElementById('share-duration').value; - const access = document.getElementById('share-access').value; - - const shareRule = visibility === 'FriendsOnly' ? 'FriendsOnly' : 'Everyone'; - const shareLifetime = duration === 'Session' ? 'Session' : 'TwoMinutes'; - const shareAccess = access === 'Permanent' ? 'Permanent' : - access === 'Session' ? 'Session' : 'NoAccess'; - - if (ContentShareMod.debugMode) { - console.log('Sharing content:', { - action, bubbleImpl, bubbleContent, - shareRule, shareLifetime, shareAccess - }); - } - - engine.call('NAKCallShareContent', action, bubbleImpl, bubbleContent, - shareRule, shareLifetime, shareAccess, contentImage, contentName); - - this.hide(); - } - }, - - Unshare: { - currentPage: 1, - totalPages: 1, - sharesPerPage: 5, - sharesList: null, - - initStyles: function() { - return ` - .unshare-dialog { - width: 800px; - height: 1000px; - transform: translate(-50%, -60%); - display: flex; - flex-direction: column; - } - - .unshare-dialog .shares-container { - flex: 1; - overflow-y: auto; - margin: 20px 0; - min-height: 0; - } - - .unshare-dialog #shares-loading, - .unshare-dialog #shares-error, - .unshare-dialog #shares-empty { - text-align: center; - padding: 2em; - font-size: 1.1em; - } - - .unshare-dialog #shares-error { - color: #ff6b6b; - } - - .unshare-dialog .share-item { - display: flex; - align-items: center; - padding: 15px; - border: 1px solid rgba(255, 255, 255, 0.1); - margin-bottom: 10px; - background: rgba(0, 0, 0, 0.2); - border-radius: 4px; - min-height: 120px; - } - - .unshare-dialog .share-item img { - width: 96px; - height: 96px; - border-radius: 4px; - margin-right: 15px; - cursor: pointer; - } - - .unshare-dialog .share-item .user-name { - flex: 1; - font-size: 1.3em; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - margin-right: 15px; - cursor: pointer; - } - - .unshare-dialog .action-btn { - width: 180px; - height: 60px; - font-size: 1.2em; - color: white; - border-radius: 4px; - display: inline-flex; - align-items: center; - justify-content: center; - margin-left: 10px; - padding: 0 20px; - text-align: center; - } - - .unshare-dialog .revoke-btn { - background-color: #ff6b6b; - } - - .unshare-dialog .undo-btn { - background-color: #4a9eff; - } - - .unshare-dialog .action-btn:disabled { - opacity: 0.5; - cursor: not-allowed; - background-color: #666; - } - - .unshare-dialog .pagination { - border-top: 1px solid rgba(255, 255, 255, 0.1); - padding-top: 20px; - } - - .unshare-dialog .page-info { - font-size: 1.1em; - opacity: 0.8; - margin-bottom: 15px; - text-align: center; - } - - .unshare-dialog .page-buttons { - display: flex; - justify-content: center; - gap: 20px; - } - - .unshare-dialog .share-item.revoked { - opacity: 0.7; - } - `; - }, - - createDialog: function() { - const dialog = document.createElement('div'); - dialog.id = 'content-unshare-dialog'; - dialog.className = 'content-sharing-base-dialog unshare-dialog hidden'; - dialog.innerHTML = ` -

Manage Shares

-
Close
- -
-
Loading shares...
- - - -
- - - `; - document.body.appendChild(dialog); - return dialog; - }, - - show: function(contentDetails) { - const dialog = ContentShareMod.unshareDialog; - ContentShareMod.applyThemeToDialog(dialog); - - dialog.classList.remove('hidden', 'out'); - setTimeout(() => dialog.classList.add('in'), 50); - - ContentShareMod.currentContentData = contentDetails; - this.currentPage = 1; - this.totalPages = 1; - this.sharesList = null; - this.requestShares(); - }, - - hide: function() { - const dialog = ContentShareMod.unshareDialog; - dialog.classList.remove('in'); - dialog.classList.add('out'); - setTimeout(() => { - dialog.classList.add('hidden'); - dialog.classList.remove('out'); - }, 200); - }, - - requestShares: function() { - const dialog = ContentShareMod.unshareDialog; - const sharesContainer = dialog.querySelector('.shares-container'); - - sharesContainer.querySelector('#shares-loading').style.display = ''; - sharesContainer.querySelector('#shares-error').style.display = 'none'; - sharesContainer.querySelector('#shares-empty').style.display = 'none'; - sharesContainer.querySelector('#shares-list').style.display = 'none'; - - const contentDetails = ContentShareMod.currentContentData; - const contentType = contentDetails.AvatarId ? 'Avatar' : 'Spawnable'; - const contentId = contentDetails.AvatarId || contentDetails.SpawnableId; - - engine.call('NAKGetContentShares', contentType, contentId); - }, - - handleSharesResponse: function(success, shares) { - const dialog = ContentShareMod.unshareDialog; - const sharesContainer = dialog.querySelector('.shares-container'); - const loadingElement = sharesContainer.querySelector('#shares-loading'); - const errorElement = sharesContainer.querySelector('#shares-error'); - const emptyElement = sharesContainer.querySelector('#shares-empty'); - const sharesListElement = sharesContainer.querySelector('#shares-list'); - - loadingElement.style.display = 'none'; - - if (!success) { - errorElement.style.display = ''; - return; - } - - try { - const response = JSON.parse(shares); - this.sharesList = response.Data.value; - - if (!this.sharesList || this.sharesList.length === 0) { - emptyElement.style.display = ''; - const pagination = dialog.querySelector('.pagination'); - const [prevButton, nextButton] = pagination.querySelectorAll('.page-btn'); - prevButton.disabled = true; - nextButton.disabled = true; - pagination.querySelector('.page-info').textContent = '1/1'; - return; - } - - this.totalPages = Math.ceil(this.sharesList.length / this.sharesPerPage); - this.updatePageContent(); - } catch (error) { - console.error('Error parsing shares:', error); - errorElement.style.display = ''; - } - }, - - updatePageContent: function() { - const dialog = ContentShareMod.unshareDialog; - const sharesListElement = dialog.querySelector('#shares-list'); - - const startIndex = (this.currentPage - 1) * this.sharesPerPage; - const endIndex = startIndex + this.sharesPerPage; - const currentShares = this.sharesList.slice(startIndex, endIndex); - - sharesListElement.innerHTML = currentShares.map(share => ` - - `).join(''); - - sharesListElement.style.display = ''; - - const pagination = dialog.querySelector('.pagination'); - pagination.querySelector('.page-info').textContent = `${this.currentPage}/${this.totalPages}`; - const [prevButton, nextButton] = pagination.querySelectorAll('.page-btn'); - prevButton.disabled = this.currentPage === 1; - nextButton.disabled = this.currentPage === this.totalPages; - }, - - previousPage: function() { - if (this.currentPage > 1) { - this.currentPage--; - this.updatePageContent(); - } - }, - - nextPage: function() { - if (this.currentPage < this.totalPages) { - this.currentPage++; - this.updatePageContent(); - } - }, - - viewUserProfile: function(userId) { - this.hide(); - getUserDetails(userId); - }, - - revokeShare: function(userId, buttonElement) { - const contentDetails = ContentShareMod.currentContentData; - const contentType = contentDetails.AvatarId ? 'Avatar' : 'Spawnable'; - const contentId = contentDetails.AvatarId || contentDetails.SpawnableId; - - buttonElement.disabled = true; - buttonElement.textContent = 'Revoking...'; - - engine.call('NAKRevokeContentShare', contentType, contentId, userId); - }, - - handleRevokeResponse: function(success, userId, error) { - const dialog = ContentShareMod.unshareDialog; - const shareItem = dialog.querySelector(`[data-user-id="${userId}"]`); - if (!shareItem) return; - - const actionButton = shareItem.querySelector('button'); - - if (success) { - shareItem.classList.add('revoked'); - actionButton.className = 'action-btn undo-btn button'; - actionButton.textContent = 'Undo'; - actionButton.onclick = () => { - actionButton.disabled = true; - actionButton.textContent = 'Restoring...'; - - const contentDetails = ContentShareMod.currentContentData; - const contentType = contentDetails.AvatarId ? 'Avatar' : 'Spawnable'; - const contentId = contentDetails.AvatarId || contentDetails.SpawnableId; - - engine.call('NAKCallShareContentDirect', contentType, contentId, userId); - }; - uiPushShow("Share revoked successfully", 3); - } else { - actionButton.textContent = 'Failed'; - actionButton.classList.add('failed'); - uiPushShow(error || "Failed to revoke share", 3); - - // Reset button after a moment - setTimeout(() => { - actionButton.disabled = false; - actionButton.textContent = 'Revoke'; - actionButton.classList.remove('failed'); - }, 1000); - } - }, - - handleShareResponse: function(success, userId, error) { - const dialog = ContentShareMod.unshareDialog; - const shareItem = dialog.querySelector(`[data-user-id="${userId}"]`); - if (!shareItem) return; - - const actionButton = shareItem.querySelector('button'); - - if (success) { - this.requestShares(); - uiPushShow("Share restored successfully", 3); - } else { - actionButton.textContent = 'Failed'; - actionButton.classList.add('failed'); - uiPushShow(error || "Failed to restore share", 3); - - // Reset button after a moment - setTimeout(() => { - actionButton.disabled = false; - actionButton.textContent = 'Undo'; - actionButton.classList.remove('failed'); - }, 1000); - } - } - }, - - DirectShare: { - currentPage: 1, - totalPages: 1, - usersPerPage: 5, - usersList: null, - isInstanceUsers: true, - - initStyles: function() { - return ` - .direct-share-dialog { - width: 800px; - height: 1000px; - transform: translate(-50%, -60%); - display: flex; - flex-direction: column; - } - - .direct-share-dialog .search-container { - margin: 20px 0; - padding: 10px; - background: rgba(0, 0, 0, 0.2); - border-radius: 4px; - } - - .direct-share-dialog .search-input { - width: 100%; - padding: 10px; - border: none; - background: transparent; - color: inherit; - font-size: 1.1em; - } - - .direct-share-dialog .source-indicator { - padding: 10px; - text-align: center; - opacity: 0.8; - background: rgba(0, 0, 0, 0.1); - border-radius: 4px; - margin-bottom: 20px; - } - - .direct-share-dialog .users-container { - flex: 1; - overflow-y: auto; - margin-bottom: 20px; - min-height: 0; - } - - .direct-share-dialog .user-item { - display: flex; - align-items: center; - padding: 15px; - border: 1px solid rgba(255, 255, 255, 0.1); - margin-bottom: 10px; - background: rgba(0, 0, 0, 0.2); - border-radius: 4px; - min-height: 96px; - } - - .direct-share-dialog .user-item img { - width: 96px; - height: 96px; - margin-right: 15px; - cursor: pointer; - border-radius: 4px; - } - - .direct-share-dialog .user-item .user-name { - flex: 1; - font-size: 1.3em; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - margin-right: 15px; - cursor: pointer; - } - - .direct-share-dialog .user-item .action-btn { - width: 140px; - height: 50px; - font-size: 1.2em; - color: white; - background-color: rgba(27, 80, 55, 1); - border-radius: 4px; - display: inline-flex; - align-items: center; - justify-content: center; - } - - .direct-share-dialog .user-item .action-btn:disabled { - opacity: 0.5; - cursor: not-allowed; - background-color: #4a9eff; - } - - .direct-share-dialog .pagination { - border-top: 1px solid rgba(255, 255, 255, 0.1); - padding-top: 20px; - } - - .direct-share-dialog .page-info { - font-size: 1.1em; - opacity: 0.8; - margin-bottom: 15px; - text-align: center; - } - - .direct-share-dialog .page-buttons { - display: flex; - justify-content: center; - gap: 20px; - } - - .direct-share-dialog .user-item .action-btn { - width: 180px; - height: 60px; - font-size: 1.2em; - color: white; - border-radius: 4px; - display: inline-flex; - align-items: center; - justify-content: center; - margin-left: 10px; - padding: 0 20px; - text-align: center; - background-color: rgba(27, 80, 55, 1); - } - - .direct-share-dialog .user-item .action-btn:disabled { - opacity: 0.5; - cursor: not-allowed; - } - - .direct-share-dialog .user-item .action-btn.shared { - background-color: #4a9eff; - } - - .direct-share-dialog .user-item .action-btn.failed { - background-color: #ff6b6b; - } - `; - }, - - createDialog: function() { - const dialog = document.createElement('div'); - dialog.id = 'content-direct-share-dialog'; - dialog.className = 'content-sharing-base-dialog direct-share-dialog hidden'; - dialog.innerHTML = ` -

Direct Share

-
Close
- -
-
Loading users...
- - - -
- - - `; - document.body.appendChild(dialog); - return dialog; - }, - - show: function(contentDetails) { - const dialog = ContentShareMod.directShareDialog; - ContentShareMod.applyThemeToDialog(dialog); - - dialog.classList.remove('hidden', 'out'); - setTimeout(() => dialog.classList.add('in'), 50); - - ContentShareMod.currentContentData = contentDetails; - this.currentPage = 1; - this.totalPages = 1; - this.usersList = null; - this.requestUsers(true); - }, - - hide: function() { - const dialog = ContentShareMod.directShareDialog; - dialog.classList.remove('in'); - dialog.classList.add('out'); - setTimeout(() => { - dialog.classList.add('hidden'); - dialog.classList.remove('out'); - }, 200); - }, - - handleUsersResponse: function(success, users, isInstanceUsers) { - const dialog = ContentShareMod.directShareDialog; - const usersContainer = dialog.querySelector('.users-container'); - // const sourceIndicator = dialog.querySelector('.source-indicator'); - const loadingElement = usersContainer.querySelector('#users-loading'); - const errorElement = usersContainer.querySelector('#users-error'); - const emptyElement = usersContainer.querySelector('#users-empty'); - const usersListElement = usersContainer.querySelector('#users-list'); - - loadingElement.style.display = 'none'; - // sourceIndicator.textContent = isInstanceUsers ? - // 'Showing users in current instance' : - // 'Showing search results'; - - // TODO: Add source indicator to html: - //
- // Showing users in current instance - //
- - if (!success) { - errorElement.style.display = ''; - return; - } - - try { - const response = JSON.parse(users); - this.usersList = response.entries; - this.isInstanceUsers = isInstanceUsers; - - if (!this.usersList || this.usersList.length === 0) { - emptyElement.style.display = ''; - this.updatePagination(); - return; - } - - this.totalPages = Math.ceil(this.usersList.length / this.usersPerPage); - this.updatePageContent(); - } catch (error) { - console.error('Error parsing users:', error); - errorElement.style.display = ''; - } - }, - - handleSearch: function(event) { - if (event.key === 'Enter') { - const searchValue = event.target.value.trim(); - // Pass true for instance users when empty search, false for search results - this.requestUsers(searchValue === '', searchValue); - } - }, - - requestUsers: function(isInstanceUsers, searchQuery = '') { - const dialog = ContentShareMod.directShareDialog; - const usersContainer = dialog.querySelector('.users-container'); - - usersContainer.querySelector('#users-loading').style.display = ''; - usersContainer.querySelector('#users-error').style.display = 'none'; - usersContainer.querySelector('#users-empty').style.display = 'none'; - usersContainer.querySelector('#users-list').style.display = 'none'; - - engine.call('NAKGetUsersForSharing', searchQuery); - }, - - updatePageContent: function() { - const dialog = ContentShareMod.directShareDialog; - const usersListElement = dialog.querySelector('#users-list'); - - const startIndex = (this.currentPage - 1) * this.usersPerPage; - const endIndex = startIndex + this.usersPerPage; - const currentUsers = this.usersList.slice(startIndex, endIndex); - - usersListElement.innerHTML = currentUsers.map(user => ` -
- ${user.name}'s avatar - ${user.name} - -
- `).join(''); - - usersListElement.style.display = ''; - this.updatePagination(); - }, - - updatePagination: function() { - const dialog = ContentShareMod.directShareDialog; - const pagination = dialog.querySelector('.pagination'); - const [prevButton, nextButton] = pagination.querySelectorAll('.page-btn'); - - pagination.querySelector('.page-info').textContent = `Page ${this.currentPage}/${this.totalPages}`; - prevButton.disabled = this.currentPage === 1; - nextButton.disabled = this.currentPage === this.totalPages; - }, - - previousPage: function() { - if (this.currentPage > 1) { - this.currentPage--; - this.updatePageContent(); - } - }, - - nextPage: function() { - if (this.currentPage < this.totalPages) { - this.currentPage++; - this.updatePageContent(); - } - }, - - viewUserProfile: function(userId) { - this.hide(); - getUserDetails(userId); - }, - - shareWithUser: function(userId, buttonElement) { - const contentDetails = ContentShareMod.currentContentData; - const contentType = contentDetails.AvatarId ? 'Avatar' : 'Spawnable'; - const contentId = contentDetails.AvatarId || contentDetails.SpawnableId; - const contentName = contentDetails.AvatarName || contentDetails.SpawnableName; - const contentImage = contentDetails.AvatarImageURL || contentDetails.SpawnableImageURL; - - buttonElement.disabled = true; - buttonElement.textContent = 'Sharing...'; - - engine.call('NAKCallShareContentDirect', contentType, contentId, userId, contentName, contentImage); - }, - - handleShareResponse: function(success, userId, error) { - const dialog = ContentShareMod.directShareDialog; - const userItem = dialog.querySelector(`[data-user-id="${userId}"]`); - if (!userItem) return; - - const actionButton = userItem.querySelector('button'); - - if (success) { - actionButton.textContent = 'Shared'; - actionButton.disabled = true; - actionButton.classList.add('shared'); - uiPushShow("Content shared successfully", 3, "shareresponse"); - } else { - actionButton.disabled = false; - actionButton.textContent = 'Failed'; - actionButton.classList.add('failed'); - uiPushShow(error || "Failed to share content", 3, "shareresponse"); - - // Reset button after a moment - setTimeout(() => { - actionButton.disabled = false; - actionButton.textContent = 'Share'; - actionButton.classList.remove('failed', 'shared'); - }, 1000); - } - } - }, - - ShareSelect: { - initStyles: function() { - return ` - .share-select-dialog { - width: 650px; - height: 480px; - transform: translate(-50%, -80%); - } - - .share-select-dialog .share-options { - display: flex; - flex-direction: column; - gap: 15px; - margin-top: 20px; - } - - .share-select-dialog .share-option { - padding: 20px; - text-align: left; - cursor: pointer; - background: rgba(0, 0, 0, 0.2); - border: 1px solid rgba(255, 255, 255, 0.1); - border-radius: 4px; - transition: background-color 0.2s ease; - } - - .share-select-dialog .share-option:hover { - background-color: rgba(27, 80, 55, 1); - border-color: rgba(255, 255, 255, 0.2); - } - - .share-select-dialog h3 { - margin: 0 0 8px 0; - font-size: 1.2em; - } - - .share-select-dialog p { - margin: 0; - opacity: 0.8; - font-size: 0.95em; - line-height: 1.4; - } - `; - }, - - createDialog: function() { - const dialog = document.createElement('div'); - dialog.id = 'content-share-select-dialog'; - dialog.className = 'content-sharing-base-dialog share-select-dialog hidden'; - dialog.innerHTML = ` -

Share Content

-
Close
- - - `; - document.body.appendChild(dialog); - return dialog; - }, - - show: function(contentDetails) { - const dialog = ContentShareMod.shareSelectDialog; - ContentShareMod.applyThemeToDialog(dialog); - - dialog.classList.remove('hidden', 'out'); - setTimeout(() => dialog.classList.add('in'), 50); - - ContentShareMod.currentContentData = contentDetails; - }, - - hide: function() { - const dialog = ContentShareMod.shareSelectDialog; - dialog.classList.remove('in'); - dialog.classList.add('out'); - setTimeout(() => { - dialog.classList.add('hidden'); - dialog.classList.remove('out'); - }, 200); - }, - - openShareBubble: function() { - this.hide(); - ContentShareMod.ShareBubble.show(ContentShareMod.currentContentData); - }, - - openDirectShare: function() { - this.hide(); - ContentShareMod.DirectShare.show(ContentShareMod.currentContentData); - } - }, - - // Toolbar initialization and event bindings - initializeToolbars: function() { - const findEmptyButtons = (toolbar) => { - return Array.from(toolbar.querySelectorAll('.toolbar-btn')).filter( - btn => btn.textContent.trim() === "" - ); - }; - - const setupToolbar = (selector) => { - const toolbar = document.querySelector(selector); - if (!toolbar) return; - - const emptyButtons = findEmptyButtons(toolbar); - if (emptyButtons.length >= 2) { - emptyButtons[0].classList.add('content-share-btn'); - emptyButtons[0].textContent = 'Share'; - - emptyButtons[1].classList.add('content-unshare-btn'); - emptyButtons[1].textContent = 'Unshare'; - } - }; - - setupToolbar('#avatar-detail .avatar-toolbar'); - setupToolbar('#prop-detail .avatar-toolbar'); - }, - - bindEvents: function() { - // Avatar events - engine.on("LoadAvatarDetails", (avatarDetails) => { - const shareBtn = document.querySelector('#avatar-detail .content-share-btn'); - const unshareBtn = document.querySelector('#avatar-detail .content-unshare-btn'); - const canShareDirectly = avatarDetails.IsMine; - const canUnshare = avatarDetails.IsMine || avatarDetails.IsSharedWithMe; - - if (shareBtn) { - shareBtn.classList.remove('disabled'); - - if (canShareDirectly) { - shareBtn.onclick = () => ContentShareMod.ShareSelect.show(avatarDetails); - } else { - shareBtn.onclick = () => ContentShareMod.ShareBubble.show(avatarDetails); - } - } - - if (unshareBtn) { - if (canUnshare) { - unshareBtn.classList.remove('disabled'); - unshareBtn.onclick = () => { - if (avatarDetails.IsMine) { - ContentShareMod.Unshare.show(avatarDetails); - } else { - uiConfirmShow("Unshare Avatar", - "Are you sure you want to unshare this avatar?", - "unshare_avatar_confirmation", - avatarDetails.AvatarId); - } - }; - } else { - unshareBtn.classList.add('disabled'); - unshareBtn.onclick = null; - } - } - - ContentShareMod.currentContentData = avatarDetails; - }); - - // Prop events - engine.on("LoadPropDetails", (propDetails) => { - const shareBtn = document.querySelector('#prop-detail .content-share-btn'); - const unshareBtn = document.querySelector('#prop-detail .content-unshare-btn'); - const canShareDirectly = propDetails.IsMine; - const canUnshare = propDetails.IsMine || propDetails.IsSharedWithMe; - - if (shareBtn) { - shareBtn.classList.remove('disabled'); - - if (canShareDirectly) { - shareBtn.onclick = () => ContentShareMod.ShareSelect.show(propDetails); - } else { - shareBtn.onclick = () => ContentShareMod.ShareBubble.show(propDetails); - } - } - - if (unshareBtn) { - if (canUnshare) { - unshareBtn.classList.remove('disabled'); - unshareBtn.onclick = () => { - if (propDetails.IsMine) { - ContentShareMod.Unshare.show(propDetails); - } else { - uiConfirmShow("Unshare Prop", - "Are you sure you want to unshare this prop?", - "unshare_prop_confirmation", - propDetails.SpawnableId); - } - }; - } else { - unshareBtn.classList.add('disabled'); - unshareBtn.onclick = null; - } - } - - ContentShareMod.currentContentData = propDetails; - }); - - // Share response handlers - engine.on("OnHandleSharesResponse", (success, shares) => { - if (ContentShareMod.debugMode) { - console.log('Shares response:', success, shares); - } - ContentShareMod.Unshare.handleSharesResponse(success, shares); - }); - - engine.on("OnHandleRevokeResponse", (success, userId, error) => { - ContentShareMod.Unshare.handleRevokeResponse(success, userId, error); - }); - - engine.on("OnHandleShareResponse", function(success, userId, error) { - // Pass event to Unshare and DirectShare modules depending on which dialog is open - if (ContentShareMod.unshareDialog && !ContentShareMod.unshareDialog.classList.contains('hidden')) { - ContentShareMod.Unshare.handleShareResponse(success, userId, error); - } else if (ContentShareMod.directShareDialog && !ContentShareMod.directShareDialog.classList.contains('hidden')) { - ContentShareMod.DirectShare.handleShareResponse(success, userId, error); - } - }); - - // Share release handlers - engine.on("OnReleasedAvatarShare", (contentId) => { - if (!ContentShareMod.currentContentData || - ContentShareMod.currentContentData.AvatarId !== contentId) return; - - const unshareBtn = document.querySelector('#avatar-detail .content-unshare-btn'); - ContentShareMod.currentContentData.IsSharedWithMe = false; - - if (unshareBtn) { - unshareBtn.classList.add('disabled'); - unshareBtn.onclick = null; - } - - const contentIsAccessible = ContentShareMod.currentContentData.IsMine || - ContentShareMod.currentContentData.IsPublic; - - if (!contentIsAccessible) { - const detail = document.querySelector('#avatar-detail'); - if (detail) { - ['drop-btn', 'select-btn', 'fav-btn'].forEach(className => { - const button = detail.querySelector('.' + className); - if (button) { - button.classList.add('disabled'); - button.removeAttribute('onclick'); - } - }); - } - } - }); - - engine.on("OnReleasedPropShare", (contentId) => { - if (!ContentShareMod.currentContentData || - ContentShareMod.currentContentData.SpawnableId !== contentId) return; - - const unshareBtn = document.querySelector('#prop-detail .content-unshare-btn'); - ContentShareMod.currentContentData.IsSharedWithMe = false; - - if (unshareBtn) { - unshareBtn.classList.add('disabled'); - unshareBtn.onclick = null; - } - - const contentIsAccessible = ContentShareMod.currentContentData.IsMine || - ContentShareMod.currentContentData.IsPublic; - - if (!contentIsAccessible) { - const detail = document.querySelector('#prop-detail'); - if (detail) { - ['drop-btn', 'select-btn', 'fav-btn'].forEach(className => { - const button = detail.querySelector('.' + className); - if (button) { - button.classList.add('disabled'); - button.removeAttribute('onclick'); - } - }); - } - } - }); - - engine.on("OnHandleUsersResponse", (success, users, isInstanceUsers) => { - if (ContentShareMod.debugMode) { - console.log('Users response:', success, isInstanceUsers, users); - } - ContentShareMod.DirectShare.handleUsersResponse(success, users, isInstanceUsers); - }); - } -}; - -ContentShareMod.init(); - -"""; - - private const string UiConfirmId_ReleaseAvatarShareWarning = "unshare_avatar_confirmation"; - private const string UiConfirmId_ReleasePropShareWarning = "unshare_prop_confirmation"; - [HarmonyPostfix] - [HarmonyPatch(typeof(ViewManager), nameof(ViewManager.Start))] - public static void Postfix_ViewManager_Start(ViewManager __instance) + [HarmonyPatch(typeof(ViewManager), nameof(ViewManager.RegisterShareEvents))] + public static void Postfix_ViewManager_RegisterShareEvents(ViewManager __instance) { - // Inject the details toolbar patches when the game menu view is loaded - __instance.gameMenuView.Listener.FinishLoad += (_) => { - __instance.gameMenuView.View._view.ExecuteScript(DETAILS_TOOLBAR_PATCHES); - __instance.gameMenuView.View.BindCall("NAKCallShareContent", OnShareContent); - __instance.gameMenuView.View.BindCall("NAKGetContentShares", OnGetContentShares); - __instance.gameMenuView.View.BindCall("NAKRevokeContentShare", OnRevokeContentShare); - __instance.gameMenuView.View.BindCall("NAKCallShareContentDirect", OnShareContentDirect); - __instance.gameMenuView.View.BindCall("NAKGetUsersForSharing", OnGetUsersForSharing); + __instance.cohtmlView.View.BindCall("NAKCallShareContent", OnShareContent); + __instance.cohtmlView.Listener.FinishLoad += (_) => { + __instance.cohtmlView.View._view.ExecuteScript( +""" +(function waitForContentShare(){ + if (typeof ContentShare !== 'undefined') { + ContentShare.HasShareBubbles = true; + console.log('ShareBubbles patch applied'); + } else { + setTimeout(waitForContentShare, 50); + } +})(); +"""); }; - - // Add the event listener for the unshare confirmation dialog - __instance.OnUiConfirm.AddListener(OnReleaseContentShareConfirmation); - - return; + return; void OnShareContent( - string action, - string bubbleImpl, - string bubbleContent, - string shareRule, + string action, + string bubbleImpl, + string bubbleContent, + string shareRule, string shareLifetime, string shareAccess, string contentImage, @@ -1492,21 +96,21 @@ ContentShareMod.init(); // ShareRule: Public, FriendsOnly // ShareLifetime: TwoMinutes, Session // ShareAccess: PermanentAccess, SessionAccess, NoAccess - + ShareRule rule = shareRule switch { "Everyone" => ShareRule.Everyone, "FriendsOnly" => ShareRule.FriendsOnly, _ => ShareRule.Everyone }; - + ShareLifetime lifetime = shareLifetime switch { "Session" => ShareLifetime.Session, "TwoMinutes" => ShareLifetime.TwoMinutes, _ => ShareLifetime.TwoMinutes }; - + ShareAccess access = shareAccess switch { "Permanent" => ShareAccess.Permanent, @@ -1536,196 +140,9 @@ ContentShareMod.init(); ShareBubbleManager.Instance.SelectBubbleForPlace(contentImage, contentName, bubbleData); break; } - + // Close menu ViewManager.Instance.UiStateToggle(false); } - - void OnReleaseContentShareConfirmation(string id, string value, string contentId) - { - // Check if the confirmation event is for unsharing content - if (id != UiConfirmId_ReleaseAvatarShareWarning - && id != UiConfirmId_ReleasePropShareWarning) - return; - - //ShareBubblesMod.Logger.Msg($"Unshare confirmation received: {id}, {value}"); - - // Check if the user confirmed the unshare action - if (value != "true") - { - //ShareBubblesMod.Logger.Msg("Unshare action cancelled by user"); - return; - } - - //ShareBubblesMod.Logger.Msg("Releasing share..."); - - // Determine the content type based on the confirmation ID - ShareApiHelper.ShareContentType contentType = id == UiConfirmId_ReleaseAvatarShareWarning - ? ShareApiHelper.ShareContentType.Avatar - : ShareApiHelper.ShareContentType.Spawnable; - - Task.Run(async () => { - try - { - await ShareApiHelper.ReleaseShareAsync(contentType, contentId); - MTJobManager.RunOnMainThread("release_share_response", () => - { - // Cannot display a success message as opening details page pushes itself to top - // after talking to api, so success message would need to be timed to show after - // if (contentType == ApiShareHelper.ShareContentType.Avatar) - // ViewManager.Instance.RequestAvatarDetailsPage(contentId); - // else - // ViewManager.Instance.GetPropDetails(contentId); - - ViewManager.Instance.gameMenuView.View._view.TriggerEvent( - contentType == ShareApiHelper.ShareContentType.Avatar - ? "OnReleasedAvatarShare" : "OnReleasedPropShare", - contentId); - - ViewManager.Instance.TriggerPushNotification("Content unshared successfully", 3f); - }); - } - catch (ShareApiException ex) - { - ShareBubblesMod.Logger.Error($"Share API error: {ex.Message}"); - MTJobManager.RunOnMainThread("release_share_error", () => { - ViewManager.Instance.TriggerAlert("Release Share Error", ex.UserFriendlyMessage, -1, true); - }); - } - catch (Exception ex) - { - ShareBubblesMod.Logger.Error($"Unexpected error releasing share: {ex.Message}"); - MTJobManager.RunOnMainThread("release_share_error", () => { - ViewManager.Instance.TriggerAlert("Release Share Error", "An unexpected error occurred", -1, true); - }); - } - }); - } - - async void OnGetContentShares(string contentType, string contentId) - { - try - { - var response = await ShareApiHelper.GetSharesAsync>( - contentType == "Avatar" ? ShareApiHelper.ShareContentType.Avatar : ShareApiHelper.ShareContentType.Spawnable, - contentId - ); - - // TODO: somethign better than this cause this is ass and i need to replace the image urls with ImageCache coui ones - // FUICJK< - string json = JsonConvert.SerializeObject(response.Data); - - // log the json to console - //ShareBubblesMod.Logger.Msg($"Shares response: {json}"); - - __instance.gameMenuView.View.TriggerEvent("OnHandleSharesResponse", true, json); - } - catch (Exception ex) - { - ShareBubblesMod.Logger.Error($"Failed to get content shares: {ex.Message}"); - __instance.gameMenuView.View.TriggerEvent("OnHandleSharesResponse", false); - } - } - - async void OnRevokeContentShare(string contentType, string contentId, string userId) - { - try - { - await ShareApiHelper.ReleaseShareAsync( - contentType == "Avatar" ? ShareApiHelper.ShareContentType.Avatar : ShareApiHelper.ShareContentType.Spawnable, - contentId, - userId - ); - - __instance.gameMenuView.View.TriggerEvent("OnHandleRevokeResponse", true, userId); - } - catch (ShareApiException ex) - { - ShareBubblesMod.Logger.Error($"Share API error revoking share: {ex.Message}"); - __instance.gameMenuView.View.TriggerEvent("OnHandleRevokeResponse", false, userId, ex.UserFriendlyMessage); - } - catch (Exception ex) - { - ShareBubblesMod.Logger.Error($"Unexpected error revoking share: {ex.Message}"); - __instance.gameMenuView.View.TriggerEvent("OnHandleRevokeResponse", false, userId, "An unexpected error occurred"); - } - } - - async void OnShareContentDirect(string contentType, string contentId, string userId, string contentName = "", string contentImage = "") - { - try - { - ShareApiHelper.ShareContentType shareContentType = contentType == "Avatar" - ? ShareApiHelper.ShareContentType.Avatar - : ShareApiHelper.ShareContentType.Spawnable; - - await ShareApiHelper.ShareContentAsync( - shareContentType, - contentId, - userId - ); - - // Alert the user that the share occurred - //ModNetwork.SendDirectShareNotification(userId, shareContentType, contentId); - - __instance.gameMenuView.View._view.TriggerEvent("OnHandleShareResponse", true, userId); - } - catch (ShareApiException ex) - { - ShareBubblesMod.Logger.Error($"Share API error: {ex.Message}"); - __instance.gameMenuView.View._view.TriggerEvent("OnHandleShareResponse", false, userId, ex.UserFriendlyMessage); - } - catch (Exception ex) - { - ShareBubblesMod.Logger.Error($"Unexpected error sharing content: {ex.Message}"); - __instance.gameMenuView.View._view.TriggerEvent("OnHandleShareResponse", false, userId, "An unexpected error occurred"); - } - } - void OnGetUsersForSharing(string searchTerm = "") - { - try - { - if (!string.IsNullOrEmpty(searchTerm)) - { - // TODO: Search users implementation will go here - // For now just return an empty list - var response = new { entries = new List() }; - string json = JsonConvert.SerializeObject(response); - __instance.gameMenuView.View.TriggerEvent("OnHandleUsersResponse", true, json, false); - } - else - { - // Get instance users - CVRPlayerManager playerManager = CVRPlayerManager.Instance; - if (playerManager == null) - { - __instance.gameMenuView.View.TriggerEvent("OnHandleUsersResponse", false, false, true); - return; - } - - var response = new - { - entries = playerManager.NetworkPlayers - .Where(p => p != null && !string.IsNullOrEmpty(p.Uuid) - && !MetaPort.Instance.blockedUserIds.Contains(p.Uuid)) // You SHOULDNT HAVE TO DO THIS, but GS dumb - .Select(p => new - { - id = p.Uuid, - name = p.Username, - image = p.ApiProfileImageUrl - }) - .ToList() - }; - - string json = JsonConvert.SerializeObject(response); - __instance.gameMenuView.View.TriggerEvent("OnHandleUsersResponse", true, json, true); - } - } - catch (Exception ex) - { - ShareBubblesMod.Logger.Error($"Failed to get users: {ex.Message}"); - __instance.gameMenuView.View.TriggerEvent("OnHandleUsersResponse", false, false, string.IsNullOrEmpty(searchTerm)); - } - } } } \ No newline at end of file diff --git a/ShareBubbles/Properties/AssemblyInfo.cs b/ShareBubbles/Properties/AssemblyInfo.cs index ce8f183..13d5a60 100644 --- a/ShareBubbles/Properties/AssemblyInfo.cs +++ b/ShareBubbles/Properties/AssemblyInfo.cs @@ -17,7 +17,7 @@ using NAK.ShareBubbles.Properties; downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ShareBubbles" )] -[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonGame("ChilloutVR", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] [assembly: MelonColor(255, 246, 25, 99)] // red-pink @@ -27,6 +27,6 @@ using NAK.ShareBubbles.Properties; namespace NAK.ShareBubbles.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.5"; + public const string Version = "1.1.6"; public const string Author = "NotAKidoS, Exterrata, Noachi, RaidShadowLily, Tejler"; } \ No newline at end of file diff --git a/ShareBubbles/ShareBubbles/API/Exceptions/ShareApiExceptions.cs b/ShareBubbles/ShareBubbles/API/Exceptions/ShareApiExceptions.cs deleted file mode 100644 index 799a6a2..0000000 --- a/ShareBubbles/ShareBubbles/API/Exceptions/ShareApiExceptions.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System.Net; - -namespace NAK.ShareBubbles.API.Exceptions; - -public class ShareApiException : Exception -{ - public HttpStatusCode StatusCode { get; } // TODO: network back status code to claiming client, to show why the request failed - public string UserFriendlyMessage { get; } - - public ShareApiException(HttpStatusCode statusCode, string message, string userFriendlyMessage) - : base(message) - { - StatusCode = statusCode; - UserFriendlyMessage = userFriendlyMessage; - } -} - -public class ContentNotSharedException : ShareApiException -{ - public ContentNotSharedException(string contentId) - : base(HttpStatusCode.BadRequest, - $"Content {contentId} is not currently shared", - "This content is not currently shared with anyone") - { - } -} - -public class ContentNotFoundException : ShareApiException -{ - public ContentNotFoundException(string contentId) - : base(HttpStatusCode.NotFound, - $"Content {contentId} not found", - "The specified content could not be found") - { - } -} - -public class UserOnlyAllowsSharesFromFriendsException : ShareApiException -{ - public UserOnlyAllowsSharesFromFriendsException(string userId) - : base(HttpStatusCode.Forbidden, - $"User {userId} only accepts shares from friends", - "This user only accepts shares from friends") - { - } -} - -public class UserNotFoundException : ShareApiException -{ - public UserNotFoundException(string userId) - : base(HttpStatusCode.NotFound, - $"User {userId} not found", - "The specified user could not be found") - { - } -} - -public class ContentAlreadySharedException : ShareApiException -{ - public ContentAlreadySharedException(string contentId, string userId) - : base(HttpStatusCode.Conflict, - $"Content {contentId} is already shared with user {userId}", - "This content is already shared with this user") - { - } -} \ No newline at end of file diff --git a/ShareBubbles/ShareBubbles/API/PedestalInfoBatchProcessor.cs b/ShareBubbles/ShareBubbles/API/PedestalInfoBatchProcessor.cs index 967734b..43287cc 100644 --- a/ShareBubbles/ShareBubbles/API/PedestalInfoBatchProcessor.cs +++ b/ShareBubbles/ShareBubbles/API/PedestalInfoBatchProcessor.cs @@ -1,6 +1,5 @@ using ABI_RC.Core.Networking.API; using ABI_RC.Core.Networking.API.Responses; -using NAK.ShareBubbles.API.Responses; namespace NAK.ShareBubbles.API; @@ -34,6 +33,8 @@ public static class PedestalInfoBatchProcessor { PedestalType.Prop, false } }; + // This breaks compile accepting this change. + // ReSharper disable once ChangeFieldTypeToSystemThreadingLock private static readonly object _lock = new(); private const float BATCH_DELAY = 2f; diff --git a/ShareBubbles/ShareBubbles/API/Responses/ActiveSharesResponse.cs b/ShareBubbles/ShareBubbles/API/Responses/ActiveSharesResponse.cs deleted file mode 100644 index 70dc731..0000000 --- a/ShareBubbles/ShareBubbles/API/Responses/ActiveSharesResponse.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Newtonsoft.Json; - -namespace NAK.ShareBubbles.API.Responses; - -public class ActiveSharesResponse -{ - [JsonProperty("value")] - public List Value { get; set; } -} - -// Idk why not just reuse UserDetails -public class ShareUser -{ - [JsonProperty("image")] - public string Image { get; set; } - - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } -} \ No newline at end of file diff --git a/ShareBubbles/ShareBubbles/API/ShareApiHelper.cs b/ShareBubbles/ShareBubbles/API/ShareApiHelper.cs deleted file mode 100644 index c338930..0000000 --- a/ShareBubbles/ShareBubbles/API/ShareApiHelper.cs +++ /dev/null @@ -1,237 +0,0 @@ -using System.Net; -using System.Net.Http; -using System.Text; -using System.Web; -using ABI_RC.Core.Networking; -using ABI_RC.Core.Networking.API; -using ABI_RC.Core.Networking.API.Responses; -using ABI_RC.Core.Savior; -using NAK.ShareBubbles.API.Exceptions; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace NAK.ShareBubbles.API; - -/// -/// API for content sharing management. -/// -public static class ShareApiHelper -{ - #region Enums - - public enum ShareContentType - { - Avatar, - Spawnable - } - - private enum ShareApiOperation - { - ShareAvatar, - ReleaseAvatar, - - ShareSpawnable, - ReleaseSpawnable, - - GetAvatarShares, - GetSpawnableShares - } - - #endregion Enums - - #region Public API - - /// - /// Shares content with a specified user. - /// - /// Type of content to share - /// ID of the content - /// Target user ID - /// Response containing share information - /// Thrown when API request fails - /// Thrown when target user is not found - /// Thrown when content is not found - /// Thrown when user only accepts shares from friends - /// Thrown when content is already shared with user - public static Task> ShareContentAsync(ShareContentType type, string contentId, string userId) - { - ShareApiOperation operation = type == ShareContentType.Avatar - ? ShareApiOperation.ShareAvatar - : ShareApiOperation.ShareSpawnable; - - ShareRequest data = new() - { - ContentId = contentId, - UserId = userId - }; - - return MakeApiRequestAsync(operation, data); - } - - /// - /// Releases shared content from a specified user. - /// - /// Type of content to release - /// ID of the content - /// Optional user ID. If null, releases share from self - /// Response indicating success - /// Thrown when API request fails - /// Thrown when content is not shared - /// Thrown when content is not found - /// Thrown when specified user is not found - public static Task> ReleaseShareAsync(ShareContentType type, string contentId, string userId = null) - { - ShareApiOperation operation = type == ShareContentType.Avatar - ? ShareApiOperation.ReleaseAvatar - : ShareApiOperation.ReleaseSpawnable; - - // If no user ID is provided, release share from self - userId ??= MetaPort.Instance.ownerId; - - ShareRequest data = new() - { - ContentId = contentId, - UserId = userId - }; - - return MakeApiRequestAsync(operation, data); - } - - /// - /// Gets all shares for specified content. - /// - /// Type of content - /// ID of the content - /// Response containing share information - /// Thrown when API request fails - /// Thrown when content is not found - public static Task> GetSharesAsync(ShareContentType type, string contentId) - { - ShareApiOperation operation = type == ShareContentType.Avatar - ? ShareApiOperation.GetAvatarShares - : ShareApiOperation.GetSpawnableShares; - - ShareRequest data = new() { ContentId = contentId }; - return MakeApiRequestAsync(operation, data); - } - - #endregion Public API - - #region Private Implementation - - [Serializable] - private record ShareRequest - { - public string ContentId { get; set; } - public string UserId { get; set; } - } - - private static async Task> MakeApiRequestAsync(ShareApiOperation operation, ShareRequest data) - { - ValidateAuthenticationState(); - - (string endpoint, HttpMethod method) = GetApiEndpointAndMethod(operation, data); - using HttpRequestMessage request = CreateHttpRequest(endpoint, method, data); - - try - { - using HttpResponseMessage response = await ApiConnection._client.SendAsync(request); - string content = await response.Content.ReadAsStringAsync(); - - return HandleApiResponse(response, content, data.ContentId, data.UserId); - } - catch (HttpRequestException ex) - { - throw new ShareApiException( - HttpStatusCode.ServiceUnavailable, - $"Failed to communicate with the server: {ex.Message}", - "Unable to connect to the server. Please check your internet connection."); - } - catch (JsonException ex) - { - throw new ShareApiException( - HttpStatusCode.UnprocessableEntity, - $"Failed to process response data: {ex.Message}", - "Server returned invalid data. Please try again later."); - } - } - - private static void ValidateAuthenticationState() - { - if (!AuthManager.IsAuthenticated) - { - throw new ShareApiException( - HttpStatusCode.Unauthorized, - "User is not authenticated", - "Please log in to perform this action"); - } - } - - private static HttpRequestMessage CreateHttpRequest(string endpoint, HttpMethod method, ShareRequest data) - { - HttpRequestMessage request = new(method, endpoint); - - if (method == HttpMethod.Post) - { - JObject json = JObject.FromObject(data); - request.Content = new StringContent(json.ToString(), Encoding.UTF8, "application/json"); - } - - return request; - } - - private static BaseResponse HandleApiResponse(HttpResponseMessage response, string content, string contentId, string userId) - { - if (response.IsSuccessStatusCode) - return CreateSuccessResponse(content); - - // Let specific exceptions propagate up to the caller - throw response.StatusCode switch - { - HttpStatusCode.BadRequest => new ContentNotSharedException(contentId), - HttpStatusCode.NotFound when userId != null => new UserNotFoundException(userId), - HttpStatusCode.NotFound => new ContentNotFoundException(contentId), - HttpStatusCode.Forbidden => new UserOnlyAllowsSharesFromFriendsException(userId), - HttpStatusCode.Conflict => new ContentAlreadySharedException(contentId, userId), - _ => new ShareApiException( - response.StatusCode, - $"API request failed with status {response.StatusCode}: {content}", - "An unexpected error occurred. Please try again later.") - }; - } - - private static BaseResponse CreateSuccessResponse(string content) - { - var response = new BaseResponse("") - { - IsSuccessStatusCode = true, - HttpStatusCode = HttpStatusCode.OK - }; - - if (!string.IsNullOrEmpty(content)) - { - response.Data = JsonConvert.DeserializeObject(content); - } - - return response; - } - - private static (string endpoint, HttpMethod method) GetApiEndpointAndMethod(ShareApiOperation operation, ShareRequest data) - { - string baseUrl = $"{ApiConnection.APIAddress}/{ApiConnection.APIVersion}"; - string encodedContentId = HttpUtility.UrlEncode(data.ContentId); - - return operation switch - { - ShareApiOperation.GetAvatarShares => ($"{baseUrl}/avatars/{encodedContentId}/shares", HttpMethod.Get), - ShareApiOperation.ShareAvatar => ($"{baseUrl}/avatars/{encodedContentId}/shares/{HttpUtility.UrlEncode(data.UserId)}", HttpMethod.Post), - ShareApiOperation.ReleaseAvatar => ($"{baseUrl}/avatars/{encodedContentId}/shares/{HttpUtility.UrlEncode(data.UserId)}", HttpMethod.Delete), - ShareApiOperation.GetSpawnableShares => ($"{baseUrl}/spawnables/{encodedContentId}/shares", HttpMethod.Get), - ShareApiOperation.ShareSpawnable => ($"{baseUrl}/spawnables/{encodedContentId}/shares/{HttpUtility.UrlEncode(data.UserId)}", HttpMethod.Post), - ShareApiOperation.ReleaseSpawnable => ($"{baseUrl}/spawnables/{encodedContentId}/shares/{HttpUtility.UrlEncode(data.UserId)}", HttpMethod.Delete), - _ => throw new ArgumentException($"Unknown operation: {operation}") - }; - } - - #endregion Private Implementation -} \ No newline at end of file diff --git a/ShareBubbles/ShareBubbles/Implementation/AvatarBubbleImpl.cs b/ShareBubbles/ShareBubbles/Implementation/AvatarBubbleImpl.cs index b79f0c8..1c9e3de 100644 --- a/ShareBubbles/ShareBubbles/Implementation/AvatarBubbleImpl.cs +++ b/ShareBubbles/ShareBubbles/Implementation/AvatarBubbleImpl.cs @@ -1,10 +1,10 @@ using ABI_RC.Core.EventSystem; using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.IO; +using ABI_RC.Core.Networking.API; +using ABI_RC.Core.Networking.API.Exceptions; using ABI_RC.Core.Networking.API.UserWebsocket; -using ABI_RC.Core.Savior; using NAK.ShareBubbles.API; -using NAK.ShareBubbles.API.Exceptions; using ShareBubbles.ShareBubbles.Implementation; using UnityEngine; using Object = UnityEngine.Object; diff --git a/ShareBubbles/ShareBubbles/Implementation/SpawnableBubbleImpl.cs b/ShareBubbles/ShareBubbles/Implementation/SpawnableBubbleImpl.cs index 813222c..9de2b05 100644 --- a/ShareBubbles/ShareBubbles/Implementation/SpawnableBubbleImpl.cs +++ b/ShareBubbles/ShareBubbles/Implementation/SpawnableBubbleImpl.cs @@ -1,10 +1,10 @@ using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.IO; +using ABI_RC.Core.Networking.API; +using ABI_RC.Core.Networking.API.Exceptions; using ABI_RC.Core.Networking.API.UserWebsocket; using ABI_RC.Core.Player; -using ABI_RC.Core.Savior; using NAK.ShareBubbles.API; -using NAK.ShareBubbles.API.Exceptions; using ShareBubbles.ShareBubbles.Implementation; using UnityEngine; using Object = UnityEngine.Object; diff --git a/ShareBubbles/ShareBubbles/Implementation/TempShareManager.cs b/ShareBubbles/ShareBubbles/Implementation/TempShareManager.cs index d35810a..f0425e5 100644 --- a/ShareBubbles/ShareBubbles/Implementation/TempShareManager.cs +++ b/ShareBubbles/ShareBubbles/Implementation/TempShareManager.cs @@ -1,8 +1,8 @@ -using ABI_RC.Core.Networking.API.UserWebsocket; +using ABI_RC.Core.Networking.API; +using ABI_RC.Core.Networking.API.UserWebsocket; using ABI_RC.Core.Networking.IO.Instancing; using ABI_RC.Core.Player; using ABI_RC.Systems.GameEventSystem; -using NAK.ShareBubbles.API; using Newtonsoft.Json; using UnityEngine; diff --git a/ShareBubbles/ShareBubbles/Networking/ModNetwork.Inbound.cs b/ShareBubbles/ShareBubbles/Networking/ModNetwork.Inbound.cs index a9caec4..cdf302c 100644 --- a/ShareBubbles/ShareBubbles/Networking/ModNetwork.Inbound.cs +++ b/ShareBubbles/ShareBubbles/Networking/ModNetwork.Inbound.cs @@ -1,7 +1,7 @@ -using ABI_RC.Core.Networking.IO.Social; +using ABI_RC.Core.Networking.API; +using ABI_RC.Core.Networking.IO.Social; using ABI_RC.Core.Savior; using ABI_RC.Systems.ModNetwork; -using NAK.ShareBubbles.API; using UnityEngine; namespace NAK.ShareBubbles.Networking; diff --git a/ShareBubbles/ShareBubbles/Networking/ModNetwork.Outbound.cs b/ShareBubbles/ShareBubbles/Networking/ModNetwork.Outbound.cs index a09e0e1..16b065c 100644 --- a/ShareBubbles/ShareBubbles/Networking/ModNetwork.Outbound.cs +++ b/ShareBubbles/ShareBubbles/Networking/ModNetwork.Outbound.cs @@ -1,5 +1,5 @@ -using ABI_RC.Systems.ModNetwork; -using NAK.ShareBubbles.API; +using ABI_RC.Core.Networking.API; +using ABI_RC.Systems.ModNetwork; using UnityEngine; namespace NAK.ShareBubbles.Networking; diff --git a/ShareBubbles/ShareBubbles/UI/BubbleInteract.cs b/ShareBubbles/ShareBubbles/UI/BubbleInteract.cs index ad2b4f4..ea5f369 100644 --- a/ShareBubbles/ShareBubbles/UI/BubbleInteract.cs +++ b/ShareBubbles/ShareBubbles/UI/BubbleInteract.cs @@ -1,6 +1,8 @@ using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.InteractionSystem.Base; using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using ABI_RC.Systems.InputManagement; using UnityEngine; namespace NAK.ShareBubbles.UI; @@ -9,11 +11,23 @@ namespace NAK.ShareBubbles.UI; // Must be added manually by ShareBubble creation... public class BubbleInteract : Interactable { - public override bool IsInteractableWithinRange(Vector3 sourcePos) + public override bool IsInteractable { - return Vector3.Distance(transform.position, sourcePos) < 1.5f; + get + { + if (ViewManager.Instance.IsAnyMenuOpen) + return true; + + if (!MetaPort.Instance.isUsingVr + && CVRInputManager.Instance.unlockMouse) + return true; + + return false; + } } + public override bool IsInteractableWithinRange(Vector3 sourcePos) => true; + public override void OnInteractDown(InteractionContext context, ControllerRay controllerRay) { // Not used diff --git a/ShareBubbles/format.json b/ShareBubbles/format.json index d2028d6..05b88e6 100644 --- a/ShareBubbles/format.json +++ b/ShareBubbles/format.json @@ -1,9 +1,9 @@ { "_id": 244, "name": "ShareBubbles", - "modversion": "1.0.5", - "gameversion": "2025r179", - "loaderversion": "0.6.1", + "modversion": "1.1.6", + "gameversion": "2025r80", + "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS, Exterrata, Noachi, RaidShadowLily, Tejler, Luc", "description": "Share Bubbles! Allows you to drop down bubbles containing Avatars & Props. Requires both users to have the mod installed. Synced over Mod Network.\n### Features:\n- Can drop Share Bubbles linking to **any** Avatar or Prop page.\n - Share Bubbles can grant Permanent or Temporary shares to your **Private** Content if configured.\n- Adds basic in-game Share Management:\n - Directly share content to users within the current instance.\n - Revoke granted or received content shares.\n### Important:\nThe claiming of content shares through Share Bubbles will likely fail if you do not allow content shares from non-friends in your ABI Account settings!\n\n-# More information can be found on the [README](https://github.com/NotAKidoS/NAK_CVR_Mods/blob/main/ShareBubbles/README.md).", @@ -17,8 +17,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ShareBubbles.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/ShareBubbles.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ShareBubbles/", - "changelog": "- Fixes for 2025r179\n- Fixed Public/Private text on bubble not being correct\n- Fixed bubble displaying as locked or not claimed despite being shared the content if it was private and not owned by you", + "changelog": "- Fixes for 2025r180", "embedcolor": "#f61963" } \ No newline at end of file From e378a717d3e3ed8472c6b454bba8282306fe3045 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Tue, 19 Aug 2025 23:34:09 -0500 Subject: [PATCH 102/119] [RCCVirtualSteeringWheel] Fixes for 2025r180 --- RCCVirtualSteeringWheel/Properties/AssemblyInfo.cs | 4 ++-- .../Components/SteeringWheelPickup.cs | 4 ++-- RCCVirtualSteeringWheel/format.json | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/RCCVirtualSteeringWheel/Properties/AssemblyInfo.cs b/RCCVirtualSteeringWheel/Properties/AssemblyInfo.cs index 38d7ecc..03e9324 100644 --- a/RCCVirtualSteeringWheel/Properties/AssemblyInfo.cs +++ b/RCCVirtualSteeringWheel/Properties/AssemblyInfo.cs @@ -18,7 +18,7 @@ using NAK.RCCVirtualSteeringWheel.Properties; downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/RCCVirtualSteeringWheel" )] -[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonGame("ChilloutVR", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] [assembly: MelonColor(255, 246, 25, 99)] // red-pink @@ -28,6 +28,6 @@ using NAK.RCCVirtualSteeringWheel.Properties; namespace NAK.RCCVirtualSteeringWheel.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.4"; + public const string Version = "1.0.6"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/RCCVirtualSteeringWheel/RCCVirtualSteeringWheel/Components/SteeringWheelPickup.cs b/RCCVirtualSteeringWheel/RCCVirtualSteeringWheel/Components/SteeringWheelPickup.cs index 7981d63..91495dd 100644 --- a/RCCVirtualSteeringWheel/RCCVirtualSteeringWheel/Components/SteeringWheelPickup.cs +++ b/RCCVirtualSteeringWheel/RCCVirtualSteeringWheel/Components/SteeringWheelPickup.cs @@ -26,8 +26,8 @@ public class SteeringWheelPickup : Pickupable public override void OnUseDown(InteractionContext context) { } public override void OnUseUp(InteractionContext context) { } - public override void OnFlingTowardsTarget(Vector3 target) { } - + public override void FlingTowardsTarget(ControllerRay controllerRay) { } + public override void OnGrab(InteractionContext context, Vector3 grabPoint) { if (ControllerRay?.pivotPoint != null) root.StartTrackingTransform(ControllerRay.transform); diff --git a/RCCVirtualSteeringWheel/format.json b/RCCVirtualSteeringWheel/format.json index c1c44c8..78825b0 100644 --- a/RCCVirtualSteeringWheel/format.json +++ b/RCCVirtualSteeringWheel/format.json @@ -1,9 +1,9 @@ { "_id": 248, "name": "RCCVirtualSteeringWheel", - "modversion": "1.0.4", - "gameversion": "2025r179", - "loaderversion": "0.6.1", + "modversion": "1.0.6", + "gameversion": "2025r180", + "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS", "description": "Allows you to physically grab rigged RCC steering wheels in VR to provide steering input. No explicit setup required other than defining the Steering Wheel transform within the RCC component.\n", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/RCCVirtualSteeringWheel.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/RCCVirtualSteeringWheel.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/RCCVirtualSteeringWheel/", - "changelog": "- Recompiled for 2025r179\n- Fixed generated steering wheel pickup collider not being marked isTrigger\n- Fixed error spam when sitting in a CVRSeat with lockControls, but no RCC component in parent", + "changelog": "- Fixes for 2025r180", "embedcolor": "#f61963" } \ No newline at end of file From aaeb187b9e16549f325a7871052c10e51119236f Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Tue, 19 Aug 2025 23:34:19 -0500 Subject: [PATCH 103/119] [PropUndoButton] Fixes for 2025r180 --- PropUndoButton/Main.cs | 12 ++++++------ PropUndoButton/Properties/AssemblyInfo.cs | 4 ++-- PropUndoButton/format.json | 10 +++++----- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/PropUndoButton/Main.cs b/PropUndoButton/Main.cs index f0c0c67..c3c6337 100644 --- a/PropUndoButton/Main.cs +++ b/PropUndoButton/Main.cs @@ -16,17 +16,17 @@ namespace NAK.PropUndoButton; public class PropUndoButton : MelonMod { - public static readonly MelonPreferences_Category Category = + private static readonly MelonPreferences_Category Category = MelonPreferences.CreateCategory(nameof(PropUndoButton)); - public static readonly MelonPreferences_Entry EntryEnabled = + private static readonly MelonPreferences_Entry EntryEnabled = Category.CreateEntry("Enabled", true, description: "Toggle Undo Prop Button."); - public static readonly MelonPreferences_Entry EntryUseSFX = + private static readonly MelonPreferences_Entry EntryUseSFX = Category.CreateEntry("Use SFX", true, description: "Toggle audio queues for prop spawn, undo, redo, and warning."); - internal static List deletedProps = new(); + private static readonly List deletedProps = []; // audio clip names, InterfaceAudio adds "PropUndo_" prefix private const string sfx_spawn = "PropUndo_sfx_spawn"; @@ -92,11 +92,11 @@ public class PropUndoButton : MelonMod if (!File.Exists(clipPath)) { // read the clip data from embedded resources - byte[] clipData = null; + byte[] clipData; var resourceName = "PropUndoButton.SFX." + clipName; using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) { - clipData = new byte[stream.Length]; + clipData = new byte[stream!.Length]; stream.Read(clipData, 0, clipData.Length); } diff --git a/PropUndoButton/Properties/AssemblyInfo.cs b/PropUndoButton/Properties/AssemblyInfo.cs index ca45627..3849345 100644 --- a/PropUndoButton/Properties/AssemblyInfo.cs +++ b/PropUndoButton/Properties/AssemblyInfo.cs @@ -17,7 +17,7 @@ using System.Reflection; downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/UndoPropButton" )] -[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonGame("ChilloutVR", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] [assembly: MelonColor(255, 246, 25, 99)] // red-pink @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.PropUndoButton.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.3"; + public const string Version = "1.0.4"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/PropUndoButton/format.json b/PropUndoButton/format.json index 32227a9..721593d 100644 --- a/PropUndoButton/format.json +++ b/PropUndoButton/format.json @@ -1,9 +1,9 @@ { "_id": 147, "name": "PropUndoButton", - "modversion": "1.0.3", - "gameversion": "2025r179", - "loaderversion": "0.6.1", + "modversion": "1.0.4", + "gameversion": "2025r180", + "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS", "description": "**CTRL+Z** to undo latest spawned prop. **CTRL+SHIFT+Z** to redo deleted prop.\nIncludes optional SFX for prop spawn, undo, redo, warn, and deny, which can be disabled in settings.\n\nYou can replace the sfx in 'ChilloutVR\\ChilloutVR_Data\\StreamingAssets\\Cohtml\\UIResources\\GameUI\\mods\\PropUndo\\audio'.", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/PropUndoButton.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/PropUndoButton.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/PropUndoButton/", - "changelog": "- Recompiled for 2025r179", + "changelog": "- Fixes for 2025r180", "embedcolor": "#00FFFF" } \ No newline at end of file From 07daceea44f770b177b894073f97f513458e6a44 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Tue, 19 Aug 2025 23:35:04 -0500 Subject: [PATCH 104/119] [ScrollFlight] Fixes for 2025r180 --- ScrollFlight/Main.cs | 3 --- ScrollFlight/Properties/AssemblyInfo.cs | 4 ++-- ScrollFlight/format.json | 10 +++++----- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/ScrollFlight/Main.cs b/ScrollFlight/Main.cs index f2180b8..4cce7f0 100644 --- a/ScrollFlight/Main.cs +++ b/ScrollFlight/Main.cs @@ -1,10 +1,7 @@ using System.Globalization; -using System.Reflection; using ABI_RC.Core.UI; -using ABI_RC.Systems.IK.VRIKHandlers; using ABI_RC.Systems.Movement; using ABI.CCK.Components; -using HarmonyLib; using MelonLoader; using UnityEngine; diff --git a/ScrollFlight/Properties/AssemblyInfo.cs b/ScrollFlight/Properties/AssemblyInfo.cs index 64e0133..22630c9 100644 --- a/ScrollFlight/Properties/AssemblyInfo.cs +++ b/ScrollFlight/Properties/AssemblyInfo.cs @@ -17,7 +17,7 @@ using System.Reflection; downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ScrollFlight" )] -[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonGame("ChilloutVR", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] [assembly: MelonColor(255, 246, 25, 99)] // red-pink @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.ScrollFlight.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.3"; + public const string Version = "1.0.4"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/ScrollFlight/format.json b/ScrollFlight/format.json index 3cc60bd..486ad34 100644 --- a/ScrollFlight/format.json +++ b/ScrollFlight/format.json @@ -1,9 +1,9 @@ { "_id": 219, "name": "ScrollFlight", - "modversion": "1.0.3", - "gameversion": "2025r179", - "loaderversion": "0.6.1", + "modversion": "1.0.4", + "gameversion": "2025r180", + "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS", "description": "Scroll-wheel to adjust flight speed in Desktop. Stole idea from Luc.", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ScrollFlight.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/ScrollFlight.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ScrollFlight/", - "changelog": "- Recompiled for 2025r179\n- Added an option to reset flight speed to default on exit flight", + "changelog": "- Fixes for 2025r180", "embedcolor": "#f61963" } \ No newline at end of file From 218344a12179ac39d0a1902945fa8e952146abcf Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Tue, 19 Aug 2025 23:41:03 -0500 Subject: [PATCH 105/119] [ShareBubbles] Updated format.json --- ShareBubbles/format.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ShareBubbles/format.json b/ShareBubbles/format.json index 05b88e6..2dcf79f 100644 --- a/ShareBubbles/format.json +++ b/ShareBubbles/format.json @@ -2,7 +2,7 @@ "_id": 244, "name": "ShareBubbles", "modversion": "1.1.6", - "gameversion": "2025r80", + "gameversion": "2025r180", "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS, Exterrata, Noachi, RaidShadowLily, Tejler, Luc", From 1a591749c60e053bf9e666181ea48dd8ae3e369a Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Tue, 19 Aug 2025 23:42:54 -0500 Subject: [PATCH 106/119] [YouAreMyPropNowWeAreHavingSoftTacosLater] Update format.json --- YouAreMyPropNowWeAreHavingSoftTacosLater/format.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json b/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json index b88a58b..c59e4aa 100644 --- a/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json +++ b/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/YouAreMyPropNowWeAreHavingSoftTacosLater.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/YouAreMyPropNowWeAreHavingSoftTacosLater.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/YouAreMyPropNowWeAreHavingSoftTacosLater/", - "changelog": "- Initial Release", - "embedcolor": "#00FFFF" + "changelog": "- Initial release", + "embedcolor": "#f61963" } \ No newline at end of file From 7deddd88eaf021336c54f3a2040e33d9be06add4 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Tue, 19 Aug 2025 23:47:06 -0500 Subject: [PATCH 107/119] [CustomSpawnPoint] Fixes for 2025r180 --- CustomSpawnPoint/Properties/AssemblyInfo.cs | 4 ++-- CustomSpawnPoint/SpawnPointManager.cs | 14 +++++++------- CustomSpawnPoint/format.json | 10 +++++----- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/CustomSpawnPoint/Properties/AssemblyInfo.cs b/CustomSpawnPoint/Properties/AssemblyInfo.cs index 3676fa0..d1887b3 100644 --- a/CustomSpawnPoint/Properties/AssemblyInfo.cs +++ b/CustomSpawnPoint/Properties/AssemblyInfo.cs @@ -17,7 +17,7 @@ using System.Reflection; downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/CustomSpawnPoint" )] -[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonGame("ChilloutVR", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] [assembly: MelonColor(255, 246, 25, 99)] // red-pink @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.CustomSpawnPoint.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.2"; + public const string Version = "1.0.3"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/CustomSpawnPoint/SpawnPointManager.cs b/CustomSpawnPoint/SpawnPointManager.cs index 350d07c..78c81dd 100644 --- a/CustomSpawnPoint/SpawnPointManager.cs +++ b/CustomSpawnPoint/SpawnPointManager.cs @@ -41,20 +41,20 @@ internal static class SpawnPointManager { while (ViewManager.Instance == null) yield return null; - while (ViewManager.Instance.gameMenuView == null) + while (ViewManager.Instance.cohtmlView == null) yield return null; - while (ViewManager.Instance.gameMenuView.Listener == null) + while (ViewManager.Instance.cohtmlView.Listener == null) yield return null; ViewManager.Instance.OnUiConfirm.AddListener(OnClearSpawnpointConfirm); - ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) => + ViewManager.Instance.cohtmlView.Listener.FinishLoad += (_) => { - ViewManager.Instance.gameMenuView.View._view.ExecuteScript(spawnpointJs); + ViewManager.Instance.cohtmlView.View._view.ExecuteScript(spawnpointJs); }; - ViewManager.Instance.gameMenuView.Listener.ReadyForBindings += () => + ViewManager.Instance.cohtmlView.Listener.ReadyForBindings += () => { // listen for setting the spawn point on our custom button - ViewManager.Instance.gameMenuView.View.BindCall("NAKCallSetSpawnpoint", SetSpawnPoint); + ViewManager.Instance.cohtmlView.View.BindCall("NAKCallSetSpawnpoint", SetSpawnPoint); }; // create our custom spawn point object @@ -179,7 +179,7 @@ internal static class SpawnPointManager private static void UpdateMenuButtonState(bool hasSpawnpoint, bool isInWorld) { - ViewManager.Instance.gameMenuView.View.TriggerEvent("NAKUpdateSpawnpointStatus", hasSpawnpoint.ToString(), isInWorld.ToString()); + ViewManager.Instance.cohtmlView.View.TriggerEvent("NAKUpdateSpawnpointStatus", hasSpawnpoint.ToString(), isInWorld.ToString()); } private static void ClearCurrentWorldState() diff --git a/CustomSpawnPoint/format.json b/CustomSpawnPoint/format.json index 98f22da..52fe5e3 100644 --- a/CustomSpawnPoint/format.json +++ b/CustomSpawnPoint/format.json @@ -1,9 +1,9 @@ { "_id": 228, "name": "CustomSpawnPoint", - "modversion": "1.0.2", - "gameversion": "2025r179", - "loaderversion": "0.6.1", + "modversion": "1.0.3", + "gameversion": "2025r180", + "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS", "description": "Replaces the unused Images button in the World Details page with a button to set a custom spawn point.", @@ -17,8 +17,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/CustomSpawnPoint.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/CustomSpawnPoint.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/CustomSpawnPoint/", - "changelog": "- Recompiled for 2025r179", + "changelog": "- Fixes for 2025r180", "embedcolor": "#f61963" } \ No newline at end of file From 969bd00df34796dad9c8dfdac8a22e2df5571ee3 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Tue, 19 Aug 2025 23:57:04 -0500 Subject: [PATCH 108/119] [YouAreMyPropNowWeAreHavingSoftTacosLater] Updated format.json --- YouAreMyPropNowWeAreHavingSoftTacosLater/format.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json b/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json index c59e4aa..c25dfa5 100644 --- a/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json +++ b/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json @@ -1,12 +1,12 @@ { - "_id": -1, + "_id": 262, "name": "YouAreMyPropNowWeAreHavingSoftTacosLater", "modversion": "1.0.0", "gameversion": "2025r180", "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS", - "description": "Lets you bring held & attached props through world loads.\nhttps://youtu.be/9P6Jeh-VN58?si=eXTPGyKB_0wq1gZO", + "description": "Lets you bring held, attached, and occupied props through world loads. This is configurable in the mod settings.\nhttps://youtu.be/9P6Jeh-VN58?si=eXTPGyKB_0wq1gZO\n\nThere is special logic in place for bringing air vehicles through world loads. If above the ground you will be placed up to 10m above the spawnpoint of the next world.", "searchtags": [ "prop", "spawn", From 6d28f734da330f6de9d2c9c8e7c097277fe409b8 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Wed, 20 Aug 2025 00:04:03 -0500 Subject: [PATCH 109/119] [YouAreMyPropNowWeAreHavingSoftTacosLater] Updated format.json --- YouAreMyPropNowWeAreHavingSoftTacosLater/format.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json b/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json index c25dfa5..8e68782 100644 --- a/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json +++ b/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json @@ -6,7 +6,7 @@ "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS", - "description": "Lets you bring held, attached, and occupied props through world loads. This is configurable in the mod settings.\nhttps://youtu.be/9P6Jeh-VN58?si=eXTPGyKB_0wq1gZO\n\nThere is special logic in place for bringing air vehicles through world loads. If above the ground you will be placed up to 10m above the spawnpoint of the next world.", + "description": "Lets you bring held, attached, and occupied props through world loads. This is configurable in the mod settings.\nhttps://youtu.be/9P6Jeh-VN58?si=eXTPGyKB_0wq1gZO\n\nThere is special logic in place for bringing air vehicles through world loads. If above the ground you will be placed up to 20m above the spawnpoint of the next world.", "searchtags": [ "prop", "spawn", From 2f668b289ccee2a23c9f6f6ccd1610c80560124e Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Wed, 20 Aug 2025 12:09:14 -0500 Subject: [PATCH 110/119] [YouAreMyPropNowWeAreHavingSoftTacosLater] Updated README.md --- YouAreMyPropNowWeAreHavingSoftTacosLater/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/YouAreMyPropNowWeAreHavingSoftTacosLater/README.md b/YouAreMyPropNowWeAreHavingSoftTacosLater/README.md index 9ddff99..b092e40 100644 --- a/YouAreMyPropNowWeAreHavingSoftTacosLater/README.md +++ b/YouAreMyPropNowWeAreHavingSoftTacosLater/README.md @@ -1,9 +1,12 @@ # YouAreMyPropNowWeAreHavingSoftTacosLater -Lets you bring held & attached props through world loads. +Lets you bring held, attached, and occupied props through world loads. This is configurable in the mod settings. https://youtu.be/9P6Jeh-VN58?si=eXTPGyKB_0wq1gZO +There is special logic in place for bringing air vehicles through world loads. +If above the ground you will be placed up to 20m above the spawnpoint of the next world. + ## Examples https://fixupx.com/NotAKidoS/status/1910545346922422675 From 6ad23e6fc52fc929d68c6049a8ac8ab65e1bdc4e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 20 Aug 2025 17:09:37 +0000 Subject: [PATCH 111/119] [NAK_CVR_Mods] Update mod list in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 93d8d1e..76534fa 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ | [SmootherRay](SmootherRay/README.md) | Smoothes your controller while the raycast lines are visible. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/SmootherRay.dll) | | [Stickers](Stickers/README.md) | Stickers! Allows you to place small images on any surface. Requires both users to have the mod installed. Synced over Mod Network. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/Stickers.dll) | | [ThirdPerson](ThirdPerson/README.md) | Original repo: https://github.com/oestradiol/CVR-Mods | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ThirdPerson.dll) | -| [YouAreMyPropNowWeAreHavingSoftTacosLater](YouAreMyPropNowWeAreHavingSoftTacosLater/README.md) | Lets you bring held & attached props through world loads. | No Download | +| [YouAreMyPropNowWeAreHavingSoftTacosLater](YouAreMyPropNowWeAreHavingSoftTacosLater/README.md) | Lets you bring held, attached, and occupied props through world loads. This is configurable in the mod settings. | No Download | ### Experimental Mods From 6dc7f8a26752544ff3826fe8b54919550a9c0cab Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Wed, 20 Aug 2025 12:31:04 -0500 Subject: [PATCH 112/119] [ShareBubbles] Updated format.json --- ShareBubbles/README.md | 3 ++- ShareBubbles/format.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ShareBubbles/README.md b/ShareBubbles/README.md index f56f04f..650f790 100644 --- a/ShareBubbles/README.md +++ b/ShareBubbles/README.md @@ -28,7 +28,8 @@ While viewing content details of an item shared *to you* by another player, you Access Control is only available for **Private Content** and serves as a way to share content in-game. -**Note:** Session Access requires the game to be running to revoke access once you or the claimant leaves the instance. If the game is closed unexpectedly, the claimant will keep the content until you next launch the game and connect to an online instance. +**Note:** Session Access requires the game to be running to revoke access once you or the claimant leaves the instance. +If the game is closed unexpectedly, the claimant will keep the content until you next launch the game and connect to an online instance. ## Credits - Noachi - the bubble diff --git a/ShareBubbles/format.json b/ShareBubbles/format.json index 2dcf79f..4c07d5d 100644 --- a/ShareBubbles/format.json +++ b/ShareBubbles/format.json @@ -6,7 +6,7 @@ "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS, Exterrata, Noachi, RaidShadowLily, Tejler, Luc", - "description": "Share Bubbles! Allows you to drop down bubbles containing Avatars & Props. Requires both users to have the mod installed. Synced over Mod Network.\n### Features:\n- Can drop Share Bubbles linking to **any** Avatar or Prop page.\n - Share Bubbles can grant Permanent or Temporary shares to your **Private** Content if configured.\n- Adds basic in-game Share Management:\n - Directly share content to users within the current instance.\n - Revoke granted or received content shares.\n### Important:\nThe claiming of content shares through Share Bubbles will likely fail if you do not allow content shares from non-friends in your ABI Account settings!\n\n-# More information can be found on the [README](https://github.com/NotAKidoS/NAK_CVR_Mods/blob/main/ShareBubbles/README.md).", + "description": "Share Bubbles! Allows you to drop down bubbles containing Avatars & Props. Requires both users to have the mod installed. Synced over Mod Network.\n### Features:\n- Can drop Share Bubbles linking to **any** Avatar or Prop page.\n - Share Bubbles can grant Permanent or Temporary shares to your **Private** Content if configured.\n### Important:\nThe claiming of content shares through Share Bubbles will likely fail if you do not allow content shares from non-friends in your ChilloutVR Account settings on the Hub!\n\n-# More information can be found on the [README](https://github.com/NotAKidoS/NAK_CVR_Mods/blob/main/ShareBubbles/README.md).", "searchtags": [ "share", "bubbles", From 4123a1f25d9047137bc764adcaf4bc923835c2cf Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Wed, 27 Aug 2025 01:23:37 -0500 Subject: [PATCH 113/119] [ASTExtension] Fixes for 2025r180 --- ASTExtension/Extensions/PlayerSetupExtensions.cs | 4 ++-- ASTExtension/Integrations/BTKUI/BtkUiAddon.cs | 6 +++--- ASTExtension/Main.cs | 15 +++++++++------ ASTExtension/Properties/AssemblyInfo.cs | 4 ++-- ASTExtension/format.json | 10 +++++----- 5 files changed, 21 insertions(+), 18 deletions(-) diff --git a/ASTExtension/Extensions/PlayerSetupExtensions.cs b/ASTExtension/Extensions/PlayerSetupExtensions.cs index 7fa9e5b..661a94a 100644 --- a/ASTExtension/Extensions/PlayerSetupExtensions.cs +++ b/ASTExtension/Extensions/PlayerSetupExtensions.cs @@ -9,13 +9,13 @@ public static class PlayerSetupExtensions // immediate measurement of the player's avatar height public static float GetCurrentAvatarHeight(this PlayerSetup playerSetup) { - if (playerSetup._avatar == null) + if (!playerSetup.IsAvatarLoaded) { ASTExtensionMod.Logger.Error("GetCurrentAvatarHeight: Avatar is null"); return 0f; } - Vector3 localScale = playerSetup._avatar.transform.localScale; + Vector3 localScale = playerSetup.AvatarTransform.localScale; Vector3 initialScale = playerSetup.initialScale; float initialHeight = playerSetup._initialAvatarHeight; Vector3 scaleDifference = CVRTools.DivideVectors(localScale - initialScale, initialScale); diff --git a/ASTExtension/Integrations/BTKUI/BtkUiAddon.cs b/ASTExtension/Integrations/BTKUI/BtkUiAddon.cs index e0e294a..e075e88 100644 --- a/ASTExtension/Integrations/BTKUI/BtkUiAddon.cs +++ b/ASTExtension/Integrations/BTKUI/BtkUiAddon.cs @@ -49,7 +49,7 @@ public static partial class BtkUiAddon if (!CVRPlayerManager.Instance.GetPlayerPuppetMaster(_selectedPlayer, out PuppetMaster player)) return; - if (player._avatar == null) + if (!player.IsAvatarLoaded) return; float height = player.netIkController.GetRemoteHeight(); @@ -64,8 +64,8 @@ public static partial class BtkUiAddon if (!CVRPlayerManager.Instance.GetPlayerPuppetMaster(_selectedPlayer, out PuppetMaster player)) return; - AvatarAnimatorManager localAnimator = PlayerSetup.Instance.animatorManager; - AvatarAnimatorManager remoteAnimator = player.animatorManager; + AvatarAnimatorManager localAnimator = PlayerSetup.Instance.AnimatorManager; + AvatarAnimatorManager remoteAnimator = player.AnimatorManager; if (!localAnimator.IsInitialized || !remoteAnimator.IsInitialized) return; diff --git a/ASTExtension/Main.cs b/ASTExtension/Main.cs index 461dc16..4ddf871 100644 --- a/ASTExtension/Main.cs +++ b/ASTExtension/Main.cs @@ -81,7 +81,7 @@ public class ASTExtensionMod : MelonMod ); HarmonyInstance.Patch( - typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.ClearAvatar), + typeof(PlayerBase).GetMethod(nameof(PlayerBase.ClearAvatar), BindingFlags.Public | BindingFlags.Instance), prefix: new HarmonyMethod(typeof(ASTExtensionMod).GetMethod(nameof(OnClearAvatar), BindingFlags.NonPublic | BindingFlags.Static)) @@ -112,8 +112,11 @@ public class ASTExtensionMod : MelonMod Instance.OnLocalAvatarLoad(); } - private static void OnClearAvatar(ref CVRAvatar ____avatarDescriptor) - => Instance.OnLocalAvatarClear(____avatarDescriptor); + private static void OnClearAvatar(ref PlayerBase __instance) + { + if (!__instance.IsLocalPlayer) return; + Instance.OnLocalAvatarClear(__instance.AvatarDescriptor); + } #endregion Harmony Patches @@ -227,7 +230,7 @@ public class ASTExtensionMod : MelonMod { parameterName = null; - AvatarAnimatorManager animatorManager = PlayerSetup.Instance.animatorManager; + AvatarAnimatorManager animatorManager = PlayerSetup.Instance.AnimatorManager; if (!animatorManager.IsInitialized) { Logger.Error("AnimatorManager is not initialized!"); @@ -254,7 +257,7 @@ public class ASTExtensionMod : MelonMod maxHeight = 0f; modifier = 1f; - AvatarAnimatorManager animatorManager = PlayerSetup.Instance.animatorManager; + AvatarAnimatorManager animatorManager = PlayerSetup.Instance.AnimatorManager; if (!animatorManager.IsInitialized) { Logger.Error("AnimatorManager is not initialized!"); @@ -319,7 +322,7 @@ public class ASTExtensionMod : MelonMod if (!_currentAvatarSupported) return; - AvatarAnimatorManager animatorManager = PlayerSetup.Instance.animatorManager; + AvatarAnimatorManager animatorManager = PlayerSetup.Instance.AnimatorManager; if (!animatorManager.IsInitialized) { Logger.Error("AnimatorManager is not initialized!"); diff --git a/ASTExtension/Properties/AssemblyInfo.cs b/ASTExtension/Properties/AssemblyInfo.cs index 0200119..2e4d7b4 100644 --- a/ASTExtension/Properties/AssemblyInfo.cs +++ b/ASTExtension/Properties/AssemblyInfo.cs @@ -17,7 +17,7 @@ using System.Reflection; downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ASTExtension" )] -[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonGame("ChilloutVR", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] [assembly: MelonColor(255, 246, 25, 99)] // red-pink @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.ASTExtension.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.3"; + public const string Version = "1.0.4"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/ASTExtension/format.json b/ASTExtension/format.json index 934110a..abcdbfc 100644 --- a/ASTExtension/format.json +++ b/ASTExtension/format.json @@ -1,9 +1,9 @@ { "_id": 223, "name": "ASTExtension", - "modversion": "1.0.3", - "gameversion": "2025r179", - "loaderversion": "0.6.1", + "modversion": "1.0.4", + "gameversion": "2025r180", + "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS", "description": "Extension mod for [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool):\n- VR Gesture to scale\n- Persistent height\n- Copy height from others\n\nBest used with Avatar Scale Tool, but will attempt to work with found scaling setups.\nRequires already having Avatar Scaling on the avatar. This is **not** Universal Scaling.", @@ -17,8 +17,8 @@ "requirements": [ "BTKUILib" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ASTExtension.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/ASTExtension.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ASTExtension/", - "changelog": "- Recompiled for 2025r179", + "changelog": "- Fixes for 2025r180", "embedcolor": "#f61963" } \ No newline at end of file From c9acb000882dc5673246425e155a4ce59a9c4ed5 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Wed, 27 Aug 2025 01:23:45 -0500 Subject: [PATCH 114/119] [DoubleTapJumpToExitSeat] Fixes for 2025r180 --- DoubleTapJumpToExitSeat/Main.cs | 4 ++-- DoubleTapJumpToExitSeat/Properties/AssemblyInfo.cs | 4 ++-- DoubleTapJumpToExitSeat/format.json | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/DoubleTapJumpToExitSeat/Main.cs b/DoubleTapJumpToExitSeat/Main.cs index c3b5a6f..18dd9fb 100644 --- a/DoubleTapJumpToExitSeat/Main.cs +++ b/DoubleTapJumpToExitSeat/Main.cs @@ -73,8 +73,8 @@ public class DoubleTapJumpToExitSeatMod : MelonMod // Steal sync if (__instance.lockControls) { - if (__instance._spawnable != null) __instance._spawnable.ForceUpdate(4); - if (__instance._objectSync != null) __instance._objectSync.ForceUpdate(4); + if (__instance._spawnable) __instance._spawnable.ForceUpdate(4); + if (__instance._objectSync) __instance._objectSync.ForceUpdate(4); } return false; // don't call original method diff --git a/DoubleTapJumpToExitSeat/Properties/AssemblyInfo.cs b/DoubleTapJumpToExitSeat/Properties/AssemblyInfo.cs index fd30036..2e85366 100644 --- a/DoubleTapJumpToExitSeat/Properties/AssemblyInfo.cs +++ b/DoubleTapJumpToExitSeat/Properties/AssemblyInfo.cs @@ -17,7 +17,7 @@ using System.Reflection; downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/DoubleTapJumpToExitSeat" )] -[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonGame("ChilloutVR", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] [assembly: MelonColor(255, 246, 25, 99)] // red-pink @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.DoubleTapJumpToExitSeat.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.0"; + public const string Version = "1.0.1"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/DoubleTapJumpToExitSeat/format.json b/DoubleTapJumpToExitSeat/format.json index ab8e14e..e14365c 100644 --- a/DoubleTapJumpToExitSeat/format.json +++ b/DoubleTapJumpToExitSeat/format.json @@ -1,9 +1,9 @@ { - "_id": -1, + "_id": 255, "name": "DoubleTapJumpToExitSeat", - "modversion": "1.0.0", - "gameversion": "2025r179", - "loaderversion": "0.6.1", + "modversion": "1.0.1", + "gameversion": "2025r180", + "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS", "description": "Replaces seat exit controls with a double-tap of the jump button, avoiding accidental exits from joystick drift or opening the menu.", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/DoubleTapJumpToExitSeat.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/DoubleTapJumpToExitSeat.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/DoubleTapJumpToExitSeat/", - "changelog": "- Initial release", + "changelog": "- Fixes for 2025r180", "embedcolor": "#f61963" } \ No newline at end of file From 30c069388c0e76414f2e152df9413d7c5be29311 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Wed, 27 Aug 2025 01:23:56 -0500 Subject: [PATCH 115/119] [PathCamDisabler] Fixes for 2025r180 --- PathCamDisabler/Properties/AssemblyInfo.cs | 4 ++-- PathCamDisabler/format.json | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/PathCamDisabler/Properties/AssemblyInfo.cs b/PathCamDisabler/Properties/AssemblyInfo.cs index 8e01437..5dedc26 100644 --- a/PathCamDisabler/Properties/AssemblyInfo.cs +++ b/PathCamDisabler/Properties/AssemblyInfo.cs @@ -17,7 +17,7 @@ using System.Reflection; downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/PathCamDisabler" )] -[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonGame("ChilloutVR", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] [assembly: MelonColor(255, 246, 25, 99)] // red-pink @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.PathCamDisabler.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.3"; + public const string Version = "1.0.4"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/PathCamDisabler/format.json b/PathCamDisabler/format.json index 6a8d8df..44362ba 100644 --- a/PathCamDisabler/format.json +++ b/PathCamDisabler/format.json @@ -1,9 +1,9 @@ { "_id": 110, "name": "PathCamDisabler", - "modversion": "1.0.3", - "gameversion": "2025r179", - "loaderversion": "0.6.1", + "modversion": "1.0.4", + "gameversion": "2025r180", + "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS", "description": "Adds option to disable the Path Camera Controller to free up your numkeys.\nAdditional option to disable flight binding.", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/PathCamDisabler.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/PathCamDisabler.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/PathCamDisabler/", - "changelog": "- Recompiled for 2025r179", + "changelog": "- Fixes for 2025r180", "embedcolor": "#f61963" } \ No newline at end of file From c368daab4fa132d9b33ff51b8d4a004eb4c55562 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Wed, 27 Aug 2025 01:34:56 -0500 Subject: [PATCH 116/119] killed RelativeSync, now its just RelativeSyncJitterFix --- RelativeSync/Main.cs | 48 ---- RelativeSync/ModSettings.cs | 43 ---- RelativeSync/Networking/ModNetwork.cs | 151 ------------- RelativeSync/Patches.cs | 108 --------- RelativeSync/README.md | 30 --- .../Components/RelativeSyncController.cs | 206 ------------------ .../Components/RelativeSyncMarker.cs | 110 ---------- .../Components/RelativeSyncMonitor.cs | 79 ------- .../RelativeSync/RelativeSyncManager.cs | 71 ------ RelativeSync/format.json | 23 -- RelativeSyncJitterFix/Main.cs | 25 +++ RelativeSyncJitterFix/Patches.cs | 22 ++ .../Properties/AssemblyInfo.cs | 18 +- RelativeSyncJitterFix/README.md | 21 ++ .../RelativeSyncJitterFix.csproj | 0 RelativeSyncJitterFix/format.json | 23 ++ 16 files changed, 100 insertions(+), 878 deletions(-) delete mode 100644 RelativeSync/Main.cs delete mode 100644 RelativeSync/ModSettings.cs delete mode 100644 RelativeSync/Networking/ModNetwork.cs delete mode 100644 RelativeSync/Patches.cs delete mode 100644 RelativeSync/README.md delete mode 100644 RelativeSync/RelativeSync/Components/RelativeSyncController.cs delete mode 100644 RelativeSync/RelativeSync/Components/RelativeSyncMarker.cs delete mode 100644 RelativeSync/RelativeSync/Components/RelativeSyncMonitor.cs delete mode 100644 RelativeSync/RelativeSync/RelativeSyncManager.cs delete mode 100644 RelativeSync/format.json create mode 100644 RelativeSyncJitterFix/Main.cs create mode 100644 RelativeSyncJitterFix/Patches.cs rename {RelativeSync => RelativeSyncJitterFix}/Properties/AssemblyInfo.cs (65%) create mode 100644 RelativeSyncJitterFix/README.md rename RelativeSync/RelativeSync.csproj => RelativeSyncJitterFix/RelativeSyncJitterFix.csproj (100%) create mode 100644 RelativeSyncJitterFix/format.json diff --git a/RelativeSync/Main.cs b/RelativeSync/Main.cs deleted file mode 100644 index 0a50472..0000000 --- a/RelativeSync/Main.cs +++ /dev/null @@ -1,48 +0,0 @@ -using MelonLoader; -using NAK.RelativeSync.Networking; -using NAK.RelativeSync.Patches; - -namespace NAK.RelativeSync; - -public class RelativeSyncMod : MelonMod -{ - internal static MelonLogger.Instance Logger; - - public override void OnInitializeMelon() - { - Logger = LoggerInstance; - - ModNetwork.Subscribe(); - ModSettings.Initialize(); - - // Experimental sync hack - ApplyPatches(typeof(CVRSpawnablePatches)); - - // Send relative sync update after network root data update - ApplyPatches(typeof(NetworkRootDataUpdatePatches)); - - // Add components if missing (for relative sync monitor and controller) - ApplyPatches(typeof(PlayerSetupPatches)); - ApplyPatches(typeof(PuppetMasterPatches)); - - // Add components if missing (for relative sync markers) - ApplyPatches(typeof(CVRSeatPatches)); - ApplyPatches(typeof(CVRMovementParentPatches)); - - // So we run after the client moves the remote player - ApplyPatches(typeof(NetIKController_Patches)); - } - - private void ApplyPatches(Type type) - { - try - { - HarmonyInstance.PatchAll(type); - } - catch (Exception e) - { - LoggerInstance.Msg($"Failed while patching {type.Name}!"); - LoggerInstance.Error(e); - } - } -} \ No newline at end of file diff --git a/RelativeSync/ModSettings.cs b/RelativeSync/ModSettings.cs deleted file mode 100644 index f8567ad..0000000 --- a/RelativeSync/ModSettings.cs +++ /dev/null @@ -1,43 +0,0 @@ -using MelonLoader; -using NAK.RelativeSync.Networking; - -namespace NAK.RelativeSync; - -internal static class ModSettings -{ - internal const string ModName = nameof(RelativeSync); - - #region Melon Preferences - - private static readonly MelonPreferences_Category Category = - MelonPreferences.CreateCategory(ModName); - - private static readonly MelonPreferences_Entry DebugLogInbound = - Category.CreateEntry("DebugLogInbound", false, - "Debug Log Inbound", description: "Log inbound network messages."); - - private static readonly MelonPreferences_Entry DebugLogOutbound = - Category.CreateEntry("DebugLogOutbound", false, - "Debug Log Outbound", description: "Log outbound network messages."); - - private static readonly MelonPreferences_Entry ExpSyncedObjectHack = - Category.CreateEntry("ExpSyncedObjectHack", true, - "Exp Spawnable Sync Fix", description: "Forces CVRSpawnable to update position in FixedUpdate. May help reduce local jitter on synced movement parents."); - - #endregion Melon Preferences - - internal static void Initialize() - { - foreach (MelonPreferences_Entry setting in Category.Entries) - setting.OnEntryValueChangedUntyped.Subscribe(OnSettingsChanged); - - OnSettingsChanged(); - } - - private static void OnSettingsChanged(object oldValue = null, object newValue = null) - { - ModNetwork.Debug_NetworkInbound = DebugLogInbound.Value; - ModNetwork.Debug_NetworkOutbound = DebugLogOutbound.Value; - Patches.CVRSpawnablePatches.UseHack = ExpSyncedObjectHack.Value; - } -} \ No newline at end of file diff --git a/RelativeSync/Networking/ModNetwork.cs b/RelativeSync/Networking/ModNetwork.cs deleted file mode 100644 index 713f27c..0000000 --- a/RelativeSync/Networking/ModNetwork.cs +++ /dev/null @@ -1,151 +0,0 @@ -using ABI_RC.Core.Networking; -using ABI_RC.Systems.ModNetwork; -using DarkRift; -using UnityEngine; - -namespace NAK.RelativeSync.Networking; - -public static class ModNetwork -{ - public static bool Debug_NetworkInbound = false; - public static bool Debug_NetworkOutbound = false; - - private static bool _isSubscribedToModNetwork; - - private struct MovementParentSyncData - { - public bool HasSyncedThisData; - public int MarkerHash; - public Vector3 RootPosition; - public Vector3 RootRotation; - // public Vector3 HipPosition; - // public Vector3 HipRotation; - } - - private static MovementParentSyncData _latestMovementParentSyncData; - - #region Constants - - private const string ModId = "MelonMod.NAK.RelativeSync"; - - #endregion - - #region Enums - - private enum MessageType : byte - { - MovementParentOrChair = 0 - //RelativePickup = 1, - //RelativeAttachment = 2, - } - - #endregion - - #region Mod Network Internals - - internal static void Subscribe() - { - ModNetworkManager.Subscribe(ModId, OnMessageReceived); - - _isSubscribedToModNetwork = ModNetworkManager.IsSubscribed(ModId); - if (!_isSubscribedToModNetwork) - Debug.LogError("Failed to subscribe to Mod Network!"); - } - - // Called right after NetworkRootDataUpdate.Submit() - internal static void SendRelativeSyncUpdate() - { - if (!_isSubscribedToModNetwork) - return; - - if (_latestMovementParentSyncData.HasSyncedThisData) - return; - - SendMessage(MessageType.MovementParentOrChair, _latestMovementParentSyncData.MarkerHash, - _latestMovementParentSyncData.RootPosition, _latestMovementParentSyncData.RootRotation); - - _latestMovementParentSyncData.HasSyncedThisData = true; - } - - public static void SetLatestRelativeSync( - int markerHash, - Vector3 position, Vector3 rotation) - { - // check if the data has changed - if (_latestMovementParentSyncData.MarkerHash == markerHash - && _latestMovementParentSyncData.RootPosition == position - && _latestMovementParentSyncData.RootRotation == rotation) - return; // no need to update (shocking) - - _latestMovementParentSyncData.HasSyncedThisData = false; // reset - _latestMovementParentSyncData.MarkerHash = markerHash; - _latestMovementParentSyncData.RootPosition = position; - _latestMovementParentSyncData.RootRotation = rotation; - } - - private static void SendMessage(MessageType messageType, int markerHash, Vector3 position, Vector3 rotation) - { - if (!IsConnectedToGameNetwork()) - return; - - using ModNetworkMessage modMsg = new(ModId); - modMsg.Write((byte)messageType); - modMsg.Write(markerHash); - modMsg.Write(position); - modMsg.Write(rotation); - modMsg.Send(); - - if (Debug_NetworkOutbound) - Debug.Log( - $"[Outbound] MessageType: {messageType}, MarkerHash: {markerHash}, Position: {position}, " + - $"Rotation: {rotation}"); - } - - private static void OnMessageReceived(ModNetworkMessage msg) - { - msg.Read(out byte msgTypeRaw); - - if (!Enum.IsDefined(typeof(MessageType), msgTypeRaw)) - return; - - switch ((MessageType)msgTypeRaw) - { - case MessageType.MovementParentOrChair: - msg.Read(out int markerHash); - msg.Read(out Vector3 receivedPosition); - msg.Read(out Vector3 receivedRotation); - // msg.Read(out Vector3 receivedHipPosition); - // msg.Read(out Vector3 receivedHipRotation); - - OnNetworkPositionUpdateReceived(msg.Sender, markerHash, receivedPosition, receivedRotation); - - if (Debug_NetworkInbound) - Debug.Log($"[Inbound] Sender: {msg.Sender}, MarkerHash: {markerHash}, " + - $"Position: {receivedPosition}, Rotation: {receivedRotation}"); - break; - default: - Debug.LogError($"Invalid message type received from: {msg.Sender}"); - break; - } - } - - #endregion - - #region Private Methods - - private static bool IsConnectedToGameNetwork() - { - return NetworkManager.Instance != null - && NetworkManager.Instance.GameNetwork != null - && NetworkManager.Instance.GameNetwork.ConnectionState == ConnectionState.Connected; - } - - private static void OnNetworkPositionUpdateReceived( - string sender, int markerHash, - Vector3 position, Vector3 rotation) - { - RelativeSyncManager.ApplyRelativeSync(sender, markerHash, position, rotation); - } - - #endregion -} \ No newline at end of file diff --git a/RelativeSync/Patches.cs b/RelativeSync/Patches.cs deleted file mode 100644 index 10acf15..0000000 --- a/RelativeSync/Patches.cs +++ /dev/null @@ -1,108 +0,0 @@ -using ABI_RC.Core.Base; -using ABI_RC.Core.InteractionSystem; -using ABI_RC.Core.Networking.Jobs; -using ABI_RC.Core.Player; -using ABI.CCK.Components; -using HarmonyLib; -using NAK.RelativeSync.Components; -using NAK.RelativeSync.Networking; -using UnityEngine; - -namespace NAK.RelativeSync.Patches; - -internal static class PlayerSetupPatches -{ - [HarmonyPostfix] - [HarmonyPatch(typeof(PlayerSetup), nameof(PlayerSetup.Start))] - private static void Postfix_PlayerSetup_Start(ref PlayerSetup __instance) - { - __instance.AddComponentIfMissing(); - } -} - -internal static class PuppetMasterPatches -{ - [HarmonyPostfix] - [HarmonyPatch(typeof(PuppetMaster), nameof(PuppetMaster.Start))] - private static void Postfix_PuppetMaster_Start(ref PuppetMaster __instance) - { - __instance.AddComponentIfMissing(); - } -} - -internal static class CVRSeatPatches -{ - [HarmonyPostfix] - [HarmonyPatch(typeof(CVRSeat), nameof(CVRSeat.Awake))] - private static void Postfix_CVRSeat_Awake(ref CVRSeat __instance) - { - __instance.AddComponentIfMissing(); - } -} - -internal static class CVRMovementParentPatches -{ - [HarmonyPostfix] - [HarmonyPatch(typeof(CVRMovementParent), nameof(CVRMovementParent.Start))] - private static void Postfix_CVRMovementParent_Start(ref CVRMovementParent __instance) - { - __instance.AddComponentIfMissing(); - } -} - -internal static class NetworkRootDataUpdatePatches -{ - [HarmonyPostfix] - [HarmonyPatch(typeof(NetworkRootDataUpdate), nameof(NetworkRootDataUpdate.Submit))] - private static void Postfix_NetworkRootDataUpdater_Submit() - { - ModNetwork.SendRelativeSyncUpdate(); // Send the relative sync update after the network root data update - } -} - -internal static class CVRSpawnablePatches -{ - internal static bool UseHack; - - private static bool _canUpdate; - - [HarmonyPrefix] - [HarmonyPatch(typeof(CVRSpawnable), nameof(CVRSpawnable.Update))] - private static bool Prefix_CVRSpawnable_Update() - => !UseHack || _canUpdate; - - [HarmonyPostfix] - [HarmonyPatch(typeof(CVRSpawnable), nameof(CVRSpawnable.FixedUpdate))] - private static void Postfix_CVRSpawnable_FixedUpdate(ref CVRSpawnable __instance) - { - if (!UseHack) return; - - _canUpdate = true; - __instance.Update(); - _canUpdate = false; - } -} - -internal static class NetIKController_Patches -{ - [HarmonyPostfix] - [HarmonyPatch(typeof(NetIKController), nameof(NetIKController.LateUpdate))] - private static void Postfix_NetIKController_LateUpdate(ref NetIKController __instance) - { - if (!RelativeSyncManager.NetIkControllersToRelativeSyncControllers.TryGetValue(__instance, - out RelativeSyncController syncController)) - return; - - // Apply relative sync after the network IK has been applied - syncController.OnPostNetIkControllerLateUpdate(); - } - - [HarmonyPrefix] - [HarmonyPatch(typeof(NetIKController), nameof(NetIKController.GetLocalPlayerPosition))] - private static bool Prefix_NetIKController_GetLocalPlayerPosition(ref NetIKController __instance, ref Vector3 __result) - { - // why is the original method so bad - __result = PlayerSetup.Instance.activeCam.transform.position; - return false; - } -} \ No newline at end of file diff --git a/RelativeSync/README.md b/RelativeSync/README.md deleted file mode 100644 index 4ab0455..0000000 --- a/RelativeSync/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# RelativeSync - -Relative sync for Movement Parent & Chairs. Requires both users to have the mod installed. Synced over Mod Network. - -https://github.com/NotAKidoS/NAK_CVR_Mods/assets/37721153/ae6c6e4b-7529-42e2-bd2c-afa050849906 - -## Mod Settings -- **Debug Network Inbound**: Log network messages received from other players. -- **Debug Network Outbound**: Log network messages sent to other players. -- **Exp Spawnable Sync Hack**: Forces CVRSpawnable to update position in FixedUpdate. This can help with local jitter while on a remote synced movement parent. -- **Exp Disable Interpolation on BBCC**: Disables interpolation on BetterBetterCharacterController. This can help with local jitter while on any movement parent. - -## Known Issues -- Movement Parents on remote users will still locally jitter. - - PuppetMaster/NetIkController applies received position updates in LateUpdate, while character controller updates in FixedUpdate. -- Movement Parents using CVRObjectSync synced by remote users will still locally jitter. - - CVRObjectSync applies received position updates in LateUpdate, while character controller updates in FixedUpdate. -- Slight interpolation issue with humanoid avatar hips while standing on a Movement Parent. - - Requires further investigation. I believe it to be because hips are not synced properly, requiring me to relative sync the hips as well. - ---- - -Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. -https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games - -> This mod is an independent creation 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/RelativeSync/RelativeSync/Components/RelativeSyncController.cs b/RelativeSync/RelativeSync/Components/RelativeSyncController.cs deleted file mode 100644 index a94cde0..0000000 --- a/RelativeSync/RelativeSync/Components/RelativeSyncController.cs +++ /dev/null @@ -1,206 +0,0 @@ -using ABI_RC.Core.Player; -using ABI_RC.Systems.Movement; -using UnityEngine; - -namespace NAK.RelativeSync.Components; - -[DefaultExecutionOrder(9000)] // make sure this runs after NetIKController, but before Totally Wholesome LineController (9999) -public class RelativeSyncController : MonoBehaviour -{ - private const float MaxMagnitude = 750000000000f; - - private float _updateInterval = 0.05f; - private float _lastUpdate; - - private string _userId; - private PuppetMaster puppetMaster { get; set; } - private RelativeSyncMarker _relativeSyncMarker; - - private RelativeSyncData _relativeSyncData; - private RelativeSyncData _lastSyncData; - - #region Unity Events - - private void Start() - { - puppetMaster = GetComponent(); - - _userId = puppetMaster._playerDescriptor.ownerId; - RelativeSyncManager.RelativeSyncControllers.Add(_userId, this); - RelativeSyncManager.NetIkControllersToRelativeSyncControllers.Add(puppetMaster.netIkController, this); - } - - private void OnDestroy() - { - RelativeSyncManager.RelativeSyncControllers.Remove(_userId); - - if (puppetMaster == null - || puppetMaster.netIkController == null) - { - // remove by value ? - foreach (var kvp in RelativeSyncManager.NetIkControllersToRelativeSyncControllers) - { - if (kvp.Value != this) continue; - RelativeSyncManager.NetIkControllersToRelativeSyncControllers.Remove(kvp.Key); - break; - } - return; - } - RelativeSyncManager.NetIkControllersToRelativeSyncControllers.Remove(puppetMaster.netIkController); - } - - internal void OnPostNetIkControllerLateUpdate() - { - // if (puppetMaster._isHidden) - // return; - - if (_relativeSyncMarker == null) - return; - - if (!_relativeSyncMarker.IsComponentActive) - return; - - Animator animator = puppetMaster._animator; - if (animator == null) - return; - - Transform avatarTransform = animator.transform; - Transform hipTrans = (animator.avatar != null && animator.isHuman) - ? animator.GetBoneTransform(HumanBodyBones.Hips) : null; - - Vector3 relativeHipPos = default; - Quaternion relativeHipRot = default; - if (hipTrans != null) - { - Vector3 worldRootPos = avatarTransform.position; - Quaternion worldRootRot = avatarTransform.rotation; - - Vector3 hipPos = hipTrans.position; - Quaternion hipRot = hipTrans.rotation; - - relativeHipPos = Quaternion.Inverse(worldRootRot) * (hipPos - worldRootPos); - relativeHipRot = Quaternion.Inverse(worldRootRot) * hipRot; - } - - // TODO: handle the case where hip is not synced but is found on remote client - - float lerp = Mathf.Min((Time.time - _lastUpdate) / _updateInterval, 1f); - - ApplyRelativeRotation(avatarTransform, hipTrans, lerp); - ApplyRelativePosition(hipTrans, lerp); - - // idk if needed (both player root & avatar root are set to same world position) -_-_-_- - avatarTransform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); - - // fix hip syncing because it is not relative to root, it is synced in world space -_- - if (hipTrans != null) - { - hipTrans.position = transform.position + transform.rotation * relativeHipPos; - hipTrans.rotation = transform.rotation * relativeHipRot; - } - - // Reprocess the root distance so we don't fuck avatar distance hider - NetIKController netIkController = puppetMaster.netIkController; - netIkController._rootDistance = Vector3.Distance((netIkController._collider.transform.position + netIkController._collider.center), - netIkController.GetLocalPlayerPosition()) - (netIkController._collider.radius + BetterBetterCharacterController.Instance.Radius); - } - - private void ApplyRelativeRotation(Transform avatarTransform, Transform hipTransform, float lerp) - { - if (!_relativeSyncMarker.ApplyRelativeRotation || - !(_relativeSyncData.LocalRootRotation.sqrMagnitude < MaxMagnitude)) - return; // not applying relative rotation or data is invalid - - Quaternion markerRotation = _relativeSyncMarker.transform.rotation; - Quaternion lastWorldRotation = markerRotation * Quaternion.Euler(_lastSyncData.LocalRootRotation); - Quaternion worldRotation = markerRotation * Quaternion.Euler(_relativeSyncData.LocalRootRotation); - - if (_relativeSyncMarker.OnlyApplyRelativeHeading) - { - Vector3 currentWorldUp = avatarTransform.up; - - Vector3 currentForward = lastWorldRotation * Vector3.forward; - Vector3 targetForward = worldRotation * Vector3.forward; - - currentForward = Vector3.ProjectOnPlane(currentForward, currentWorldUp).normalized; - targetForward = Vector3.ProjectOnPlane(targetForward, currentWorldUp).normalized; - - lastWorldRotation = Quaternion.LookRotation(currentForward, currentWorldUp); - worldRotation = Quaternion.LookRotation(targetForward, currentWorldUp); - } - - transform.rotation = Quaternion.Slerp(lastWorldRotation, worldRotation, lerp); - } - - private void ApplyRelativePosition(Transform hipTransform, float lerp) - { - if (!_relativeSyncMarker.ApplyRelativePosition || - !(_relativeSyncData.LocalRootPosition.sqrMagnitude < MaxMagnitude)) - return; // not applying relative position or data is invalid - - Transform targetTransform = _relativeSyncMarker.transform; - - Vector3 lastWorldPosition = targetTransform.TransformPoint(_lastSyncData.LocalRootPosition); - Vector3 worldPosition = targetTransform.TransformPoint(_relativeSyncData.LocalRootPosition); - transform.position = Vector3.Lerp(lastWorldPosition, worldPosition, lerp); - - // if (hipTransform == null) - // return; - // - // Vector3 lastWorldHipPosition = targetTransform.TransformPoint(_lastSyncData.LocalHipPosition); - // Vector3 worldHipPosition = targetTransform.TransformPoint(_relativeSyncData.LocalHipPosition); - // hipTransform.position = Vector3.Lerp(lastWorldHipPosition, worldHipPosition, lerp); - } - - #endregion Unity Events - - #region Public Methods - - public void SetRelativeSyncMarker(RelativeSyncMarker target) - { - if (_relativeSyncMarker == target) - return; - - _relativeSyncMarker = target; - - // calculate relative position and rotation so lerp can smooth it out (hack) - if (_relativeSyncMarker == null) - return; - - Animator avatarAnimator = puppetMaster._animator; - if (avatarAnimator == null) - return; // i dont care to bother - - RelativeSyncManager.GetRelativeAvatarPositionsFromMarker( - avatarAnimator, _relativeSyncMarker.transform, - out Vector3 relativePosition, out Vector3 relativeRotation); - - // set last sync data to current position and rotation so we don't lerp from the last marker - _lastSyncData.LocalRootPosition = relativePosition; - _lastSyncData.LocalRootRotation = relativeRotation; - _lastUpdate = Time.time; // reset update time - } - - public void SetRelativePositions(Vector3 position, Vector3 rotation) - { - // calculate update interval - float prevUpdate = _lastUpdate; - _lastUpdate = Time.time; - _updateInterval = _lastUpdate - prevUpdate; - - // cycle last sync data - _lastSyncData = _relativeSyncData; - - // set new sync data - _relativeSyncData.LocalRootPosition = position; - _relativeSyncData.LocalRootRotation = rotation; - } - - #endregion Public Methods - - private struct RelativeSyncData - { - public Vector3 LocalRootPosition; - public Vector3 LocalRootRotation; - } -} \ No newline at end of file diff --git a/RelativeSync/RelativeSync/Components/RelativeSyncMarker.cs b/RelativeSync/RelativeSync/Components/RelativeSyncMarker.cs deleted file mode 100644 index 9627146..0000000 --- a/RelativeSync/RelativeSync/Components/RelativeSyncMarker.cs +++ /dev/null @@ -1,110 +0,0 @@ -using ABI_RC.Core.InteractionSystem; -using ABI_RC.Core.Player; -using ABI_RC.Core.Savior; -using ABI.CCK.Components; -using UnityEngine; - -namespace NAK.RelativeSync.Components; - -public class RelativeSyncMarker : MonoBehaviour -{ - public int pathHash { get; private set; } - - public bool IsComponentActive - => _component.isActiveAndEnabled; - - public bool ApplyRelativePosition = true; - public bool ApplyRelativeRotation = true; - public bool OnlyApplyRelativeHeading; - - private MonoBehaviour _component; - - private void Start() - { - RegisterWithManager(); - ConfigureForPotentialMovementParent(); - } - - private void OnDestroy() - { - RelativeSyncManager.RelativeSyncTransforms.Remove(pathHash); - } - - public void OnHavingSoftTacosNow() - => RegisterWithManager(); - - private void RegisterWithManager() - { - // Remove old hash in case this is a re-registration - RelativeSyncManager.RelativeSyncTransforms.Remove(pathHash); - - string path = GetGameObjectPath(transform); - int hash = path.GetHashCode(); - - // check if it already exists (this **should** only matter in worlds) - if (RelativeSyncManager.RelativeSyncTransforms.ContainsKey(hash)) - { - RelativeSyncMod.Logger.Warning($"Duplicate RelativeSyncMarker found at path {path}"); - if (!FindAvailableHash(ref hash)) // super lazy fix idfc - { - RelativeSyncMod.Logger.Error($"Failed to find available hash for RelativeSyncMarker after 16 tries! {path}"); - return; - } - } - - pathHash = hash; - RelativeSyncManager.RelativeSyncTransforms.Add(hash, this); - } - - private void ConfigureForPotentialMovementParent() - { - if (!gameObject.TryGetComponent(out CVRMovementParent movementParent)) - { - _component = GetComponent(); // users cant animate enabled state so i dont think matters - return; - } - _component = movementParent; - - // TODO: a refactor may be needed to handle the orientation mode being animated - - // respect orientation mode & gravity zone - ApplyRelativeRotation = movementParent.orientationMode == CVRMovementParent.OrientationMode.RotateWithParent; - OnlyApplyRelativeHeading = movementParent.GetComponent() == null; - } - - private static string GetGameObjectPath(Transform transform) - { - // props already have a unique instance identifier at root - // worlds uhhhh, dont duplicate the same thing over and over thx - // avatars on remote/local client have diff path, we need to account for it -_- - - string path = transform.name; - while (transform.parent != null) - { - transform = transform.parent; - - // only true at root of local player object - if (transform.CompareTag("Player")) - { - path = MetaPort.Instance.ownerId + "/" + path; - break; - } // remote player object root is already player guid - - path = transform.name + "/" + path; - } - - return path; - } - - private static bool FindAvailableHash(ref int hash) - { - for (int i = 0; i < 16; i++) - { - hash += 1; - if (!RelativeSyncManager.RelativeSyncTransforms.ContainsKey(hash)) return true; - } - - // failed to find a hash in 16 tries, dont care - return false; - } -} diff --git a/RelativeSync/RelativeSync/Components/RelativeSyncMonitor.cs b/RelativeSync/RelativeSync/Components/RelativeSyncMonitor.cs deleted file mode 100644 index 134234c..0000000 --- a/RelativeSync/RelativeSync/Components/RelativeSyncMonitor.cs +++ /dev/null @@ -1,79 +0,0 @@ -using ABI_RC.Core.Player; -using ABI_RC.Systems.Movement; -using NAK.RelativeSync.Networking; -using UnityEngine; - -namespace NAK.RelativeSync.Components; - -[DefaultExecutionOrder(int.MaxValue)] -public class RelativeSyncMonitor : MonoBehaviour -{ - private BetterBetterCharacterController _characterController { get; set; } - - private RelativeSyncMarker _relativeSyncMarker; - private RelativeSyncMarker _lastRelativeSyncMarker; - - private void Start() - { - _characterController = GetComponent(); - } - - private void LateUpdate() - { - if (_characterController == null) - return; - - CheckForRelativeSyncMarker(); - - if (_relativeSyncMarker == null) - { - if (_lastRelativeSyncMarker == null) - return; - - // send empty position and rotation to stop syncing - SendEmptyPositionAndRotation(); - _lastRelativeSyncMarker = null; - return; - } - - _lastRelativeSyncMarker = _relativeSyncMarker; - - Animator avatarAnimator = PlayerSetup.Instance._animator; - if (avatarAnimator == null) - return; // i dont care to bother - - RelativeSyncManager.GetRelativeAvatarPositionsFromMarker( - avatarAnimator, _relativeSyncMarker.transform, - out Vector3 relativePosition, out Vector3 relativeRotation); - - ModNetwork.SetLatestRelativeSync( - _relativeSyncMarker.pathHash, - relativePosition, relativeRotation); - } - - private void CheckForRelativeSyncMarker() - { - if (_characterController._isSitting && _characterController._lastCvrSeat) - { - RelativeSyncMarker newMarker = _characterController._lastCvrSeat.GetComponent(); - _relativeSyncMarker = newMarker; - return; - } - - if (_characterController._previousMovementParent != null) - { - RelativeSyncMarker newMarker = _characterController._previousMovementParent.GetComponent(); - _relativeSyncMarker = newMarker; - return; - } - - // none found - _relativeSyncMarker = null; - } - - private void SendEmptyPositionAndRotation() - { - ModNetwork.SetLatestRelativeSync(RelativeSyncManager.NoTarget, - Vector3.zero, Vector3.zero); - } -} \ No newline at end of file diff --git a/RelativeSync/RelativeSync/RelativeSyncManager.cs b/RelativeSync/RelativeSync/RelativeSyncManager.cs deleted file mode 100644 index 052ca3c..0000000 --- a/RelativeSync/RelativeSync/RelativeSyncManager.cs +++ /dev/null @@ -1,71 +0,0 @@ -using ABI_RC.Core.Base; -using ABI_RC.Core.Player; -using NAK.RelativeSync.Components; -using UnityEngine; - -namespace NAK.RelativeSync; - -public static class RelativeSyncManager -{ - public const int NoTarget = -1; - - public static readonly Dictionary RelativeSyncTransforms = new(); - public static readonly Dictionary RelativeSyncControllers = new(); - public static readonly Dictionary NetIkControllersToRelativeSyncControllers = new(); - - public static void ApplyRelativeSync(string userId, int target, Vector3 position, Vector3 rotation) - { - if (!RelativeSyncControllers.TryGetValue(userId, out RelativeSyncController controller)) - { - if (CVRPlayerManager.Instance.GetPlayerPuppetMaster(userId, out PuppetMaster pm)) - { - controller = pm.AddComponentIfMissing(); - RelativeSyncMod.Logger.Msg($"Found PuppetMaster for user {userId}. This user is now eligible for relative sync."); - } - else - { - RelativeSyncControllers.Add(userId, null); // add null controller to prevent future lookups - RelativeSyncMod.Logger.Warning($"Failed to find PuppetMaster for user {userId}. This is likely because the user is blocked or has blocked you. This user will not be eligible for relative sync until next game restart."); - } - } - - if (controller == null) - return; - - // find target transform - RelativeSyncMarker syncMarker = null; - if (target != NoTarget) RelativeSyncTransforms.TryGetValue(target, out syncMarker); - - controller.SetRelativeSyncMarker(syncMarker); - controller.SetRelativePositions(position, rotation); - } - - public static void GetRelativeAvatarPositionsFromMarker( - Animator avatarAnimator, Transform markerTransform, - out Vector3 relativePosition, out Vector3 relativeRotation) - // out Vector3 relativeHipPosition, out Vector3 relativeHipRotation) - { - Transform avatarTransform = avatarAnimator.transform; - - // because our syncing is retarded, we need to sync relative from the avatar root... - Vector3 avatarRootPosition = avatarTransform.position; // PlayerSetup.Instance.GetPlayerPosition() - Quaternion avatarRootRotation = avatarTransform.rotation; // PlayerSetup.Instance.GetPlayerRotation() - - relativePosition = markerTransform.InverseTransformPoint(avatarRootPosition); - relativeRotation = (Quaternion.Inverse(markerTransform.rotation) * avatarRootRotation).eulerAngles; - - // Transform hipTrans = (avatarAnimator.avatar != null && avatarAnimator.isHuman) - // ? avatarAnimator.GetBoneTransform(HumanBodyBones.Hips) : null; - // - // if (hipTrans == null) - // { - // relativeHipPosition = Vector3.zero; - // relativeHipRotation = Vector3.zero; - // } - // else - // { - // relativeHipPosition = markerTransform.InverseTransformPoint(hipTrans.position); - // relativeHipRotation = (Quaternion.Inverse(markerTransform.rotation) * hipTrans.rotation).eulerAngles; - // } - } -} \ No newline at end of file diff --git a/RelativeSync/format.json b/RelativeSync/format.json deleted file mode 100644 index a5346fa..0000000 --- a/RelativeSync/format.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "_id": 211, - "name": "RelativeSync", - "modversion": "1.0.5", - "gameversion": "2025r179", - "loaderversion": "0.6.1", - "modtype": "Mod", - "author": "NotAKidoS", - "description": "Relative sync for Movement Parent & Chairs. Requires both users to have the mod installed. Synced over Mod Network.\n\nProvides some Experimental settings to also fix local jitter on movement parents.", - "searchtags": [ - "relative", - "sync", - "movement", - "chair" - ], - "requirements": [ - "None" - ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/RelativeSync.dll", - "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/RelativeSync/", - "changelog": "- Recompiled for 2025r179\n- Fixed execution order of RelativeSyncController so moving at high speeds with passengers does not disrupt voice or avatar distance hider", - "embedcolor": "#f61963" -} \ No newline at end of file diff --git a/RelativeSyncJitterFix/Main.cs b/RelativeSyncJitterFix/Main.cs new file mode 100644 index 0000000..19863d1 --- /dev/null +++ b/RelativeSyncJitterFix/Main.cs @@ -0,0 +1,25 @@ +using MelonLoader; + +namespace NAK.RelativeSyncJitterFix; + +public class RelativeSyncJitterFixMod : MelonMod +{ + public override void OnInitializeMelon() + { + // Experimental sync hack + ApplyPatches(typeof(Patches.CVRSpawnablePatches)); + } + + private void ApplyPatches(Type type) + { + try + { + HarmonyInstance.PatchAll(type); + } + catch (Exception e) + { + LoggerInstance.Msg($"Failed while patching {type.Name}!"); + LoggerInstance.Error(e); + } + } +} \ No newline at end of file diff --git a/RelativeSyncJitterFix/Patches.cs b/RelativeSyncJitterFix/Patches.cs new file mode 100644 index 0000000..71a67f7 --- /dev/null +++ b/RelativeSyncJitterFix/Patches.cs @@ -0,0 +1,22 @@ +using ABI.CCK.Components; +using HarmonyLib; + +namespace NAK.RelativeSyncJitterFix.Patches; + +internal static class CVRSpawnablePatches +{ + private static bool _canUpdate; + + [HarmonyPostfix] + [HarmonyPatch(typeof(CVRSpawnable), nameof(CVRSpawnable.FixedUpdate))] + private static void Postfix_CVRSpawnable_FixedUpdate(ref CVRSpawnable __instance) + { + _canUpdate = true; + __instance.Update(); + _canUpdate = false; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(CVRSpawnable), nameof(CVRSpawnable.Update))] + private static bool Prefix_CVRSpawnable_Update() => _canUpdate; +} \ No newline at end of file diff --git a/RelativeSync/Properties/AssemblyInfo.cs b/RelativeSyncJitterFix/Properties/AssemblyInfo.cs similarity index 65% rename from RelativeSync/Properties/AssemblyInfo.cs rename to RelativeSyncJitterFix/Properties/AssemblyInfo.cs index ef60248..ff4fcd8 100644 --- a/RelativeSync/Properties/AssemblyInfo.cs +++ b/RelativeSyncJitterFix/Properties/AssemblyInfo.cs @@ -1,32 +1,32 @@ -using NAK.RelativeSync.Properties; +using NAK.RelativeSyncJitterFix.Properties; using MelonLoader; using System.Reflection; [assembly: AssemblyVersion(AssemblyInfoParams.Version)] [assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] [assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] -[assembly: AssemblyTitle(nameof(NAK.RelativeSync))] +[assembly: AssemblyTitle(nameof(NAK.RelativeSyncJitterFix))] [assembly: AssemblyCompany(AssemblyInfoParams.Author)] -[assembly: AssemblyProduct(nameof(NAK.RelativeSync))] +[assembly: AssemblyProduct(nameof(NAK.RelativeSyncJitterFix))] [assembly: MelonInfo( - typeof(NAK.RelativeSync.RelativeSyncMod), - nameof(NAK.RelativeSync), + typeof(NAK.RelativeSyncJitterFix.RelativeSyncJitterFixMod), + nameof(NAK.RelativeSyncJitterFix), AssemblyInfoParams.Version, AssemblyInfoParams.Author, - downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/RelativeSync" + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/RelativeSyncJitterFix" )] -[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonGame("ChilloutVR", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] [assembly: MelonColor(255, 246, 25, 99)] // red-pink [assembly: MelonAuthorColor(255, 158, 21, 32)] // red [assembly: HarmonyDontPatchAll] -namespace NAK.RelativeSync.Properties; +namespace NAK.RelativeSyncJitterFix.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.5"; + public const string Version = "1.0.0"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/RelativeSyncJitterFix/README.md b/RelativeSyncJitterFix/README.md new file mode 100644 index 0000000..7978ed2 --- /dev/null +++ b/RelativeSyncJitterFix/README.md @@ -0,0 +1,21 @@ +# RelativeSyncJitterFix + +Relative sync jitter fix is the single harmony patch that could not make it into the native release of RelativeSync. +Changes when props apply their incoming sync data to be before the character controller simulation. + +## Known Issues +- Movement Parents on remote users will still locally jitter. + - PuppetMaster/NetIkController applies received position updates in LateUpdate, while character controller updates in FixedUpdate. +- Movement Parents using CVRObjectSync synced by remote users will still locally jitter. + - CVRObjectSync applies received position updates in LateUpdate, while character controller updates in FixedUpdate. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ChilloutVR. +https://docs.chilloutvr.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation not affiliated with, supported by, or approved by ChilloutVR. + +> 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 ChilloutVR. diff --git a/RelativeSync/RelativeSync.csproj b/RelativeSyncJitterFix/RelativeSyncJitterFix.csproj similarity index 100% rename from RelativeSync/RelativeSync.csproj rename to RelativeSyncJitterFix/RelativeSyncJitterFix.csproj diff --git a/RelativeSyncJitterFix/format.json b/RelativeSyncJitterFix/format.json new file mode 100644 index 0000000..b128e2a --- /dev/null +++ b/RelativeSyncJitterFix/format.json @@ -0,0 +1,23 @@ +{ + "_id": -1, + "name": "RelativeSyncJitterFix", + "modversion": "1.0.0", + "gameversion": "2025r180", + "loaderversion": "0.7.2", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Relative sync jitter fix is the single harmony patch that could not make it into the native release of RelativeSync.\nChanges when props apply their incoming sync data to be before the character controller simulation.", + "searchtags": [ + "relative", + "sync", + "movement", + "chair" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/RelativeSyncJitterFix.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/RelativeSyncJitterFix/", + "changelog": "- Removed RelativeSync except for a single harmony patch", + "embedcolor": "#f61963" +} \ No newline at end of file From 1496c25184aa87d04fb0ee7402e6c19d28a9fbc7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 27 Aug 2025 06:35:11 +0000 Subject: [PATCH 117/119] [NAK_CVR_Mods] Update mod list in README --- README.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 76534fa..2d2371e 100644 --- a/README.md +++ b/README.md @@ -6,22 +6,22 @@ | Name | Description | Download | |------|-------------|----------| -| [ASTExtension](ASTExtension/README.md) | Extension mod for [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool): | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ASTExtension.dll) | -| [AvatarQueueSystemTweaks](AvatarQueueSystemTweaks/README.md) | Small tweaks to the Avatar Queue System. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/AvatarQueueSystemTweaks.dll) | +| [ASTExtension](ASTExtension/README.md) | Extension mod for [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool): | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/ASTExtension.dll) | +| [AvatarQueueSystemTweaks](AvatarQueueSystemTweaks/README.md) | Small tweaks to the Avatar Queue System. | No Download | | [ConfigureCalibrationPose](ConfigureCalibrationPose/README.md) | Select FBT calibration pose. | No Download | -| [CustomSpawnPoint](CustomSpawnPoint/README.md) | Replaces the unused Images button in the World Details page with a button to set a custom spawn point. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/CustomSpawnPoint.dll) | -| [DoubleTapJumpToExitSeat](DoubleTapJumpToExitSeat/README.md) | Replaces seat exit controls with a double-tap of the jump button, avoiding accidental exits from joystick drift or opening the menu. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/DoubleTapJumpToExitSeat.dll) | -| [FuckToes](FuckToes/README.md) | Prevents VRIK from autodetecting toes in Halfbody or Fullbody. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/FuckToes.dll) | -| [KeepVelocityOnExitFlight](KeepVelocityOnExitFlight/README.md) | Keeps the player's velocity when exiting flight mode. Makes it possible to fling yourself like in Garry's Mod. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/KeepVelocityOnExitFlight.dll) | -| [LazyPrune](LazyPrune/README.md) | Prevents loaded objects from immediately unloading on destruction. Should prevent needlessly unloading & reloading all avatars/props on world rejoin or GS reconnection. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/LazyPrune.dll) | -| [PropLoadingHexagon](PropLoadingHexagon/README.md) | https://github.com/NotAKidoS/NAK_CVR_Mods/assets/37721153/a892c765-71c1-47f3-a781-bdb9b60ba117 | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/PropLoadingHexagon.dll) | -| [RCCVirtualSteeringWheel](RCCVirtualSteeringWheel/README.md) | Allows you to physically grab rigged RCC steering wheels in VR to provide steering input. No explicit setup required other than defining the Steering Wheel transform within the RCC component. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/RCCVirtualSteeringWheel.dll) | -| [RelativeSync](RelativeSync/README.md) | Relative sync for Movement Parent & Chairs. Requires both users to have the mod installed. Synced over Mod Network. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/RelativeSync.dll) | -| [ShareBubbles](ShareBubbles/README.md) | Share Bubbles! Allows you to drop down bubbles containing Avatars & Props. Requires both users to have the mod installed. Synced over Mod Network. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ShareBubbles.dll) | -| [SmootherRay](SmootherRay/README.md) | Smoothes your controller while the raycast lines are visible. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/SmootherRay.dll) | -| [Stickers](Stickers/README.md) | Stickers! Allows you to place small images on any surface. Requires both users to have the mod installed. Synced over Mod Network. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/Stickers.dll) | -| [ThirdPerson](ThirdPerson/README.md) | Original repo: https://github.com/oestradiol/CVR-Mods | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/ThirdPerson.dll) | -| [YouAreMyPropNowWeAreHavingSoftTacosLater](YouAreMyPropNowWeAreHavingSoftTacosLater/README.md) | Lets you bring held, attached, and occupied props through world loads. This is configurable in the mod settings. | No Download | +| [CustomSpawnPoint](CustomSpawnPoint/README.md) | Replaces the unused Images button in the World Details page with a button to set a custom spawn point. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/CustomSpawnPoint.dll) | +| [DoubleTapJumpToExitSeat](DoubleTapJumpToExitSeat/README.md) | Replaces seat exit controls with a double-tap of the jump button, avoiding accidental exits from joystick drift or opening the menu. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/DoubleTapJumpToExitSeat.dll) | +| [FuckToes](FuckToes/README.md) | Prevents VRIK from autodetecting toes in Halfbody or Fullbody. | No Download | +| [KeepVelocityOnExitFlight](KeepVelocityOnExitFlight/README.md) | Keeps the player's velocity when exiting flight mode. Makes it possible to fling yourself like in Garry's Mod. | No Download | +| [LazyPrune](LazyPrune/README.md) | Prevents loaded objects from immediately unloading on destruction. Should prevent needlessly unloading & reloading all avatars/props on world rejoin or GS reconnection. | No Download | +| [PropLoadingHexagon](PropLoadingHexagon/README.md) | https://github.com/NotAKidoS/NAK_CVR_Mods/assets/37721153/a892c765-71c1-47f3-a781-bdb9b60ba117 | No Download | +| [RCCVirtualSteeringWheel](RCCVirtualSteeringWheel/README.md) | Allows you to physically grab rigged RCC steering wheels in VR to provide steering input. No explicit setup required other than defining the Steering Wheel transform within the RCC component. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/RCCVirtualSteeringWheel.dll) | +| [RelativeSyncJitterFix](RelativeSyncJitterFix/README.md) | Relative sync jitter fix is the single harmony patch that could not make it into the native release of RelativeSync. | No Download | +| [ShareBubbles](ShareBubbles/README.md) | Share Bubbles! Allows you to drop down bubbles containing Avatars & Props. Requires both users to have the mod installed. Synced over Mod Network. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/ShareBubbles.dll) | +| [SmootherRay](SmootherRay/README.md) | Smoothes your controller while the raycast lines are visible. | No Download | +| [Stickers](Stickers/README.md) | Stickers! Allows you to place small images on any surface. Requires both users to have the mod installed. Synced over Mod Network. | No Download | +| [ThirdPerson](ThirdPerson/README.md) | Original repo: https://github.com/oestradiol/CVR-Mods | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/ThirdPerson.dll) | +| [YouAreMyPropNowWeAreHavingSoftTacosLater](YouAreMyPropNowWeAreHavingSoftTacosLater/README.md) | Lets you bring held, attached, and occupied props through world loads. This is configurable in the mod settings. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/YouAreMyPropNowWeAreHavingSoftTacosLater.dll) | ### Experimental Mods @@ -29,7 +29,7 @@ |------|-------------|----------| | [CVRLuaToolsExtension](.Experimental/CVRLuaToolsExtension/README.md) | Extension mod for [CVRLuaTools](https://github.com/NotAKidoS/CVRLuaTools) Hot Reload functionality. | No Download | | [CustomRichPresence](.Experimental/CustomRichPresence/README.md) | Lets you customize the Steam & Discord rich presence messages & values. | No Download | -| [LuaNetworkVariables](.Experimental/LuaNetworkVariables/README.md) | Adds a simple module for creating network variables & events *kinda* similar to Garry's Mod. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/LuaNetworkVariables.dll) | +| [LuaNetworkVariables](.Experimental/LuaNetworkVariables/README.md) | Adds a simple module for creating network variables & events *kinda* similar to Garry's Mod. | No Download | | [LuaTTS](.Experimental/LuaTTS/README.md) | Provides access to the built-in text-to-speech (TTS) functionality to lua scripts. Allows you to make the local player speak. | No Download | | [OriginShift](.Experimental/OriginShift/README.md) | Experimental mod that allows world origin to be shifted to prevent floating point precision issues. | No Download | | [ScriptingSpoofer](.Experimental/ScriptingSpoofer/README.md) | Prevents **local** scripts from accessing your Username or UserID by spoofing them with random values each session. | No Download | From 6bef1d0c9694a3704b5747a619a23eaa7defbf03 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidoS@users.noreply.github.com> Date: Wed, 27 Aug 2025 05:21:26 -0500 Subject: [PATCH 118/119] [Tinyboard] Initial release --- Tinyboard/Main.cs | 346 +++++++++++++++++++++++++++ Tinyboard/Properties/AssemblyInfo.cs | 32 +++ Tinyboard/README.md | 19 ++ Tinyboard/Tinyboard.csproj | 6 + Tinyboard/format.json | 23 ++ 5 files changed, 426 insertions(+) create mode 100644 Tinyboard/Main.cs create mode 100644 Tinyboard/Properties/AssemblyInfo.cs create mode 100644 Tinyboard/README.md create mode 100644 Tinyboard/Tinyboard.csproj create mode 100644 Tinyboard/format.json diff --git a/Tinyboard/Main.cs b/Tinyboard/Main.cs new file mode 100644 index 0000000..540d150 --- /dev/null +++ b/Tinyboard/Main.cs @@ -0,0 +1,346 @@ +using System.Reflection; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Savior; +using ABI_RC.Core.UI; +using ABI_RC.Core.UI.UIRework.Managers; +using ABI_RC.Systems.VRModeSwitch; +using ABI_RC.VideoPlayer.Scripts; +using HarmonyLib; +using MelonLoader; +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +namespace NAK.Tinyboard; + +public class TinyboardMod : MelonMod +{ + #region Melon Preferences + + private static readonly MelonPreferences_Category Category = + MelonPreferences.CreateCategory(nameof(Tinyboard)); + + private static readonly MelonPreferences_Entry EntrySmartAlignToMenu = + Category.CreateEntry( + identifier: "smart_align_to_menu", + true, + display_name: "Smart Align To Menu", + description: "Should the keyboard align to the menu it was opened from? (Main Menu, World-Anchored Quick Menu)"); + + private static readonly MelonPreferences_Entry EntryEnforceTitle = + Category.CreateEntry( + identifier: "enforce_title", + true, + display_name: "Enforce Title", + description: "Should the keyboard enforce a title when opened from an input field or main menu?"); + + private static readonly MelonPreferences_Entry EntryResizeKeyboard = + Category.CreateEntry( + identifier: "resize_keyboard", + true, + display_name: "Resize Keyboard", + description: "Should the keyboard be resized to match XSOverlays width?"); + + private static readonly MelonPreferences_Entry EntryUseModifiers = + Category.CreateEntry( + identifier: "use_scale_distance_modifiers", + true, + display_name: "Use Scale/Distance/Offset Modifiers", + description: "Should the scale/distance/offset modifiers be used?"); + + private static readonly MelonPreferences_Entry EntryDesktopScaleModifier = + Category.CreateEntry( + identifier: "desktop_scale_modifier", + 0.75f, + display_name: "Desktop Scale Modifier", + description: "Scale modifier for desktop mode."); + + private static readonly MelonPreferences_Entry EntryDesktopDistance = + Category.CreateEntry( + identifier: "desktop_distance_modifier", + 0f, + display_name: "Desktop Distance Modifier", + description: "Distance modifier for desktop mode."); + + private static readonly MelonPreferences_Entry EntryDesktopVerticalAdjustment = + Category.CreateEntry( + identifier: "desktop_vertical_adjustment", + 0.1f, + display_name: "Desktop Vertical Adjustment", + description: "Vertical adjustment for desktop mode."); + + private static readonly MelonPreferences_Entry EntryVRScaleModifier = + Category.CreateEntry( + identifier: "vr_scale_modifier", + 0.85f, + display_name: "VR Scale Modifier", + description: "Scale modifier for VR mode."); + + private static readonly MelonPreferences_Entry EntryVRDistance = + Category.CreateEntry( + identifier: "vr_distance_modifier", + 0.2f, + display_name: "VR Distance Modifier", + description: "Distance modifier for VR mode."); + + private static readonly MelonPreferences_Entry EntryVRVerticalAdjustment = + Category.CreateEntry( + identifier: "vr_vertical_adjustment", + 0f, + display_name: "VR Vertical Adjustment", + description: "Vertical adjustment for VR mode."); + + #endregion Melon Preferences + + private static Transform _tinyBoardOffset; + private static void ApplyTinyBoardOffsetsForVRMode() + { + if (!EntryUseModifiers.Value) + { + _tinyBoardOffset.localScale = Vector3.one; + _tinyBoardOffset.localPosition = Vector3.zero; + return; + } + float distanceModifier; + float scaleModifier; + float verticalAdjustment; + if (MetaPort.Instance.isUsingVr) + { + scaleModifier = EntryVRScaleModifier.Value; + distanceModifier = EntryVRDistance.Value; + verticalAdjustment = EntryVRVerticalAdjustment.Value; + } + else + { + scaleModifier = EntryDesktopScaleModifier.Value; + distanceModifier = EntryDesktopDistance.Value; + verticalAdjustment = EntryDesktopVerticalAdjustment.Value; + } + _tinyBoardOffset.localScale = Vector3.one * scaleModifier; + _tinyBoardOffset.localPosition = new Vector3(0f, verticalAdjustment, distanceModifier); + } + + private static void ApplyTinyBoardWidthResize() + { + KeyboardManager km = KeyboardManager.Instance; + CohtmlControlledView cohtmlView = km.cohtmlView; + Transform keyboardTransform = cohtmlView.transform; + + int targetWidthPixels = EntryResizeKeyboard.Value ? 1330 : 1520; + float targetScaleX = EntryResizeKeyboard.Value ? 1.4f : 1.6f; + + cohtmlView.Width = targetWidthPixels; + Vector3 currentScale = keyboardTransform.localScale; + currentScale.x = targetScaleX; + keyboardTransform.localScale = currentScale; + } + + public override void OnInitializeMelon() + { + // add our shim transform to scale the menu down by 0.75 + HarmonyInstance.Patch( + typeof(CVRKeyboardPositionHelper).GetMethod(nameof(CVRKeyboardPositionHelper.Awake), + BindingFlags.NonPublic | BindingFlags.Instance), + postfix: new HarmonyMethod(typeof(TinyboardMod).GetMethod(nameof(OnCVRKeyboardPositionHelperAwake), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + // reposition the keyboard when it is opened to match the menu position if it is opened from a menu + HarmonyInstance.Patch( + typeof(MenuPositionHelperBase).GetMethod(nameof(MenuPositionHelperBase.OnMenuOpen), + BindingFlags.NonPublic | BindingFlags.Instance), + postfix: new HarmonyMethod(typeof(TinyboardMod).GetMethod(nameof(OnMenuPositionHelperBaseOnMenuOpen), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + // enforces a title for the keyboard in cases it did not already have one + HarmonyInstance.Patch( + typeof(KeyboardManager).GetMethod(nameof(KeyboardManager.ShowKeyboard), + BindingFlags.Public | BindingFlags.Instance), + prefix: new HarmonyMethod(typeof(TinyboardMod).GetMethod(nameof(OnKeyboardManagerShowKeyboard), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + // resize keyboard to match XSOverlays width + HarmonyInstance.Patch( + typeof(KeyboardManager).GetMethod(nameof(KeyboardManager.Start), + BindingFlags.NonPublic | BindingFlags.Instance), + postfix: new HarmonyMethod(typeof(TinyboardMod).GetMethod(nameof(OnKeyboardManagerStart), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + // update offsets when switching VR modes + VRModeSwitchEvents.OnPostVRModeSwitch.AddListener((_) => ApplyTinyBoardOffsetsForVRMode()); + + // listen for setting changes + EntryUseModifiers.OnEntryValueChanged.Subscribe((_,_) => ApplyTinyBoardOffsetsForVRMode()); + EntryDesktopScaleModifier.OnEntryValueChanged.Subscribe((_,_) => ApplyTinyBoardOffsetsForVRMode()); + EntryVRScaleModifier.OnEntryValueChanged.Subscribe((_,_) => ApplyTinyBoardOffsetsForVRMode()); + EntryDesktopDistance.OnEntryValueChanged.Subscribe((_,_) => ApplyTinyBoardOffsetsForVRMode()); + EntryVRDistance.OnEntryValueChanged.Subscribe((_,_) => ApplyTinyBoardOffsetsForVRMode()); + EntryResizeKeyboard.OnEntryValueChanged.Subscribe((_,_) => ApplyTinyBoardWidthResize()); + } + + private static void OnCVRKeyboardPositionHelperAwake(CVRKeyboardPositionHelper __instance) + { + _tinyBoardOffset = new GameObject("NAKTinyBoard").transform; + + Transform offsetTransform = __instance.transform.GetChild(0); + _tinyBoardOffset.SetParent(offsetTransform, false); + + ApplyTinyBoardOffsetsForVRMode(); + + Transform menuTransform = __instance.menuTransform; + menuTransform.SetParent(_tinyBoardOffset, false); + } + + private static void OnMenuPositionHelperBaseOnMenuOpen(MenuPositionHelperBase __instance) + { + if (!EntrySmartAlignToMenu.Value) return; + if (__instance is not CVRKeyboardPositionHelper { IsMenuOpen: true }) return; + + // Check if the open source was an open menu + KeyboardManager.OpenSource? openSource = KeyboardManager.Instance._keyboardOpenSource; + + MenuPositionHelperBase menuPositionHelper; + switch (openSource) + { + case KeyboardManager.OpenSource.MainMenu: + menuPositionHelper = CVRMainMenuPositionHelper.Instance; + break; + case KeyboardManager.OpenSource.QuickMenu: + menuPositionHelper = CVRQuickMenuPositionHelper.Instance; + if (!menuPositionHelper.IsUsingWorldAnchoredMenu) return; // hand anchored quick menu, don't touch + break; + default: return; + } + + // get modifiers + float rootScaleModifier = __instance.transform.lossyScale.x; + float keyboardDistanceModifier = __instance.MenuDistanceModifier; + float menuDistanceModifier = menuPositionHelper.MenuDistanceModifier; + + // get difference between modifiers + float distanceModifier = keyboardDistanceModifier - menuDistanceModifier; + + // place keyboard at menu position + difference in modifiers + Transform menuOffsetTransform = menuPositionHelper._offsetTransform; + Quaternion keyboardRotation = menuOffsetTransform.rotation; + Vector3 keyboardPosition = menuOffsetTransform.position + + menuOffsetTransform.forward * (rootScaleModifier * distanceModifier); + + // place keyboard as if it was opened with player camera in same place as menu was + __instance._offsetTransform.SetPositionAndRotation(keyboardPosition, keyboardRotation); + } + + private static void OnKeyboardManagerStart() => ApplyTinyBoardWidthResize(); + + /* + public void ShowKeyboard( + string currentText, + Action callback, + string placeholder = null, + string successText = "Success", + int maxCharacterCount = 0, + bool hidden = false, + bool multiLine = false, + string title = null, + OpenSource openSource = OpenSource.Other) + */ + + // using mix of index and args params because otherwise explodes with invalid IL ? + private static void OnKeyboardManagerShowKeyboard(ref string __7, ref string __2, object[] __args) + { + if (!EntryEnforceTitle.Value) return; + + // ReSharper disable thrice InlineTemporaryVariable + ref string title = ref __7; + ref string placeholder = ref __2; + if (!string.IsNullOrWhiteSpace(title)) return; + + Action callback = __args[1] as Action; + KeyboardManager.OpenSource? openSource = __args[8] as KeyboardManager.OpenSource?; + + if (callback?.Target != null) + { + var target = callback.Target; + switch (openSource) + { + case KeyboardManager.OpenSource.CVRInputFieldKeyboardHandler: + TrySetPlaceholderFromKeyboardHandler(target, ref title, ref placeholder); + break; + case KeyboardManager.OpenSource.MainMenu: + title = TryExtractTitleFromMainMenu(target); + break; + } + } + + if (!string.IsNullOrWhiteSpace(placeholder)) + { + // fallback to placeholder if no title found + if (string.IsNullOrWhiteSpace(title)) title = placeholder; + + // clear placeholder if it is longer than 10 characters + if (placeholder.Length > 10) placeholder = string.Empty; + } + } + + private static void TrySetPlaceholderFromKeyboardHandler(object target, ref string title, ref string placeholder) + { + Type type = target.GetType(); + + TMP_InputField tmpInput = type.GetField("input", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(target) as TMP_InputField; + if (tmpInput != null) + { + if (tmpInput.GetComponentInParent()) title = "VideoPlayer URL or Search"; + if (tmpInput.placeholder is TMP_Text ph) + { + placeholder = ph.text; + return; + } + placeholder = PrettyString(tmpInput.gameObject.name); + return; + } + + InputField legacyInput = type.GetField("inputField", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(target) as InputField; + if (legacyInput != null) + { + if (legacyInput.placeholder is Text ph) + { + placeholder = ph.text; + return; + } + placeholder = PrettyString(legacyInput.gameObject.name); + return; + } + } + + private static string TryExtractTitleFromMainMenu(object target) + { + Type type = target.GetType(); + string targetId = type.GetField("targetId", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(target) as string; + return string.IsNullOrWhiteSpace(targetId) ? null : PrettyString(targetId); + } + + private static string PrettyString(string str) + { + int len = str.Length; + Span buffer = stackalloc char[len * 2]; + int pos = 0; + bool newWord = true; + for (int i = 0; i < len; i++) + { + char c = str[i]; + if (c is '_' or '-') + { + buffer[pos++] = ' '; + newWord = true; + continue; + } + if (char.IsUpper(c) && i > 0 && !newWord) buffer[pos++] = ' '; + buffer[pos++] = newWord ? char.ToUpperInvariant(c) : c; + newWord = false; + } + return new string(buffer[..pos]); + } +} \ No newline at end of file diff --git a/Tinyboard/Properties/AssemblyInfo.cs b/Tinyboard/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..b3048a5 --- /dev/null +++ b/Tinyboard/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using MelonLoader; +using NAK.Tinyboard.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.Tinyboard))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.Tinyboard))] + +[assembly: MelonInfo( + typeof(NAK.Tinyboard.TinyboardMod), + nameof(NAK.Tinyboard), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/Tinyboard" +)] + +[assembly: MelonGame("ChilloutVR", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: MelonColor(255, 246, 25, 99)] // red-pink +[assembly: MelonAuthorColor(255, 158, 21, 32)] // red +[assembly: HarmonyDontPatchAll] + +namespace NAK.Tinyboard.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/Tinyboard/README.md b/Tinyboard/README.md new file mode 100644 index 0000000..7ff0922 --- /dev/null +++ b/Tinyboard/README.md @@ -0,0 +1,19 @@ +# Tinyboard + +Makes the keyboard small and smart. + +Few small tweaks to the keyboard: +- Shrinks the keyboard to a size that isn't fit for grandma. +- Adjusts keyboard placement logic to align with the menu that it spawns from. +- Enforces a title on the keyboard input if one is not found. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation 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/Tinyboard/Tinyboard.csproj b/Tinyboard/Tinyboard.csproj new file mode 100644 index 0000000..5a8badc --- /dev/null +++ b/Tinyboard/Tinyboard.csproj @@ -0,0 +1,6 @@ + + + + YouAreMineNow + + diff --git a/Tinyboard/format.json b/Tinyboard/format.json new file mode 100644 index 0000000..da65a56 --- /dev/null +++ b/Tinyboard/format.json @@ -0,0 +1,23 @@ +{ + "_id": -1, + "name": "Tinyboard", + "modversion": "1.0.0", + "gameversion": "2025r180", + "loaderversion": "0.7.2", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Few small tweaks to the keyboard:\n- Shrinks the keyboard to a size that isn't fit for grandma.\n- Adjusts keyboard placement logic to align with the menu that it spawns from.\n- Enforces a title on the keyboard input if one is not found.", + "searchtags": [ + "keyboard", + "menu", + "ui", + "input" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/Tinyboard.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/Tinyboard/", + "changelog": "- Initial release", + "embedcolor": "#f61963" +} \ No newline at end of file From 226b3695378b56fc63a51cbfc8fa1f153309afa6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 27 Aug 2025 10:22:00 +0000 Subject: [PATCH 119/119] [NAK_CVR_Mods] Update mod list in README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2d2371e..ed9da33 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,12 @@ | [LazyPrune](LazyPrune/README.md) | Prevents loaded objects from immediately unloading on destruction. Should prevent needlessly unloading & reloading all avatars/props on world rejoin or GS reconnection. | No Download | | [PropLoadingHexagon](PropLoadingHexagon/README.md) | https://github.com/NotAKidoS/NAK_CVR_Mods/assets/37721153/a892c765-71c1-47f3-a781-bdb9b60ba117 | No Download | | [RCCVirtualSteeringWheel](RCCVirtualSteeringWheel/README.md) | Allows you to physically grab rigged RCC steering wheels in VR to provide steering input. No explicit setup required other than defining the Steering Wheel transform within the RCC component. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/RCCVirtualSteeringWheel.dll) | -| [RelativeSyncJitterFix](RelativeSyncJitterFix/README.md) | Relative sync jitter fix is the single harmony patch that could not make it into the native release of RelativeSync. | No Download | +| [RelativeSyncJitterFix](RelativeSyncJitterFix/README.md) | Relative sync jitter fix is the single harmony patch that could not make it into the native release of RelativeSync. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/RelativeSyncJitterFix.dll) | | [ShareBubbles](ShareBubbles/README.md) | Share Bubbles! Allows you to drop down bubbles containing Avatars & Props. Requires both users to have the mod installed. Synced over Mod Network. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/ShareBubbles.dll) | | [SmootherRay](SmootherRay/README.md) | Smoothes your controller while the raycast lines are visible. | No Download | | [Stickers](Stickers/README.md) | Stickers! Allows you to place small images on any surface. Requires both users to have the mod installed. Synced over Mod Network. | No Download | | [ThirdPerson](ThirdPerson/README.md) | Original repo: https://github.com/oestradiol/CVR-Mods | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/ThirdPerson.dll) | +| [Tinyboard](Tinyboard/README.md) | Makes the keyboard small and smart. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/Tinyboard.dll) | | [YouAreMyPropNowWeAreHavingSoftTacosLater](YouAreMyPropNowWeAreHavingSoftTacosLater/README.md) | Lets you bring held, attached, and occupied props through world loads. This is configurable in the mod settings. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/YouAreMyPropNowWeAreHavingSoftTacosLater.dll) | ### Experimental Mods