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 01/78] [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 02/78] [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 03/78] [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 04/78] [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 05/78] [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 06/78] [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 07/78] [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 08/78] [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 09/78] [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 10/78] [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 11/78] [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 12/78] [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 13/78] [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 14/78] [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 15/78] [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 16/78] [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 17/78] [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 18/78] [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 19/78] [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 20/78] [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 21/78] [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 22/78] [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 23/78] [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 24/78] [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 25/78] [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 26/78] [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 27/78] [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 28/78] [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 29/78] [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 30/78] [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 31/78] 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 32/78] [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 33/78] [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 34/78] [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 35/78] [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 36/78] [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 37/78] [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 38/78] [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 39/78] [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 40/78] [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 41/78] [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 42/78] [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 43/78] [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 44/78] [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 45/78] [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 46/78] [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 47/78] [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 48/78] 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 49/78] [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 50/78] [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 51/78] [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 52/78] [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 53/78] [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 54/78] 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 55/78] [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 56/78] [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 57/78] [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 58/78] [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 59/78] [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 60/78] [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 61/78] [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 62/78] [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 63/78] [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 64/78] [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 65/78] [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 66/78] [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 67/78] [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 68/78] [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 69/78] [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 70/78] [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 71/78] [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 72/78] [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 73/78] [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 74/78] [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 75/78] 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 76/78] [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 77/78] [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 78/78] [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