diff --git a/AvatarQueueSystemTweaks/AvatarQueueSystemTweaks.csproj b/.Deprecated/AvatarQueueSystemTweaks/AvatarQueueSystemTweaks.csproj similarity index 100% rename from AvatarQueueSystemTweaks/AvatarQueueSystemTweaks.csproj rename to .Deprecated/AvatarQueueSystemTweaks/AvatarQueueSystemTweaks.csproj diff --git a/AvatarQueueSystemTweaks/Main.cs b/.Deprecated/AvatarQueueSystemTweaks/Main.cs similarity index 98% rename from AvatarQueueSystemTweaks/Main.cs rename to .Deprecated/AvatarQueueSystemTweaks/Main.cs index 403e33b..ce03ff8 100644 --- a/AvatarQueueSystemTweaks/Main.cs +++ b/.Deprecated/AvatarQueueSystemTweaks/Main.cs @@ -1,4 +1,4 @@ -using MelonLoader; +using MelonLoader; using NAK.AvatarQueueSystemTweaks.Patches; namespace NAK.AvatarQueueSystemTweaks; diff --git a/AvatarQueueSystemTweaks/Patches.cs b/.Deprecated/AvatarQueueSystemTweaks/Patches.cs similarity index 99% rename from AvatarQueueSystemTweaks/Patches.cs rename to .Deprecated/AvatarQueueSystemTweaks/Patches.cs index 74a86ac..f9ef61b 100644 --- a/AvatarQueueSystemTweaks/Patches.cs +++ b/.Deprecated/AvatarQueueSystemTweaks/Patches.cs @@ -1,4 +1,3 @@ -using System.Collections; using ABI_RC.Core; using ABI_RC.Core.IO; using ABI_RC.Core.Networking.IO.Social; diff --git a/AvatarQueueSystemTweaks/Properties/AssemblyInfo.cs b/.Deprecated/AvatarQueueSystemTweaks/Properties/AssemblyInfo.cs similarity index 98% rename from AvatarQueueSystemTweaks/Properties/AssemblyInfo.cs rename to .Deprecated/AvatarQueueSystemTweaks/Properties/AssemblyInfo.cs index 821459b..092e11b 100644 --- a/AvatarQueueSystemTweaks/Properties/AssemblyInfo.cs +++ b/.Deprecated/AvatarQueueSystemTweaks/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -using MelonLoader; +using MelonLoader; using NAK.AvatarQueueSystemTweaks.Properties; using System.Reflection; diff --git a/AvatarQueueSystemTweaks/README.md b/.Deprecated/AvatarQueueSystemTweaks/README.md similarity index 100% rename from AvatarQueueSystemTweaks/README.md rename to .Deprecated/AvatarQueueSystemTweaks/README.md diff --git a/AvatarQueueSystemTweaks/format.json b/.Deprecated/AvatarQueueSystemTweaks/format.json similarity index 100% rename from AvatarQueueSystemTweaks/format.json rename to .Deprecated/AvatarQueueSystemTweaks/format.json diff --git a/.Deprecated/BufferParticleFixer/BufferParticleFixer.csproj b/.Deprecated/BufferParticleFixer/BufferParticleFixer.csproj new file mode 100644 index 0000000..e94f9dc --- /dev/null +++ b/.Deprecated/BufferParticleFixer/BufferParticleFixer.csproj @@ -0,0 +1,2 @@ + + diff --git a/.Deprecated/BufferParticleFixer/Main.cs b/.Deprecated/BufferParticleFixer/Main.cs new file mode 100644 index 0000000..8295e79 --- /dev/null +++ b/.Deprecated/BufferParticleFixer/Main.cs @@ -0,0 +1,109 @@ +using System.Reflection; +using ABI_RC.Core.Networking.API.Responses; +using ABI_RC.Core.Util.AssetFiltering; +using HarmonyLib; +using MelonLoader; +using UnityEngine; + +namespace NAK.BufferParticleFixer; + +public class BufferParticleFixerMod : MelonMod +{ + private static MelonLogger.Instance Logger; + + private static readonly MelonPreferences_Category Category = + MelonPreferences.CreateCategory(nameof(BufferParticleFixer)); + + private static readonly MelonPreferences_Entry EntryFixBufferParticles = + Category.CreateEntry( + identifier: "fix_buffer_particles", + true, + display_name: "Fix Buffer Particles", + description: "Should the mod attempt to fix buffer particles by modifying their lifetime and sub-emitter settings?"); + + public override void OnInitializeMelon() + { + Logger = LoggerInstance; + + HarmonyInstance.Patch( + typeof(SharedFilter).GetMethod(nameof(SharedFilter.ProcessParticleComponent), + BindingFlags.Public | BindingFlags.Static), + postfix: new HarmonyMethod(typeof(BufferParticleFixerMod).GetMethod(nameof(OnProcessParticleComponent), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + } + + private static void OnProcessParticleComponent( + string collectionId, + Component particleComponent, + bool physicsCollision, + CompatibilityVersions compatibilityVersion) + { + if (particleComponent is not ParticleSystem particleSystem) + return; + + if (!EntryFixBufferParticles.Value) + return; + + // Logger.Msg($"Processing particle system on collection '{collectionId}'."); + + if (!IsLikelyBufferParticle(particleSystem)) + return; + + Logger.Msg($"Detected likely buffer particle system '{particleSystem.name}' on collection '{collectionId}'. Applying fix..."); + + // Set start lifetime to 1000 + // All sub-emitters to "Spawn on Birth" + // https://x.com/hfcRedddd/status/1696914565919813679 + + ParticleSystem.MainModule mainModule = particleSystem.main; + + mainModule.startLifetime = 1f; + + for (int i = 0; i < particleSystem.subEmitters.subEmittersCount; i++) + { + ParticleSystem subEmitter = particleSystem.subEmitters.GetSubEmitterSystem(i); + if (subEmitter) particleSystem.subEmitters.SetSubEmitterType(i, ParticleSystemSubEmitterType.Birth); + } + } + + // https://x.com/hfcRedddd/status/1696913727415537807 + private static bool IsLikelyBufferParticle(ParticleSystem ps) + { + // Check if the sub-emitters are children of the particle system + Transform psTransform = ps.transform; + + bool hasSubEmitterNotChild = false; + + ParticleSystem.SubEmittersModule subEmitters = ps.subEmitters; + int subEmitterCount = subEmitters.subEmittersCount; + + for (int i = 0; i < subEmitterCount; i++) + { + ParticleSystem subEmitter = subEmitters.GetSubEmitterSystem(i); + + // Skip null sub-emitters + if (!subEmitter) + { + Logger.Warning($"Particle system '{ps.name}' has a null sub-emitter at index {i}."); + continue; + } + + // If any sub-emitter is not a child of the particle system, it's likely a buffer particle. + // This setup is also what shits into our logs... + if (!subEmitter.transform.IsChildOf(psTransform)) + hasSubEmitterNotChild = true; + } + + if (hasSubEmitterNotChild) + { + // Buffer particles have very short lifetimes + if (!(ps.main.startLifetime.constant > 0.05f)) + return true; + + Logger.Msg($"A potential buffer particle system '{ps.name}' has a start lifetime of {ps.main.startLifetime.constant}, which is longer than expected."); + } + + return false; + } +} \ No newline at end of file diff --git a/.Deprecated/BufferParticleFixer/Properties/AssemblyInfo.cs b/.Deprecated/BufferParticleFixer/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..53fab6b --- /dev/null +++ b/.Deprecated/BufferParticleFixer/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using MelonLoader; +using NAK.BufferParticleFixer.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.BufferParticleFixer))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.BufferParticleFixer))] + +[assembly: MelonInfo( + typeof(NAK.BufferParticleFixer.BufferParticleFixerMod), + nameof(NAK.BufferParticleFixer), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/BufferParticleFixer" +)] + +[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.BufferParticleFixer.Properties; +internal static class AssemblyInfoParams +{ + public const string Version = "1.0.0"; + public const string Author = "NotAKidoS"; +} \ No newline at end of file diff --git a/.Deprecated/BufferParticleFixer/README.md b/.Deprecated/BufferParticleFixer/README.md new file mode 100644 index 0000000..1c4c5bc --- /dev/null +++ b/.Deprecated/BufferParticleFixer/README.md @@ -0,0 +1,14 @@ +# SearchWithSpacesFix + +Fixes search terms that use spaces. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation not affiliated with, supported by, or approved by Alpha Blend Interactive. + +> Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use. + +> To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive. diff --git a/.Deprecated/BufferParticleFixer/format.json b/.Deprecated/BufferParticleFixer/format.json new file mode 100644 index 0000000..f8950ca --- /dev/null +++ b/.Deprecated/BufferParticleFixer/format.json @@ -0,0 +1,23 @@ +{ + "_id": -1, + "name": "SearchWithSpacesFix", + "modversion": "1.0.0", + "gameversion": "2024r177", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Fixes search terms that include spaces.", + "searchtags": [ + "search", + "spaces", + "fix", + "meow" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r42/SearchWithSpacesFix.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/SearchWithSpacesFix/", + "changelog": "- Initial release", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/.Deprecated/CVRGizmos/Properties/AssemblyInfo.cs b/.Deprecated/CVRGizmos/Properties/AssemblyInfo.cs index 8fb1e54..2bffafd 100644 --- a/.Deprecated/CVRGizmos/Properties/AssemblyInfo.cs +++ b/.Deprecated/CVRGizmos/Properties/AssemblyInfo.cs @@ -17,7 +17,7 @@ using System.Reflection; downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/CVRGizmos" )] -[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonGame("ChilloutVR", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] diff --git a/.Deprecated/ChatBoxTweaks/ChatBoxTweaks.csproj b/.Deprecated/ChatBoxTweaks/ChatBoxTweaks.csproj new file mode 100644 index 0000000..caeac6b --- /dev/null +++ b/.Deprecated/ChatBoxTweaks/ChatBoxTweaks.csproj @@ -0,0 +1,9 @@ + + + + PlayerCloneAttachment + + + + + diff --git a/.Deprecated/ChatBoxTweaks/Main.cs b/.Deprecated/ChatBoxTweaks/Main.cs new file mode 100644 index 0000000..2cd915f --- /dev/null +++ b/.Deprecated/ChatBoxTweaks/Main.cs @@ -0,0 +1,92 @@ +using System.Reflection; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.UI.UIRework.Managers; +using ABI_RC.Systems.ChatBox; +using ABI_RC.Systems.InputManagement; +using HarmonyLib; +using MelonLoader; + +using System; +using System.Linq; +using UnityEngine; +using UnityEngine.LowLevel; +using UnityEngine.PlayerLoop; + +namespace NAK.ChatBoxTweaks; + +public class ChatBoxTweaksMod : MelonMod +{ + public override void OnInitializeMelon() + { + HarmonyInstance.Patch( + typeof(KeyboardManager).GetMethod(nameof(KeyboardManager.OnKeyboardSubmit), + BindingFlags.NonPublic | BindingFlags.Instance), + prefix: new HarmonyMethod(typeof(ChatBoxTweaksMod).GetMethod(nameof(OnPreKeyboardManagerKeyboardSubmit), + BindingFlags.NonPublic | BindingFlags.Static)), + postfix: new HarmonyMethod(typeof(ChatBoxTweaksMod).GetMethod(nameof(OnPostKeyboardManagerKeyboardSubmit), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + } + + private static void OnPreKeyboardManagerKeyboardSubmit(ref KeyboardManager __instance, ref KeyboardManager.OpenSource? __state) + { + __state = __instance.KeyboardOpenSource; + } + + private static void OnPostKeyboardManagerKeyboardSubmit(ref KeyboardManager.OpenSource? __state) + { + if (__state == KeyboardManager.OpenSource.TextComms) ChatBoxAPI.OpenKeyboard(); + } +} + + +/* +public static class NetworkLoopInjector +{ + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + static void InjectNetworkFixedUpdate() + { + var playerLoop = PlayerLoop.GetCurrentPlayerLoop(); + + // Find the FixedUpdate phase + int fixedUpdateIndex = Array.FindIndex(playerLoop.subSystemList, s => s.type == typeof(FixedUpdate)); + if (fixedUpdateIndex < 0) + { + Debug.LogError("FixedUpdate not found in player loop!"); + return; + } + + var fixedUpdate = playerLoop.subSystemList[fixedUpdateIndex]; + + // Create your custom PlayerLoopSystem + var networkSystem = new PlayerLoopSystem + { + type = typeof(NetworkFixedUpdate), + updateDelegate = NetworkFixedUpdate.Run + }; + + // Insert at the start so it runs before physics, animation, etc. + var subs = fixedUpdate.subSystemList.ToList(); + subs.Insert(0, networkSystem); + fixedUpdate.subSystemList = subs.ToArray(); + + // Reassign and set back + playerLoop.subSystemList[fixedUpdateIndex] = fixedUpdate; + PlayerLoop.SetPlayerLoop(playerLoop); + + Debug.Log("[NetworkLoopInjector] Inserted NetworkFixedUpdate at start of FixedUpdate loop"); + } + + static class NetworkFixedUpdate + { + static int lastStateFrame = -1; + + public static void Run() + { + // Apply your networked object state syncs before physics simulation + Debug.Log("Last State Frame: " + lastStateFrame + " Current Frame: " + Time.frameCount); + lastStateFrame = Time.frameCount; + } + } +} +*/ diff --git a/.Deprecated/ChatBoxTweaks/Properties/AssemblyInfo.cs b/.Deprecated/ChatBoxTweaks/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..9444b4d --- /dev/null +++ b/.Deprecated/ChatBoxTweaks/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using MelonLoader; +using NAK.ChatBoxTweaks.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.ChatBoxTweaks))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.ChatBoxTweaks))] + +[assembly: MelonInfo( + typeof(NAK.ChatBoxTweaks.ChatBoxTweaksMod), + nameof(NAK.ChatBoxTweaks), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ChatBoxTweaks" +)] + +[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.ChatBoxTweaks.Properties; +internal static class AssemblyInfoParams +{ + public const string Version = "1.0.0"; + public const string Author = "NotAKidoS"; +} \ No newline at end of file diff --git a/.Deprecated/ChatBoxTweaks/README.md b/.Deprecated/ChatBoxTweaks/README.md new file mode 100644 index 0000000..b092e40 --- /dev/null +++ b/.Deprecated/ChatBoxTweaks/README.md @@ -0,0 +1,22 @@ +# YouAreMyPropNowWeAreHavingSoftTacosLater + +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 + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation not affiliated with, supported by, or approved by Alpha Blend Interactive. + +> Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use. + +> To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive. diff --git a/.Deprecated/ChatBoxTweaks/format.json b/.Deprecated/ChatBoxTweaks/format.json new file mode 100644 index 0000000..8e68782 --- /dev/null +++ b/.Deprecated/ChatBoxTweaks/format.json @@ -0,0 +1,23 @@ +{ + "_id": 262, + "name": "YouAreMyPropNowWeAreHavingSoftTacosLater", + "modversion": "1.0.0", + "gameversion": "2025r180", + "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 20m above the spawnpoint of the next world.", + "searchtags": [ + "prop", + "spawn", + "friend", + "load" + ], + "requirements": [ + "None" + ], + "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": "#f61963" +} \ No newline at end of file diff --git a/.Deprecated/ChatBubbles/ChatBubbles.csproj b/.Deprecated/ChatBubbles/ChatBubbles.csproj new file mode 100644 index 0000000..5a8badc --- /dev/null +++ b/.Deprecated/ChatBubbles/ChatBubbles.csproj @@ -0,0 +1,6 @@ + + + + YouAreMineNow + + diff --git a/.Deprecated/ChatBubbles/Main.cs b/.Deprecated/ChatBubbles/Main.cs new file mode 100644 index 0000000..ac42f7d --- /dev/null +++ b/.Deprecated/ChatBubbles/Main.cs @@ -0,0 +1,236 @@ +using System.Reflection; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Player; +using ABI_RC.Core.Util; +using ABI_RC.Systems.Communications; +using ABI_RC.Systems.GameEventSystem; +using ABI_RC.Systems.RuntimeDebug; +using HarmonyLib; +using MelonLoader; +using UnityEngine; + +namespace NAK.YouAreMyPropNowWeAreHavingSoftTacosLater; + +public class ChatBubblesMod : MelonMod +{ + #region Melon Preferences + + private static readonly MelonPreferences_Category Category = + MelonPreferences.CreateCategory(nameof(YouAreMyPropNowWeAreHavingSoftTacosLater)); + + private static readonly MelonPreferences_Entry EntryChatBubblesKey = + Category.CreateEntry("keyboard_bind", KeyCode.Y, display_name: "Chat Bubbles Key", + description: "Key to open chat bubble input."); + + private static readonly MelonPreferences_Entry EntryBubbleDuration = + Category.CreateEntry("bubble_duration", 5.0f, display_name: "Bubble Duration", + description: "Base duration in seconds for chat bubbles to stay visible."); + + private static readonly MelonPreferences_Entry EntryDurationPerChar = + Category.CreateEntry("duration_per_char", 0.05f, display_name: "Duration Per Character", + description: "Additional duration per character in the message."); + + private static readonly MelonPreferences_Entry EntryPoolSize = + Category.CreateEntry("pool_size", 20, display_name: "Pool Size", + description: "Maximum number of chat bubbles that can be displayed at once."); + + private static readonly MelonPreferences_Entry EntryBubbleColor = + Category.CreateEntry("bubble_color", new Color(1.0f, 1.0f, 1.0f, 1.0f), display_name: "Bubble Color", + description: "Color of chat bubble text."); + + #endregion Melon Preferences + + #region Object Pool + + private class ChatBubble + { + public CVRPlayerEntity Player { get; set; } + public string Message { get; set; } + public float Duration { get; set; } + public float Timer { get; set; } + public bool IsActive { get; set; } + + public void Reset() + { + Player = null; + Message = string.Empty; + Duration = 0f; + Timer = 0f; + IsActive = false; + } + } + + private readonly List _chatBubblePool = []; + private readonly List _activeBubbles = []; + + private void InitializePool() + { + MelonLogger.Msg("Initializing chat bubble pool with size: " + EntryPoolSize.Value); + _chatBubblePool.Clear(); + + for (int i = 0; i < EntryPoolSize.Value; i++) + { + _chatBubblePool.Add(new ChatBubble()); + } + } + + private ChatBubble GetBubbleFromPool() + { + // First try to find an inactive bubble + foreach (var bubble in _chatBubblePool) + { + if (!bubble.IsActive) + { + bubble.Reset(); + bubble.IsActive = true; + _activeBubbles.Add(bubble); + return bubble; + } + } + + // If all bubbles are active, reuse the oldest one + if (_activeBubbles.Count > 0) + { + var oldestBubble = _activeBubbles[0]; + _activeBubbles.RemoveAt(0); + oldestBubble.Reset(); + oldestBubble.IsActive = true; + _activeBubbles.Add(oldestBubble); + return oldestBubble; + } + + // This should never happen if the pool is initialized properly + MelonLogger.Warning("No chat bubbles available in pool!"); + return null; + } + + private void ReturnBubbleToPool(ChatBubble bubble) + { + bubble.IsActive = false; + _activeBubbles.Remove(bubble); + } + + #endregion Object Pool + + #region Melon Events + + public override void OnInitializeMelon() + { + MelonLogger.Msg("Initializing Chat Bubbles Mod"); + InitializePool(); + + CVRGameEventSystem.Communications.TextChat.Local.OnMessageReceived.AddListener(OnLocalMessageReceived); + CVRGameEventSystem.Communications.TextChat.Direct.OnMessageReceived.AddListener(OnGlobalMessageReceived); + CVRGameEventSystem.Communications.TextChat.Global.OnMessageReceived.AddListener(OnDirectMessageReceived); + + HarmonyInstance.Patch( + typeof(ViewManager).GetMethod(nameof(ViewManager.SendToWorldUi), + BindingFlags.NonPublic | BindingFlags.Instance), + postfix: new HarmonyMethod(typeof(ChatBubblesMod).GetMethod(nameof(OnViewManagerSendToWorldUi), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + + MelonLogger.Msg("Chat Bubbles Mod initialized successfully"); + } + + public override void OnUpdate() + { + // Process key input to open chat + if (Input.GetKeyDown(EntryChatBubblesKey.Value)) + { + if (!CVRSyncHelper.IsConnectedToGameNetwork()) + return; + + IsInKeyboardToWriteANiceMessage = true; + ViewManager.Instance.openMenuKeyboard(string.Empty); + } + + // Update and render active chat bubbles + UpdateChatBubbles(); + } + + private void UpdateChatBubbles() + { + // Make a copy of the list to avoid issues when modifying during iteration + var bubblesToUpdate = new List(_activeBubbles); + + foreach (var bubble in bubblesToUpdate) + { + if (bubble.Player == null || bubble.Player.PuppetMaster == null) + { + ReturnBubbleToPool(bubble); + continue; + } + + bubble.Timer += Time.deltaTime; + + if (bubble.Timer >= bubble.Duration) + { + ReturnBubbleToPool(bubble); + continue; + } + + // Draw the bubble text at the player's nameplate position + var nameplatePosition = bubble.Player.PuppetMaster.GetNamePlateWorldPosition(); + // Offset slightly above the nameplate + nameplatePosition.y += 0.2f; + + RuntimeGizmos.DrawText(nameplatePosition, bubble.Message, 5, EntryBubbleColor.Value); + } + } + + #endregion Melon Events + + #region Game Events + + public static bool IsInKeyboardToWriteANiceMessage { get; set; } + + private static void OnViewManagerSendToWorldUi(string value) + { + if (!IsInKeyboardToWriteANiceMessage) return; + IsInKeyboardToWriteANiceMessage = false; + Comms_Manager.SendLocalTextMessage(value); + Comms_Manager.SendDirectTextMessage(CVRPlayerManager.Instance.NetworkPlayers[0].Uuid, value); + Comms_Manager.SendGlobalTextMessage(value); + MelonLogger.Msg("Sending message: " + value); + } + + private void OnLocalMessageReceived(CVRPlayerEntity player, string message) + { + CreateChatBubble(player, message); + MelonLogger.Msg("OnLocalMessageReceived - Player: " + player?.Username + ", Message: " + message); + } + + private void OnDirectMessageReceived(CVRPlayerEntity player, string message) + { + CreateChatBubble(player, message); + MelonLogger.Msg("OnDirectMessageReceived - Player: " + player?.Username + ", Message: " + message); + } + + private void OnGlobalMessageReceived(CVRPlayerEntity player, string message) + { + CreateChatBubble(player, message); + MelonLogger.Msg("OnGlobalMessageReceived - Player: " + player?.Username + ", Message: " + message); + } + + private void CreateChatBubble(CVRPlayerEntity player, string message) + { + if (player == null || player.PuppetMaster == null) + return; + + // Calculate duration based on message length + float baseDuration = EntryBubbleDuration.Value; + float charDuration = EntryDurationPerChar.Value * message.Length; + float totalDuration = Mathf.Clamp(baseDuration + charDuration, baseDuration, 15f); + + ChatBubble bubble = GetBubbleFromPool(); + if (bubble == null) return; + + bubble.Player = player; + bubble.Message = message; + bubble.Duration = totalDuration; + bubble.Timer = 0f; + } + + #endregion Game Events +} \ No newline at end of file diff --git a/.Deprecated/ChatBubbles/Properties/AssemblyInfo.cs b/.Deprecated/ChatBubbles/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..8743650 --- /dev/null +++ b/.Deprecated/ChatBubbles/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.ChatBubblesMod), + nameof(NAK.YouAreMyPropNowWeAreHavingSoftTacosLater), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ChatBubbles" +)] + +[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/.Deprecated/ChatBubbles/README.md b/.Deprecated/ChatBubbles/README.md new file mode 100644 index 0000000..9ddff99 --- /dev/null +++ b/.Deprecated/ChatBubbles/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/.Deprecated/ChatBubbles/format.json b/.Deprecated/ChatBubbles/format.json new file mode 100644 index 0000000..78c5bbc --- /dev/null +++ b/.Deprecated/ChatBubbles/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 diff --git a/.Deprecated/ControlToUnlockEyes/ControlToUnlockEyes.csproj b/.Deprecated/ControlToUnlockEyes/ControlToUnlockEyes.csproj new file mode 100644 index 0000000..caeac6b --- /dev/null +++ b/.Deprecated/ControlToUnlockEyes/ControlToUnlockEyes.csproj @@ -0,0 +1,9 @@ + + + + PlayerCloneAttachment + + + + + diff --git a/.Deprecated/ControlToUnlockEyes/Main.cs b/.Deprecated/ControlToUnlockEyes/Main.cs new file mode 100644 index 0000000..2afaaad --- /dev/null +++ b/.Deprecated/ControlToUnlockEyes/Main.cs @@ -0,0 +1,169 @@ +using ABI_RC.Core; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using ABI_RC.Systems.FaceTracking; +using ABI_RC.Systems.InputManagement; +using MelonLoader; +using UnityEngine; + +namespace NAK.ControlToUnlockEyes; + +public class ControlToUnlockEyesMod : MelonMod +{ + public override void OnInitializeMelon() + { + HarmonyInstance.Patch( + typeof(FaceTrackingManager).GetMethod(nameof(FaceTrackingManager.RegisterBuiltinModules), + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance), + postfix: new HarmonyLib.HarmonyMethod(typeof(ControlToUnlockEyesMod).GetMethod(nameof(OnPostFaceTrackingManagerRegisterBuiltinModules), + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)) + ); + } + + private static void OnPostFaceTrackingManagerRegisterBuiltinModules(FaceTrackingManager __instance) + => __instance.RegisterEyeModule(new DefaultEyeModule()); + + public class DefaultEyeModule : IEyeTrackingModule + { + private const float FixedDistance = 10f; + private bool _useFixedDistance = true; + + private readonly EyeTrackingData _eyeTrackingData = new(); + private bool _dataAvailable; + private bool _running; + + private ControllerRay _activeRay; + private Transform _rayDirectionTransform; + + private CVRHand lastInteractHand = CVRHand.Right; + + public bool Start(bool vr) + { + _running = true; + return true; + } + + public void Stop() + { + _running = false; + } + + public void Update() + { + if (!PlayerSetup.Instance) + return; + + UpdateLastInteractHand(); + UpdateFakedEyeTrackingData(); + } + + private void UpdateLastInteractHand() + { + ControllerRay leftRay = PlayerSetup.Instance.vrRayLeft; + ControllerRay rightRay = PlayerSetup.Instance.vrRayRight; + + if (!MetaPort.Instance.isUsingVr) + { + _activeRay = PlayerSetup.Instance.desktopRay; + _rayDirectionTransform = _activeRay.rayDirectionTransform; + return; + } + + bool leftAvailable = IsHandAvailable(leftRay, CVRHand.Left); + bool rightAvailable = IsHandAvailable(rightRay, CVRHand.Right); + + if (CVRInputManager.Instance.interactLeftDown && leftAvailable) + lastInteractHand = CVRHand.Left; + else if (CVRInputManager.Instance.interactRightDown && rightAvailable) + lastInteractHand = CVRHand.Right; + + _activeRay = GetLastInteractRay(); + _rayDirectionTransform = _activeRay.rayDirectionTransform; + } + + private void UpdateFakedEyeTrackingData() + { + _dataAvailable = _activeRay.CanSelectPlayersAndProps(); + if (!_dataAvailable) + return; + + _eyeTrackingData.blinking = false; + + Transform ourCameraTransform = PlayerSetup.Instance.activeCam.transform; + + Vector3 rayForward = _rayDirectionTransform.forward; + float rayDistance = _useFixedDistance ? FixedDistance : _activeRay.Hit.distance; + + // TODO: dot product check to flip direction if behind camera + + // Convert to camera-local *direction* (normalized) and multiply by selected distance so the gazePoint + // is on a sphere around the camera rather than mapped to a "square". + Vector3 localDir = ourCameraTransform.InverseTransformDirection(rayForward).normalized; + Vector3 localGazePoint = localDir * rayDistance; + + _eyeTrackingData.gazePoint = localGazePoint; + } + + private ControllerRay GetLastInteractRay() + { + if (!MetaPort.Instance.isUsingVr) + return PlayerSetup.Instance.desktopRay; + + ControllerRay leftRay = PlayerSetup.Instance.vrRayLeft; + ControllerRay rightRay = PlayerSetup.Instance.vrRayRight; + + if (lastInteractHand == CVRHand.Left && IsHandAvailable(leftRay, CVRHand.Left)) + return leftRay; + if (lastInteractHand == CVRHand.Right && IsHandAvailable(rightRay, CVRHand.Right)) + return rightRay; + + return GetBestAvailableHand(); + } + + private ControllerRay GetBestAvailableHand() + { + if (!MetaPort.Instance.isUsingVr) + return PlayerSetup.Instance.desktopRay; + + ControllerRay leftRay = PlayerSetup.Instance.vrRayLeft; + ControllerRay rightRay = PlayerSetup.Instance.vrRayRight; + + bool leftAvailable = IsHandAvailable(leftRay, CVRHand.Left); + bool rightAvailable = IsHandAvailable(rightRay, CVRHand.Right); + + if (CVRInputManager.Instance.interactLeftDown && leftAvailable) + return leftRay; + if (CVRInputManager.Instance.interactRightDown && rightAvailable) + return rightRay; + + if (lastInteractHand == CVRHand.Left && leftAvailable) + return leftRay; + if (lastInteractHand == CVRHand.Right && rightAvailable) + return rightRay; + + if (rightAvailable) return rightRay; + if (leftAvailable) return leftRay; + + return rightRay; + } + + private static bool IsHandAvailable(ControllerRay ray, CVRHand hand) + { + if (ray.grabbedObject) + return false; + + if (CVR_MenuManager.Instance.IsViewShown && + CVR_MenuManager.Instance.SelectedQuickMenuHand == hand) + return false; + + return true; + } + + public bool IsRunning() => _running; + public bool IsDataAvailable() => _dataAvailable; + public EyeTrackingData GetTrackingData() => _eyeTrackingData; + public string GetModuleName() => "None"; + public string GetModuleShortName() => "None"; + } +} \ No newline at end of file diff --git a/.Deprecated/ControlToUnlockEyes/Properties/AssemblyInfo.cs b/.Deprecated/ControlToUnlockEyes/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..5396117 --- /dev/null +++ b/.Deprecated/ControlToUnlockEyes/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using MelonLoader; +using NAK.ControlToUnlockEyes.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.ControlToUnlockEyes))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.ControlToUnlockEyes))] + +[assembly: MelonInfo( + typeof(NAK.ControlToUnlockEyes.ControlToUnlockEyesMod), + nameof(NAK.ControlToUnlockEyes), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ControlToUnlockEyes" +)] + +[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.ControlToUnlockEyes.Properties; +internal static class AssemblyInfoParams +{ + public const string Version = "1.0.0"; + public const string Author = "NotAKidoS"; +} \ No newline at end of file diff --git a/.Deprecated/ControlToUnlockEyes/README.md b/.Deprecated/ControlToUnlockEyes/README.md new file mode 100644 index 0000000..b092e40 --- /dev/null +++ b/.Deprecated/ControlToUnlockEyes/README.md @@ -0,0 +1,22 @@ +# YouAreMyPropNowWeAreHavingSoftTacosLater + +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 + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation not affiliated with, supported by, or approved by Alpha Blend Interactive. + +> Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use. + +> To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive. diff --git a/.Deprecated/ControlToUnlockEyes/format.json b/.Deprecated/ControlToUnlockEyes/format.json new file mode 100644 index 0000000..8e68782 --- /dev/null +++ b/.Deprecated/ControlToUnlockEyes/format.json @@ -0,0 +1,23 @@ +{ + "_id": 262, + "name": "YouAreMyPropNowWeAreHavingSoftTacosLater", + "modversion": "1.0.0", + "gameversion": "2025r180", + "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 20m above the spawnpoint of the next world.", + "searchtags": [ + "prop", + "spawn", + "friend", + "load" + ], + "requirements": [ + "None" + ], + "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": "#f61963" +} \ No newline at end of file diff --git a/.Deprecated/FuckCameras/FuckCameras.csproj b/.Deprecated/FuckCameras/FuckCameras.csproj new file mode 100644 index 0000000..5a8badc --- /dev/null +++ b/.Deprecated/FuckCameras/FuckCameras.csproj @@ -0,0 +1,6 @@ + + + + YouAreMineNow + + diff --git a/.Deprecated/FuckCameras/Main.cs b/.Deprecated/FuckCameras/Main.cs new file mode 100644 index 0000000..ecb06fb --- /dev/null +++ b/.Deprecated/FuckCameras/Main.cs @@ -0,0 +1,228 @@ +using ABI_RC.Core.Util.AssetFiltering; +using System.Reflection; +using HarmonyLib; +using MelonLoader; +using UnityEngine; + +namespace NAK.FuckCameras; + +public class FuckCamerasMod : MelonMod +{ + public override void OnInitializeMelon() + { + HarmonyInstance.Patch( + typeof(SharedFilter).GetMethod(nameof(SharedFilter.ProcessCamera), + BindingFlags.Public | BindingFlags.Static), + postfix: new HarmonyMethod(typeof(FuckCamerasMod).GetMethod(nameof(OnProcessCamera), + BindingFlags.NonPublic | BindingFlags.Static)) + ); + } + + private static void OnProcessCamera(string collectionId, Camera camera) + => camera.gameObject.AddComponent(); + + public class FuckCameraComponent : MonoBehaviour + { + private Camera _cam; + private int _originalMask; + + private Camera _pooledCam; + private bool fuck; + + private void Awake() + { + _originalMask = _cam.cullingMask; + _cam.Reset(); + // _cam.cullingMask = _originalMask; + } + + /*private void OnPreCull() + { + MelonLogger.Msg("PreCull"); + if (!TryGetComponent(out _cam)) return; + + if (fuck) + { + // unset default layer + _originalMask &= ~(1 << 0); + _cam.cullingMask = _originalMask; + Destroy(this); + return; + } + + _originalMask = _cam.cullingMask; + _cam.cullingMask = 0; + fuck = true; + }*/ + + /*private IEnumerator OnPostRender() + { + MelonLogger.Msg("PostRender"); + // Restore the original mask if it has not changed since we set it to 0 + if (_cam.cullingMask == 0) _cam.cullingMask = _originalMask; + + _cam.enabled = false; + yield return new WaitForEndOfFrame(); + _cam.enabled = true; + + MelonLogger.Msg("FuckCameraComponent: OnPostRender called for camera: " + _cam.name); + // Destroy now that we have saved the day + enabled = false; + Destroy(this); + }*/ + } + + + + public class CameraPoolManager : MonoBehaviour + { + private static CameraPoolManager _instance; + public static CameraPoolManager Instance + { + get + { + if (_instance == null) + { + GameObject obj = new("CameraPoolManager"); + obj.SetActive(false); + _instance = obj.AddComponent(); + DontDestroyOnLoad(obj); + } + return _instance; + } + } + + private readonly List _cameraObjects = new(); + + public Camera CreatePooledCamera(Camera source) + { + var go = new GameObject("PooledCamera"); + go.SetActive(false); + var camera = go.AddComponent(); + camera.CopyFrom(source); + _cameraObjects.Add(go); + return camera; + } + + public void RestoreCameraProperties(Camera target, Camera pooledCam) + { + // target.CopyFrom(pooledCam); + CopyCameraProperties(pooledCam, target); + } + + public void ReleasePooledCamera(Camera pooledCam) + { + if (pooledCam != null) + { + var go = pooledCam.gameObject; + _cameraObjects.Remove(go); + Destroy(go); + } + } + + // Skipped known diffs: + // nearClipPlane + // farClipPlane + // fieldOfView + // aspect + // cullingMask + // useOcclusionCulling + // clearFlags + // depthTextureMode + // pixelRect + // targetTexture + + public static void CopyCameraProperties(Camera source, Camera target) + { + if (source == null || target == null) return; + + target.nearClipPlane = source.nearClipPlane; + target.farClipPlane = source.farClipPlane; + + target.fieldOfView = source.fieldOfView; + target.aspect = source.aspect; + + int cullingMask = 0; + + cullingMask = (cullingMask & ~(1 << 0)) | (source.cullingMask & (1 << 0)); + + cullingMask = (cullingMask & ~(1 << 1)) | (source.cullingMask & (1 << 1)); + cullingMask = (cullingMask & ~(1 << 2)) | (source.cullingMask & (1 << 2)); + cullingMask = (cullingMask & ~(1 << 3)) | (source.cullingMask & (1 << 3)); + cullingMask = (cullingMask & ~(1 << 4)) | (source.cullingMask & (1 << 4)); + + cullingMask = (cullingMask & ~(1 << 5)) | (source.cullingMask & (1 << 5)); + cullingMask = (cullingMask & ~(1 << 6)) | (source.cullingMask & (1 << 6)); + cullingMask = (cullingMask & ~(1 << 7)) | (source.cullingMask & (1 << 7)); + cullingMask = (cullingMask & ~(1 << 8)) | (source.cullingMask & (1 << 8)); + + cullingMask = (cullingMask & ~(1 << 9)) | (source.cullingMask & (1 << 9)); + cullingMask = (cullingMask & ~(1 << 10)) | (source.cullingMask & (1 << 10)); + cullingMask = (cullingMask & ~(1 << 11)) | (source.cullingMask & (1 << 11)); + cullingMask = (cullingMask & ~(1 << 12)) | (source.cullingMask & (1 << 12)); + cullingMask = (cullingMask & ~(1 << 13)) | (source.cullingMask & (1 << 13)); + cullingMask = (cullingMask & ~(1 << 14)) | (source.cullingMask & (1 << 14)); + cullingMask = (cullingMask & ~(1 << 15)) | (source.cullingMask & (1 << 15)); + cullingMask = (cullingMask & ~(1 << 16)) | (source.cullingMask & (1 << 16)); + cullingMask = (cullingMask & ~(1 << 17)) | (source.cullingMask & (1 << 17)); + cullingMask = (cullingMask & ~(1 << 18)) | (source.cullingMask & (1 << 18)); + cullingMask = (cullingMask & ~(1 << 19)) | (source.cullingMask & (1 << 19)); + cullingMask = (cullingMask & ~(1 << 20)) | (source.cullingMask & (1 << 20)); + cullingMask = (cullingMask & ~(1 << 21)) | (source.cullingMask & (1 << 21)); + cullingMask = (cullingMask & ~(1 << 22)) | (source.cullingMask & (1 << 22)); + cullingMask = (cullingMask & ~(1 << 23)) | (source.cullingMask & (1 << 23)); + cullingMask = (cullingMask & ~(1 << 24)) | (source.cullingMask & (1 << 24)); + cullingMask = (cullingMask & ~(1 << 25)) | (source.cullingMask & (1 << 25)); + cullingMask = (cullingMask & ~(1 << 26)) | (source.cullingMask & (1 << 26)); + cullingMask = (cullingMask & ~(1 << 27)) | (source.cullingMask & (1 << 27)); + cullingMask = (cullingMask & ~(1 << 28)) | (source.cullingMask & (1 << 28)); + cullingMask = (cullingMask & ~(1 << 29)) | (source.cullingMask & (1 << 29)); + cullingMask = (cullingMask & ~(1 << 30)) | (source.cullingMask & (1 << 30)); + cullingMask = (cullingMask & ~(1 << 31)) | (source.cullingMask & (1 << 31)); + + target.cullingMask = cullingMask; + + target.clearFlags = source.clearFlags; + target.depthTextureMode = source.depthTextureMode; + target.useOcclusionCulling = source.useOcclusionCulling; + target.pixelRect = source.pixelRect; + target.targetTexture = source.targetTexture; + + target.renderingPath = source.renderingPath; + target.allowHDR = source.allowHDR; + target.allowMSAA = source.allowMSAA; + target.allowDynamicResolution = source.allowDynamicResolution; + target.forceIntoRenderTexture = source.forceIntoRenderTexture; + target.orthographic = source.orthographic; + target.orthographicSize = source.orthographicSize; + target.depth = source.depth; + target.eventMask = source.eventMask; + target.layerCullSpherical = source.layerCullSpherical; + target.backgroundColor = source.backgroundColor; + target.clearStencilAfterLightingPass = source.clearStencilAfterLightingPass; + target.usePhysicalProperties = source.usePhysicalProperties; + // target.iso = source.iso; + // target.shutterSpeed = source.shutterSpeed; + // target.aperture = source.aperture; + // target.focusDistance = source.focusDistance; + // target.bladeCount = source.bladeCount; + // target.curvature = source.curvature; + // target.barrelClipping = source.barrelClipping; + // target.anamorphism = source.anamorphism; + // target.enabled = source.enabled; + // target.transform.position = source.transform.position; + // target.transform.rotation = source.transform.rotation; + // target.transform.localScale = source.transform.localScale; + target.focalLength = source.focalLength; + target.sensorSize = source.sensorSize; + target.lensShift = source.lensShift; + target.gateFit = source.gateFit; + target.rect = source.rect; + + target.targetDisplay = source.targetDisplay; + target.stereoSeparation = source.stereoSeparation; + target.stereoConvergence = source.stereoConvergence; + target.stereoTargetEye = source.stereoTargetEye; + } + } +} diff --git a/.Deprecated/FuckCameras/Properties/AssemblyInfo.cs b/.Deprecated/FuckCameras/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..7165e1a --- /dev/null +++ b/.Deprecated/FuckCameras/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using MelonLoader; +using NAK.FuckCameras.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.FuckCameras))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.FuckCameras))] + +[assembly: MelonInfo( + typeof(NAK.FuckCameras.FuckCamerasMod), + nameof(NAK.FuckCameras), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/FuckCameras" +)] + +[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.FuckCameras.Properties; +internal static class AssemblyInfoParams +{ + public const string Version = "1.0.0"; + public const string Author = "NotAKidoS"; +} \ No newline at end of file diff --git a/.Deprecated/FuckCameras/README.md b/.Deprecated/FuckCameras/README.md new file mode 100644 index 0000000..9ddff99 --- /dev/null +++ b/.Deprecated/FuckCameras/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/.Deprecated/FuckCameras/format.json b/.Deprecated/FuckCameras/format.json new file mode 100644 index 0000000..78c5bbc --- /dev/null +++ b/.Deprecated/FuckCameras/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 diff --git a/.Deprecated/FuckCohtml2/FuckCohtml2.csproj b/.Deprecated/FuckCohtml2/FuckCohtml2.csproj new file mode 100644 index 0000000..5a8badc --- /dev/null +++ b/.Deprecated/FuckCohtml2/FuckCohtml2.csproj @@ -0,0 +1,6 @@ + + + + YouAreMineNow + + diff --git a/.Deprecated/FuckCohtml2/Main.cs b/.Deprecated/FuckCohtml2/Main.cs new file mode 100644 index 0000000..fa69e9f --- /dev/null +++ b/.Deprecated/FuckCohtml2/Main.cs @@ -0,0 +1,57 @@ +using System.Reflection; +using ABI_RC.Core.UI; +using HarmonyLib; +using MelonLoader; + +namespace NAK.FuckCohtml2; + +public class FuckCohtml2Mod : MelonMod +{ + private static readonly MelonPreferences_Category Category = + MelonPreferences.CreateCategory(nameof(FuckCohtml2)); + + private static readonly MelonPreferences_Entry EntryFixShouldAdvance = + Category.CreateEntry( + identifier: "fix_should_advance", + true, + display_name: "Fix ShouldAdvance", + description: "Fix CohtmlControlledView.ShouldAdvance to respect the Enabled property."); + + private static readonly MelonPreferences_Entry EntryFixShouldRender = + Category.CreateEntry( + identifier: "fix_should_render", + true, + display_name: "Fix ShouldRender", + description: "Fix CohtmlControlledView.ShouldRender to respect the Enabled property."); + + public override void OnInitializeMelon() + { + PatchProperty(nameof(CohtmlControlledView.ShouldAdvance), nameof(OnShouldAdvance)); + PatchProperty(nameof(CohtmlControlledView.ShouldRender), nameof(OnShouldRender)); + } + + private void PatchProperty(string propertyName, string handlerName) + { + PropertyInfo prop = typeof(CohtmlControlledView).GetProperty(propertyName, + BindingFlags.Public | BindingFlags.Instance); + MethodInfo getter = prop!.GetGetMethod(true); + + MethodInfo postfixMethod = typeof(FuckCohtml2Mod).GetMethod(handlerName, + BindingFlags.NonPublic | BindingFlags.Static, null, + [typeof(object), typeof(bool).MakeByRefType()], null); + + HarmonyInstance.Patch(getter, postfix: new HarmonyMethod(postfixMethod)); + } + + private static void OnShouldAdvance(object __instance, ref bool __result) + { + if (!EntryFixShouldAdvance.Value) return; + if (__instance is CohtmlControlledView inst) __result &= inst.Enabled; + } + + private static void OnShouldRender(object __instance, ref bool __result) + { + if (!EntryFixShouldRender.Value) return; + if (__instance is CohtmlControlledView inst) __result &= inst.Enabled; + } +} \ No newline at end of file diff --git a/.Deprecated/FuckCohtml2/Properties/AssemblyInfo.cs b/.Deprecated/FuckCohtml2/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..334d3fd --- /dev/null +++ b/.Deprecated/FuckCohtml2/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using MelonLoader; +using NAK.FuckCohtml2.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.FuckCohtml2))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.FuckCohtml2))] + +[assembly: MelonInfo( + typeof(NAK.FuckCohtml2.FuckCohtml2Mod), + nameof(NAK.FuckCohtml2), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/FuckCohtml2" +)] + +[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.FuckCohtml2.Properties; +internal static class AssemblyInfoParams +{ + public const string Version = "1.0.0"; + public const string Author = "NotAKidoS"; +} \ No newline at end of file diff --git a/.Deprecated/FuckCohtml2/README.md b/.Deprecated/FuckCohtml2/README.md new file mode 100644 index 0000000..9ddff99 --- /dev/null +++ b/.Deprecated/FuckCohtml2/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/.Deprecated/FuckCohtml2/format.json b/.Deprecated/FuckCohtml2/format.json new file mode 100644 index 0000000..78c5bbc --- /dev/null +++ b/.Deprecated/FuckCohtml2/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 diff --git a/.Deprecated/FuckOffUICamera/Properties/AssemblyInfo.cs b/.Deprecated/FuckOffUICamera/Properties/AssemblyInfo.cs index b7a9e9f..8e48465 100644 --- a/.Deprecated/FuckOffUICamera/Properties/AssemblyInfo.cs +++ b/.Deprecated/FuckOffUICamera/Properties/AssemblyInfo.cs @@ -17,7 +17,7 @@ using System.Reflection; downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/FuckOffUICamera" )] -[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/.Deprecated/IFUCKINGHATECAMERAS/IFUCKINGHATECAMERAS.csproj b/.Deprecated/IFUCKINGHATECAMERAS/IFUCKINGHATECAMERAS.csproj new file mode 100644 index 0000000..5a8badc --- /dev/null +++ b/.Deprecated/IFUCKINGHATECAMERAS/IFUCKINGHATECAMERAS.csproj @@ -0,0 +1,6 @@ + + + + YouAreMineNow + + diff --git a/.Deprecated/IFUCKINGHATECAMERAS/Main.cs b/.Deprecated/IFUCKINGHATECAMERAS/Main.cs new file mode 100644 index 0000000..74307c2 --- /dev/null +++ b/.Deprecated/IFUCKINGHATECAMERAS/Main.cs @@ -0,0 +1,39 @@ +using ABI_RC.Core.Player; +using ABI_RC.Core.Util.AnimatorManager; +using ABI_RC.Systems.GameEventSystem; +using ABI.CCK.Components; +using MelonLoader; +using UnityEngine; + +namespace NAK.IFUCKINGHATECAMERAS; + +public class IFUCKINGHATECAMERASMod : MelonMod +{ + private static readonly MelonPreferences_Category Category = + MelonPreferences.CreateCategory(nameof(IFUCKINGHATECAMERAS)); + + private static readonly MelonPreferences_Entry EntryRunHack = + Category.CreateEntry( + identifier: "run_hack", + true, + display_name: "Run Camera Hack (Avatars Only)?", + description: "Should the camera hack run? Btw I fucking hate cameras."); + + public override void OnInitializeMelon() + { + CVRGameEventSystem.Avatar.OnRemoteAvatarLoad.AddListener(OnRemoteAvatarLoad); + } + + private static void OnRemoteAvatarLoad(CVRPlayerEntity playerEntity, CVRAvatar avatar) + { + if (!EntryRunHack.Value) return; + + // HACK: Fixes a native crash (animating camera off on first frame) due to culling in specific worlds. + // I am unsure the root cause, but the local player doesn't crash, and this is similar to what that does. + + AvatarAnimatorManager AnimatorManager = playerEntity.PuppetMaster.AnimatorManager; + AnimatorManager.Animator.cullingMode = AnimatorCullingMode.AlwaysAnimate; // Set culling mode to always animate + AnimatorManager.Animator.Update(0f); // Update the animator to force it to do the first frame + AnimatorManager.Animator.cullingMode = AnimatorCullingMode.CullUpdateTransforms; // Set to cull update transforms + } +} \ No newline at end of file diff --git a/.Deprecated/IFUCKINGHATECAMERAS/Properties/AssemblyInfo.cs b/.Deprecated/IFUCKINGHATECAMERAS/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..4fefcd7 --- /dev/null +++ b/.Deprecated/IFUCKINGHATECAMERAS/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using MelonLoader; +using NAK.IFUCKINGHATECAMERAS.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.IFUCKINGHATECAMERAS))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.IFUCKINGHATECAMERAS))] + +[assembly: MelonInfo( + typeof(NAK.IFUCKINGHATECAMERAS.IFUCKINGHATECAMERASMod), + nameof(NAK.IFUCKINGHATECAMERAS), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/IFUCKINGHATECAMERAS" +)] + +[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.IFUCKINGHATECAMERAS.Properties; +internal static class AssemblyInfoParams +{ + public const string Version = "1.0.0"; + public const string Author = "NotAKidoS"; +} \ No newline at end of file diff --git a/.Deprecated/IFUCKINGHATECAMERAS/README.md b/.Deprecated/IFUCKINGHATECAMERAS/README.md new file mode 100644 index 0000000..7ff0922 --- /dev/null +++ b/.Deprecated/IFUCKINGHATECAMERAS/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/.Deprecated/IFUCKINGHATECAMERAS/format.json b/.Deprecated/IFUCKINGHATECAMERAS/format.json new file mode 100644 index 0000000..da65a56 --- /dev/null +++ b/.Deprecated/IFUCKINGHATECAMERAS/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 diff --git a/KeepVelocityOnExitFlight/KeepVelocityOnExitFlight.csproj b/.Deprecated/KeepVelocityOnExitFlight/KeepVelocityOnExitFlight.csproj similarity index 100% rename from KeepVelocityOnExitFlight/KeepVelocityOnExitFlight.csproj rename to .Deprecated/KeepVelocityOnExitFlight/KeepVelocityOnExitFlight.csproj diff --git a/KeepVelocityOnExitFlight/Main.cs b/.Deprecated/KeepVelocityOnExitFlight/Main.cs similarity index 93% rename from KeepVelocityOnExitFlight/Main.cs rename to .Deprecated/KeepVelocityOnExitFlight/Main.cs index a9dc414..994e8bd 100644 --- a/KeepVelocityOnExitFlight/Main.cs +++ b/.Deprecated/KeepVelocityOnExitFlight/Main.cs @@ -1,7 +1,5 @@ -using System.Reflection; -using ABI_RC.Core.Util.AnimatorManager; +using System.Reflection; using ABI_RC.Systems.Movement; -using ABI.CCK.Scripts; using HarmonyLib; using MelonLoader; using UnityEngine; diff --git a/KeepVelocityOnExitFlight/Properties/AssemblyInfo.cs b/.Deprecated/KeepVelocityOnExitFlight/Properties/AssemblyInfo.cs similarity index 98% rename from KeepVelocityOnExitFlight/Properties/AssemblyInfo.cs rename to .Deprecated/KeepVelocityOnExitFlight/Properties/AssemblyInfo.cs index e51a838..e9204cd 100644 --- a/KeepVelocityOnExitFlight/Properties/AssemblyInfo.cs +++ b/.Deprecated/KeepVelocityOnExitFlight/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -using MelonLoader; +using MelonLoader; using NAK.KeepVelocityOnExitFlight.Properties; using System.Reflection; diff --git a/KeepVelocityOnExitFlight/README.md b/.Deprecated/KeepVelocityOnExitFlight/README.md similarity index 100% rename from KeepVelocityOnExitFlight/README.md rename to .Deprecated/KeepVelocityOnExitFlight/README.md diff --git a/KeepVelocityOnExitFlight/format.json b/.Deprecated/KeepVelocityOnExitFlight/format.json similarity index 100% rename from KeepVelocityOnExitFlight/format.json rename to .Deprecated/KeepVelocityOnExitFlight/format.json diff --git a/LazyPrune/LazyPrune.csproj b/.Deprecated/LazyPrune/LazyPrune.csproj similarity index 100% rename from LazyPrune/LazyPrune.csproj rename to .Deprecated/LazyPrune/LazyPrune.csproj diff --git a/LazyPrune/Main.cs b/.Deprecated/LazyPrune/Main.cs similarity index 99% rename from LazyPrune/Main.cs rename to .Deprecated/LazyPrune/Main.cs index 019d2f4..6c2f690 100644 --- a/LazyPrune/Main.cs +++ b/.Deprecated/LazyPrune/Main.cs @@ -1,4 +1,4 @@ -using System.Reflection; +using System.Reflection; using ABI_RC.Core.EventSystem; using ABI_RC.Core.IO; using ABI_RC.Core.Networking.API.Responses; diff --git a/LazyPrune/Properties/AssemblyInfo.cs b/.Deprecated/LazyPrune/Properties/AssemblyInfo.cs similarity index 98% rename from LazyPrune/Properties/AssemblyInfo.cs rename to .Deprecated/LazyPrune/Properties/AssemblyInfo.cs index 169f34e..299ce21 100644 --- a/LazyPrune/Properties/AssemblyInfo.cs +++ b/.Deprecated/LazyPrune/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -using MelonLoader; +using MelonLoader; using NAK.LazyPrune.Properties; using System.Reflection; diff --git a/LazyPrune/README.md b/.Deprecated/LazyPrune/README.md similarity index 100% rename from LazyPrune/README.md rename to .Deprecated/LazyPrune/README.md diff --git a/LazyPrune/format.json b/.Deprecated/LazyPrune/format.json similarity index 100% rename from LazyPrune/format.json rename to .Deprecated/LazyPrune/format.json diff --git a/.Deprecated/SuperAwesomeMod/DepthCameraFix.cs b/.Deprecated/SuperAwesomeMod/DepthCameraFix.cs index 933cfa6..97fd404 100644 --- a/.Deprecated/SuperAwesomeMod/DepthCameraFix.cs +++ b/.Deprecated/SuperAwesomeMod/DepthCameraFix.cs @@ -3,22 +3,6 @@ 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 { diff --git a/.Deprecated/SuperAwesomeMod/Interaction/CVRPlayerHand.cs b/.Deprecated/SuperAwesomeMod/Interaction/CVRPlayerHand.cs index 949b638..42fbfd3 100644 --- a/.Deprecated/SuperAwesomeMod/Interaction/CVRPlayerHand.cs +++ b/.Deprecated/SuperAwesomeMod/Interaction/CVRPlayerHand.cs @@ -1,8 +1,6 @@ using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.InteractionSystem.Base; -using ABI_RC.Systems.InputManagement; using UnityEngine; -using UnityEngine.Serialization; namespace ABI_RC.Core.Player.Interaction { diff --git a/.Deprecated/SuperAwesomeMod/Interaction/CVRPlayerInteractionManager.cs b/.Deprecated/SuperAwesomeMod/Interaction/CVRPlayerInteractionManager.cs index 2c0d56e..b31be75 100644 --- a/.Deprecated/SuperAwesomeMod/Interaction/CVRPlayerInteractionManager.cs +++ b/.Deprecated/SuperAwesomeMod/Interaction/CVRPlayerInteractionManager.cs @@ -1,214 +1,214 @@ -using ABI_RC.Core.Player.Interaction.RaycastImpl; -using ABI_RC.Core.Savior; -using ABI_RC.Systems.InputManagement; -using UnityEngine; - -namespace ABI_RC.Core.Player.Interaction -{ - public class CVRPlayerInteractionManager : MonoBehaviour - { - #region Singleton - - public static CVRPlayerInteractionManager Instance { get; private set; } - - #endregion Singleton - - #region Serialized Fields - - [Header("Hand Components")] - [SerializeField] private CVRPlayerHand handVrLeft; - [SerializeField] private CVRPlayerHand handVrRight; - [SerializeField] private CVRPlayerHand handDesktopRight; // Desktop does not have a left hand - - [Header("Raycast Transforms")] - [SerializeField] private Transform raycastTransformVrRight; - [SerializeField] private Transform raycastTransformVrLeft; - [SerializeField] private Transform raycastTransformDesktopRight; - - [Header("Settings")] - [SerializeField] private bool interactionEnabled = true; - [SerializeField] private LayerMask interactionLayerMask = -1; // Default to all layers, will be filtered - - #endregion Serialized Fields - - #region Properties - - private CVRPlayerHand _rightHand; - private CVRPlayerHand _leftHand; - - private CVRPlayerRaycaster _rightRaycaster; - private CVRPlayerRaycaster _leftRaycaster; - - private CVRRaycastResult _rightRaycastResult; - private CVRRaycastResult _leftRaycastResult; - - // Input handler - private CVRPlayerInputHandler _inputHandler; - - // Interaction flags - public bool InteractionEnabled - { - get => interactionEnabled; - set => interactionEnabled = value; - } - - #endregion Properties - - #region Unity Events - - private void Awake() - { - if (Instance != null && Instance != this) - { - Destroy(gameObject); - return; - } - Instance = this; - - // Create the input handler - _inputHandler = gameObject.AddComponent(); - } - - private void Start() - { - // Setup interaction for current device mode - SetupInteractionForDeviceMode(); - - // Listen for VR mode changes - MetaPort.Instance.onVRModeSwitch.AddListener(SetupInteractionForDeviceMode); - } - - private void Update() - { - if (!interactionEnabled) - return; - - // Process right hand - if (_rightRaycaster != null) - { - // Determine raycast flags based on current mode - CVRPlayerRaycaster.RaycastFlags flags = DetermineRaycastFlags(_rightHand); - - // Get raycast results - _rightRaycastResult = _rightRaycaster.GetRaycastResults(flags); - - // Process input based on raycast results - _inputHandler.ProcessInput(CVRHand.Right, _rightRaycastResult); - } - - // Process left hand (if available) - if (_leftRaycaster != null) - { - // Determine raycast flags based on current mode - CVRPlayerRaycaster.RaycastFlags flags = DetermineRaycastFlags(_leftHand); - - // Get raycast results - _leftRaycastResult = _leftRaycaster.GetRaycastResults(flags); - - // Process input based on raycast results - _inputHandler.ProcessInput(CVRHand.Left, _leftRaycastResult); - } - } - - private void OnDestroy() - { - // Clean up event listener - if (MetaPort.Instance != null) - MetaPort.Instance.onVRModeSwitch.RemoveListener(SetupInteractionForDeviceMode); - } - - #endregion Unity Events - - #region Public Methods - - /// - /// Register a custom tool mode - /// - public void RegisterCustomToolMode(System.Action callback) - { - _inputHandler.RegisterCustomTool(callback); - } - - /// - /// Unregister the current custom tool mode - /// - public void UnregisterCustomToolMode() - { - _inputHandler.UnregisterCustomTool(); - } - - /// - /// Set the interaction mode - /// - public void SetInteractionMode(CVRPlayerInputHandler.InteractionMode mode) - { - _inputHandler.SetInteractionMode(mode); - } - - /// - /// Get the raycast result for a specific hand - /// - public CVRRaycastResult GetRaycastResult(CVRHand hand) - { - return hand == CVRHand.Left ? _leftRaycastResult : _rightRaycastResult; - } - - #endregion Public Methods - - #region Private Methods - - private void SetupInteractionForDeviceMode() - { - bool isVr = MetaPort.Instance.isUsingVr; - - if (isVr) - { - // VR mode - _rightHand = handVrRight; - _leftHand = handVrLeft; - - // VR uses the controller transform for raycasting - _rightRaycaster = new CVRPlayerRaycasterTransform(raycastTransformVrRight); - _leftRaycaster = new CVRPlayerRaycasterTransform(raycastTransformVrLeft); - } - else - { - // Desktop mode - _rightHand = handDesktopRight; - _leftHand = null; - - // Desktop uses the mouse position for raycasting when unlocked - Camera desktopCamera = PlayerSetup.Instance.desktopCam; - _rightRaycaster = new CVRPlayerRaycasterMouse(raycastTransformDesktopRight, desktopCamera); - _leftRaycaster = null; - } - - // Set the layer mask for raycasters - if (_rightRaycaster != null) - _rightRaycaster.SetLayerMask(interactionLayerMask); - - if (_leftRaycaster != null) - _leftRaycaster.SetLayerMask(interactionLayerMask); - } - - private static CVRPlayerRaycaster.RaycastFlags DetermineRaycastFlags(CVRPlayerHand hand) - { - // Default to all flags - CVRPlayerRaycaster.RaycastFlags flags = CVRPlayerRaycaster.RaycastFlags.All; - - // Check if hand is holding a pickup - if (hand != null && hand.IsHoldingObject) - { - // When holding an object, only check for COHTML interaction - flags = CVRPlayerRaycaster.RaycastFlags.CohtmlInteract; - } - - // Could add more conditional flag adjustments here based on the current mode - // For example, in a teleport tool mode, you might only want world hits - - return flags; - } - - #endregion Private Methods - } -} \ No newline at end of file +// using ABI_RC.Core.Player.Interaction.RaycastImpl; +// using ABI_RC.Core.Savior; +// using ABI_RC.Systems.InputManagement; +// using UnityEngine; +// +// namespace ABI_RC.Core.Player.Interaction +// { +// public class CVRPlayerInteractionManager : MonoBehaviour +// { +// #region Singleton +// +// public static CVRPlayerInteractionManager Instance { get; private set; } +// +// #endregion Singleton +// +// #region Serialized Fields +// +// [Header("Hand Components")] +// [SerializeField] private CVRPlayerHand handVrLeft; +// [SerializeField] private CVRPlayerHand handVrRight; +// [SerializeField] private CVRPlayerHand handDesktopRight; // Desktop does not have a left hand +// +// [Header("Raycast Transforms")] +// [SerializeField] private Transform raycastTransformVrRight; +// [SerializeField] private Transform raycastTransformVrLeft; +// [SerializeField] private Transform raycastTransformDesktopRight; +// +// [Header("Settings")] +// [SerializeField] private bool interactionEnabled = true; +// [SerializeField] private LayerMask interactionLayerMask = -1; // Default to all layers, will be filtered +// +// #endregion Serialized Fields +// +// #region Properties +// +// private CVRPlayerHand _rightHand; +// private CVRPlayerHand _leftHand; +// +// private CVRPlayerRaycaster _rightRaycaster; +// private CVRPlayerRaycaster _leftRaycaster; +// +// private CVRRaycastResult _rightRaycastResult; +// private CVRRaycastResult _leftRaycastResult; +// +// // Input handler +// private CVRPlayerInputHandler _inputHandler; +// +// // Interaction flags +// public bool InteractionEnabled +// { +// get => interactionEnabled; +// set => interactionEnabled = value; +// } +// +// #endregion Properties +// +// #region Unity Events +// +// private void Awake() +// { +// if (Instance != null && Instance != this) +// { +// Destroy(gameObject); +// return; +// } +// Instance = this; +// +// // Create the input handler +// _inputHandler = gameObject.AddComponent(); +// } +// +// private void Start() +// { +// // Setup interaction for current device mode +// SetupInteractionForDeviceMode(); +// +// // Listen for VR mode changes +// MetaPort.Instance.onVRModeSwitch.AddListener(SetupInteractionForDeviceMode); +// } +// +// private void Update() +// { +// if (!interactionEnabled) +// return; +// +// // Process right hand +// if (_rightRaycaster != null) +// { +// // Determine raycast flags based on current mode +// CVRPlayerRaycaster.RaycastFlags flags = DetermineRaycastFlags(_rightHand); +// +// // Get raycast results +// _rightRaycastResult = _rightRaycaster.GetRaycastResults(flags); +// +// // Process input based on raycast results +// _inputHandler.ProcessInput(CVRHand.Right, _rightRaycastResult); +// } +// +// // Process left hand (if available) +// if (_leftRaycaster != null) +// { +// // Determine raycast flags based on current mode +// CVRPlayerRaycaster.RaycastFlags flags = DetermineRaycastFlags(_leftHand); +// +// // Get raycast results +// _leftRaycastResult = _leftRaycaster.GetRaycastResults(flags); +// +// // Process input based on raycast results +// _inputHandler.ProcessInput(CVRHand.Left, _leftRaycastResult); +// } +// } +// +// private void OnDestroy() +// { +// // Clean up event listener +// if (MetaPort.Instance != null) +// MetaPort.Instance.onVRModeSwitch.RemoveListener(SetupInteractionForDeviceMode); +// } +// +// #endregion Unity Events +// +// #region Public Methods +// +// /// +// /// Register a custom tool mode +// /// +// public void RegisterCustomToolMode(System.Action callback) +// { +// _inputHandler.RegisterCustomTool(callback); +// } +// +// /// +// /// Unregister the current custom tool mode +// /// +// public void UnregisterCustomToolMode() +// { +// _inputHandler.UnregisterCustomTool(); +// } +// +// /// +// /// Set the interaction mode +// /// +// public void SetInteractionMode(CVRPlayerInputHandler.InteractionMode mode) +// { +// _inputHandler.SetInteractionMode(mode); +// } +// +// /// +// /// Get the raycast result for a specific hand +// /// +// public CVRRaycastResult GetRaycastResult(CVRHand hand) +// { +// return hand == CVRHand.Left ? _leftRaycastResult : _rightRaycastResult; +// } +// +// #endregion Public Methods +// +// #region Private Methods +// +// private void SetupInteractionForDeviceMode() +// { +// bool isVr = MetaPort.Instance.isUsingVr; +// +// if (isVr) +// { +// // VR mode +// _rightHand = handVrRight; +// _leftHand = handVrLeft; +// +// // VR uses the controller transform for raycasting +// _rightRaycaster = new CVRPlayerRaycasterTransform(raycastTransformVrRight); +// _leftRaycaster = new CVRPlayerRaycasterTransform(raycastTransformVrLeft); +// } +// else +// { +// // Desktop mode +// _rightHand = handDesktopRight; +// _leftHand = null; +// +// // Desktop uses the mouse position for raycasting when unlocked +// Camera desktopCamera = PlayerSetup.Instance.desktopCam; +// _rightRaycaster = new CVRPlayerRaycasterMouse(raycastTransformDesktopRight, desktopCamera); +// _leftRaycaster = null; +// } +// +// // Set the layer mask for raycasters +// if (_rightRaycaster != null) +// _rightRaycaster.SetLayerMask(interactionLayerMask); +// +// if (_leftRaycaster != null) +// _leftRaycaster.SetLayerMask(interactionLayerMask); +// } +// +// private static CVRPlayerRaycaster.RaycastFlags DetermineRaycastFlags(CVRPlayerHand hand) +// { +// // Default to all flags +// CVRPlayerRaycaster.RaycastFlags flags = CVRPlayerRaycaster.RaycastFlags.All; +// +// // Check if hand is holding a pickup +// if (hand != null && hand.IsHoldingObject) +// { +// // When holding an object, only check for COHTML interaction +// flags = CVRPlayerRaycaster.RaycastFlags.CohtmlInteract; +// } +// +// // Could add more conditional flag adjustments here based on the current mode +// // For example, in a teleport tool mode, you might only want world hits +// +// return flags; +// } +// +// #endregion Private Methods +// } +// } \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Interaction/Components/CVRCanvasWrapper.cs b/.Deprecated/SuperAwesomeMod/Interaction/Components/CVRCanvasWrapper.cs index 2ec46bd..382487b 100644 --- a/.Deprecated/SuperAwesomeMod/Interaction/Components/CVRCanvasWrapper.cs +++ b/.Deprecated/SuperAwesomeMod/Interaction/Components/CVRCanvasWrapper.cs @@ -1,121 +1,121 @@ -using ABI_RC.Core.Base; -using ABI_RC.Core.Player; -using UnityEngine; -using UnityEngine.EventSystems; -using UnityEngine.UI; - -namespace NAK.SuperAwesomeMod.Components -{ - public class CVRCanvasWrapper : MonoBehaviour - { - public bool IsInteractable = true; - public float MaxInteractDistance = 10f; - - private Canvas _canvas; - private GraphicRaycaster _graphicsRaycaster; - private static readonly List _raycastResults = new(); - private static readonly PointerEventData _pointerEventData = new(EventSystem.current); - - private static Selectable _workingSelectable; - private Camera _camera; - private RectTransform _rectTransform; - - #region Unity Events - - private void Awake() - { - if (!TryGetComponent(out _canvas) - || _canvas.renderMode != RenderMode.WorldSpace) - { - IsInteractable = false; - return; - } - - _rectTransform = _canvas.GetComponent(); - } - - private void Start() - { - _graphicsRaycaster = _canvas.gameObject.AddComponent(); - _camera = PlayerSetup.Instance.activeCam; - _canvas.worldCamera = _camera; - } - - #endregion Unity Events - - #region Public Methods - - public bool GetGraphicsHit(Ray worldRay, out RaycastResult result) - { - result = default; - - if (!IsInteractable || _camera == null) return false; - - // Get the plane of the canvas - Plane canvasPlane = new(transform.forward, transform.position); - - // Find where the ray intersects the canvas plane - if (!canvasPlane.Raycast(worldRay, out float distance)) - return false; - - // Get the world point of intersection - Vector3 worldHitPoint = worldRay.origin + worldRay.direction * distance; - - // Check if hit point is within max interaction distance - if (Vector3.Distance(worldRay.origin, worldHitPoint) > MaxInteractDistance) - return false; - - // Check if hit point is within canvas bounds - Vector3 localHitPoint = transform.InverseTransformPoint(worldHitPoint); - Rect canvasRect = _rectTransform.rect; - if (!canvasRect.Contains(new Vector2(localHitPoint.x, localHitPoint.y))) - return false; - - // Convert world hit point to screen space - Vector2 screenPoint = _camera.WorldToScreenPoint(worldHitPoint); - - // Update pointer event data - _pointerEventData.position = screenPoint; - _pointerEventData.delta = Vector2.zero; - - // Clear previous results and perform raycast - _raycastResults.Clear(); - _graphicsRaycaster.Raycast(_pointerEventData, _raycastResults); - - // Early out if no hits - if (_raycastResults.Count == 0) - { - //Debug.Log($"No hits on canvas {_canvas.name}"); - return false; - } - - // Find first valid interactive UI element - foreach (RaycastResult hit in _raycastResults) - { - if (!hit.isValid) - { - //Debug.Log($"Invalid hit on canvas {_canvas.name}"); - continue; - } - - // Check if the hit object has a Selectable component and is interactable - GameObject hitObject = hit.gameObject; - if (!hitObject.TryGetComponent(out _workingSelectable) - || !_workingSelectable.interactable) - { - //Debug.Log($"Non-interactable hit on canvas {_canvas.name} - {hitObject.name}"); - continue; - } - - //Debug.Log($"Hit on canvas {_canvas.name} with {hitObject.name}"); - - result = hit; - return true; - } - - return false; - } - - #endregion Public Methods - } -} \ No newline at end of file +// using ABI_RC.Core.Base; +// using ABI_RC.Core.Player; +// using UnityEngine; +// using UnityEngine.EventSystems; +// using UnityEngine.UI; +// +// namespace NAK.SuperAwesomeMod.Components +// { +// public class CVRCanvasWrapper : MonoBehaviour +// { +// public bool IsInteractable = true; +// public float MaxInteractDistance = 10f; +// +// private Canvas _canvas; +// private GraphicRaycaster _graphicsRaycaster; +// private static readonly List _raycastResults = new(); +// private static readonly PointerEventData _pointerEventData = new(EventSystem.current); +// +// private static Selectable _workingSelectable; +// private Camera _camera; +// private RectTransform _rectTransform; +// +// #region Unity Events +// +// private void Awake() +// { +// if (!TryGetComponent(out _canvas) +// || _canvas.renderMode != RenderMode.WorldSpace) +// { +// IsInteractable = false; +// return; +// } +// +// _rectTransform = _canvas.GetComponent(); +// } +// +// private void Start() +// { +// _graphicsRaycaster = _canvas.gameObject.AddComponent(); +// _camera = PlayerSetup.Instance.activeCam; +// _canvas.worldCamera = _camera; +// } +// +// #endregion Unity Events +// +// #region Public Methods +// +// public bool GetGraphicsHit(Ray worldRay, out RaycastResult result) +// { +// result = default; +// +// if (!IsInteractable || _camera == null) return false; +// +// // Get the plane of the canvas +// Plane canvasPlane = new(transform.forward, transform.position); +// +// // Find where the ray intersects the canvas plane +// if (!canvasPlane.Raycast(worldRay, out float distance)) +// return false; +// +// // Get the world point of intersection +// Vector3 worldHitPoint = worldRay.origin + worldRay.direction * distance; +// +// // Check if hit point is within max interaction distance +// if (Vector3.Distance(worldRay.origin, worldHitPoint) > MaxInteractDistance) +// return false; +// +// // Check if hit point is within canvas bounds +// Vector3 localHitPoint = transform.InverseTransformPoint(worldHitPoint); +// Rect canvasRect = _rectTransform.rect; +// if (!canvasRect.Contains(new Vector2(localHitPoint.x, localHitPoint.y))) +// return false; +// +// // Convert world hit point to screen space +// Vector2 screenPoint = _camera.WorldToScreenPoint(worldHitPoint); +// +// // Update pointer event data +// _pointerEventData.position = screenPoint; +// _pointerEventData.delta = Vector2.zero; +// +// // Clear previous results and perform raycast +// _raycastResults.Clear(); +// _graphicsRaycaster.Raycast(_pointerEventData, _raycastResults); +// +// // Early out if no hits +// if (_raycastResults.Count == 0) +// { +// //Debug.Log($"No hits on canvas {_canvas.name}"); +// return false; +// } +// +// // Find first valid interactive UI element +// foreach (RaycastResult hit in _raycastResults) +// { +// if (!hit.isValid) +// { +// //Debug.Log($"Invalid hit on canvas {_canvas.name}"); +// continue; +// } +// +// // Check if the hit object has a Selectable component and is interactable +// GameObject hitObject = hit.gameObject; +// if (!hitObject.TryGetComponent(out _workingSelectable) +// || !_workingSelectable.interactable) +// { +// //Debug.Log($"Non-interactable hit on canvas {_canvas.name} - {hitObject.name}"); +// continue; +// } +// +// //Debug.Log($"Hit on canvas {_canvas.name} with {hitObject.name}"); +// +// result = hit; +// return true; +// } +// +// return false; +// } +// +// #endregion Public Methods +// } +// } \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Interaction/ControllerRay.cs b/.Deprecated/SuperAwesomeMod/Interaction/ControllerRay.cs new file mode 100644 index 0000000..06edaf5 --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Interaction/ControllerRay.cs @@ -0,0 +1,1871 @@ +/*using System; +using System.Collections.Generic; +using ABI.CCK.Components; +using ABI_RC.Core.AudioEffects; +using ABI_RC.Core.Base; +using ABI_RC.Core.Networking.IO.Social; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using ABI_RC.Core.UI; +using ABI_RC.Core.InteractionSystem.Base; +using ABI_RC.Scripting.Attributes; +using ABI_RC.Systems.InputManagement; +using ABI_RC.Systems.RuntimeDebug; +using ABI.Scripting.CVRSTL.Client; +using HighlightPlus; +using TMPro; +using Unity.XR.OpenVR; +using Unity.XR.PXR; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.Serialization; +using UnityEngine.UI; +using UnityEngine.XR.Management; +using Button = UnityEngine.UI.Button; +using EventTrigger = UnityEngine.EventSystems.EventTrigger; +using Slider = UnityEngine.UI.Slider; +using Toggle = UnityEngine.UI.Toggle; + +namespace ABI_RC.Core.InteractionSystem +{ + [AvailableToScripting( + targetModule: TargetModule, + inheritFrom: typeof(MonoBehaviour), + optInMembers: true)] + public class ControllerRay : MonoBehaviour + { + public const string TargetModule = LuaScriptFactory.ModuleNames.CVR; + + private const float MAX_RAYCAST_LENGTH = 100f; + + [AvailableToScripting(@readonly: true)] + public Vector3 RayDirection = new Vector3(0,-0.2f,1f); + + [AvailableToScripting(@readonly: true)] + public CVRHand hand; + + [AvailableToScripting(@readonly: true)] + public bool isInteractionRay = true; + + [FormerlySerializedAs("triggerGazeEvents")] public bool triggerHoverEvents = true; + + public bool shouldPhysicalInteraction = false; + + public VelocityTracker pickupVelocityTracker; + + public LineRenderer lineRenderer; + + [FormerlySerializedAs("_vrActive")] [SerializeField] bool vrActive; + + [AvailableToScripting(@readonly: true)] + [SerializeField] private Transform hitTransform; + [SerializeField] float thickness = 0.002f; + + [AvailableToScripting(@readonly: true)] + [SerializeField] internal Pickupable grabbedObject; + + public LayerMask uiMask; + public LayerMask generalMask; + + [AvailableToScripting(@readonly: true)] + public Transform controllerTransform; + + [AvailableToScripting(@readonly: true)] + public bool enabled; + + [AvailableToScripting(@readonly: true)] + public bool isDesktopRay; + + [AvailableToScripting(@readonly: true)] + public bool isHeadRay; + + [AvailableToScripting(@readonly: true)] + public ControllerRay otherRay; + + public bool uiActive; + + public Material highlightMaterial; + + private float _lastTrigger; + private float _lastGrip; + private bool _objectWasHit = false; + + private CohtmlControlledView _lastView; + private Vector2 _lastUiCoords; + private float _lastHitDistance; + + private GameObject lastTarget; + private GameObject highlightGameObject; + private GameObject lastTelepathicGrabTarget; + private GameObject lastProximityGrabTarget; + private Slider lastSlider; + private RectTransform lastSliderRect; + private EventTrigger lastEventTrigger; + private ScrollRect lastScrollView; + private RectTransform lastScrollViewRect; + private Vector2 scrollStartPositionView; + private Vector2 scrollStartPositionContent; + + private Button lastButton; + private Dropdown lastDropdown; + private Toggle lastToggle; + private InputField lastInputField; + private TMP_InputField lastTMPInputField; + [SerializeField] + private Interactable lastInteractable; + + [SerializeField] + private Pickupable _telepathicPickupCandidate; + private bool _telepathicPickupTargeted; + private float _telepathicPickupTimer = 0f; + private float _telepathicPickupResetTime = 0.5f; + private bool _telepathicPickupLocked = false; + private List _positionMemory = new List(); + private List _timeMemory = new List(); + + private bool _enableHighlight; + private bool _enableSmoothRay; + + public Transform rayDirectionTransform; + public Transform attachmentPoint; + public Transform pivotPoint; + public float attachmentDistance = 0.2f; + public float currentAttachmentDistance = 0.2f; + + public Transform backupRayFor; + public GameObject backupCrossHair; + + private bool _enableTelepathicGrab = true; + private float _telepathicGrabMaxDistance = 50f; + + private bool _gripToGrab; + + public Vector3 HitPoint => _hit.point; + + private RaycastHit _hit; + private readonly RaycastHit[] _hits = new RaycastHit[10]; + /// + /// Comparer used to sort arrays of RaycastHits, it will result in an array where the first indexes are the closest ones. + /// + private readonly Comparer _hitsComparer = Comparer.Create((hit1, hit2) => hit1.distance.CompareTo(hit2.distance)); + + #region Proximity Grab Fields + + public const string ProximityGrabEnabled = "ExperimentalProximityGrabEnabled"; + + private bool _proximityGrabEnabled; + public const string ProximityGrabVisualizers = "ExperimentalProximityGrabVisualizers"; + public const string ProximityGrabRadiusScale = "ExperimentalProximityGrabRadiusScale"; + + public const float ProximityGrabRadiusScaleDefault = 0.1f; + private bool _proximityGrabVisualizers; + + private float _proximityDetectionRadiusRelativeValue = ProximityGrabRadiusScaleDefault; + private float ProximityDetectionRadius => _proximityDetectionRadiusRelativeValue * PlayerSetup.Instance.GetPlaySpaceScale(); + + private readonly Collider[] _proximityColliders = new Collider[15]; + + #endregion + + //Inputs + private bool _interactDown = false; + private Pickupable _proximityColliderClosestPickup; + private bool _proximityCalculatedThisFrame; + private bool _interactUp = false; + private bool _interact = false; + private bool _gripDown = false; + private bool _gripUp = false; + private bool _grip = false; + private bool _isTryingToPickup = false; + private bool _drop = false; + + private bool _hitUIInternal = false; + + private void Start() + { + vrActive = MetaPort.Instance.isUsingVr; + + #if !PLATFORM_ANDROID + bool isOpenVR = XRGeneralSettings.Instance.Manager.activeLoader is OpenVRLoader; + if (!isOpenVR) + { + transform.localPosition = new Vector3(0.001f, 0.021f, -0.009f); + transform.localRotation = new Quaternion(0.50603801f, 0.0288440064f, 0.0147214793f, 0.861903071f); + } + #else + bool isPxr = XRGeneralSettings.Instance.Manager.activeLoader is PXR_Loader; + if (!isPxr) + { + transform.localPosition = new Vector3(0.001f, 0.021f, -0.009f); + transform.localRotation = new Quaternion(0.50603801f, 0.0288440064f, 0.0147214793f, 0.861903071f); + } + else + { + transform.localPosition = new Vector3(0.001f, 0.021f, -0.009f); + transform.localRotation = new Quaternion(0.30603801f, 0.0288440064f, 0.0147214793f, 0.861903071f); + } + #endif + + // Fallback + if (controllerTransform == null) + controllerTransform = transform; + + _enableHighlight = MetaPort.Instance.settings.GetSettingsBool("GeneralInteractableHighlight"); + _enableTelepathicGrab = MetaPort.Instance.settings.GetSettingsBool("GeneralTelepathicGrip"); + _gripToGrab = MetaPort.Instance.settings.GetSettingsBool("ControlUseGripToGrab"); + _enableSmoothRay = MetaPort.Instance.settings.GetSettingsBool("ControlSmoothRaycast"); + _proximityGrabEnabled = MetaPort.Instance.settings.GetSettingsBool(ProximityGrabEnabled); + _proximityGrabVisualizers = MetaPort.Instance.settings.GetSettingsBool(ProximityGrabVisualizers) || MetaPort.Instance.showProximityGrabVisualizers; + MetaPort.Instance.settings.settingBoolChanged.AddListener(SettingsBoolChanged); + + _proximityDetectionRadiusRelativeValue = MetaPort.Instance.settings.GetSettingsFloat(ProximityGrabRadiusScale); + MetaPort.Instance.settings.settingFloatChanged.AddListener(SettingFloatChanged); + + // RayDirection object, we smooth to combat jitter hands for the ray, but not pickups + rayDirectionTransform = new GameObject("RayDirection").transform; + rayDirectionTransform.SetParent(transform); + rayDirectionTransform.SetLocalPositionAndRotation(RayDirection * attachmentDistance, Quaternion.identity); + rayDirectionTransform.localScale = Vector3.one; + gameObject.BroadcastMessage("RayDirectionTransformUpdated",SendMessageOptions.DontRequireReceiver); + + // Attachment point, snaps to the object collider on grab, used for object push/pull + attachmentPoint = new GameObject("AttachmentPoint").transform; + attachmentPoint.SetParent(transform); + attachmentPoint.SetLocalPositionAndRotation(RayDirection * attachmentDistance, Quaternion.identity); + attachmentPoint.localScale = Vector3.one; + + // Pivot point, used purely for object rotation, makes the math easy + pivotPoint = new GameObject("PivotPoint").transform; + pivotPoint.SetParent(attachmentPoint); + pivotPoint.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); + pivotPoint.localScale = Vector3.one; + + if (lineRenderer != null) + { + lineRenderer.sortingOrder = 10; + } + + pickupVelocityTracker = pivotPoint.AddComponentIfMissing(); + } + + private void OnDisable() + { + if (backupCrossHair) backupCrossHair.SetActive(true); + } + + public void UpdateGrabDistance(float distance = 0.2f) + { + Vector3 lossyScale = attachmentPoint.lossyScale; + Vector3 scale = new(1f/lossyScale.x, 1f/lossyScale.y, 1f/lossyScale.z); + currentAttachmentDistance = distance; + scale.Scale(RayDirection); + attachmentPoint.localPosition = scale * distance; + } + + public void SetPivotRotation(Quaternion rot) + { + pivotPoint.rotation = rot; + } + + public void ResetPivotRotation() + { + pivotPoint.localRotation = Quaternion.identity; + } + + private void SettingsBoolChanged(string name, bool value) + { + if (name == "GeneralInteractableHighlight") + _enableHighlight = value; + + if (name == "GeneralTelepathicGrip") + _enableTelepathicGrab = value; + + if (name == "ControlUseGripToGrab") + _gripToGrab = value; + + if (name == "ControlSmoothRaycast") + _enableSmoothRay = value; + + if (name == ProximityGrabEnabled) + _proximityGrabEnabled = value; + + if (name == ProximityGrabVisualizers) + _proximityGrabVisualizers = value; + } + + private void SettingFloatChanged(string settingName, float value) + { + if (settingName == ProximityGrabRadiusScale) + _proximityDetectionRadiusRelativeValue = value; + } + + public bool IsInteracting() + { + bool shouldDisplay = _interact || _grip || _objectWasHit; + return shouldDisplay; + } + + public void ClearGrabbedObject() + { + grabbedObject = null; + } + + private RaycastHit SphereCast(float offset, float radius, float maxDistance) + { + // Might be slower? + //_proximityColliders[0] = new(); + //Physics.SphereCastNonAlloc + + Physics.SphereCast + (transform.TransformPoint(RayDirection * offset), + radius, + transform.TransformDirection(RayDirection), + out RaycastHit output, + maxDistance, + (1 << CVRLayers.MirrorReflection), // generalMask |= (1 << CVRLayers.MirrorReflection), + QueryTriggerInteraction.Collide); + + //return _proximityColliders[0]; + return output; + } + + private void UpdateBackupRay() + { + if (backupRayFor != null) + { + isInteractionRay = uiActive = backupRayFor.localPosition == Vector3.zero; + backupCrossHair.SetActive(isInteractionRay); + if (otherRay != null) otherRay.isInteractionRay = !isInteractionRay; + } + } + + private bool CanSelectPlayersAndProps() + { + if (ViewManager.Instance.IsAnyMenuOpen) + return true; + + if (isDesktopRay + && CVRInputManager.Instance.unlockMouse) + return true; + + return false; + } + + private void UpdateInteractionMask() + { + if (CanSelectPlayersAndProps()) + { + generalMask |= (1 << CVRLayers.PlayerNetwork); + } + else + { + generalMask &= ~(1 << CVRLayers.PlayerNetwork); + } + + generalMask &= ~(1 << CVRLayers.Water); + } + + private void ResetPointAtUI() + { + if (isInteractionRay + && !isDesktopRay + && !isHeadRay) + { + if (hand == CVRHand.Left) + { + CVRInputManager.Instance.leftControllerPointingMenu = false; + CVRInputManager.Instance.leftControllerPointingCanvas = false; + } + else + { + CVRInputManager.Instance.rightControllerPointingMenu = false; + CVRInputManager.Instance.rightControllerPointingCanvas = false; + } + } + } + + private void UpdateInputs() + { + _interactDown = false; + _interactUp = false; + _interact = false; + _gripDown = false; + _gripUp = false; + _grip = false; + + _isTryingToPickup = false; + _drop = false; + + if (isInteractionRay) + { + _interactDown = hand == CVRHand.Left ? CVRInputManager.Instance.interactLeftDown : CVRInputManager.Instance.interactRightDown; + _interactUp = hand == CVRHand.Left ? CVRInputManager.Instance.interactLeftUp : CVRInputManager.Instance.interactRightUp; + _interact = (hand == CVRHand.Left ? CVRInputManager.Instance.interactLeftValue : CVRInputManager.Instance.interactRightValue) > 0.8f; + _gripDown = hand == CVRHand.Left ? CVRInputManager.Instance.gripLeftDown : CVRInputManager.Instance.gripRightDown; + _gripUp = hand == CVRHand.Left ? CVRInputManager.Instance.gripLeftUp : CVRInputManager.Instance.gripRightUp; + _grip = (hand == CVRHand.Left ? CVRInputManager.Instance.gripLeftValue : CVRInputManager.Instance.gripRightValue) > 0.8f; + + if (!MetaPort.Instance.isUsingVr) + { + // Non-VR mode: Use grip for pickup and drop + _isTryingToPickup = _gripDown; + _drop = _gripUp || CVRInputManager.Instance.drop; + } + else if (_gripToGrab) + { + // VR mode with grip-to-grab enabled + _isTryingToPickup = _gripDown; + _drop = _gripUp; + } + else + { + // VR mode with interact button + _isTryingToPickup = _interactDown; + _drop = _gripDown; + } + } + } + + private void CheckExitPropModes() + { + if (_gripDown && PlayerSetup.Instance.GetCurrentPropSelectionMode() != PlayerSetup.PropSelectionMode.None) + { + PlayerSetup.Instance.ClearPropToSpawn(); + } + } + + private void HandleTelepathicGrip() + { + if (!_telepathicPickupLocked) + { + if (_telepathicPickupCandidate != null && _telepathicPickupTargeted) + { + SetTelepathicGrabTargetHighlight(_telepathicPickupCandidate.gameObject); + if (_interactDown) _telepathicPickupLocked = true; + } + else if (_telepathicPickupCandidate != null) + { + _telepathicPickupTimer += Time.deltaTime; + if (_telepathicPickupTimer >= _telepathicPickupResetTime) + { + ClearTelepathicGrabTargetHighlight(); + _telepathicPickupCandidate = null; + _telepathicPickupTimer = 0f; + } + } + else if (_telepathicPickupCandidate == null) + { + _telepathicPickupTimer = 0f; + } + + _telepathicPickupTargeted = false; + } + else + { + if (_positionMemory.Count >= 5) + { + _positionMemory.RemoveAt(0); + _timeMemory.RemoveAt(0); + } + _positionMemory.Add(transform.parent.localPosition); + _timeMemory.Add(Time.deltaTime); + + if (_positionMemory.Count >= 5) + { + Vector3 velocity = _positionMemory[4] - _positionMemory[0]; + float time = 0; + foreach (float v in _timeMemory) + { + time += v; + } + + if (MetaPort.Instance.isUsingVr) + { + if ((velocity * (1 / time)).magnitude >= 0.5f) + { + if (_telepathicPickupCandidate != null) + { + _telepathicPickupCandidate.FlingTowardsTarget(transform.position); + ClearTelepathicGrabTargetHighlight(); + } + + _telepathicPickupCandidate = null; + _telepathicPickupTimer = 0f; + _telepathicPickupLocked = false; + + _positionMemory.Clear(); + _timeMemory.Clear(); + } + } + else + { + if (CVRInputManager.Instance.objectPushPull <= -2) + { + if (_telepathicPickupCandidate != null) + { + _telepathicPickupCandidate.FlingTowardsTarget(transform.position); + ClearTelepathicGrabTargetHighlight(); + } + + _telepathicPickupCandidate = null; + _telepathicPickupTimer = 0f; + _telepathicPickupLocked = false; + + _positionMemory.Clear(); + _timeMemory.Clear(); + } + } + } + + if (_interactUp) + { + if (_telepathicPickupCandidate != null) ClearTelepathicGrabTargetHighlight(); + _telepathicPickupCandidate = null; + _telepathicPickupTimer = 0f; + _telepathicPickupLocked = false; + + _positionMemory.Clear(); + _timeMemory.Clear(); + } + } + } + + private void HandleGrabbedObjects() + { + if (grabbedObject == null) return; + + // pickup rotation + if (grabbedObject.IsObjectRotationAllowed) + { + Quaternion rotationX = Quaternion.AngleAxis(-CVRInputManager.Instance.objectRotationValue.x * 20f, transform.up); + Quaternion rotationY = Quaternion.AngleAxis(CVRInputManager.Instance.objectRotationValue.y * 20f, transform.right); + pivotPoint.rotation = rotationX * rotationY * pivotPoint.rotation; + } + + // pickup push/pull + if (grabbedObject.IsObjectPushPullAllowed) + { + float newDistance = currentAttachmentDistance + 0.1f + * CVRInputManager.Instance.objectPushPull * PlayerSetup.Instance.GetPlaySpaceScale(); + if (Mathf.Abs(newDistance - currentAttachmentDistance) > float.Epsilon) + UpdateGrabDistance(Mathf.Clamp(newDistance, 0f, grabbedObject.MaxPushDistance)); + } + + // pickup interaction + if (_interactDown) grabbedObject.UseDown(new InteractionContext(this)); + if (_interactUp) grabbedObject.UseUp(new InteractionContext(this)); + + Interactable interactable = grabbedObject.gameObject.GetComponent(); + + // interaction + if (grabbedObject.IsObjectUseAllowed && interactable != null) + { + if (_interactDown) interactable.InteractDown(new InteractionContext(this), this); + if (_interactUp) interactable.InteractUp(new InteractionContext(this), this); + } + + if (!grabbedObject.IsAutoHold && _drop) DropObject(); + else if (grabbedObject.IsAutoHold && CVRInputManager.Instance.drop) DropObject(true); + + DisableLineRenderer(); + + DisableProximityGrabHighlight(); + + if (_telepathicPickupCandidate != null) + { + ClearTelepathicGrabTargetHighlight(); + _telepathicPickupCandidate = null; + } + } + + private bool HandleMenuUIInteraction() + { + //Swap Ray if applicable + if (_interactDown && _hitUIInternal && !uiActive) + { + uiActive = true; + if (otherRay) otherRay.uiActive = false; + CVR_MenuManager.Instance.lastInteractedHand = hand; + } + + if (!uiActive) + return false; + + Ray menuRay = new Ray(rayDirectionTransform.position, rayDirectionTransform.TransformDirection(RayDirection)); + CohtmlControlledView hitView = CohtmlViewInputHandler.Instance.RayToView(menuRay, out float hitDistance, out Vector2 hitCoords); + + if (hitView == null) + return false; + + float minDistance = 0.15f * PlayerSetup.Instance.GetPlaySpaceScale(); + + // physical-like touch, very satisfying + if (shouldPhysicalInteraction && (hitDistance < minDistance && _lastHitDistance >= minDistance)) + CohtmlViewInputHandler.Instance.DoViewInput(hitView, hitCoords, true, false, 0f); + else if (shouldPhysicalInteraction && (hitDistance >= minDistance && _lastHitDistance < minDistance)) + CohtmlViewInputHandler.Instance.DoViewInput(hitView, hitCoords, false, true, 0f); + else + CohtmlViewInputHandler.Instance.DoViewInput(hitView, hitCoords, _interactDown, _interactUp, + CVRInputManager.Instance.scrollValue); + + if (_lastView != null && hitView != _lastView) + CohtmlViewInputHandler.Instance.ReleaseViewInput(_lastView, _lastUiCoords); + + _lastView = hitView; + _lastUiCoords = hitCoords; + _lastHitDistance = hitDistance; + _objectWasHit = true; + + if (isInteractionRay && !isDesktopRay && !isHeadRay) + { + if (hand == CVRHand.Left) + CVRInputManager.Instance.leftControllerPointingMenu = true; + else + CVRInputManager.Instance.rightControllerPointingMenu = true; + } + + if (lineRenderer) + { + lineRenderer.enabled = true; + lineRenderer.SetPosition(0, lineRenderer.transform.InverseTransformPoint(rayDirectionTransform.position)); + lineRenderer.SetPosition(1, lineRenderer.transform.InverseTransformPoint(rayDirectionTransform.position + rayDirectionTransform.TransformDirection(RayDirection) * hitDistance)); + } + + return true; + } + + private void DisableLineRenderer() + { + if (lineRenderer) + lineRenderer.enabled = false; + + } + + private void DisableProximityGrabHighlight() + { + if (!_proximityCalculatedThisFrame) + ClearProximityGrabTargetHighlight(); + _proximityCalculatedThisFrame = false; + } + + private void HandleMenuUIInteractionRelease() + { + if (_lastView == null) return; + if (!_interactUp && uiActive) return; + CohtmlViewInputHandler.Instance.ReleaseViewInput(_lastView, _lastUiCoords); + _lastView = null; + } + + private bool FindTargets(out bool hitUiInternal) + { + const int uiInternalMask = 1 << CVRLayers.UIInternal; + + // Transform the point and direction from local to world space + Vector3 origin = rayDirectionTransform.TransformPoint(RayDirection * -0.15f); + Vector3 direction = rayDirectionTransform.TransformDirection(RayDirection); + + // Ray Cast to the internal UI layer + int hitCount = Physics.RaycastNonAlloc(origin, direction, _hits, MAX_RAYCAST_LENGTH, uiInternalMask); + + // Sort hits by distance (closer hits first) + Array.Sort(_hits, 0, hitCount, _hitsComparer); + + // Iterate through the internal UI layers + for (int i = 0; i < hitCount; i++) + { + RaycastHit hit = _hits[i]; + Collider hitCollider = hit.collider; + + // Ignore Quick Menu from the menu holding ray cast hand + if (!isDesktopRay && !isHeadRay && CVR_MenuManager.Instance.IsQuickMenuOpen && + hand == CVR_MenuManager.Instance.SelectedQuickMenuHand && + hitCollider == CVR_MenuManager.Instance.quickMenuCollider && + !CVRInputManager.Instance.oneHanded) + continue; + + _hit = hit; + hitTransform = hit.collider.transform; + hitUiInternal = true; + return true; + } + + // General mask except Mirror Reflection and UI Internal (Since we already looked for it) + int generalLayersMask = generalMask & ~(1 << CVRLayers.MirrorReflection) & ~uiInternalMask; + + // Ray Cast to the general layers + if (Physics.Raycast(origin, direction, out _hit, MAX_RAYCAST_LENGTH, generalLayersMask)) + { + hitTransform = _hit.collider.transform; + hitUiInternal = false; + return true; + } + + DisableLineRenderer(); + _objectWasHit = false; + + if (lastInteractable != null) + { + if (triggerHoverEvents) lastInteractable.HoverExit(new InteractionContext(this, PlayerSetup.PlayerLocalId), this); + // interactable handles ignoring if we didn't already interact + lastInteractable.InteractUp(new InteractionContext(this, PlayerSetup.PlayerLocalId), this); + lastInteractable = null; + } + + lastSlider = null; + + if (isInteractionRay) CVR_MenuManager.Instance.SetHandTarget("", "", "", Vector3.zero, "", hand); + if (triggerHoverEvents) CVR_MenuManager.Instance.SetViewTarget("", "", "", Vector3.zero, ""); + + ClearTargetHighlight(); + hitUiInternal = false; + return false; + } + + private Pickupable CheckPickupDirect() + { + Pickupable pickup = hitTransform.GetComponent(); + + if (pickup == null + || !pickup.CanPickup) + return null; + + if (pickup.MaxGrabDistance < _hit.distance) return null; + + if (_enableTelepathicGrab && !pickup.IsGrabbedByMe) + { + _telepathicPickupCandidate = pickup; + _telepathicPickupTargeted = true; + } + + return pickup; + } + + private PlayerDescriptor HandlePlayerClicked() + { + if (PlayerSetup.Instance.GetCurrentPropSelectionMode() + != PlayerSetup.PropSelectionMode.None) + return null; + + PlayerDescriptor descriptor = null; + if (CanSelectPlayersAndProps() && hitTransform.TryGetComponent(out descriptor)) + if (_interactDown) Users.ShowDetails(descriptor.ownerId); + + return descriptor; + } + + private Interactable HandleInteractable() + { + Interactable interactable = hitTransform.GetComponent(); + + // this handles swapping interactables when the raycast hits anything, otherwise + // FindObjects handles resetting when *nothing* is hit + // TODO: rework this so lastInteractable cannot be updated if an interaction is in progress + + if (interactable != lastInteractable) + { + if (triggerHoverEvents) + { + if (lastInteractable) lastInteractable.HoverExit(new InteractionContext(this, PlayerSetup.PlayerLocalId), this); + if (interactable) interactable.HoverEnter(new InteractionContext(this, PlayerSetup.PlayerLocalId), this); + } + + // interactable handles ignoring if we didn't already interact + if (lastInteractable) lastInteractable.InteractUp(new InteractionContext(this, PlayerSetup.PlayerLocalId), this); + + lastInteractable = interactable; + } + + if (interactable == null) return null; + + // Ignore interactable interactions if in prop delete or spawn mode + if (!isInteractionRay || PlayerSetup.Instance.GetCurrentPropSelectionMode() != PlayerSetup.PropSelectionMode.None) + return interactable; + + if (interactable.IsInteractableWithinRange(transform.position)) + { + if (_interactDown) interactable.InteractDown(new InteractionContext(this, PlayerSetup.PlayerLocalId), this); + if (_interactUp) interactable.InteractUp(new InteractionContext(this, PlayerSetup.PlayerLocalId), this); + } + + return interactable; + } + + private CVRSpawnable HandleSpawnableClicked() + { + CVRSpawnable spawnable = hitTransform.GetComponentInParent(); + if (spawnable == null) return null; + + PlayerSetup.PropSelectionMode selectionMode = PlayerSetup.Instance.GetCurrentPropSelectionMode(); + switch (selectionMode) + { + case PlayerSetup.PropSelectionMode.None: + { + // Click a prop while a menu is open to open the details menu + if (_interactDown + && CanSelectPlayersAndProps() + && spawnable.TryGetComponent(out CVRAssetInfo assetInfo)) + { + // Open the details menu of the spawnable + ViewManager.Instance.GetPropDetails(assetInfo.objectId); + ViewManager.Instance.UiStateToggle(true); + + _interactDown = false; // Consume the click + } + break; + } + case PlayerSetup.PropSelectionMode.Delete: + { + // Click a prop while in delete mode to delete it + if (_interactDown + && spawnable.ownerId != "SYSTEM" + && spawnable.ownerId != "LocalServer") + { + spawnable.Delete(); + _interactDown = false; // Consume the click + return null; // Don't return the spawnable, it's been deleted + } + break; + } + } + + // Return normal prop hover + return spawnable; + } + + private bool HandleUnityUI() + { + if (isDesktopRay && Cursor.lockState != CursorLockMode.Locked) + return false; // Unity does this for us + + Canvas canvas = hitTransform.GetComponentInParent(); + + Button button = hitTransform.GetComponent(); + Toggle toggle = hitTransform.GetComponent(); + Slider slider = hitTransform.GetComponent(); + EventTrigger eventTrigger = hitTransform.GetComponent(); + InputField inputField = hitTransform.GetComponent(); + TMP_InputField tmp_InputField = hitTransform.GetComponent(); + Dropdown dropDown = hitTransform.GetComponent(); + + ScrollRect scrollRect = hitTransform.GetComponent(); + + // Ignore interatable interactions if in prop delete or spawn mode + if (!isInteractionRay || PlayerSetup.Instance.GetCurrentPropSelectionMode() != PlayerSetup.PropSelectionMode.None) return true; + + //Lock controls when pointing at UI + if (!isDesktopRay && !isHeadRay) + if (hand == CVRHand.Left) + CVRInputManager.Instance.leftControllerPointingCanvas = canvas != null && canvas.gameObject.layer == CVRLayers.UIInternal; + else + CVRInputManager.Instance.rightControllerPointingCanvas = canvas != null && canvas.gameObject.layer == CVRLayers.UIInternal; + + HandleUnityUIButton(button, ref eventTrigger); + + HandleUnityUIToggle(toggle, ref eventTrigger); + + HandleUnityUIDropdown(dropDown, ref eventTrigger); + + HandleUnityUIInputField(inputField, ref eventTrigger); + + HandleUnityUITMPInputField(tmp_InputField, ref eventTrigger); + + HandleUnityUISlider(slider, ref eventTrigger); + + HandleUnityUIScrollRect(scrollRect, ref eventTrigger); + + HandleUnityUIEventTrigger(eventTrigger); + + if (canvas == null && button == null && toggle == null && slider == null && eventTrigger == null && + inputField == null && tmp_InputField == null && dropDown == null && scrollRect == null) + return false; + return true; + } + + private void HandleUnityUIButton(Button button, ref EventTrigger eventTrigger) + { + if (button != null) + { + if (button != lastButton) + { + button.OnPointerEnter(null); + if (lastButton != null) lastButton.OnPointerExit(null); + lastButton = button; + } + + if (eventTrigger == null) eventTrigger = button.GetComponentInParent(); + + if (_interactDown) + { + button.onClick.Invoke(); + if (CVRWorld.Instance.uiHighlightSoundObjects.Contains(button.gameObject)) + InterfaceAudio.Play(AudioClipField.Click); + } + } + else + { + if (lastButton != null) lastButton.OnPointerExit(null); + lastButton = null; + } + } + + private void HandleUnityUIToggle(Toggle toggle, ref EventTrigger eventTrigger) + { + if (toggle != null) + { + if (toggle != lastToggle) + { + toggle.OnPointerEnter(null); + if (lastToggle != null) lastToggle.OnPointerExit(null); + lastToggle = toggle; + } + + if (eventTrigger == null) eventTrigger = toggle.GetComponentInParent(); + + if (_interactDown) + { + toggle.isOn = !toggle.isOn; + if (CVRWorld.Instance.uiHighlightSoundObjects.Contains(toggle.gameObject)) + InterfaceAudio.Play(AudioClipField.Click); + } + } + else + { + if (lastToggle != null) lastToggle.OnPointerExit(null); + lastToggle = null; + } + } + + private void HandleUnityUIDropdown(Dropdown dropDown, ref EventTrigger eventTrigger) + { + if (dropDown != null) + { + if (dropDown != lastDropdown) + { + dropDown.OnPointerEnter(null); + if (lastDropdown != null) lastDropdown.OnPointerExit(null); + lastDropdown = dropDown; + } + + if (eventTrigger == null) eventTrigger = dropDown.GetComponentInParent(); + + if (_interactDown) + { + if (dropDown.transform.childCount != 3) + { + dropDown.Hide(); + if (CVRWorld.Instance.uiHighlightSoundObjects.Contains(dropDown.gameObject)) + InterfaceAudio.Play(AudioClipField.Click); + } + else + { + dropDown.Show(); + if (CVRWorld.Instance.uiHighlightSoundObjects.Contains(dropDown.gameObject)) + InterfaceAudio.Play(AudioClipField.Click); + } + + var toggles = dropDown.gameObject.GetComponentsInChildren(true); + foreach (var t in toggles) + { + if (t.GetComponent() == null) + { + BoxCollider col = t.gameObject.AddComponent(); + col.isTrigger = true; + var rectTransform = t.gameObject.GetComponent(); + col.size = new Vector3( + Mathf.Max(rectTransform.sizeDelta.x, rectTransform.rect.width), + rectTransform.sizeDelta.y, 0.1f); + col.center = new Vector3(col.size.x * (0.5f - rectTransform.pivot.x), + col.size.y * (0.5f - rectTransform.pivot.y), 0f); + } + } + } + } + else + { + if (lastDropdown != null) lastDropdown.OnPointerExit(null); + lastDropdown = null; + } + } + + private void HandleUnityUIInputField(InputField inputField, ref EventTrigger eventTrigger) + { + if (inputField != null) + { + if (inputField != lastInputField) + { + inputField.OnPointerEnter(null); + if (lastInputField != null) lastInputField.OnPointerExit(null); + lastInputField = inputField; + } + + if (eventTrigger == null) eventTrigger = inputField.GetComponentInParent(); + + if (_interactDown) + { + inputField.Select(); + inputField.ActivateInputField(); + ViewManager.Instance.openMenuKeyboard(inputField); + } + } + else + { + if (lastInputField != null) lastInputField.OnPointerExit(null); + lastInputField = null; + } + } + + private void HandleUnityUITMPInputField(TMP_InputField tmp_InputField, ref EventTrigger eventTrigger) + { + if (tmp_InputField != null) + { + if (tmp_InputField != lastTMPInputField) + { + tmp_InputField.OnPointerEnter(null); + if (lastTMPInputField != null) lastTMPInputField.OnPointerExit(null); + lastTMPInputField = tmp_InputField; + } + + if (eventTrigger == null) eventTrigger = tmp_InputField.GetComponentInParent(); + + if (_interactDown) + { + tmp_InputField.Select(); + tmp_InputField.ActivateInputField(); + ViewManager.Instance.openMenuKeyboard(tmp_InputField); + } + } + else + { + if (lastTMPInputField != null) lastTMPInputField.OnPointerExit(null); + lastTMPInputField = null; + } + } + + private void HandleUnityUISlider(Slider slider, ref EventTrigger eventTrigger) + { + if (slider != null) + { + if (eventTrigger == null) eventTrigger = slider.GetComponentInParent(); + + if (_interactDown) + { + lastSlider = slider; + lastSliderRect = slider.GetComponent(); + SetSliderValueFromRay(slider, _hit, lastSliderRect); + } + + if (_interactUp) + { + if (slider.gameObject.TryGetComponent(out SliderDragHelper sliderDragHelper)) + sliderDragHelper.Invoke(slider.value); + } + } + } + + private void HandleUnityUIScrollRect(ScrollRect scrollRect, ref EventTrigger eventTrigger) + { + + // If it's not a scroll rect itself, search for a parent scroll rect + bool isParentScrollRect = scrollRect == null; + if (isParentScrollRect) + { + scrollRect = hitTransform.GetComponentInParent(); + // Ignore if not found + if (scrollRect == null) return; + } + + // If directly targeting the scroll rect and there isn't one mark it as the event trigger + if (!isParentScrollRect && eventTrigger == null) + eventTrigger = scrollRect.GetComponentInParent(); + + // Handle the hold and drag of the scroll rect to scroll + if (_interactDown) + { + lastScrollView = scrollRect; + scrollStartPositionView = GetScreenPositionFromRaycastHit(_hit, scrollRect.viewport); + scrollStartPositionContent = scrollRect.content.anchoredPosition; + SetScrollViewValueFromRay(scrollRect, _hit); + } + + // Handle the scroll input changes + if (!Mathf.Approximately(CVRInputManager.Instance.scrollValue, 0f)) + { + Vector2 anchoredPosition = scrollRect.content.anchoredPosition; + + if (scrollRect.vertical) + { + anchoredPosition.y -= CVRInputManager.Instance.scrollValue * 1000f; + } + else if (scrollRect.horizontal) + { + anchoredPosition.x -= CVRInputManager.Instance.scrollValue * 1000f; + } + + scrollRect.content.anchoredPosition = anchoredPosition; + } + + // Ensure the scroll rect stays within their scrolling limits + scrollRect.verticalNormalizedPosition = Mathf.Clamp01(scrollRect.verticalNormalizedPosition); + scrollRect.horizontalNormalizedPosition = Mathf.Clamp01(scrollRect.horizontalNormalizedPosition); + } + + private void HandleUnityUIEventTrigger(EventTrigger eventTrigger) + { + if (eventTrigger != null) + { + if (eventTrigger != lastEventTrigger) + { + if (lastEventTrigger != null) + { + foreach (var trigger in lastEventTrigger.triggers) + { + if (trigger.eventID == EventTriggerType.PointerExit) + { + trigger.callback.Invoke(null); + } + } + } + + lastEventTrigger = eventTrigger; + + foreach (var trigger in eventTrigger.triggers) + { + if (trigger.eventID == EventTriggerType.PointerEnter) + { + if (CVRWorld.Instance.uiHighlightSoundObjects.Contains(eventTrigger.gameObject)) InterfaceAudio.Play(AudioClipField.Hover); + trigger.callback.Invoke(null); + } + } + } + + if (_interactDown) + { + foreach (var trigger in eventTrigger.triggers) + { + if (trigger.eventID == EventTriggerType.PointerDown || + trigger.eventID == EventTriggerType.PointerClick) + { + trigger.callback.Invoke(null); + if (CVRWorld.Instance.uiHighlightSoundObjects.Contains(eventTrigger.gameObject)) + InterfaceAudio.Play(AudioClipField.Click); + } + } + } + + if (_interactUp) + { + foreach (var trigger in eventTrigger.triggers) + { + if (trigger.eventID == EventTriggerType.PointerUp) + { + trigger.callback.Invoke(null); + } + } + } + + + } + if ((eventTrigger == null && lastEventTrigger != null) || (eventTrigger != null && lastEventTrigger != eventTrigger)) + { + foreach (var trigger in lastEventTrigger.triggers) + { + if (trigger.eventID == EventTriggerType.PointerExit) + { + trigger.callback.Invoke(null); + } + } + + lastEventTrigger = null; + } + else if (eventTrigger != lastEventTrigger) + { + foreach (var trigger in lastEventTrigger.triggers) + { + if (trigger.eventID == EventTriggerType.PointerExit) + { + trigger.callback.Invoke(null); + } + } + + lastEventTrigger = eventTrigger; + } + } + + private void HandleIndirectUnityUI() + { + if (lastSlider != null) + { + if (_interact) + { + SetSliderValueFromRay(lastSlider, _hit, lastSliderRect); + } + } + + if (lastScrollView != null) + { + if (_interact) + { + SetScrollViewValueFromRay(lastScrollView, _hit); + } + } + + if (_interactUp) + { + lastSlider = null; + lastScrollView = null; + } + } + + private void DisplayRayHighlight(bool targetHasComponent, PlayerDescriptor player, Interactable interactable, CVRSpawnable spawnable, Pickupable pickup) + { + var targetRay = (interactable && interactable.IsInteractable && interactable.IsInteractableWithinRange(transform.position)) || + (player && CanSelectPlayersAndProps()) || + targetHasComponent || pickup || + (spawnable && PlayerSetup.Instance.GetCurrentPropSelectionMode() != PlayerSetup.PropSelectionMode.None); + + if (targetRay && lineRenderer) + { + lineRenderer.enabled = true; + lineRenderer.SetPosition(0, lineRenderer.transform.InverseTransformPoint(rayDirectionTransform.position)); + lineRenderer.SetPosition(1, lineRenderer.transform.InverseTransformPoint(_hit.point)); + } + else if(lineRenderer) + { + lineRenderer.enabled = false; + } + + if (targetRay && !_objectWasHit) + { + CVRInputManager.Instance.Vibrate(0f, 0.1f, 10f, 0.1f, hand); + } + + _objectWasHit = targetRay; + + if (lineRenderer && PlayerSetup.Instance.GetCurrentPropSelectionMode() != PlayerSetup.PropSelectionMode.None) + { + lineRenderer.enabled = true; + lineRenderer.SetPosition(0, lineRenderer.transform.InverseTransformPoint(rayDirectionTransform.position)); + lineRenderer.SetPosition(1, lineRenderer.transform.InverseTransformPoint(_hit.point)); + } + } + + private void DisplayAuraHighlight(Pickupable pickup, bool ignorePickup, PlayerDescriptor player, Interactable interactable, CVRSpawnable spawnable) + { + GameObject targetHighlightObject = null; + + // Check if the hit object is highlightable, and what root object to highlight from + if (hitTransform == null) + { + targetHighlightObject = null; + } + else if (interactable && interactable.IsInteractable + && interactable.IsInteractableWithinRange(transform.position)) + { + targetHighlightObject = interactable.gameObject; + } + else if (pickup && !ignorePickup) + { + targetHighlightObject = pickup.gameObject; + } + else if (player && CanSelectPlayersAndProps()) + { + targetHighlightObject = player.gameObject; + } + else if (spawnable && (CanSelectPlayersAndProps() + || PlayerSetup.Instance.propGuidForSpawn == PlayerSetup.PropModeDeleteString)) + { + targetHighlightObject = spawnable.gameObject; + } + + // Check if the target changed + if (targetHighlightObject == lastTarget) + return; + + // Set or clear the target highlight + SetTargetHighlight(targetHighlightObject); + } + + private void SendRayTargetToMenu(CVRSpawnable spawnable, PlayerDescriptor player) + { + if (spawnable) + { + CVR_MenuManager.Instance.SetHandTarget("spawnable", spawnable.guid, spawnable.instanceId, spawnable.transform.position, "", hand); + if (triggerHoverEvents) CVR_MenuManager.Instance.SetViewTarget("spawnable", spawnable.guid, spawnable.instanceId, spawnable.transform.position, ""); + } + else if (player) + { + CVR_MenuManager.Instance.SetHandTarget("player", player.ownerId, "", player.transform.position, player.userName, hand); + if (triggerHoverEvents) CVR_MenuManager.Instance.SetViewTarget("player", player.ownerId, "", player.transform.position, player.userName); + } + else + { + CVR_MenuManager.Instance.SetHandTarget("world_point", "", "", _hit.point, "", hand); + if (triggerHoverEvents) CVR_MenuManager.Instance.SetViewTarget("world_point", "", "", _hit.point, ""); + } + } + + private void HandlePropSpawn() + { + if (PlayerSetup.Instance.GetCurrentPropSelectionMode() != PlayerSetup.PropSelectionMode.Spawn) + return; + + if (_hitUIInternal) return; + + RaycastHit waterRayHit; + RaycastHit generalRayHit; + bool waterHit = Physics.Raycast(rayDirectionTransform.TransformPoint(RayDirection * -0.15f), + rayDirectionTransform.TransformDirection(RayDirection), out waterRayHit, MAX_RAYCAST_LENGTH, 1 << CVRLayers.Water, + QueryTriggerInteraction.Collide); + bool generalHit = Physics.Raycast(rayDirectionTransform.TransformPoint(RayDirection * -0.15f), + rayDirectionTransform.TransformDirection(RayDirection), out generalRayHit, MAX_RAYCAST_LENGTH, generalMask, + QueryTriggerInteraction.Ignore); + + if (waterHit && generalHit) + if (waterRayHit.distance < generalRayHit.distance) _hit = waterRayHit; + else _hit = generalRayHit; + else if (waterHit) _hit = waterRayHit; + else if (generalHit) _hit = generalRayHit; + + if (_interactDown && (waterHit || generalHit)) + { + PlayerSetup.Instance.SpawnProp(PlayerSetup.Instance.propGuidForSpawn, _hit.point); + } + } + + private void TeleTargetSelection() + { + if (_telepathicPickupLocked || !_enableTelepathicGrab) return; + + RaycastHit teleHit = SphereCast(0.15f, 0.3f, 100f); + if ((teleHit.collider != null) + && (teleHit.collider.transform.parent != null)) + { + Pickupable telePickup = teleHit.collider.transform.GetComponentInParent(); + if (telePickup != null + && telePickup.CanPickup + && (telePickup.MaxGrabDistance >= teleHit.distance) + && !telePickup.IsGrabbedByMe) + { + if ((_telepathicPickupCandidate != null) + && (telePickup != _telepathicPickupCandidate)) + ClearTelepathicGrabTargetHighlight(); + + _telepathicPickupCandidate = telePickup; + _telepathicPickupTargeted = true; + } + } + } + + private void LateUpdate() + { + // TODO: ControllerRay is being rewritten so this is a temporary addition + Raycast(); + DisplayLineRendererIfNeeded(); + } + + private void Raycast() + { + UpdateBackupRay(); + + UpdateInteractionMask(); + + ResetPointAtUI(); + DisableLineRenderer(); + + if (!enabled || !IsTracking()) + return; + + UpdateInputs(); + + CheckExitPropModes(); + + HandleTelepathicGrip(); + + HandleGrabbedObjects(); + + bool interactedWithMainMenu = HandleMenuUIInteraction(); + HandleMenuUIInteractionRelease(); + if (interactedWithMainMenu) + return; // interacting with UI + + if (!CVR_InteractableManager.enableInteractions) + return; // interactions disabled (in calibration or downed by combat) + + if (grabbedObject != null) return; + + Pickupable pickup = null; + PlayerDescriptor player = null; + Interactable interactable = null; + CVRSpawnable spawnable = null; + + bool targetHasComponent = false; + bool targetShouldHighlight = false; + bool proxyGrab = false; + bool foundTargets = FindTargets(out _hitUIInternal); + if (foundTargets) + { + spawnable = HandleSpawnableClicked(); + targetHasComponent |= spawnable; + + pickup = CheckPickupDirect(); + targetHasComponent |= pickup; + + player = HandlePlayerClicked(); + targetHasComponent |= player; + + interactable = HandleInteractable(); + targetHasComponent |= interactable; + + + + targetShouldHighlight |= HandleUnityUI(); + targetHasComponent |= targetShouldHighlight; + + HandleIndirectUnityUI(); + + } + + if (!pickup && !_hitUIInternal && !isDesktopRay && !isHeadRay) + { + proxyGrab = ProximityTargetSelection(ref pickup); + if (!proxyGrab && !targetHasComponent) TeleTargetSelection(); + } + + GrabObject(pickup, proxyGrab); + + HandlePropSpawn(); + + if (foundTargets && !proxyGrab) DisplayRayHighlight(targetShouldHighlight || interactedWithMainMenu || _hitUIInternal, player, interactable, spawnable, pickup); + + DisplayAuraHighlight(pickup, proxyGrab, player, interactable, spawnable); + + SendRayTargetToMenu(spawnable, player); + } + + #region Where Am I Pointing + + private const float ORIGINAL_ALPHA = 0.502f; + private const float INTERACTION_ALPHA = 0.1f; + + private void DisplayLineRendererIfNeeded() + { + if (isDesktopRay + || !enabled + || !IsTracking() + || !lineRenderer) + return; + + UpdateLineRendererAlpha(); + + if (lineRenderer.enabled + || !ShouldOverrideLineRenderer()) + return; + + UpdateLineRendererPosition(); + } + + private void UpdateLineRendererAlpha() + { + Material material = lineRenderer.material; + Color color = material.color; + + bool anyMenuOpen = ViewManager.Instance.IsAnyMenuOpen; + float targetAlpha = (!anyMenuOpen || uiActive) ? ORIGINAL_ALPHA : INTERACTION_ALPHA; + if (!(Math.Abs(color.a - targetAlpha) > float.Epsilon)) return; + + color.a = targetAlpha; + material.color = color; + } + + private bool ShouldOverrideLineRenderer() + { + if (!ViewManager.Instance.IsAnyMenuOpen) + return false; + + if (CVR_MenuManager.Instance.IsQuickMenuOpen + && hand == CVR_MenuManager.Instance.SelectedQuickMenuHand) + return false; + + return true; + } + + private void UpdateLineRendererPosition() + { + Vector3 rayOrigin = rayDirectionTransform.position; + Vector3 rayEnd = rayOrigin + rayDirectionTransform.forward * MAX_RAYCAST_LENGTH; + + lineRenderer.SetPosition(0, lineRenderer.transform.InverseTransformPoint(rayOrigin)); + lineRenderer.SetPosition(1, lineRenderer.transform.InverseTransformPoint(rayEnd)); + lineRenderer.enabled = true; + } + + #endregion Where Am I Pointing + + private void GrabObject(Pickupable pickup, RaycastHit hit) + { + if (!pickup.CanPickup) + return; + + //UpdateGrabDistance(attachmentDistance); + pivotPoint.rotation = pickup.transform.rotation; + pickup.Grab(new InteractionContext(this), this, hit.point); + grabbedObject = pickup; + ClearTargetHighlight(); + } + + private Vector3 GetHandProximityCenterPosition() + { + Vector3 handPosition = transform.position; + + // Offset the detection center forward, so we don't grab stuff behind our writs + handPosition += transform.forward * (ProximityDetectionRadius * 0.25f); + + // Offset the detection center away from the palm, so we don't grab stuff behind our hand palm + Vector3 palmOffset = transform.right * (ProximityDetectionRadius * 0.75f); + if (hand == CVRHand.Left) + handPosition += palmOffset; + else + handPosition -= palmOffset; + + return handPosition; + } + + private void GrabObject(Pickupable pickup, Vector3 pos) + { + if (!pickup.CanPickup) + return; + + //UpdateGrabDistance(attachmentDistance); + pivotPoint.rotation = pickup.transform.rotation; + pickup.Grab(new InteractionContext(this), this, pos); + grabbedObject = pickup; + ClearTargetHighlight(); + } + + private bool ProximityTargetSelection(ref Pickupable selectedPickup) + { + if (!isInteractionRay || !_proximityGrabEnabled) return false; + + float detectionRadius = ProximityDetectionRadius; + Vector3 handPosition = GetHandProximityCenterPosition(); + int generalLayersMask = generalMask & ~(1 << CVRLayers.MirrorReflection) & ~(1 << CVRLayers.UIInternal); + + if (_proximityGrabVisualizers) + RuntimeGizmos.DrawSphere(handPosition, ProximityDetectionRadius*2, Color.blue, CVRLayers.UIInternal, 0.2f); + + // Reset results + bool foundPickup = false; + _proximityColliderClosestPickup = null; + float closestPickupDistance = float.MaxValue; + GameObject closestPickupHitObject = null; + + // Mark as processed this frame to prevent clearing the pickup highlight the next frame + _proximityCalculatedThisFrame = true; + + // Detect all colliders within the detection radius that can have pickups + int overlapCount = Physics.OverlapSphereNonAlloc(handPosition, detectionRadius, _proximityColliders, generalLayersMask, QueryTriggerInteraction.Collide); + if (overlapCount <= 0) + { + ClearProximityGrabTargetHighlight(); + return false; + } + + // Calculate the distance of the results + for (int i = 0; i < overlapCount; i++) + { + Collider colliderCandidate = _proximityColliders[i]; + + // Look for the closest pickup that is within grab reach + if (colliderCandidate.TryGetComponent(out Pickupable pickupCandidate) + && pickupCandidate.CanPickup) + //&& pickupCandidate.IsWithinGrabReach(handPosition)) + { + float pickupDistance = Vector3.Distance(handPosition, pickupCandidate.RootTransform.position); + if (pickupDistance < closestPickupDistance) + { + closestPickupDistance = pickupDistance; + _proximityColliderClosestPickup = pickupCandidate; + closestPickupHitObject = colliderCandidate.gameObject; + foundPickup = true; + } + } + } + + if (foundPickup) + { + selectedPickup = _proximityColliderClosestPickup; + SetProximityGrabTargetHighlight(closestPickupHitObject); + return true; + } + + ClearProximityGrabTargetHighlight(); + return false; + } + + public void DropObject(bool force = false) + { + if (grabbedObject == null) return; + if (grabbedObject.IsAutoHold && !force) return; + grabbedObject.Drop(new InteractionContext(this)); + grabbedObject = null; + pivotPoint.localRotation = Quaternion.identity; + } + + #region Highlight Handling + + private void SetTargetHighlight(GameObject hit) + { + ClearTargetHighlight(); + + if (hit == null) return; + + // if (triggerGazeEvents) + // { + // var interactables = hit.GetComponentsInChildren(); + // foreach (var interactable in interactables) + // { + // interactable.isLookedAt = true; + // } + // } + + if (PlayerSetup.Instance.GetCurrentPropSelectionMode() == PlayerSetup.PropSelectionMode.Delete) + { + CVRSpawnable spawnable = hit.GetComponentInParent(); + if (spawnable != null && spawnable.gameObject != hit) hit = spawnable.gameObject; + } + + if (!isInteractionRay) return; + + if (_enableHighlight) + { + if (!hit.TryGetComponent(out HighlightEffect highlight)) + { + highlight = hit.AddComponent(); + + var foundRenderers = new List(8); + var stack = new Stack(); + stack.Push(hit.transform); + + while (stack.Count > 0) + { + Transform current = stack.Pop(); + + // skip things that *should* highlight their own children + if (current.TryGetComponent(out Pickupable _)) continue; + if (current.TryGetComponent(out CVRInteractable _)) continue; + + // add found renderers + if (current.TryGetComponent(out Renderer render)) foundRenderers.Add(render); + + // add children to stack + for (int i = 0; i < current.childCount; i++) stack.Push(current.GetChild(i)); + } + + highlight.SetTargets(hit.transform, foundRenderers.ToArray()); + } + + highlight.ProfileLoad(MetaPort.Instance.worldHighlightProfile); + highlight.Refresh(); + highlight.SetHighlighted(true); + } + + lastTarget = hit; + } + + private void GrabObject(Pickupable pickup, bool foundProximityGrab) + { + if (pickup == null || !_isTryingToPickup) return; + + if (foundProximityGrab) GrabObject(pickup, GetHandProximityCenterPosition()); + else GrabObject(pickup, _hit); + } + + private void SetTelepathicGrabTargetHighlight(GameObject hit) + { + if (!isInteractionRay) return; + + ClearTelepathicGrabTargetHighlight(); + + if (hit == null) return; + + if (!_enableHighlight) return; + + if (!hit.TryGetComponent(out HighlightEffect highlight)) + highlight = hit.AddComponent(); + + highlight.ProfileLoad(MetaPort.Instance.worldHighlightProfile); + highlight.Refresh(); + highlight.SetHighlighted(true); + + lastTelepathicGrabTarget = hit; + } + + private void ClearTargetHighlight() + { + // There is no previous object to remove the highlight + if (lastTarget == null) return; + + // If there is no other source for the object highlight, remove it + if (lastTarget != lastTelepathicGrabTarget && + (!_telepathicPickupLocked || _telepathicPickupCandidate == null || lastTarget != _telepathicPickupCandidate.gameObject) && + lastTarget != lastProximityGrabTarget) + { + if (lastTarget.TryGetComponent(out HighlightEffect highlight)) + highlight.SetHighlighted(false); + } + + // var interactables = lastTarget.GetComponentsInChildren(); + // foreach (var interactable in interactables) + // { + // interactable.isLookedAt = false; + // } + + lastTarget = null; + } + + private void ClearTelepathicGrabTargetHighlight() + { + if (!isInteractionRay) return; + + // There is no previous object to remove the highlight + if (lastTelepathicGrabTarget == null) return; + + // If there is no other source for the object highlight, remove it + if (lastTelepathicGrabTarget != lastTarget && + lastTelepathicGrabTarget != lastProximityGrabTarget) + { + if (lastTelepathicGrabTarget.TryGetComponent(out HighlightEffect highlight)) + highlight.SetHighlighted(false); + } + + lastTelepathicGrabTarget = null; + } + + private void SetProximityGrabTargetHighlight(GameObject proximityPickupGameObject) + { + ClearProximityGrabTargetHighlight(); + + if (!isInteractionRay || !_enableHighlight) return; + + if (!proximityPickupGameObject.TryGetComponent(out HighlightEffect highlight)) + highlight = proximityPickupGameObject.AddComponent(); + + highlight.ProfileLoad(MetaPort.Instance.worldHighlightProfile); + highlight.Refresh(); + highlight.SetHighlighted(true); + + lastProximityGrabTarget = proximityPickupGameObject; + } + + private void ClearProximityGrabTargetHighlight() + { + if (!isInteractionRay) return; + + // There is no previous object to remove the highlight + if (lastProximityGrabTarget == null) return; + + // If there is no other source for the object highlight, remove it + if (lastProximityGrabTarget != lastTarget && + lastProximityGrabTarget != lastTelepathicGrabTarget) + { + if (lastProximityGrabTarget.TryGetComponent(out HighlightEffect highlight)) + highlight.SetHighlighted(false); + } + + lastProximityGrabTarget = null; + } + + #endregion + + private Vector2 GetScreenPositionFromRaycastHit(RaycastHit hit, RectTransform rect) + { + Vector2 position; + + var activeCamera = PlayerSetup.Instance.activeCam; + + var screenPosition = activeCamera.WorldToScreenPoint(hit.point); + + RectTransformUtility.ScreenPointToLocalPointInRectangle( + rect, + new Vector2(screenPosition.x, screenPosition.y), + activeCamera, + out position + ); + + return position; + } + + private void SetSliderValueFromRay(Slider slider, RaycastHit hit, RectTransform rect) + { + if (rect == null) return; + + Vector2 position = GetScreenPositionFromRaycastHit(hit, rect); + + float valueX = Mathf.InverseLerp(rect.rect.min.x, rect.rect.max.x, position.x); + float valueY = Mathf.InverseLerp(rect.rect.min.y, rect.rect.max.y, position.y); + + if (rect.rect.width > rect.rect.height) + { + slider.value = Mathf.Lerp(slider.minValue, slider.maxValue, Mathf.Clamp01(valueX)); + } + else + { + slider.value = Mathf.Lerp(slider.minValue, slider.maxValue, Mathf.Clamp01(valueY)); + } + } + + private void SetScrollViewValueFromRay(ScrollRect scrollRect, RaycastHit hit) + { + Vector2 position = GetScreenPositionFromRaycastHit(hit, scrollRect.viewport); + + Vector2 scrollOffset = scrollStartPositionView - position; + + Vector2 finalOffset = new Vector2( + Mathf.Clamp(scrollStartPositionContent.x - scrollOffset.x, (scrollRect.content.rect.width - scrollRect.viewport.rect.width) * -1f, 0f), + Mathf.Clamp(scrollStartPositionContent.y - scrollOffset.y, 0f, scrollRect.content.rect.height - scrollRect.viewport.rect.height) + ); + + if (!scrollRect.horizontal || scrollRect.content.rect.width <= scrollRect.viewport.rect.width) finalOffset.x = scrollStartPositionContent.x; + if (!scrollRect.vertical || scrollRect.content.rect.height <= scrollRect.viewport.rect.height) finalOffset.y = scrollStartPositionContent.y; + + scrollRect.content.anchoredPosition = finalOffset; + + //float valueX = Mathf.InverseLerp(scrollView.content.rect.min.x, scrollView.content.rect.max.x, scrollOffset.x - scrollStartPositionContent.x); + //float valueY = Mathf.InverseLerp(scrollView.content.rect.min.y, scrollView.content.rect.max.y, scrollOffset.y - scrollStartPositionContent.y); + + //scrollView.horizontalScrollbar.value = valueX; + //scrollView.verticalScrollbar.value = valueY; + } + + private void OnDrawGizmos() + { + if (isInteractionRay) Gizmos.DrawWireSphere(rayDirectionTransform.TransformPoint(RayDirection * 0.15f), 0.15f); + } + + public void SetRayScale(float scale) + { + if (lineRenderer != null) + lineRenderer.widthMultiplier = 0.005f * scale; + } + + + [AvailableToScripting] + private bool IsTracking() + { + // if is desktop ray, always return true + if (isDesktopRay) + return true; + + // if is head ray, only return true if both controllers are not tracking + if (isHeadRay) + return !CVRInputManager.Instance.IsLeftControllerTracking() && + !CVRInputManager.Instance.IsRightControllerTracking(); + + // if neither head or desktop ray, return true if the controller is tracking + return hand == CVRHand.Left + ? CVRInputManager.Instance.IsLeftControllerTracking() + : CVRInputManager.Instance.IsRightControllerTracking(); + } + + } +}*/ \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Interaction/Input/CustomInput.cs b/.Deprecated/SuperAwesomeMod/Interaction/Input/CustomInput.cs new file mode 100644 index 0000000..c4a88ff --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Interaction/Input/CustomInput.cs @@ -0,0 +1,85 @@ +using ABI_RC.Core; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using ABI_RC.Systems.InputManagement; +using UnityEngine; +using UnityEngine.EventSystems; + +namespace NAK.SuperAwesomeMod.Interaction; + +[DefaultExecutionOrder(1000)] +public class CustomBaseInput : BaseInput +{ + private Vector2 mousePositionCache; + + #region Input Overrides + + public override Vector2 mousePosition => Input.mousePosition; + + public override bool GetMouseButton(int button) + => button == (int)CVRHand.Right + ? CVRInputManager.Instance.interactLeftValue > 0.75f + : CVRInputManager.Instance.interactRightValue > 0.75f; + + public override bool GetMouseButtonDown(int button) + => button == (int)CVRHand.Right + ? CVRInputManager.Instance.interactLeftDown + : CVRInputManager.Instance.interactRightDown; + + public override Vector2 mouseScrollDelta => Vector2.zero; + + public override float GetAxisRaw(string axisName) + { + return axisName switch + { + "Mouse ScrollWheel" => CVRInputManager.Instance.scrollValue, + "Horizontal" => CVRInputManager.Instance.movementVector.x, + "Vertical" => CVRInputManager.Instance.movementVector.y, + _ => 0f + }; + } + + public override bool GetButtonDown(string buttonName) + { + return buttonName switch + { + "Mouse ScrollWheel" => CVRInputManager.Instance.scrollValue > 0.1f, + "Horizontal" => CVRInputManager.Instance.movementVector.x > 0.5f, + "Vertical" => CVRInputManager.Instance.movementVector.y > 0.5f, + _ => false + }; + } + + #endregion Input Overrides + + private CVRHand lastInteractHand; + + private void Update() + { + if (!MetaPort.Instance.isUsingVr) + { + mousePositionCache = Input.mousePosition; + return; + } + + ControllerRay leftRay = PlayerSetup.Instance.vrRayLeft; + ControllerRay rightRay = PlayerSetup.Instance.vrRayRight; + + if (leftRay._interactDown) lastInteractHand = leftRay.hand; + if (rightRay._interactDown) lastInteractHand = rightRay.hand; + + Camera vrCamera = PlayerSetup.Instance.vrCam; + + // transform the raycast position to screen position + Vector3 hitPoint = lastInteractHand == CVRHand.Left + ? leftRay.HitPoint + : rightRay.HitPoint; + + Vector3 screenPoint = vrCamera.WorldToScreenPoint(hitPoint); + screenPoint.x = Mathf.Clamp(screenPoint.x, 0, Screen.width); + screenPoint.y = Mathf.Clamp(screenPoint.y, 0, Screen.height); + mousePositionCache = new Vector2(screenPoint.x, screenPoint.y); + } +} + diff --git a/.Deprecated/SuperAwesomeMod/Interaction/Input/CustomInputModule.cs b/.Deprecated/SuperAwesomeMod/Interaction/Input/CustomInputModule.cs new file mode 100644 index 0000000..4c092f9 --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Interaction/Input/CustomInputModule.cs @@ -0,0 +1,67 @@ +using UnityEngine; +using UnityEngine.EventSystems; + +namespace NAK.SuperAwesomeMod.Interaction; + +public class CustomInputModule : StandaloneInputModule +{ + bool meow = false; + + #region Unity Events + + protected override void Start() + { + base.Start(); + + m_InputOverride = gameObject.AddComponent(); + + // Disable other event systems in the scene + DisableOtherEventSystems(); + } + + #endregion + + #region Overrides + + public override void Process() + { + CursorLockMode currentLockState = Cursor.lockState; + + Cursor.lockState = CursorLockMode.None; + + base.Process(); + + Cursor.lockState = currentLockState; + } + + protected override MouseState GetMousePointerEventData(int id) + { + MouseState pointerEventData = base.GetMousePointerEventData(id); + MouseButtonEventData leftEventData = pointerEventData.GetButtonState(PointerEventData.InputButton.Left).eventData; + RaycastResult pointerRaycast = leftEventData.buttonData.pointerCurrentRaycast; + + if (meow) leftEventData.buttonData.pointerCurrentRaycast = new RaycastResult(); + + return pointerEventData; + } + + #endregion Overrides + + #region Private Methods + + private void DisableOtherEventSystems() + { + EventSystem thisEventSystem = GetComponent(); + EventSystem[] systems = FindObjectsOfType(); + foreach (EventSystem system in systems) + { + if (system.gameObject.name == "UniverseLibCanvas") continue; + if (system != thisEventSystem) + { + system.enabled = false; + } + } + } + + #endregion Private Methods +} \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycaster.cs b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycaster.cs index aa4205a..a0a85ba 100644 --- a/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycaster.cs +++ b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycaster.cs @@ -1,9 +1,7 @@ using ABI_RC.Core.InteractionSystem.Base; using ABI_RC.Core.UI; using ABI.CCK.Components; -using NAK.SuperAwesomeMod.Components; using UnityEngine; -using UnityEngine.EventSystems; using UnityEngine.UI; namespace ABI_RC.Core.Player.Interaction.RaycastImpl @@ -108,7 +106,8 @@ namespace ABI_RC.Core.Player.Interaction.RaycastImpl // Check if there are pickups or interactables in immediate proximity if ((flags & RaycastFlags.ProximityInteract) != 0) { - ProcessProximityHits(ray, ref result); // TODO: Offset origin to center of palm based on hand type + Ray proximityRay = GetProximityRayFromImpl(); + ProcessProximityHits(proximityRay, ref result); if (result.isProximityHit) return result; } @@ -150,7 +149,7 @@ namespace ABI_RC.Core.Player.Interaction.RaycastImpl int proximityHits = Physics.SphereCastNonAlloc( ray.origin, RAYCAST_SPHERE_RADIUS, - Vector3.up, + ray.direction, _hits, 0.001f, _layerMask, @@ -313,6 +312,7 @@ namespace ABI_RC.Core.Player.Interaction.RaycastImpl result.hitInteractable = _workingInteractable; hitValidComponent = true; } + if (_workingGameObject.TryGetComponent(out _workingPickupable) && _workingPickupable.CanPickup && IsCVRPickupableWithinRange(_workingPickupable, hit)) @@ -343,6 +343,7 @@ namespace ABI_RC.Core.Player.Interaction.RaycastImpl #region Protected Methods protected abstract Ray GetRayFromImpl(); + protected abstract Ray GetProximityRayFromImpl(); #endregion Protected Methods @@ -375,10 +376,10 @@ namespace ABI_RC.Core.Player.Interaction.RaycastImpl return hit.distance <= pickupable.MaxGrabDistance; } - private static bool IsCVRCanvasWrapperWithinRange(CVRCanvasWrapper canvasWrapper, RaycastHit hit) - { - return hit.distance <= canvasWrapper.MaxInteractDistance; - } + // private static bool IsCVRCanvasWrapperWithinRange(CVRCanvasWrapper canvasWrapper, RaycastHit hit) + // { + // return hit.distance <= canvasWrapper.MaxInteractDistance; + // } #endregion Utility Because Original Methods Are Broken } diff --git a/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterMouse.cs b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterMouse.cs index 5f5e638..00d476d 100644 --- a/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterMouse.cs +++ b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterMouse.cs @@ -4,10 +4,24 @@ namespace ABI_RC.Core.Player.Interaction.RaycastImpl { public class CVRPlayerRaycasterMouse : CVRPlayerRaycaster { - private readonly Camera _camera; + #region Constructor + public CVRPlayerRaycasterMouse(Transform rayOrigin, Camera camera) : base(rayOrigin) { _camera = camera; } + + private readonly Camera _camera; + + #endregion Constructor + + #region Overrides + protected override Ray GetRayFromImpl() => Cursor.lockState == CursorLockMode.Locked ? new Ray(_camera.transform.position, _camera.transform.forward) : _camera.ScreenPointToRay(Input.mousePosition); + + protected override Ray GetProximityRayFromImpl() => Cursor.lockState == CursorLockMode.Locked + ? new Ray(_camera.transform.position, _camera.transform.forward) + : _camera.ScreenPointToRay(Input.mousePosition); + + #endregion Overrides } } \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterTransform.cs b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterTransform.cs index cc62dab..05f4f89 100644 --- a/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterTransform.cs +++ b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRPlayerRaycasterTransform.cs @@ -4,7 +4,44 @@ namespace ABI_RC.Core.Player.Interaction.RaycastImpl { public class CVRPlayerRaycasterTransform : CVRPlayerRaycaster { - public CVRPlayerRaycasterTransform(Transform rayOrigin) : base(rayOrigin) { } + #region Proximity Grab + + public const float ProximityGrabRadiusScaleDefault = 0.1f; + private float _proximityDetectionRadiusRelativeValue = ProximityGrabRadiusScaleDefault; + private float ProximityDetectionRadius => _proximityDetectionRadiusRelativeValue * PlayerSetup.Instance.GetPlaySpaceScale(); + + #endregion Proximity Grab + + #region Constructor + + public CVRPlayerRaycasterTransform(Transform rayOrigin, CVRHand hand) : base(rayOrigin) { _hand = hand; } + + private readonly CVRHand _hand; + + #endregion Constructor + + #region Overrides + protected override Ray GetRayFromImpl() => new(_rayOrigin.position, _rayOrigin.forward); + + protected override Ray GetProximityRayFromImpl() + { + Vector3 handPosition = _rayOrigin.position; + Vector3 handRight = _rayOrigin.right; + + // Offset the detection center forward, so we don't grab stuff behind our writs + handPosition += _rayOrigin.forward * (ProximityDetectionRadius * 0.25f); + + // Offset the detection center away from the palm, so we don't grab stuff behind our hand palm + Vector3 palmOffset = handRight * (ProximityDetectionRadius * 0.75f); + if (_hand == CVRHand.Left) + handPosition += palmOffset; + else + handPosition -= palmOffset; + + return new Ray(handPosition, _hand == CVRHand.Left ? handRight : -handRight); + } + + #endregion Overrides } } \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRRaycastResult.cs b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRRaycastResult.cs index 6165354..5056011 100644 --- a/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRRaycastResult.cs +++ b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/CVRRaycastResult.cs @@ -1,8 +1,6 @@ using ABI_RC.Core.InteractionSystem.Base; using ABI_RC.Core.UI; -using NAK.SuperAwesomeMod.Components; using UnityEngine; -using UnityEngine.EventSystems; using UnityEngine.UI; namespace ABI_RC.Core.Player.Interaction.RaycastImpl @@ -19,6 +17,7 @@ namespace ABI_RC.Core.Player.Interaction.RaycastImpl // Main raycast hit info public RaycastHit hit; public RaycastHit? waterHit; // Only valid if hitWater is true + public Vector2 hitScreenPoint; // Screen coordinates of the hit // Specific hit components public Pickupable hitPickupable; diff --git a/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/RaycastDebug.cs b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/RaycastDebug.cs index 5000f89..0120caf 100644 --- a/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/RaycastDebug.cs +++ b/.Deprecated/SuperAwesomeMod/Interaction/RaycastImpl/RaycastDebug.cs @@ -1,5 +1,4 @@ using UnityEngine; -using UnityEngine.EventSystems; using UnityEngine.UI; namespace ABI_RC.Core.Player.Interaction.RaycastImpl diff --git a/.Deprecated/SuperAwesomeMod/Interaction/UnityExploerer/UEMenuHelper.cs b/.Deprecated/SuperAwesomeMod/Interaction/UnityExploerer/UEMenuHelper.cs new file mode 100644 index 0000000..322dd89 --- /dev/null +++ b/.Deprecated/SuperAwesomeMod/Interaction/UnityExploerer/UEMenuHelper.cs @@ -0,0 +1,362 @@ +using ABI_RC.Core.Base; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using ABI.CCK.Components; +using MelonLoader; +using TMPro; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace NAK.SuperAwesomeMod.UExplorer; + +public class UEMenuHelper : MenuPositionHelperBase +{ + #region Singleton + + public static void Create() + { + if (Instance != null) + return; + + _universeLibCanvas = GameObject.Find("UniverseLibCanvas"); + if (_universeLibCanvas == null) + { + MelonLogger.Error( + "Failed to create UniverseLibCanvas"); // TODO: mod logger, casue https://github.com/knah/VRCMods/pull/227 + return; + } + + _explorerRoot = _universeLibCanvas.transform.Find("com.sinai.unityexplorer_Root").gameObject; + + // Fix the canvas so it renders in the UI camera + // _universeLibCanvas.SetLayerRecursive(CVRLayers.UIInternal); + + Transform menuParent = new GameObject("UEMenuParent").transform; + menuParent.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); + menuParent.localScale = Vector3.one; + + DontDestroyOnLoad(menuParent.gameObject); + + Transform offsetTransform = new GameObject("UEMenuOffset").transform; + offsetTransform.SetParent(menuParent, false); + offsetTransform.localScale = Vector3.one; + + Transform contentTransform = new GameObject("UEMenuContent").transform; + contentTransform.SetParent(offsetTransform, false); + contentTransform.localScale = Vector3.one; + + Instance = menuParent.AddComponentIfMissing(); + Instance.menuTransform = contentTransform; + // Instance._offsetTransform = offsetTransform; // Got in MenuPositionHelperBase.Start + + // Apply the component filters done in worlds + // foreach (Component c in _universeLibCanvas.GetComponentsInChildren(true)) + // SetupCollidersOnUnityUi(c); + + CVRCanvasWrapper.AddForCanvas(_universeLibCanvas.GetComponent(), true); + + Instance.ConfigureUECanvasRenderMode(RenderMode.WorldSpace); + } + + public static UEMenuHelper Instance { get; private set; } + + private static GameObject _universeLibCanvas; + private static GameObject _explorerRoot; + private static RenderMode _currentRenderMode = RenderMode.WorldSpace; + + #endregion Singleton + + #region Overrides + + public override bool IsMenuOpen => _explorerRoot.activeInHierarchy; + + public override float MenuScaleModifier => !MetaPort.Instance.isUsingVr ? 1f : 0.3f; + public override float MenuDistanceModifier => !MetaPort.Instance.isUsingVr ? 1.2f : 1f; + + #endregion Overrides + + #region Unity Events + + private void Update() + { + if (Input.GetKeyDown(KeyCode.F9)) + ToggleUeCanvasRenderMode(); + } + + #endregion Unity Events + + #region Private Methods + + private void ToggleUeCanvasRenderMode() + { + ConfigureUECanvasRenderMode(_currentRenderMode == RenderMode.WorldSpace + ? RenderMode.ScreenSpaceOverlay + : RenderMode.WorldSpace); + } + + private void ConfigureUECanvasRenderMode(RenderMode targetMode) + { + _currentRenderMode = targetMode; + var canvases = _universeLibCanvas.GetComponentsInChildren(true); + + if (targetMode == RenderMode.WorldSpace) + { + foreach (Canvas canvas in canvases) + { + canvas.renderMode = RenderMode.WorldSpace; + canvas.worldCamera = PlayerSetup.Instance.activeCam; + } + + _universeLibCanvas.transform.SetParent(menuTransform, false); + _universeLibCanvas.transform.localScale = Vector3.one * 0.0032f; + + // Center the canvas on the menuTransform + CenterCanvasOnMenuTransform(_universeLibCanvas, menuTransform); + return; + } + + foreach (Canvas canvas in canvases) + { + canvas.renderMode = RenderMode.ScreenSpaceOverlay; + canvas.worldCamera = null; + } + + _universeLibCanvas.transform.SetParent(null, false); + _universeLibCanvas.transform.localScale = Vector3.one; + } + + private void CenterCanvasOnMenuTransform(GameObject canvasRoot, Transform parentTransform) + { + // Find all the rectTransforms under the canvas, determine their bounds, and center the canvas local position + // on the menuTransform + + RectTransform canvasTransform = _explorerRoot.transform as RectTransform; + + // get the extents of the rectTransform + Vector3[] corners = new Vector3[4]; + canvasTransform.GetWorldCorners(corners); + + // now center by offsettings its localPosition + Vector3 center = (corners[0] + corners[2]) / 2f; + Vector3 extents = (corners[2] - corners[0]) / 2f; + Vector3 offset = center - extents; + offset.z = 0f; // set z to 0 to avoid depth issues + canvasTransform.localPosition = offset; + MelonLogger.Msg($"Centered canvas on menuTransform: {canvasTransform.localPosition}"); + } + + private static bool IsFloatValid(float val) + => (!float.IsNaN(val) && !float.IsInfinity(val)); + + private static void SetupCollidersOnUnityUi(Component c) + { + GameObject go = c.gameObject; + + if (c is Button) + { + BoxCollider col = go.AddComponentIfMissing(); + col.isTrigger = true; + var rectTransform = go.GetComponent(); + if (rectTransform) + { + Vector3 newSize = new Vector3(rectTransform.sizeDelta.x, rectTransform.sizeDelta.y, + 0.05f / rectTransform.lossyScale.z); + if (!IsFloatValid(newSize.x)) + newSize.x = 0.05f; + if (!IsFloatValid(newSize.y)) + newSize.y = 0.05f; + if (!IsFloatValid(newSize.z)) + newSize.z = 0.05f; + col.size = newSize; + + col.center = new Vector3(col.size.x * (0.5f - rectTransform.pivot.x), + col.size.y * (0.5f - rectTransform.pivot.y), 0f); + } + } + + if (c is Toggle) + { + BoxCollider col = go.AddComponentIfMissing(); + col.isTrigger = true; + var rectTransform = go.GetComponent(); + if (rectTransform) + { + Vector3 newSize = new Vector3(Mathf.Max(rectTransform.sizeDelta.x, rectTransform.rect.width), + rectTransform.sizeDelta.y, 0.05f / rectTransform.lossyScale.z); + if (!IsFloatValid(newSize.x)) + newSize.x = 0.05f; + if (!IsFloatValid(newSize.y)) + newSize.y = 0.05f; + if (!IsFloatValid(newSize.z)) + newSize.z = 0.05f; + col.size = newSize; + + col.center = new Vector3(col.size.x * (0.5f - rectTransform.pivot.x), + col.size.y * (0.5f - rectTransform.pivot.y), 0f); + + //Check Child if Size = 0 + if (col.size.x + col.size.y == 0f && go.transform.childCount > 0) + { + var childRectTransform = go.transform.GetChild(0).GetComponent(); + if (childRectTransform != null) + { + newSize = new Vector3( + Mathf.Max(childRectTransform.sizeDelta.x, rectTransform.rect.width), + childRectTransform.sizeDelta.y, 0.1f); + if (!IsFloatValid(newSize.x)) + newSize.x = 0.05f; + if (!IsFloatValid(newSize.y)) + newSize.y = 0.05f; + if (!IsFloatValid(newSize.z)) + newSize.z = 0.05f; + col.size = newSize; + + col.center = Vector3.zero; + } + } + } + } + + if (c is Slider) + { + BoxCollider col = go.AddComponentIfMissing(); + var rectTransform = go.GetComponent(); + if (rectTransform) + { + Vector3 newSize = new Vector3(rectTransform.sizeDelta.x, rectTransform.sizeDelta.y, + 0.05f / rectTransform.lossyScale.z); + if (!IsFloatValid(newSize.x)) + newSize.x = 0.05f; + if (!IsFloatValid(newSize.y)) + newSize.y = 0.05f; + if (!IsFloatValid(newSize.z)) + newSize.z = 0.05f; + col.size = newSize; + + col.center = new Vector3(col.size.x * (0.5f - rectTransform.pivot.x), + col.size.y * (0.5f - rectTransform.pivot.y), 0f); + } + + col.isTrigger = true; + } + + if (c is EventTrigger) + { + BoxCollider col = go.AddComponentIfMissing(); + var rectTransform = go.GetComponent(); + if (rectTransform) + { + Vector3 newSize = new Vector3(rectTransform.sizeDelta.x, rectTransform.sizeDelta.y, + 0.025f / rectTransform.lossyScale.z); + if (!IsFloatValid(newSize.x)) + newSize.x = 0.05f; + if (!IsFloatValid(newSize.y)) + newSize.y = 0.05f; + if (!IsFloatValid(newSize.z)) + newSize.z = 0.05f; + col.size = newSize; + + col.center = new Vector3(col.size.x * (0.5f - rectTransform.pivot.x), + col.size.y * (0.5f - rectTransform.pivot.y), 0f); + } + + col.isTrigger = true; + } + + if (c is InputField || c is TMP_InputField) + { + BoxCollider col = go.AddComponentIfMissing(); + col.isTrigger = true; + var rectTransform = go.GetComponent(); + if (rectTransform) + { + Vector3 newSize = new Vector3(rectTransform.sizeDelta.x, rectTransform.sizeDelta.y, + 0.05f / rectTransform.lossyScale.z); + if (!IsFloatValid(newSize.x)) + newSize.x = 0.05f; + if (!IsFloatValid(newSize.y)) + newSize.y = 0.05f; + if (!IsFloatValid(newSize.z)) + newSize.z = 0.05f; + col.size = newSize; + + col.center = new Vector3(col.size.x * (0.5f - rectTransform.pivot.x), + col.size.y * (0.5f - rectTransform.pivot.y), 0f); + } + } + + if (c is ScrollRect) + { + BoxCollider col = go.AddComponentIfMissing(); + col.isTrigger = true; + var rectTransform = go.GetComponent(); + if (rectTransform) + { + Vector3 newSize = new Vector3(rectTransform.sizeDelta.x, rectTransform.sizeDelta.y, + 0.025f / rectTransform.lossyScale.z); + if (!IsFloatValid(newSize.x)) + newSize.x = 0.025f; + if (!IsFloatValid(newSize.y)) + newSize.y = 0.025f; + if (!IsFloatValid(newSize.z)) + newSize.z = 0.025f; + col.size = newSize; + + col.center = new Vector3(col.size.x * (0.5f - rectTransform.pivot.x), + col.size.y * (0.5f - rectTransform.pivot.y), 0f); + } + } + + if (c is Dropdown) + { + BoxCollider col = go.AddComponentIfMissing(); + col.isTrigger = true; + var rectTransform = go.GetComponent(); + if (rectTransform) + { + Vector3 newSize = new Vector3(rectTransform.sizeDelta.x, rectTransform.sizeDelta.y, + 0.05f / rectTransform.lossyScale.z); + if (!IsFloatValid(newSize.x)) + newSize.x = 0.05f; + if (!IsFloatValid(newSize.y)) + newSize.y = 0.05f; + if (!IsFloatValid(newSize.z)) + newSize.z = 0.05f; + col.size = newSize; + + col.center = new Vector3(col.size.x * (0.5f - rectTransform.pivot.x), + col.size.y * (0.5f - rectTransform.pivot.y), 0f); + } + } + + //Canvas + if (c is Canvas) + { + BoxCollider col = go.AddComponentIfMissing(); + + var rectTransform = go.GetComponent(); + if (rectTransform) + { + Vector3 newSize = new Vector3(rectTransform.sizeDelta.x, rectTransform.sizeDelta.y, + 0.0125f / rectTransform.lossyScale.z); + if (!IsFloatValid(newSize.x)) + newSize.x = 0.0125f; + if (!IsFloatValid(newSize.y)) + newSize.y = 0.0125f; + if (!IsFloatValid(newSize.z)) + newSize.z = 0.0125f; + col.size = newSize; + + col.center = new Vector3(col.size.x * (0.5f - rectTransform.pivot.x), + col.size.y * (0.5f - rectTransform.pivot.y), 0f); + } + + col.isTrigger = true; + } + + } + + #endregion Private Methods +} \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/Main.cs b/.Deprecated/SuperAwesomeMod/Main.cs index 5c410f2..5cb9cd9 100644 --- a/.Deprecated/SuperAwesomeMod/Main.cs +++ b/.Deprecated/SuperAwesomeMod/Main.cs @@ -1,15 +1,14 @@ using System.Reflection; +using ABI_RC.Core.Base; using ABI_RC.Core.Base.Jobs; using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.Player; -using ABI_RC.Core.Player.Interaction.RaycastImpl; -using ABI_RC.Core.Util.AssetFiltering; -using ABI.CCK.Components; using HarmonyLib; using MelonLoader; -using NAK.SuperAwesomeMod.Components; using UnityEngine; +using UnityEngine.EventSystems; using UnityEngine.SceneManagement; +using UnityEngine.UI; namespace NAK.SuperAwesomeMod; @@ -33,13 +32,13 @@ public class SuperAwesomeModMod : MelonMod BindingFlags.NonPublic | BindingFlags.Static)) ); - // patch SharedFilter.ProcessCanvas - HarmonyInstance.Patch( - typeof(SharedFilter).GetMethod(nameof(SharedFilter.ProcessCanvas), - BindingFlags.Public | BindingFlags.Static), - postfix: new HarmonyMethod(typeof(SuperAwesomeModMod).GetMethod(nameof(OnProcessCanvas), - BindingFlags.NonPublic | BindingFlags.Static)) - ); + // // patch SharedFilter.ProcessCanvas + // HarmonyInstance.Patch( + // typeof(SharedFilter).GetMethod(nameof(SharedFilter.ProcessCanvas), + // BindingFlags.Public | BindingFlags.Static), + // postfix: new HarmonyMethod(typeof(SuperAwesomeModMod).GetMethod(nameof(OnProcessCanvas), + // BindingFlags.NonPublic | BindingFlags.Static)) + // ); LoggerInstance.Msg("SuperAwesomeModMod! OnInitializeMelon! :D"); } @@ -53,29 +52,43 @@ public class SuperAwesomeModMod : MelonMod private static void OnPlayerSetupStart() { - CVRRaycastDebugManager.Initialize(PlayerSetup.Instance.desktopCam); + // CVRRaycastDebugManager.Initialize(PlayerSetup.Instance.desktopCam); + // UEMenuHelper.Create(); } private static void OnShitLoaded(Component c, List asyncTasks = null, Scene? scene = null) { - if (c == null) + if (!c) return; - if (c.gameObject == null) + if (!c.gameObject) return; if (c.gameObject.scene.buildIndex > 0) return; - if ((scene != null) - && (c.gameObject.scene != scene)) + if ((scene != null) && (c.gameObject.scene != scene)) return; - - if (c is Canvas canvas) canvas.gameObject.AddComponent(); + + if (c is InputField input) + { + input.AddComponentIfMissing(); + } + + if (c is TMPro.TMP_InputField tmpInput) + { + tmpInput.AddComponentIfMissing(); + } } - private static void OnProcessCanvas(string collectionId, Canvas canvas) + public class InputFocusIntentDetector : MonoBehaviour, IPointerClickHandler { - canvas.gameObject.AddComponent(); + public void OnPointerClick(PointerEventData eventData) + { + if (TryGetComponent(out TMPro.TMP_InputField input) && input.isActiveAndEnabled) + ViewManager.Instance.openMenuKeyboard(input); + else if (TryGetComponent(out InputField inputField) && inputField.isActiveAndEnabled) + ViewManager.Instance.openMenuKeyboard(inputField); + } } } \ No newline at end of file diff --git a/.Deprecated/SuperAwesomeMod/SuperAwesomeMod.csproj b/.Deprecated/SuperAwesomeMod/SuperAwesomeMod.csproj index fa113da..e64907b 100644 --- a/.Deprecated/SuperAwesomeMod/SuperAwesomeMod.csproj +++ b/.Deprecated/SuperAwesomeMod/SuperAwesomeMod.csproj @@ -1,7 +1,7 @@ - ASTExtension + SuperAwesomeMod diff --git a/.Experimental/ByeByePerformanceThankYouAMD/ByeByePerformanceThankYouAMD.csproj b/.Experimental/ByeByePerformanceThankYouAMD/ByeByePerformanceThankYouAMD.csproj new file mode 100644 index 0000000..e94f9dc --- /dev/null +++ b/.Experimental/ByeByePerformanceThankYouAMD/ByeByePerformanceThankYouAMD.csproj @@ -0,0 +1,2 @@ + + diff --git a/.Experimental/ByeByePerformanceThankYouAMD/CohtmlRenderForwarder.cs b/.Experimental/ByeByePerformanceThankYouAMD/CohtmlRenderForwarder.cs new file mode 100644 index 0000000..e69de29 diff --git a/.Experimental/ByeByePerformanceThankYouAMD/CommandBufferManager.cs b/.Experimental/ByeByePerformanceThankYouAMD/CommandBufferManager.cs new file mode 100644 index 0000000..e69de29 diff --git a/.Experimental/ByeByePerformanceThankYouAMD/Main.cs b/.Experimental/ByeByePerformanceThankYouAMD/Main.cs new file mode 100644 index 0000000..2623ac1 --- /dev/null +++ b/.Experimental/ByeByePerformanceThankYouAMD/Main.cs @@ -0,0 +1,89 @@ +using System.Collections; +using ABI_RC.Core; +using ABI_RC.Core.IO; +using ABI_RC.Core.Util.Encryption; +using ABI_RC.Systems.GameEventSystem; +using HarmonyLib; +using MelonLoader; +using UnityEngine; + +namespace NAK.ByeByePerformanceThankYouAMD; + +public class ByeByePerformanceThankYouAMDMod : MelonMod +{ + private static MelonLogger.Instance Logger; + + private static readonly MelonPreferences_Category Category = + MelonPreferences.CreateCategory(nameof(ByeByePerformanceThankYouAMD)); + + private static readonly MelonPreferences_Entry EntryDisableMaterialInstancing = + Category.CreateEntry( + identifier: "disable_material_instancing", + true, + display_name: "Disable Material Instancing", + description: "Disables material instancing to mitigate a shit visual issue on AMD"); + + public override void OnInitializeMelon() + { + Logger = LoggerInstance; + ApplyPatches(typeof(CVREncryptionRouter_Patches)); + } + + private void ApplyPatches(Type type) + { + try + { + HarmonyInstance.PatchAll(type); + } + catch (Exception e) + { + LoggerInstance.Msg($"Failed while patching {type.Name}!"); + LoggerInstance.Error(e); + } + } + + internal static void ScanForInstancedMaterials() + { + if (!EntryDisableMaterialInstancing.Value) + return; + + Logger.Msg("An Asset Bundle has loaded, scanning for instanced materials to disable..."); + + if (Resources.FindObjectsOfTypeAll(typeof(Material)) is not Material[] allMaterials) + { + Logger.Msg("No materials found."); + return; + } + + int count = 0; + foreach (Material material in allMaterials) + { + if (!material || !material.enableInstancing) continue; + material.enableInstancing = false; + count++; + } + + Logger.Msg($"Finished scanning for instanced materials. Disabled instancing on {count} loaded materials."); + } +} + +internal static class CVREncryptionRouter_Patches +{ + [HarmonyPostfix] + [HarmonyPatch(typeof(CVREncryptionRouter), nameof(CVREncryptionRouter.LoadEncryptedBundle), typeof(bool))] + private static void CVREncryptionRouter_LoadEncryptedBundle_Postfix(ref IEnumerator __result) + { + __result = Wrapper(__result); + } + + private static IEnumerator Wrapper(IEnumerator inner) + { + yield return null; // before start + + while (inner.MoveNext()) + yield return inner.Current; + + // after finish + ByeByePerformanceThankYouAMDMod.ScanForInstancedMaterials(); + } +} \ No newline at end of file diff --git a/.Experimental/ByeByePerformanceThankYouAMD/Properties/AssemblyInfo.cs b/.Experimental/ByeByePerformanceThankYouAMD/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..74f96b9 --- /dev/null +++ b/.Experimental/ByeByePerformanceThankYouAMD/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using MelonLoader; +using NAK.ByeByePerformanceThankYouAMD.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.ByeByePerformanceThankYouAMD))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.ByeByePerformanceThankYouAMD))] + +[assembly: MelonInfo( + typeof(NAK.ByeByePerformanceThankYouAMD.ByeByePerformanceThankYouAMDMod), + nameof(NAK.ByeByePerformanceThankYouAMD), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ByeByePerformanceThankYouAMD" +)] + +[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.ByeByePerformanceThankYouAMD.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/.Experimental/ByeByePerformanceThankYouAMD/README.md b/.Experimental/ByeByePerformanceThankYouAMD/README.md new file mode 100644 index 0000000..1c4c5bc --- /dev/null +++ b/.Experimental/ByeByePerformanceThankYouAMD/README.md @@ -0,0 +1,14 @@ +# SearchWithSpacesFix + +Fixes search terms that use spaces. + +--- + +Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI. +https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games + +> This mod is an independent creation not affiliated with, supported by, or approved by Alpha Blend Interactive. + +> Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use. + +> To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive. diff --git a/.Experimental/ByeByePerformanceThankYouAMD/format.json b/.Experimental/ByeByePerformanceThankYouAMD/format.json new file mode 100644 index 0000000..f8950ca --- /dev/null +++ b/.Experimental/ByeByePerformanceThankYouAMD/format.json @@ -0,0 +1,23 @@ +{ + "_id": -1, + "name": "SearchWithSpacesFix", + "modversion": "1.0.0", + "gameversion": "2024r177", + "loaderversion": "0.6.1", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Fixes search terms that include spaces.", + "searchtags": [ + "search", + "spaces", + "fix", + "meow" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r42/SearchWithSpacesFix.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/SearchWithSpacesFix/", + "changelog": "- Initial release", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/.Experimental/CVRLuaToolsExtension/LuaToolsExtension/LuaHotReloadManager.cs b/.Experimental/CVRLuaToolsExtension/LuaToolsExtension/LuaHotReloadManager.cs index ec44859..9dd3fe8 100644 --- a/.Experimental/CVRLuaToolsExtension/LuaToolsExtension/LuaHotReloadManager.cs +++ b/.Experimental/CVRLuaToolsExtension/LuaToolsExtension/LuaHotReloadManager.cs @@ -1,5 +1,4 @@ using System.Text; -using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.UI; using ABI.CCK.Components; using ABI.CCK.Components.ScriptableObjects; diff --git a/.Experimental/CVRLuaToolsExtension/Main.cs b/.Experimental/CVRLuaToolsExtension/Main.cs index 1dad9d9..29157f2 100644 --- a/.Experimental/CVRLuaToolsExtension/Main.cs +++ b/.Experimental/CVRLuaToolsExtension/Main.cs @@ -4,7 +4,6 @@ using ABI.CCK.Components; using HarmonyLib; using MelonLoader; using NAK.CVRLuaToolsExtension.NamedPipes; -using UnityEngine; namespace NAK.CVRLuaToolsExtension; diff --git a/.Experimental/DummyMenu/Components/DummyMenuManager.cs b/.Experimental/DummyMenu/Components/DummyMenuManager.cs new file mode 100644 index 0000000..0840e95 --- /dev/null +++ b/.Experimental/DummyMenu/Components/DummyMenuManager.cs @@ -0,0 +1,103 @@ +using ABI_RC.Core.UI.UIRework; +using ABI_RC.Systems.InputManagement; +using UnityEngine; + +namespace NAK.DummyMenu; + +public class DummyMenuManager : CVRUIManagerBaseInput +{ + #region Boilerplate + + public static DummyMenuManager Instance { get; private set; } + + public override void Start() + { + if (Instance && Instance != this) + { + Destroy(gameObject); + return; + } + Instance = this; + base.Start(); + + ListenForModSettingChanges(); + } + + public override void ReloadView() + { + if (IsViewShown && !ModSettings.EntryReloadMenuEvenWhenOpen.Value) return; + TrySetMenuPage(); + base.ReloadView(); + } + + public override void OnFinishedLoad(string _) + { + base.OnFinishedLoad(_); + + // Usually done in OnReadyForBindings, but that isn't called for my menu :) + _cohtmlRenderMaterial = _uiRenderer.sharedMaterial; + // ReSharper disable thrice Unity.PreferAddressByIdToGraphicsParams + _cohtmlRenderMaterial.SetTexture("_DesolvePattern", pattern); + _cohtmlRenderMaterial.SetTexture("_DesolveTiming", timing); + _cohtmlRenderMaterial.SetTextureScale("_DesolvePattern", new Vector2(16, 9)); + } + + public void ToggleView() + { + bool invertShown = !IsViewShown; + ToggleView(invertShown); + CursorLockManager.Instance.SetUnlockWithId(invertShown, nameof(DummyMenuManager)); + } + + #endregion Boilerplate + + private void ListenForModSettingChanges() + { + ModSettings.EntryPageCouiPath.OnEntryValueChanged.Subscribe((oldValue, newValue) => + { + DummyMenuMod.Logger.Msg($"Changing COUI page from {oldValue} to {newValue}"); + cohtmlView.Page = newValue; + }); + + ModSettings.EntryPageWidth.OnEntryValueChanged.Subscribe((oldValue, newValue) => + { + DummyMenuMod.Logger.Msg($"Changing COUI width from {oldValue} to {newValue}"); + cohtmlView.Width = newValue; + DummyMenuPositionHelper.Instance.UpdateAspectRatio(cohtmlView.Width, cohtmlView.Height); + }); + + ModSettings.EntryPageHeight.OnEntryValueChanged.Subscribe((oldValue, newValue) => + { + DummyMenuMod.Logger.Msg($"Changing COUI height from {oldValue} to {newValue}"); + cohtmlView.Height = newValue; + DummyMenuPositionHelper.Instance.UpdateAspectRatio(cohtmlView.Width, cohtmlView.Height); + }); + + ModSettings.EntryToggleMeToResetModifiers.OnEntryValueChanged.Subscribe((_, newValue) => + { + if (!newValue) return; + DummyMenuMod.Logger.Msg("Resetting modifiers to default because the toggle was enabled"); + ModSettings.EntryToggleMeToResetModifiers.Value = false; + ModSettings.EntryDesktopMenuScaleModifier.ResetToDefault(); + ModSettings.EntryDesktopMenuDistanceModifier.ResetToDefault(); + ModSettings.EntryVrMenuScaleModifier.ResetToDefault(); + ModSettings.EntryVrMenuDistanceModifier.ResetToDefault(); + }); + } + + public void TrySetMenuPage() + { + string couiPath = ModSettings.EntryPageCouiPath.Value; + string fullCouiPath = CreateDummyMenu.GetFullCouiPath(couiPath); + if (File.Exists(fullCouiPath)) + { + DummyMenuMod.Logger.Msg($"Found COUI page at {fullCouiPath}. Setting it as the controlledview page."); + cohtmlView.Page = "coui://" + couiPath; + } + else + { + DummyMenuMod.Logger.Error($"No COUI page found at {fullCouiPath}. Please create one at that path, or change the mod setting to point to an existing file. Using default example page instead."); + cohtmlView.Page = "coui://" + CreateDummyMenu.ExampleDummyMenuPath; + } + } +} \ No newline at end of file diff --git a/.Experimental/DummyMenu/Components/DummyMenuPositionHelper.cs b/.Experimental/DummyMenu/Components/DummyMenuPositionHelper.cs new file mode 100644 index 0000000..2194b15 --- /dev/null +++ b/.Experimental/DummyMenu/Components/DummyMenuPositionHelper.cs @@ -0,0 +1,37 @@ +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Savior; +using UnityEngine; + +namespace NAK.DummyMenu; + +[DefaultExecutionOrder(16000)] // just before ControllerRay +public class DummyMenuPositionHelper : MenuPositionHelperBase +{ + public static DummyMenuPositionHelper Instance { get; private set; } + + private void Awake() + { + if (Instance && Instance != this) + { + Destroy(this); + return; + } + Instance = this; + } + + public override bool IsMenuOpen => DummyMenuManager.Instance.IsViewShown; + public override float MenuScaleModifier => MetaPort.Instance.isUsingVr ? ModSettings.EntryVrMenuScaleModifier.Value : ModSettings.EntryDesktopMenuScaleModifier.Value; + public override float MenuDistanceModifier => MetaPort.Instance.isUsingVr ? ModSettings.EntryVrMenuDistanceModifier.Value : ModSettings.EntryDesktopMenuDistanceModifier.Value; + + public void UpdateAspectRatio(float width, float height) + { + if (width <= 0f || height <= 0f) + return; + + _menuAspectRatio = width / height; + + float normalizedWidth = width / Mathf.Max(width, height); + float normalizedHeight = height / Mathf.Max(width, height); + menuTransform.localScale = new Vector3(normalizedWidth, normalizedHeight, 1f); + } +} \ No newline at end of file diff --git a/.Experimental/DummyMenu/CreateDummyMenu.cs b/.Experimental/DummyMenu/CreateDummyMenu.cs new file mode 100644 index 0000000..0e339bf --- /dev/null +++ b/.Experimental/DummyMenu/CreateDummyMenu.cs @@ -0,0 +1,243 @@ +using ABI_RC.Core; +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.UI; +using UnityEngine; + +namespace NAK.DummyMenu; + +public static class CreateDummyMenu +{ + public static void Create() + { + CreateDefaultExamplePageIfNeeded(); + + GameObject cohtmlRootObject = GameObject.Find("Cohtml"); + + // Create menu rig + // Cohtml -> Root -> Offset -> Menu + GameObject dummyMenuRoot = new("DummyMenuRoot"); + GameObject dummyMenuOffset = new("DummyMenuOffset"); + GameObject dummyMenuItself = new("DummyMenu"); + dummyMenuItself.transform.SetParent(dummyMenuOffset.transform); + dummyMenuOffset.transform.SetParent(dummyMenuRoot.transform); + dummyMenuRoot.transform.SetParent(cohtmlRootObject.transform); + + // Add dummy menu position helper + DummyMenuPositionHelper positionHelper = dummyMenuRoot.AddComponent(); + positionHelper._offsetTransform = dummyMenuOffset.transform; + positionHelper.menuTransform = dummyMenuItself.transform; + + // Add components to menu (MeshFilter, MeshRenderer, Animator, CohtmlControlledView) + MeshFilter meshFilter = dummyMenuItself.AddComponent(); + MeshRenderer meshRenderer = dummyMenuItself.AddComponent(); + Animator animator = dummyMenuItself.AddComponent(); + CohtmlControlledView controlledView = dummyMenuItself.AddComponent(); + + // Add dummy menu manager + DummyMenuManager menuManager = dummyMenuItself.AddComponent(); + menuManager.cohtmlView = controlledView; + menuManager._viewAnimator = animator; + menuManager._uiRenderer = meshRenderer; + + // Steal from main menu + menuManager.pattern = ViewManager.Instance.pattern; + menuManager.timing = ViewManager.Instance.timing; + meshFilter.mesh = ViewManager.Instance.GetComponent().sharedMesh; + meshRenderer.sharedMaterial = null; // assign empty material + animator.runtimeAnimatorController = ViewManager.Instance.GetComponent().runtimeAnimatorController; + + // Put everything on UI Internal layer + dummyMenuRoot.SetLayerRecursive(CVRLayers.UIInternal); + + // Apply initial settings + menuManager.TrySetMenuPage(); + + float pageWidth = ModSettings.EntryPageWidth.Value; + float pageHeight = ModSettings.EntryPageHeight.Value; + positionHelper.UpdateAspectRatio(pageWidth, pageHeight); + } + + internal const string ExampleDummyMenuPath = "UIResources/DummyMenu/_example.html"; + internal static string GetFullCouiPath(string couiPath) => Path.Combine(Application.streamingAssetsPath, "Cohtml", couiPath); + + private static void CreateDefaultExamplePageIfNeeded() + { + // Check if there is a file at our default path + string fullPath = GetFullCouiPath(ExampleDummyMenuPath); + if (File.Exists(fullPath)) + { + DummyMenuMod.Logger.Msg($"Dummy menu HTML file already exists at {fullPath}. No need to create a new one."); + return; + } + DummyMenuMod.Logger.Msg($"No dummy menu HTML file found at {fullPath}. Creating a default one."); + + // Create the directory if it doesn't exist + string directory = Path.GetDirectoryName(fullPath); + if (!Directory.Exists(directory)) Directory.CreateDirectory(directory!); + + // Create a default HTML file + using StreamWriter writer = new(fullPath, false); + writer.Write(DefaultHtmlContent); + writer.Flush(); + writer.Close(); + DummyMenuMod.Logger.Msg($"Created default dummy menu HTML file at {fullPath}. You can now open the dummy menu in-game."); + } + + #region Default HTML Content + + private const string DefaultHtmlContent = """ + + + + + + Cohtml Bubble Pop — 1280×720 + + + + + + Hello World + Bubble pop — Gameface fixed + + + + + + """; + + #endregion Default HTML Content +} \ No newline at end of file diff --git a/.Experimental/DummyMenu/DummyMenu.csproj b/.Experimental/DummyMenu/DummyMenu.csproj new file mode 100644 index 0000000..5a8badc --- /dev/null +++ b/.Experimental/DummyMenu/DummyMenu.csproj @@ -0,0 +1,6 @@ + + + + YouAreMineNow + + diff --git a/.Experimental/DummyMenu/Main.cs b/.Experimental/DummyMenu/Main.cs new file mode 100644 index 0000000..9df405f --- /dev/null +++ b/.Experimental/DummyMenu/Main.cs @@ -0,0 +1,21 @@ +using ABI_RC.Systems.GameEventSystem; +using MelonLoader; +using UnityEngine; + +namespace NAK.DummyMenu; + +public class DummyMenuMod : MelonMod +{ + internal static MelonLogger.Instance Logger; + + public override void OnInitializeMelon() + { + Logger = LoggerInstance; + CVRGameEventSystem.Initialization.OnPlayerSetupStart.AddListener(CreateDummyMenu.Create); + } + + public override void OnUpdate() + { + if (Input.GetKeyDown(ModSettings.EntryToggleDummyMenu.Value)) DummyMenuManager.Instance.ToggleView(); + } +} \ No newline at end of file diff --git a/.Experimental/DummyMenu/ModSettings.cs b/.Experimental/DummyMenu/ModSettings.cs new file mode 100644 index 0000000..5882e39 --- /dev/null +++ b/.Experimental/DummyMenu/ModSettings.cs @@ -0,0 +1,64 @@ +using cohtml; +using MelonLoader; +using UnityEngine; + +namespace NAK.DummyMenu; + +public static class ModSettings +{ + private static readonly MelonPreferences_Category Category = MelonPreferences.CreateCategory(nameof(DummyMenu)); + + internal static readonly MelonPreferences_Entry EntryToggleDummyMenu = + Category.CreateEntry( + identifier: "toggle_dummy_menu", + default_value: KeyCode.F3, + display_name: "Toggle Menu Key", + description: "Key used to toggle the dummy menu."); + + internal static readonly MelonPreferences_Entry EntryPageCouiPath = + Category.CreateEntry( + identifier: "page_coui_path", + default_value: "UIResources/DummyMenu/menu.html", + display_name: "Page Coui Path", + description: "Path to the folder containing the root menu html. This is relative to the StreamingAssets folder."); + + internal static readonly MelonPreferences_Entry EntryPageWidth = + Category.CreateEntry("page_width", CohtmlView.DefaultWidth, + display_name: "Page Width", + description: "Width of the menu page in pixels. Default is 1280 pixels."); + + internal static readonly MelonPreferences_Entry EntryPageHeight = + Category.CreateEntry("page_height", CohtmlView.DefaultHeight, + display_name: "Page Height", + description: "Height of the menu page in pixels. Default is 720 pixels."); + + internal static readonly MelonPreferences_Entry EntryReloadMenuEvenWhenOpen = + Category.CreateEntry("reload_menu_even_when_open", false, + display_name: "Reload Menu Even When Open", + description: "If enabled, the menu will be reloaded even if it is already open."); + + internal static readonly MelonPreferences_Entry EntryVrMenuScaleModifier = + Category.CreateEntry("vr_menu_scale_modifier", 0.75f, + display_name: "VR Menu Scale Modifier", + description: "Adjusts the scale of the menu while in VR. Default is 0.75."); + + internal static readonly MelonPreferences_Entry EntryDesktopMenuScaleModifier = + Category.CreateEntry("desktop_menu_scale_modifier", 1f, + display_name: "Desktop Menu Scale Modifier", + description: "Adjusts the scale of the menu while in Desktop mode. Default is 1."); + + internal static readonly MelonPreferences_Entry EntryVrMenuDistanceModifier = + Category.CreateEntry("vr_menu_distance_modifier", 1f, + display_name: "VR Menu Distance Modifier", + description: "Adjusts the distance of the menu from the camera while in VR. Default is 1."); + + internal static readonly MelonPreferences_Entry EntryDesktopMenuDistanceModifier = + Category.CreateEntry("desktop_menu_distance_modifier", 1.2f, + display_name: "Desktop Menu Distance Modifier", + description: "Adjusts the distance of the menu from the camera while in Desktop mode. Default is 1.2."); + + internal static readonly MelonPreferences_Entry EntryToggleMeToResetModifiers = + Category.CreateEntry("toggle_me_to_reset_modifiers", false, + display_name: "Toggle Me To Reset Modifiers", + description: "If enabled, toggling the menu will reset any scale/distance modifiers applied by other mods."); +} \ No newline at end of file diff --git a/.Experimental/DummyMenu/Properties/AssemblyInfo.cs b/.Experimental/DummyMenu/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..b311333 --- /dev/null +++ b/.Experimental/DummyMenu/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using MelonLoader; +using NAK.DummyMenu.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.DummyMenu))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.DummyMenu))] + +[assembly: MelonInfo( + typeof(NAK.DummyMenu.DummyMenuMod), + nameof(NAK.DummyMenu), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/DummyMenu" +)] + +[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.DummyMenu.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/.Experimental/LuaNetworkVariables/Main.cs b/.Experimental/LuaNetworkVariables/Main.cs index ce59fa0..a389c28 100644 --- a/.Experimental/LuaNetworkVariables/Main.cs +++ b/.Experimental/LuaNetworkVariables/Main.cs @@ -1,6 +1,4 @@ -using ABI_RC.Core.Player; -using MelonLoader; -using UnityEngine; +using MelonLoader; namespace NAK.LuaNetworkVariables; diff --git a/.Experimental/LuaNetworkVariables/Properties/AssemblyInfo.cs b/.Experimental/LuaNetworkVariables/Properties/AssemblyInfo.cs index 66b2858..72b002e 100644 --- a/.Experimental/LuaNetworkVariables/Properties/AssemblyInfo.cs +++ b/.Experimental/LuaNetworkVariables/Properties/AssemblyInfo.cs @@ -17,7 +17,7 @@ using System.Reflection; downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/LuaNetworkVariables" )] -[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.LuaNetworkVariables.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/.Experimental/LuaNetworkVariables/format.json b/.Experimental/LuaNetworkVariables/format.json deleted file mode 100644 index 654911a..0000000 --- a/.Experimental/LuaNetworkVariables/format.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "_id": 234, - "name": "WhereAmIPointing", - "modversion": "1.0.1", - "gameversion": "2024r175", - "loaderversion": "0.6.1", - "modtype": "Mod", - "author": "NotAKidoS", - "description": "Simple mod that makes your controller rays always visible when the menus are open. Useful for when you're trying to aim at something in the distance. Also visualizes which ray is being used for menu interaction.", - "searchtags": [ - "controller", - "ray", - "line", - "tomato" - ], - "requirements": [ - "None" - ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r40/WhereAmIPointing.dll", - "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/WhereAmIPointing/", - "changelog": "- Fixed line renderer alpha not being reset when the menu is closed.", - "embedcolor": "#f61963" -} \ No newline at end of file diff --git a/.Experimental/OriginShift/Integrations/BTKUI/BtkUiAddon_CAT_OriginShiftMod.cs b/.Experimental/OriginShift/Integrations/BTKUI/BtkUiAddon_CAT_OriginShiftMod.cs index cd32e4f..86eaaee 100644 --- a/.Experimental/OriginShift/Integrations/BTKUI/BtkUiAddon_CAT_OriginShiftMod.cs +++ b/.Experimental/OriginShift/Integrations/BTKUI/BtkUiAddon_CAT_OriginShiftMod.cs @@ -1,7 +1,7 @@ using ABI_RC.Core.Player; -using BTKUILib; -using BTKUILib.UIObjects; -using BTKUILib.UIObjects.Components; +using ABI_RC.Systems.UI.UILib; +using ABI_RC.Systems.UI.UILib.UIObjects; +using ABI_RC.Systems.UI.UILib.UIObjects.Components; using NAK.OriginShift; namespace NAK.OriginShiftMod.Integrations; diff --git a/.Experimental/OriginShift/Integrations/BTKUI/BtkuiAddon.cs b/.Experimental/OriginShift/Integrations/BTKUI/BtkuiAddon.cs index f980330..e905dec 100644 --- a/.Experimental/OriginShift/Integrations/BTKUI/BtkuiAddon.cs +++ b/.Experimental/OriginShift/Integrations/BTKUI/BtkuiAddon.cs @@ -1,6 +1,6 @@ using ABI_RC.Core.Player; -using BTKUILib; -using BTKUILib.UIObjects; +using ABI_RC.Systems.UI.UILib; +using ABI_RC.Systems.UI.UILib.UIObjects; using NAK.OriginShift; namespace NAK.OriginShiftMod.Integrations; diff --git a/.Experimental/OriginShift/Integrations/BTKUI/BtkuiAddon_Utils.cs b/.Experimental/OriginShift/Integrations/BTKUI/BtkuiAddon_Utils.cs index 823d41f..241c793 100644 --- a/.Experimental/OriginShift/Integrations/BTKUI/BtkuiAddon_Utils.cs +++ b/.Experimental/OriginShift/Integrations/BTKUI/BtkuiAddon_Utils.cs @@ -1,7 +1,7 @@ using System.Reflection; -using BTKUILib; -using BTKUILib.UIObjects; -using BTKUILib.UIObjects.Components; +using ABI_RC.Systems.UI.UILib; +using ABI_RC.Systems.UI.UILib.UIObjects; +using ABI_RC.Systems.UI.UILib.UIObjects.Components; using MelonLoader; using UnityEngine; diff --git a/.Experimental/OriginShift/Integrations/ThirdPerson/ThirdPersonAddon.cs b/.Experimental/OriginShift/Integrations/ThirdPerson/ThirdPersonAddon.cs index baf92ee..1157400 100644 --- a/.Experimental/OriginShift/Integrations/ThirdPerson/ThirdPersonAddon.cs +++ b/.Experimental/OriginShift/Integrations/ThirdPerson/ThirdPersonAddon.cs @@ -28,6 +28,7 @@ public static class ThirdPersonAddon private static IEnumerator FixThirdPersonCompatibility() { + yield return null; // wait a frame for the camera to be setup yield return null; // wait a frame for the camera to be setup GameObject thirdPersonCameraObj = GameObject.Find("_PLAYERLOCAL/[CameraRigDesktop]/Camera/ThirdPersonCameraObj"); thirdPersonCameraObj.AddComponentIfMissing(); diff --git a/.Experimental/OriginShift/Main.cs b/.Experimental/OriginShift/Main.cs index eb617e0..b1a6462 100644 --- a/.Experimental/OriginShift/Main.cs +++ b/.Experimental/OriginShift/Main.cs @@ -1,13 +1,9 @@ #if !UNITY_EDITOR -using System.Globalization; -using ABI_RC.Core.UI; using ABI_RC.Core.Util.AssetFiltering; -using ABI_RC.Systems.Movement; using MelonLoader; using NAK.OriginShift.Components; using NAK.OriginShiftMod.Integrations; using OriginShift.Integrations; -using UnityEngine; namespace NAK.OriginShift; @@ -36,7 +32,6 @@ public class OriginShiftMod : MelonMod // Compatibility Mode ApplyPatches(typeof(Patches.PlayerSetupPatches)); // net ik, camera occlusion culling - ApplyPatches(typeof(Patches.Comms_ClientPatches)); // voice pos ApplyPatches(typeof(Patches.CVRSyncHelperPatches)); // spawnable pos ApplyPatches(typeof(Patches.PuppetMasterPatches)); // remote player pos ApplyPatches(typeof(Patches.CVRObjectSyncPatches)); // remote object pos diff --git a/.Experimental/OriginShift/Networking/ModNetwork.cs b/.Experimental/OriginShift/Networking/ModNetwork.cs index c9e6b52..0f0b4ae 100644 --- a/.Experimental/OriginShift/Networking/ModNetwork.cs +++ b/.Experimental/OriginShift/Networking/ModNetwork.cs @@ -26,7 +26,7 @@ // // #region Constants // -// private const string ModId = "MelonMod.NAK.RelativeSync"; +// private const string ModId = "MelonMod.NAK.RelativeSyncJitterFix"; // // #endregion // diff --git a/.Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftEventReceiver.cs b/.Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftEventReceiver.cs index 11fe6fc..325e317 100644 --- a/.Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftEventReceiver.cs +++ b/.Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftEventReceiver.cs @@ -1,11 +1,9 @@ using ABI.CCK.Components; -using JetBrains.Annotations; using UnityEngine; using UnityEngine.Events; #if !UNITY_EDITOR using ABI_RC.Core.Util; -using ABI_RC.Core.Util.AssetFiltering; #endif namespace NAK.OriginShift.Components; diff --git a/.Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftParticleSystemReceiver.cs b/.Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftParticleSystemReceiver.cs index c5f4c52..8474f11 100644 --- a/.Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftParticleSystemReceiver.cs +++ b/.Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftParticleSystemReceiver.cs @@ -18,7 +18,7 @@ public class OriginShiftParticleSystemReceiver : MonoBehaviour _particleSystems = GetComponentsInChildren(true); if (_particleSystems.Length == 0) { - OriginShiftMod.Logger.Error("OriginShiftParticleSystemReceiver: No ParticleSystems found on GameObject: " + gameObject.name, this); + // OriginShiftMod.Logger.Error("OriginShiftParticleSystemReceiver: No ParticleSystems found on GameObject: " + gameObject.name, this); enabled = false; } } diff --git a/.Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftRigidbodyReceiver.cs b/.Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftRigidbodyReceiver.cs index 7fdc939..0dd4a40 100644 --- a/.Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftRigidbodyReceiver.cs +++ b/.Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftRigidbodyReceiver.cs @@ -15,7 +15,7 @@ public class OriginShiftRigidbodyReceiver : MonoBehaviour _rigidbody = GetComponentInChildren(); if (_rigidbody == null) { - OriginShiftMod.Logger.Error("OriginShiftRigidbodyReceiver: No Rigidbody found on GameObject: " + gameObject.name, this); + // OriginShiftMod.Logger.Error("OriginShiftRigidbodyReceiver: No Rigidbody found on GameObject: " + gameObject.name, this); enabled = false; } } diff --git a/.Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftTrailRendererReceiver.cs b/.Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftTrailRendererReceiver.cs index 4c3b34d..ccc50b9 100644 --- a/.Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftTrailRendererReceiver.cs +++ b/.Experimental/OriginShift/OriginShift/Components/Receivers/OriginShiftTrailRendererReceiver.cs @@ -18,7 +18,7 @@ public class OriginShiftTrailRendererReceiver : MonoBehaviour _trailRenderers = GetComponentsInChildren(true); if (_trailRenderers.Length == 0) { - OriginShiftMod.Logger.Error("OriginShiftTrailRendererReceiver: No TrailRenderers found on GameObject: " + gameObject.name, this); + // OriginShiftMod.Logger.Error("OriginShiftTrailRendererReceiver: No TrailRenderers found on GameObject: " + gameObject.name, this); enabled = false; } } diff --git a/.Experimental/OriginShift/OriginShift/OriginShiftManager.cs b/.Experimental/OriginShift/OriginShift/OriginShiftManager.cs index 1c48b72..b47c932 100644 --- a/.Experimental/OriginShift/OriginShift/OriginShiftManager.cs +++ b/.Experimental/OriginShift/OriginShift/OriginShiftManager.cs @@ -1,4 +1,3 @@ -using System; using ABI_RC.Core.Base; using ABI_RC.Core.Player; using ABI.CCK.Components; diff --git a/.Experimental/OriginShift/OriginShift/Player/OriginShiftMonitor.cs b/.Experimental/OriginShift/OriginShift/Player/OriginShiftMonitor.cs index f2157a0..24d7829 100644 --- a/.Experimental/OriginShift/OriginShift/Player/OriginShiftMonitor.cs +++ b/.Experimental/OriginShift/OriginShift/Player/OriginShiftMonitor.cs @@ -1,5 +1,3 @@ -using System.Collections; -using ABI_RC.Core; using ABI_RC.Core.Player; using NAK.OriginShift.Components; using NAK.OriginShift.Extensions; diff --git a/.Experimental/OriginShift/Patches.cs b/.Experimental/OriginShift/Patches.cs index cd61791..36848a3 100644 --- a/.Experimental/OriginShift/Patches.cs +++ b/.Experimental/OriginShift/Patches.cs @@ -6,11 +6,9 @@ using ABI_RC.Core.Player; using ABI_RC.Core.Util; using ABI_RC.Systems.Camera; using ABI_RC.Systems.Communications.Networking; -using ABI_RC.Systems.GameEventSystem; using ABI_RC.Systems.Movement; using ABI.CCK.Components; using DarkRift; -using ECM2; using HarmonyLib; using NAK.OriginShift.Components; using NAK.OriginShift.Hacks; @@ -129,7 +127,7 @@ internal static class PortableCameraPatches [HarmonyPatch(typeof(PortableCamera), nameof(PortableCamera.Start))] private static void Postfix_PortableCamera_Start(ref PortableCamera __instance) { - __instance.cameraComponent.AddComponentIfMissing(); + __instance.CameraComponent.AddComponentIfMissing(); } } @@ -143,17 +141,6 @@ internal static class PathingCameraPatches } } -internal static class Comms_ClientPatches -{ - [HarmonyPrefix] - [HarmonyPatch(typeof(Comms_Client), nameof(Comms_Client.SetPosition))] - private static void Prefix_Comms_Client_GetPlayerMovementData(ref Vector3 listenerPosition) - { - if (OriginShiftManager.CompatibilityMode) // adjust root position back to absolute world position - listenerPosition = OriginShiftManager.GetAbsolutePosition(listenerPosition); - } -} - internal static class CVRSyncHelperPatches { [HarmonyPrefix] // outbound spawnable @@ -180,15 +167,11 @@ internal static class CVRSyncHelperPatches [HarmonyPrefix] // outbound spawn prop [HarmonyPatch(typeof(CVRSyncHelper), nameof(CVRSyncHelper.SpawnProp))] - private static void Prefix_CVRSyncHelper_SpawnProp(ref float posX, ref float posY, ref float posZ) + private static void Prefix_CVRSyncHelper_SpawnProp(ref Vector3 position) { if (OriginShiftManager.CompatibilityMode) // adjust root position back to absolute world position { - Vector3 position = new(posX, posY, posZ); // imagine not using Vector3 position = OriginShiftManager.GetAbsolutePosition(position); - posX = position.x; - posY = position.y; - posZ = position.z; } } diff --git a/.Experimental/OriginShift/Properties/AssemblyInfo.cs b/.Experimental/OriginShift/Properties/AssemblyInfo.cs index 696f343..5c6a924 100644 --- a/.Experimental/OriginShift/Properties/AssemblyInfo.cs +++ b/.Experimental/OriginShift/Properties/AssemblyInfo.cs @@ -18,7 +18,7 @@ using System.Reflection; downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/OriginShift" )] -[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonGame("ChilloutVR", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] [assembly: MelonColor(255, 125, 126, 129)] @@ -28,7 +28,7 @@ using System.Reflection; namespace NAK.OriginShift.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.0"; + public const string Version = "1.0.1"; public const string Author = "NotAKidoS"; } #endif \ No newline at end of file diff --git a/.Experimental/OriginShift/format.json b/.Experimental/OriginShift/format.json deleted file mode 100644 index 39d8c48..0000000 --- a/.Experimental/OriginShift/format.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "_id": 211, - "name": "RelativeSync", - "modversion": "1.0.3", - "gameversion": "2024r175", - "loaderversion": "0.6.1", - "modtype": "Mod", - "author": "NotAKidoS", - "description": "Relative sync for Movement Parent & Chairs. Requires both users to have the mod installed. Synced over Mod Network.\n\nProvides some Experimental settings to also fix local jitter on movement parents.", - "searchtags": [ - "relative", - "sync", - "movement", - "chair" - ], - "requirements": [ - "None" - ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r29/RelativeSync.dll", - "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/RelativeSync/", - "changelog": "- Enabled the Experimental settings to fix **local** jitter on Movement Parents by default\n- Adjusted BBCC No Interpolation fix to account for potential native fix (now respects initial value)", - "embedcolor": "#507e64" -} \ No newline at end of file diff --git a/ASTExtension/Properties/AssemblyInfo.cs b/ASTExtension/Properties/AssemblyInfo.cs index 2e4d7b4..427308d 100644 --- a/ASTExtension/Properties/AssemblyInfo.cs +++ b/ASTExtension/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.ASTExtension.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.4"; + public const string Version = "1.0.5"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/ASTExtension/format.json b/ASTExtension/format.json index abcdbfc..390aeac 100644 --- a/ASTExtension/format.json +++ b/ASTExtension/format.json @@ -1,8 +1,8 @@ { "_id": 223, "name": "ASTExtension", - "modversion": "1.0.4", - "gameversion": "2025r180", + "modversion": "1.0.5", + "gameversion": "2025r181", "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS", @@ -17,8 +17,8 @@ "requirements": [ "BTKUILib" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/ASTExtension.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/ASTExtension.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ASTExtension/", - "changelog": "- Fixes for 2025r180", + "changelog": "- Rebuilt for CVR 2025r181", "embedcolor": "#f61963" } \ No newline at end of file diff --git a/ConfigureCalibrationPose/Main.cs b/ConfigureCalibrationPose/Main.cs index df677fd..5445b42 100644 --- a/ConfigureCalibrationPose/Main.cs +++ b/ConfigureCalibrationPose/Main.cs @@ -2,7 +2,6 @@ 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; diff --git a/CustomSpawnPoint/Properties/AssemblyInfo.cs b/CustomSpawnPoint/Properties/AssemblyInfo.cs index d1887b3..e2cba0e 100644 --- a/CustomSpawnPoint/Properties/AssemblyInfo.cs +++ b/CustomSpawnPoint/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.CustomSpawnPoint.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.3"; + public const string Version = "1.0.4"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/CustomSpawnPoint/format.json b/CustomSpawnPoint/format.json index 52fe5e3..50bd5f5 100644 --- a/CustomSpawnPoint/format.json +++ b/CustomSpawnPoint/format.json @@ -1,8 +1,8 @@ { "_id": 228, "name": "CustomSpawnPoint", - "modversion": "1.0.3", - "gameversion": "2025r180", + "modversion": "1.0.4", + "gameversion": "2025r181", "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS", @@ -17,8 +17,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/CustomSpawnPoint.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/CustomSpawnPoint.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/CustomSpawnPoint/", - "changelog": "- Fixes for 2025r180", + "changelog": "- Rebuilt for CVR 2025r181", "embedcolor": "#f61963" } \ No newline at end of file diff --git a/DoubleTapJumpToExitSeat/Properties/AssemblyInfo.cs b/DoubleTapJumpToExitSeat/Properties/AssemblyInfo.cs index 2e85366..60b5c49 100644 --- a/DoubleTapJumpToExitSeat/Properties/AssemblyInfo.cs +++ b/DoubleTapJumpToExitSeat/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.DoubleTapJumpToExitSeat.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/DoubleTapJumpToExitSeat/format.json b/DoubleTapJumpToExitSeat/format.json index e14365c..c852d60 100644 --- a/DoubleTapJumpToExitSeat/format.json +++ b/DoubleTapJumpToExitSeat/format.json @@ -1,8 +1,8 @@ { "_id": 255, "name": "DoubleTapJumpToExitSeat", - "modversion": "1.0.1", - "gameversion": "2025r180", + "modversion": "1.0.2", + "gameversion": "2025r181", "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/DoubleTapJumpToExitSeat.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/DoubleTapJumpToExitSeat.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/DoubleTapJumpToExitSeat/", - "changelog": "- Fixes for 2025r180", + "changelog": "- Rebuilt for CVR 2025r181", "embedcolor": "#f61963" } \ No newline at end of file diff --git a/FuckToes/Properties/AssemblyInfo.cs b/FuckToes/Properties/AssemblyInfo.cs index c308a51..e7d0769 100644 --- a/FuckToes/Properties/AssemblyInfo.cs +++ b/FuckToes/Properties/AssemblyInfo.cs @@ -17,7 +17,7 @@ using System.Reflection; downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/FuckToes" )] -[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.FuckToes.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.4"; + public const string Version = "1.0.5"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/FuckToes/format.json b/FuckToes/format.json index c7c42ee..70cc874 100644 --- a/FuckToes/format.json +++ b/FuckToes/format.json @@ -1,9 +1,9 @@ { "_id": 129, "name": "FuckToes", - "modversion": "1.0.4", - "gameversion": "2025r179", - "loaderversion": "0.6.1", + "modversion": "1.0.5", + "gameversion": "2025r181", + "loaderversion": "0.7.2", "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](https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/FuckToes/README.md) for relevant imagery detailing the problem.", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/FuckToes.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/FuckToes.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/FuckToes/", - "changelog": "- Recompiled for 2025r179", + "changelog": "- Rebuilt for CVR 2025r181", "embedcolor": "#f61963" } \ No newline at end of file diff --git a/PathCamDisabler/Properties/AssemblyInfo.cs b/PathCamDisabler/Properties/AssemblyInfo.cs index 5dedc26..d9f7d9f 100644 --- a/PathCamDisabler/Properties/AssemblyInfo.cs +++ b/PathCamDisabler/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.PathCamDisabler.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.4"; + public const string Version = "1.0.5"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/PathCamDisabler/format.json b/PathCamDisabler/format.json index 44362ba..4dae81f 100644 --- a/PathCamDisabler/format.json +++ b/PathCamDisabler/format.json @@ -1,8 +1,8 @@ { "_id": 110, "name": "PathCamDisabler", - "modversion": "1.0.4", - "gameversion": "2025r180", + "modversion": "1.0.5", + "gameversion": "2025r181", "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/PathCamDisabler.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/PathCamDisabler.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/PathCamDisabler/", - "changelog": "- Fixes for 2025r180", + "changelog": "- Rebuilt for CVR 2025r181", "embedcolor": "#f61963" } \ No newline at end of file diff --git a/PortableCameraAdditions/HarmonyPatches.cs b/PortableCameraAdditions/HarmonyPatches.cs index 3478534..bbcc91d 100644 --- a/PortableCameraAdditions/HarmonyPatches.cs +++ b/PortableCameraAdditions/HarmonyPatches.cs @@ -16,7 +16,7 @@ internal class PortableCameraPatches } [HarmonyPostfix] - [HarmonyPatch(typeof(PortableCamera), nameof(PortableCamera.OnWorldLoaded))] + [HarmonyPatch(typeof(PortableCamera), nameof(PortableCamera.CopyRefCamValues))] private static void Postfix_PortableCamera_OnWorldLoaded(Camera refCamera) { VisualMods.CameraAdditions.Instance?.OnWorldLoaded(refCamera); diff --git a/PortableCameraAdditions/Properties/AssemblyInfo.cs b/PortableCameraAdditions/Properties/AssemblyInfo.cs index 841c286..f3cffe0 100644 --- a/PortableCameraAdditions/Properties/AssemblyInfo.cs +++ b/PortableCameraAdditions/Properties/AssemblyInfo.cs @@ -17,7 +17,7 @@ using System.Reflection; downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/PortableCameraAdditions" )] -[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.PortableCameraAdditions.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.6"; + public const string Version = "1.0.7"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/PortableCameraAdditions/VisualMods/CameraAdditions.cs b/PortableCameraAdditions/VisualMods/CameraAdditions.cs index 6a69e3f..d28e559 100644 --- a/PortableCameraAdditions/VisualMods/CameraAdditions.cs +++ b/PortableCameraAdditions/VisualMods/CameraAdditions.cs @@ -25,23 +25,23 @@ public class CameraAdditions { Instance = this; - __instance.@interface.AddAndGetHeader(null, typeof(CameraAdditions), "Additional Settings"); + __instance.@interface.AddAndGetHeader(null, nameof(CameraAdditions), "Additional Settings"); //Basic Settings PortableCameraSetting setting_CopyWorldNearClip = __instance.@interface.AddAndGetSetting(PortableCameraSettingType.Bool); setting_CopyWorldNearClip.BoolChanged = new Action(value => UpdateCameraSettingBool("CopyNearClip", value)); - setting_CopyWorldNearClip.SettingName = "CopyNearClip"; + setting_CopyWorldNearClip.SettingIdentifier = "CopyNearClip"; setting_CopyWorldNearClip.DisplayName = "Copy World Near Clip"; - setting_CopyWorldNearClip.OriginType = typeof(CameraAdditions); + setting_CopyWorldNearClip.OriginType = nameof(CameraAdditions); setting_CopyWorldNearClip.DefaultValue = true; setting_CopyWorldNearClip.Load(); PortableCameraSetting setting_CopyWorldFarClip = __instance.@interface.AddAndGetSetting(PortableCameraSettingType.Bool); setting_CopyWorldFarClip.BoolChanged = new Action(value => UpdateCameraSettingBool("CopyFarClip", value)); - setting_CopyWorldFarClip.SettingName = "CopyFarClip"; + setting_CopyWorldFarClip.SettingIdentifier = "CopyFarClip"; setting_CopyWorldFarClip.DisplayName = "Copy World Far Clip"; - setting_CopyWorldFarClip.OriginType = typeof(CameraAdditions); + setting_CopyWorldFarClip.OriginType = nameof(CameraAdditions); setting_CopyWorldFarClip.DefaultValue = true; setting_CopyWorldFarClip.Load(); @@ -49,10 +49,10 @@ public class CameraAdditions PortableCameraSetting setting_Orthographic = __instance.@interface.AddAndGetSetting(PortableCameraSettingType.Bool); setting_Orthographic.BoolChanged = new Action(value => UpdateCameraSettingBool("Orthographic", value)); - setting_Orthographic.SettingName = "Orthographic"; + setting_Orthographic.SettingIdentifier = "Orthographic"; setting_Orthographic.DisplayName = "Orthographic"; setting_Orthographic.isExpertSetting = true; - setting_Orthographic.OriginType = typeof(CameraAdditions); + setting_Orthographic.OriginType = nameof(CameraAdditions); setting_Orthographic.DefaultValue = false; setting_Orthographic.Load(); @@ -60,10 +60,10 @@ public class CameraAdditions setting_NearClip = __instance.@interface.AddAndGetSetting(PortableCameraSettingType.Float); setting_NearClip.FloatChanged = new Action(value => UpdateCameraSettingFloat("NearClip", value)); - setting_NearClip.SettingName = "NearClip"; + setting_NearClip.SettingIdentifier = "NearClip"; setting_NearClip.DisplayName = "Near Clip Plane"; setting_NearClip.isExpertSetting = true; - setting_NearClip.OriginType = typeof(CameraAdditions); + setting_NearClip.OriginType = nameof(CameraAdditions); setting_NearClip.DefaultValue = 0.01f; setting_NearClip.MinValue = 0.001f; setting_NearClip.MaxValue = 5000f; @@ -71,10 +71,10 @@ public class CameraAdditions setting_FarClip = __instance.@interface.AddAndGetSetting(PortableCameraSettingType.Float); setting_FarClip.FloatChanged = new Action(value => UpdateCameraSettingFloat("FarClip", value)); - setting_FarClip.SettingName = "FarClip"; + setting_FarClip.SettingIdentifier = "FarClip"; setting_FarClip.DisplayName = "Far Clip Plane"; setting_FarClip.isExpertSetting = true; - setting_FarClip.OriginType = typeof(CameraAdditions); + setting_FarClip.OriginType = nameof(CameraAdditions); setting_FarClip.DefaultValue = 1000f; setting_FarClip.MinValue = 0.002f; setting_FarClip.MaxValue = 5000f; @@ -84,10 +84,10 @@ public class CameraAdditions setting_OrthographicSize = __instance.@interface.AddAndGetSetting(PortableCameraSettingType.Float); setting_OrthographicSize.FloatChanged = new Action(value => UpdateCameraSettingFloat("OrthographicSize", value)); - setting_OrthographicSize.SettingName = "OrthographicSize"; + setting_OrthographicSize.SettingIdentifier = "OrthographicSize"; setting_OrthographicSize.DisplayName = "Orthographic Size"; setting_OrthographicSize.isExpertSetting = true; - setting_OrthographicSize.OriginType = typeof(CameraAdditions); + setting_OrthographicSize.OriginType = nameof(CameraAdditions); setting_OrthographicSize.DefaultValue = 5f; setting_OrthographicSize.MinValue = 0.01f; setting_OrthographicSize.MaxValue = 150f; @@ -95,10 +95,10 @@ public class CameraAdditions setting_OrthographicNearClip = __instance.@interface.AddAndGetSetting(PortableCameraSettingType.Float); setting_OrthographicNearClip.FloatChanged = new Action(value => UpdateCameraSettingFloat("OrthographicNearClip", value)); - setting_OrthographicNearClip.SettingName = "OrthographicNearClip"; + setting_OrthographicNearClip.SettingIdentifier = "OrthographicNearClip"; setting_OrthographicNearClip.DisplayName = "Orthographic Near"; setting_OrthographicNearClip.isExpertSetting = true; - setting_OrthographicNearClip.OriginType = typeof(CameraAdditions); + setting_OrthographicNearClip.OriginType = nameof(CameraAdditions); setting_OrthographicNearClip.DefaultValue = 0.001f; setting_OrthographicNearClip.MinValue = -5000f; setting_OrthographicNearClip.MaxValue = 5000f; @@ -106,10 +106,10 @@ public class CameraAdditions setting_OrthographicFarClip = __instance.@interface.AddAndGetSetting(PortableCameraSettingType.Float); setting_OrthographicFarClip.FloatChanged = new Action(value => UpdateCameraSettingFloat("OrthographicFarClip", value)); - setting_OrthographicFarClip.SettingName = "OrthographicFarClip"; + setting_OrthographicFarClip.SettingIdentifier = "OrthographicFarClip"; setting_OrthographicFarClip.DisplayName = "Orthographic Far"; setting_OrthographicFarClip.isExpertSetting = true; - setting_OrthographicFarClip.OriginType = typeof(CameraAdditions); + setting_OrthographicFarClip.OriginType = nameof(CameraAdditions); setting_OrthographicFarClip.DefaultValue = 1000f; setting_OrthographicFarClip.MinValue = -5000f; setting_OrthographicFarClip.MaxValue = 5000f; @@ -147,7 +147,7 @@ public class CameraAdditions private void UpdateOrthographicMode() { if (PortableCamera.Instance != null) - PortableCamera.Instance.cameraComponent.orthographic = orthographicMode; + PortableCamera.Instance.CameraComponent.orthographic = orthographicMode; if (orthographicMode) { @@ -198,23 +198,23 @@ public class CameraAdditions //Camera Settings case "NearClip": if (!orthographicMode) - PortableCamera.Instance.cameraComponent.nearClipPlane = value; + PortableCamera.Instance.CameraComponent.nearClipPlane = value; break; case "FarClip": if (!orthographicMode) - PortableCamera.Instance.cameraComponent.farClipPlane = value; + PortableCamera.Instance.CameraComponent.farClipPlane = value; break; //Orthographic Mode case "OrthographicSize": - PortableCamera.Instance.cameraComponent.orthographicSize = value; + PortableCamera.Instance.CameraComponent.orthographicSize = value; break; case "OrthographicNearClip": if (orthographicMode) - PortableCamera.Instance.cameraComponent.nearClipPlane = value; + PortableCamera.Instance.CameraComponent.nearClipPlane = value; break; case "OrthographicFarClip": if (orthographicMode) - PortableCamera.Instance.cameraComponent.farClipPlane = value; + PortableCamera.Instance.CameraComponent.farClipPlane = value; break; } } diff --git a/PortableCameraAdditions/format.json b/PortableCameraAdditions/format.json index 957110c..ced7642 100644 --- a/PortableCameraAdditions/format.json +++ b/PortableCameraAdditions/format.json @@ -1,9 +1,9 @@ { "_id": 123, "name": "PortableCameraAdditions", - "modversion": "1.0.6", - "gameversion": "2025r179", - "loaderversion": "0.6.1", + "modversion": "1.0.7", + "gameversion": "2025r181", + "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS", "description": "Adds a few basic settings to the Portable Camera.\n\nExpert settings for Near Clip & Far Clip.\nExpert settings for Orthographic & Orthographic Size.\nBy default, Near Clip & Far Clip are copied on world load.", @@ -18,8 +18,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/PortableCameraAdditions.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/PortableCameraAdditions.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/PortableCameraAdditions/", - "changelog": "- Recompiled for 2025r179", - "embedcolor": "#ffd96a" + "changelog": "- Rebuilt for CVR 2025r181", + "embedcolor": "#f61963" } \ No newline at end of file diff --git a/PropLoadingHexagon/Main.cs b/PropLoadingHexagon/Main.cs index eac818f..73ea303 100644 --- a/PropLoadingHexagon/Main.cs +++ b/PropLoadingHexagon/Main.cs @@ -244,7 +244,7 @@ public class PropLoadingHexagonMod : MelonMod loadingObject = Object.Instantiate(loadingHexPrefab, Vector3.zero, Quaternion.identity, loadingHexContainer.transform); loadingHexComponent = loadingObject.GetComponent(); - float avatarHeight = PlayerSetup.Instance._avatarHeight; + float avatarHeight = PlayerSetup.Instance.AvatarHeight; Transform hexTransform = loadingObject.transform; hexTransform.localScale = Vector3.one * avatarHeight / 4f; // scale modifier hexTransform.GetChild(0).position = Vector3.up * avatarHeight / 2f; // position modifier diff --git a/PropLoadingHexagon/PropLoadingHexagon.csproj b/PropLoadingHexagon/PropLoadingHexagon.csproj index dd11616..d5ff139 100644 --- a/PropLoadingHexagon/PropLoadingHexagon.csproj +++ b/PropLoadingHexagon/PropLoadingHexagon.csproj @@ -2,7 +2,7 @@ net48 - PropSpawnTweaks + PropLoadingHexagon diff --git a/PropLoadingHexagon/Properties/AssemblyInfo.cs b/PropLoadingHexagon/Properties/AssemblyInfo.cs index 35e50f1..c1f4ed9 100644 --- a/PropLoadingHexagon/Properties/AssemblyInfo.cs +++ b/PropLoadingHexagon/Properties/AssemblyInfo.cs @@ -17,7 +17,7 @@ using System.Reflection; downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/PropLoadingHexagon" )] -[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.PropLoadingHexagon.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.1"; + public const string Version = "1.0.2"; public const string Author = "Exterrata & NotAKidoS"; } \ No newline at end of file diff --git a/PropLoadingHexagon/format.json b/PropLoadingHexagon/format.json index 4d12613..4e0935c 100644 --- a/PropLoadingHexagon/format.json +++ b/PropLoadingHexagon/format.json @@ -1,9 +1,9 @@ { "_id": 220, "name": "PropLoadingHexagon", - "modversion": "1.0.1", - "gameversion": "2025r179", - "loaderversion": "0.6.1", + "modversion": "1.0.2", + "gameversion": "2025r181", + "loaderversion": "0.7.2", "modtype": "Mod", "author": "Exterrata & NotAKidoS", "description": "Adds a hexagon indicator to downloading props. Indicator is styled to look similar to Portals.\n\nCan use Delete Mode on loading hexagons to cancel stuck downloads. Setting is provided to display the hexagon for Blocked/Filtered props.", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/PropLoadingHexagon.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/PropLoadingHexagon.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/PropLoadingHexagon/", - "changelog": "- Fixes for 2025r179", + "changelog": "- Rebuilt for CVR 2025r181", "embedcolor": "#f61963" } \ No newline at end of file diff --git a/PropUndoButton/Main.cs b/PropUndoButton/Main.cs index c3c6337..2e7b4a9 100644 --- a/PropUndoButton/Main.cs +++ b/PropUndoButton/Main.cs @@ -1,6 +1,7 @@ using System.Reflection; using ABI_RC.Core.AudioEffects; using ABI_RC.Core.Networking; +using ABI_RC.Core.Networking.GameServer; using ABI_RC.Core.Savior; using ABI_RC.Core.Util; using ABI_RC.Systems.InputManagement.InputModules; @@ -35,11 +36,16 @@ public class PropUndoButton : MelonMod private const string sfx_warn = "PropUndo_sfx_warn"; private const string sfx_deny = "PropUndo_sfx_deny"; - private const int redoHistoryLimit = 20; // amount that can be in history at once + private static int maxPropsPerUser = 20; + + // Amount that can be in history at once. + private static readonly int redoHistoryLimit = Mathf.Max(maxPropsPerUser, CVRSyncHelper.MyPropCount); private const int redoTimeoutLimit = 120; // seconds public override void OnInitializeMelon() { + GSInfoHandler.OnGSInfoUpdate += OnGSInfoUpdate; + HarmonyInstance.Patch( // delete my props in reverse order for redo typeof(CVRSyncHelper).GetMethod(nameof(CVRSyncHelper.DeleteMyProps)), new HarmonyMethod(typeof(PropUndoButton).GetMethod(nameof(OnDeleteMyProps), @@ -61,7 +67,7 @@ public class PropUndoButton : MelonMod BindingFlags.NonPublic | BindingFlags.Static)) ); HarmonyInstance.Patch( // desktop input patch so we don't run in menus/gui - typeof(CVRInputModule_Keyboard).GetMethod(nameof(CVRInputModule_Keyboard.UpdateInput)), + typeof(CVRInputModule_Keyboard).GetMethod(nameof(CVRInputModule_Keyboard.Update_Binds)), postfix: new HarmonyMethod(typeof(PropUndoButton).GetMethod(nameof(OnUpdateInput), BindingFlags.NonPublic | BindingFlags.Static)) ); @@ -73,7 +79,7 @@ public class PropUndoButton : MelonMod SetupDefaultAudioClips(); } - + private void SetupDefaultAudioClips() { // PropUndo and audio folders do not exist, create them if dont exist yet @@ -111,6 +117,12 @@ public class PropUndoButton : MelonMod } } + private void OnGSInfoUpdate(GSInfoUpdate update, GSInfoChanged changed) + { + if (changed == GSInfoChanged.MaxPropsPerUser) + maxPropsPerUser = update.MaxPropsPerUser; + } + private static void OnWorldLoad() { deletedProps.Clear(); @@ -296,9 +308,9 @@ public class PropUndoButton : MelonMod && NetworkManager.Instance.GameNetwork.ConnectionState == ConnectionState.Connected; } - public static bool IsAtPropLimit(int limit = 21) + public static bool IsAtPropLimit() { - return GetAllPropsByOwnerId().Count >= limit; + return GetAllPropsByOwnerId().Count >= maxPropsPerUser; } private static CVRSyncHelper.PropData GetPropByInstanceIdAndOwnerId(string instanceId) diff --git a/PropUndoButton/Properties/AssemblyInfo.cs b/PropUndoButton/Properties/AssemblyInfo.cs index 3849345..ec7d524 100644 --- a/PropUndoButton/Properties/AssemblyInfo.cs +++ b/PropUndoButton/Properties/AssemblyInfo.cs @@ -14,7 +14,7 @@ using System.Reflection; nameof(NAK.PropUndoButton), AssemblyInfoParams.Version, AssemblyInfoParams.Author, - downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/UndoPropButton" + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/PropUndoButton" )] [assembly: MelonGame("ChilloutVR", "ChilloutVR")] @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.PropUndoButton.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.4"; + public const string Version = "1.0.5"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/PropUndoButton/format.json b/PropUndoButton/format.json index 721593d..a4f803e 100644 --- a/PropUndoButton/format.json +++ b/PropUndoButton/format.json @@ -1,8 +1,8 @@ { "_id": 147, "name": "PropUndoButton", - "modversion": "1.0.4", - "gameversion": "2025r180", + "modversion": "1.0.5", + "gameversion": "2025r181", "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/PropUndoButton.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/PropUndoButton.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/PropUndoButton/", - "changelog": "- Fixes for 2025r180", - "embedcolor": "#00FFFF" + "changelog": "- Rebuilt for CVR 2025r181\n- Implemented logic to handle server-side change of prop spawn limits", + "embedcolor": "#f61963" } \ No newline at end of file diff --git a/RCCVirtualSteeringWheel/Properties/AssemblyInfo.cs b/RCCVirtualSteeringWheel/Properties/AssemblyInfo.cs index 03e9324..08d3cc9 100644 --- a/RCCVirtualSteeringWheel/Properties/AssemblyInfo.cs +++ b/RCCVirtualSteeringWheel/Properties/AssemblyInfo.cs @@ -28,6 +28,6 @@ using NAK.RCCVirtualSteeringWheel.Properties; namespace NAK.RCCVirtualSteeringWheel.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.6"; + public const string Version = "1.0.7"; 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 91495dd..adcf951 100644 --- a/RCCVirtualSteeringWheel/RCCVirtualSteeringWheel/Components/SteeringWheelPickup.cs +++ b/RCCVirtualSteeringWheel/RCCVirtualSteeringWheel/Components/SteeringWheelPickup.cs @@ -17,6 +17,7 @@ public class SteeringWheelPickup : Pickupable public override bool IsAutoHold => false; public override bool IsObjectRotationAllowed => false; public override bool IsObjectPushPullAllowed => false; + public override bool IsTelepathicGrabAllowed => false; public override bool IsObjectUseAllowed => false; public override bool CanPickup => IsPickupable && !IsPickedUp && MetaPort.Instance.isUsingVr; diff --git a/RCCVirtualSteeringWheel/format.json b/RCCVirtualSteeringWheel/format.json index 78825b0..f15b55d 100644 --- a/RCCVirtualSteeringWheel/format.json +++ b/RCCVirtualSteeringWheel/format.json @@ -1,8 +1,8 @@ { "_id": 248, "name": "RCCVirtualSteeringWheel", - "modversion": "1.0.6", - "gameversion": "2025r180", + "modversion": "1.0.7", + "gameversion": "2025r181", "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/RCCVirtualSteeringWheel.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/RCCVirtualSteeringWheel.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/RCCVirtualSteeringWheel/", - "changelog": "- Fixes for 2025r180", + "changelog": "- Rebuilt for CVR 2025r181", "embedcolor": "#f61963" } \ No newline at end of file diff --git a/RelativeSyncJitterFix/Properties/AssemblyInfo.cs b/RelativeSyncJitterFix/Properties/AssemblyInfo.cs index ff4fcd8..e07ef4e 100644 --- a/RelativeSyncJitterFix/Properties/AssemblyInfo.cs +++ b/RelativeSyncJitterFix/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.RelativeSyncJitterFix.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/RelativeSyncJitterFix/format.json b/RelativeSyncJitterFix/format.json index b128e2a..7397421 100644 --- a/RelativeSyncJitterFix/format.json +++ b/RelativeSyncJitterFix/format.json @@ -1,12 +1,12 @@ { - "_id": -1, + "_id": 263, "name": "RelativeSyncJitterFix", - "modversion": "1.0.0", - "gameversion": "2025r180", + "modversion": "1.0.1", + "gameversion": "2025r181", "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.", + "description": "Relative sync jitter fix is the single harmony patch that could not make it into the native release of RelativeSync.\n\nChanges when props apply their incoming sync data to be before the character controller simulation.", "searchtags": [ "relative", "sync", @@ -16,7 +16,7 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/RelativeSyncJitterFix.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/RelativeSyncJitterFix.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/RelativeSyncJitterFix/", "changelog": "- Removed RelativeSync except for a single harmony patch", "embedcolor": "#f61963" diff --git a/ScrollFlight/Properties/AssemblyInfo.cs b/ScrollFlight/Properties/AssemblyInfo.cs index 22630c9..acf8416 100644 --- a/ScrollFlight/Properties/AssemblyInfo.cs +++ b/ScrollFlight/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.ScrollFlight.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.4"; + public const string Version = "1.0.5"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/ScrollFlight/format.json b/ScrollFlight/format.json index 486ad34..4dfdc9d 100644 --- a/ScrollFlight/format.json +++ b/ScrollFlight/format.json @@ -1,8 +1,8 @@ { "_id": 219, "name": "ScrollFlight", - "modversion": "1.0.4", - "gameversion": "2025r180", + "modversion": "1.0.5", + "gameversion": "2025r181", "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/ScrollFlight.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/ScrollFlight.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ScrollFlight/", - "changelog": "- Fixes for 2025r180", + "changelog": "- Rebuilt for CVR 2025r181", "embedcolor": "#f61963" } \ No newline at end of file diff --git a/ShareBubbles/Properties/AssemblyInfo.cs b/ShareBubbles/Properties/AssemblyInfo.cs index 13d5a60..90123a3 100644 --- a/ShareBubbles/Properties/AssemblyInfo.cs +++ b/ShareBubbles/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using NAK.ShareBubbles.Properties; namespace NAK.ShareBubbles.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.1.6"; - public const string Author = "NotAKidoS, Exterrata, Noachi, RaidShadowLily, Tejler"; + public const string Version = "1.1.7"; + public const string Author = "NotAKidoS, Exterrata, Noachi, RaidShadowLily, Tejler, Luc"; } \ No newline at end of file diff --git a/ShareBubbles/format.json b/ShareBubbles/format.json index 4c07d5d..0a434c3 100644 --- a/ShareBubbles/format.json +++ b/ShareBubbles/format.json @@ -1,8 +1,8 @@ { "_id": 244, "name": "ShareBubbles", - "modversion": "1.1.6", - "gameversion": "2025r180", + "modversion": "1.1.7", + "gameversion": "2025r181", "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS, Exterrata, Noachi, RaidShadowLily, Tejler, Luc", @@ -17,8 +17,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/ShareBubbles.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/ShareBubbles.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ShareBubbles/", - "changelog": "- Fixes for 2025r180", + "changelog": "- Updated for CVR 2025r181", "embedcolor": "#f61963" } \ No newline at end of file diff --git a/ShowPlayerInSelfMirror/Main.cs b/ShowPlayerInSelfMirror/Main.cs new file mode 100644 index 0000000..6c54d51 --- /dev/null +++ b/ShowPlayerInSelfMirror/Main.cs @@ -0,0 +1,154 @@ +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using ABI_RC.Systems.ContentClones; +using ABI_RC.Systems.GameEventSystem; +using ABI_RC.Systems.UI.UILib; +using ABI_RC.Systems.UI.UILib.UIObjects; +using ABI_RC.Systems.UI.UILib.UIObjects.Components; +using ABI.CCK.Components; +using MelonLoader; + +namespace NAK.ShowPlayerInSelfMirror; + +public class ShowPlayerInSelfMirrorMod : MelonMod +{ + public override void OnInitializeMelon() + { + PlayerPlayerMirror.Initialize(); + } +} + +/// +/// Manages adding/removing player clones to/from the personal mirror via the Player Select Page. +/// +public static class PlayerPlayerMirror +{ + private static readonly Dictionary _clonedPlayers = new(); + + private static Category _ourCategory; + private static ToggleButton _toggle; + + public static void Initialize() + { + _ourCategory = QuickMenuAPI.PlayerSelectPage.AddCategory("Show Player In Self Mirror"); + _toggle = _ourCategory.AddToggle( + "Add To Self Mirrors", + "Should this player be shown in your self mirrors?", + false + ); + + _toggle.OnValueUpdated += OnToggleChanged; + QuickMenuAPI.OnPlayerSelected += OnPlayerSelected; + + CVRGameEventSystem.Avatar.OnRemoteAvatarClear.AddListener(OnRemoteAvatarCleared); + CVRGameEventSystem.Avatar.OnRemoteAvatarLoad.AddListener(OnRemoteAvatarLoad); + CVRGameEventSystem.Player.OnLeaveEntity.AddListener(OnRemotePlayerLeave); + } + + private static void OnToggleChanged(bool value) + { + string playerId = QuickMenuAPI.SelectedPlayerID; + if (string.IsNullOrEmpty(playerId)) + return; + + if (value) + { + if (!_clonedPlayers.TryAdd(playerId, null)) + return; + + if (CVRPlayerManager.Instance.TryGetPlayerBase(playerId, out PlayerBase player)) + { + if (!TryCreateClone(playerId, player)) + { + _clonedPlayers.Remove(playerId); + _toggle.ToggleValue = false; + } + } + } + else + { + RemoveAndForgetClone(playerId); + } + } + + private static void OnPlayerSelected(object _, string playerId) + { + // If this is us, hide the category entirely + if (playerId == MetaPort.Instance.ownerId) + { + _ourCategory.Hidden = true; + return; + } + + // Show the category for other players + _ourCategory.Hidden = false; + + bool enabled = _clonedPlayers.ContainsKey(playerId); + _toggle.ToggleValue = enabled; + } + + private static void OnRemoteAvatarCleared(CVRPlayerEntity playerEntity, CVRAvatar _) + { + string playerId = playerEntity.Uuid; + + if (!_clonedPlayers.TryGetValue(playerId, out ContentCloneManager.CloneData clone)) + return; + + if (clone != null) + { + ContentCloneManager.DestroyClone(clone); + _clonedPlayers[playerId] = null; + } + } + + private static void OnRemoteAvatarLoad(CVRPlayerEntity playerEntity, CVRAvatar _) + { + string playerId = playerEntity.Uuid; + + if (!_clonedPlayers.ContainsKey(playerId)) + return; + + if (!CVRPlayerManager.Instance.TryGetPlayerBase(playerId, out PlayerBase player)) + return; + + TryCreateClone(playerId, player); + } + + private static void OnRemotePlayerLeave(CVRPlayerEntity playerEntity) + { + string playerId = playerEntity.Uuid; + RemoveAndForgetClone(playerId); + } + + private static bool TryCreateClone(string playerId, PlayerBase player) + { + if (!player.AvatarObject) + return false; + + if (_clonedPlayers.TryGetValue(playerId, out ContentCloneManager.CloneData existing) + && existing is { IsDestroyed: false }) + return true; + + ContentCloneManager.CloneData clone = ContentCloneManager.CreateClone( + player.AvatarObject, + ContentCloneManager.CloneOptions.ExtensionOfPlayer + ); + + if (clone == null) + return false; + + _clonedPlayers[playerId] = clone; + return true; + } + + private static void RemoveAndForgetClone(string playerId) + { + if (_clonedPlayers.TryGetValue(playerId, out ContentCloneManager.CloneData clone)) + { + if (clone != null) + ContentCloneManager.DestroyClone(clone); + } + + _clonedPlayers.Remove(playerId); + } +} \ No newline at end of file diff --git a/ShowPlayerInSelfMirror/Properties/AssemblyInfo.cs b/ShowPlayerInSelfMirror/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..b9d5c4c --- /dev/null +++ b/ShowPlayerInSelfMirror/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using MelonLoader; +using NAK.ShowPlayerInSelfMirror.Properties; +using System.Reflection; + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.ShowPlayerInSelfMirror))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.ShowPlayerInSelfMirror))] + +[assembly: MelonInfo( + typeof(NAK.ShowPlayerInSelfMirror.ShowPlayerInSelfMirrorMod), + nameof(NAK.ShowPlayerInSelfMirror), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ShowPlayerInSelfMirror" +)] + +[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.ShowPlayerInSelfMirror.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/ShowPlayerInSelfMirror/README.md b/ShowPlayerInSelfMirror/README.md new file mode 100644 index 0000000..3c85033 --- /dev/null +++ b/ShowPlayerInSelfMirror/README.md @@ -0,0 +1,16 @@ +# ShowPlayerInSelfMirror + +Adds an option in the Quick Menu selected player page to show the target player's avatar in your self mirror. + +Probably useful for only showing specific people in your mirror while in a puddle of many. + +--- + +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/ShowPlayerInSelfMirror/ShowPlayerInSelfMirror.csproj b/ShowPlayerInSelfMirror/ShowPlayerInSelfMirror.csproj new file mode 100644 index 0000000..14fc5af --- /dev/null +++ b/ShowPlayerInSelfMirror/ShowPlayerInSelfMirror.csproj @@ -0,0 +1,9 @@ + + + + PlayerCloneAttachment + + + + + diff --git a/ShowPlayerInSelfMirror/format.json b/ShowPlayerInSelfMirror/format.json new file mode 100644 index 0000000..ab4bb75 --- /dev/null +++ b/ShowPlayerInSelfMirror/format.json @@ -0,0 +1,23 @@ +{ + "_id": -1, + "name": "ShowPlayerInSelfMirror", + "modversion": "1.0.0", + "gameversion": "2025r181", + "loaderversion": "0.7.2", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "Adds an option in the Quick Menu selected player page to show the target player's avatar in your self mirror.\n\nProbably useful for only showing specific people in your mirror while in a puddle of many.", + "searchtags": [ + "player", + "mirror", + "clone", + "show" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/ShowPlayerInSelfMirror.dll", + "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ShowPlayerInSelfMirror/", + "changelog": "- Initial release", + "embedcolor": "#f61963" +} \ No newline at end of file diff --git a/SmootherRay/Main.cs b/SmootherRay/Main.cs index 1d6d3f4..978740b 100644 --- a/SmootherRay/Main.cs +++ b/SmootherRay/Main.cs @@ -1,5 +1,4 @@ -using System; -using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.InteractionSystem; using ABI_RC.Core.Player; using HarmonyLib; using MelonLoader; diff --git a/SmootherRay/Properties/AssemblyInfo.cs b/SmootherRay/Properties/AssemblyInfo.cs index c47196d..02bd78f 100644 --- a/SmootherRay/Properties/AssemblyInfo.cs +++ b/SmootherRay/Properties/AssemblyInfo.cs @@ -17,7 +17,7 @@ using System.Reflection; downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/SmootherRay" )] -[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.SmootherRay.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.7"; + public const string Version = "1.0.8"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/SmootherRay/SmootherRayer.cs b/SmootherRay/SmootherRayer.cs index 6262824..7448b75 100644 --- a/SmootherRay/SmootherRayer.cs +++ b/SmootherRay/SmootherRayer.cs @@ -142,14 +142,12 @@ public class SmootherRayer : MonoBehaviour if (!_isEnabled) return; // only care about setting being enabled - ray._enableSmoothRay = false; // ensure built-in smoothing is disabled - if (MetaPort.Instance.settings.GetSettingsBool("ControlSmoothRaycast")) return; // disable saved setting once SmootherRayMod.Logger.Msg("Built-in SmootherRay setting found to be enabled. Disabling built-in SmootherRay implementation in favor of modded implementation."); MetaPort.Instance.settings.SetSettingsBool("ControlSmoothRaycast", false); - ViewManager.SetGameSettingBool("ControlSmoothRaycast", false); + // ViewManager.SetGameSettingBool("ControlSmoothRaycast", false); // ^ did you know the game doesn't even use this method native... } diff --git a/SmootherRay/format.json b/SmootherRay/format.json index 5e49dd0..1f89397 100644 --- a/SmootherRay/format.json +++ b/SmootherRay/format.json @@ -1,9 +1,9 @@ { "_id": 162, "name": "SmootherRay", - "modversion": "1.0.6", - "gameversion": "2025r177", - "loaderversion": "0.6.1", + "modversion": "1.0.8", + "gameversion": "2025r181", + "loaderversion": "0.7.2", "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\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.", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/SmootherRay.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/SmootherRay.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/SmootherRay/", - "changelog": "- Fixes for 2025r179", + "changelog": "- Rebuilt for CVR 2025r181", "embedcolor": "#f61963" } \ No newline at end of file diff --git a/Stickers/Integrations/BTKUI/UIAddon.Category.StickersMod.cs b/Stickers/Integrations/BTKUI/UIAddon.Category.StickersMod.cs index 0e9c0c6..b1c2097 100644 --- a/Stickers/Integrations/BTKUI/UIAddon.Category.StickersMod.cs +++ b/Stickers/Integrations/BTKUI/UIAddon.Category.StickersMod.cs @@ -96,6 +96,9 @@ public static partial class BTKUIAddon public static void OnStickerRestrictionUpdated(bool isRestricted = false) //TODO: add Icon changing, Bono needs to expose the value first. { + if (_rootPage == null || _placeStickersButton == null) + return; + if (isRestricted) { _rootPage.MenuSubtitle = "Stickers... are sadly disabled in this world."; diff --git a/Stickers/Integrations/BTKUI/UIAddon.Main.cs b/Stickers/Integrations/BTKUI/UIAddon.Main.cs index 327949b..fe2a4d7 100644 --- a/Stickers/Integrations/BTKUI/UIAddon.Main.cs +++ b/Stickers/Integrations/BTKUI/UIAddon.Main.cs @@ -3,7 +3,6 @@ using BTKUILib.UIObjects; using NAK.Stickers.Networking; using NAK.Stickers.Utilities; using System.Reflection; -using System.Runtime.InteropServices; namespace NAK.Stickers.Integrations; @@ -50,10 +49,10 @@ public static partial class BTKUIAddon { _rootPage = new Page(ModSettings.ModName, ModSettings.SM_SettingsCategory, true, "Stickers-Puzzle") // sticker icon will be left blank as it is updated on world join, AFTER Icon value is exposed.. { - MenuTitle = ModSettings.SM_SettingsCategory, + MenuTitle = ModSettings.SM_SettingsCategory + $" (Network Version v{ModNetwork.NetworkVersion})", MenuSubtitle = "", // left this blank as it is defined when the world loads }; - + _rootPageElementID = _rootPage.ElementID; QuickMenuAPI.OnTabChange += OnTabChange; diff --git a/Stickers/Integrations/BTKUI/UIAddon.Page.StickerSelect.cs b/Stickers/Integrations/BTKUI/UIAddon.Page.StickerSelect.cs index c36c8cb..c2798d4 100644 --- a/Stickers/Integrations/BTKUI/UIAddon.Page.StickerSelect.cs +++ b/Stickers/Integrations/BTKUI/UIAddon.Page.StickerSelect.cs @@ -1,5 +1,4 @@ -using System.Diagnostics; -using BTKUILib; +using BTKUILib; using BTKUILib.UIObjects; using BTKUILib.UIObjects.Components; using MTJobSystem; diff --git a/Stickers/Main.cs b/Stickers/Main.cs index 1234f10..ebf005c 100644 --- a/Stickers/Main.cs +++ b/Stickers/Main.cs @@ -1,7 +1,5 @@ -using ABI_RC.Core; -using ABI_RC.Core.InteractionSystem; -using ABI_RC.Core.Player; -using ABI_RC.Core.Savior; +using ABI_RC.Core.Player; +using ABI_RC.Core.UI.UIRework.Managers; using ABI_RC.Systems.InputManagement; using MelonLoader; using NAK.Stickers.Integrations; @@ -55,8 +53,8 @@ public class StickerMod : MelonMod if (!Input.GetKeyDown((KeyCode)ModSettings.Entry_PlaceBinding.Value)) return; - if (CVRInputManager.Instance.textInputFocused - || ViewManager.Instance.textInputFocused) // BRUH + if (CVRInputManager.Instance.EventSystemOverwritten + || KeyboardManager.Instance.IsViewShown) // BRUH return; // prevent placing stickers while typing StickerSystem.Instance.PlaceStickerFromControllerRay(PlayerSetup.Instance.activeCam.transform); diff --git a/Stickers/ModSettings.cs b/Stickers/ModSettings.cs index 0ea6971..a8b637f 100644 --- a/Stickers/ModSettings.cs +++ b/Stickers/ModSettings.cs @@ -59,6 +59,12 @@ public static class ModSettings internal static readonly MelonPreferences_Entry Entry_FriendsOnly = Category.CreateEntry("friends_only", false, "Friends Only", "Only allow friends to use stickers."); + internal static readonly MelonPreferences_Entry Entry_StickerSize = + Category.CreateEntry("sticker_size", StickerSize.Chonk, "Sticker Size", "The size of the sticker when placed."); + + internal static readonly MelonPreferences_Entry Entry_StickerOpacity = + Category.CreateEntry("opacity", 1f, "Opacity", "The opacity of the sticker when placed."); + #endregion Stickers Mod Settings #region Debug Settings diff --git a/Stickers/Properties/AssemblyInfo.cs b/Stickers/Properties/AssemblyInfo.cs index db9f15b..e7e3e30 100644 --- a/Stickers/Properties/AssemblyInfo.cs +++ b/Stickers/Properties/AssemblyInfo.cs @@ -17,7 +17,7 @@ using System.Reflection; downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/Stickers" )] -[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.Stickers.Properties; internal static class AssemblyInfoParams { - public const string Version = "1.0.9"; - public const string Author = "NotAKidoS, SketchFoxsky"; + public const string Version = "1.1.1"; + public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/Stickers/Stickers/Enums/StickerSize.cs b/Stickers/Stickers/Enums/StickerSize.cs new file mode 100644 index 0000000..9ab8138 --- /dev/null +++ b/Stickers/Stickers/Enums/StickerSize.cs @@ -0,0 +1,34 @@ +namespace NAK.Stickers; + +public enum StickerSize +{ + Jarret, + Bean, + Smol, + ChonkLite, + Chonk, // Default (was Medium) + HeckinChonk, + DoubleHeckinChonk, + TripleCursedUnit, + RealityTearingAbomination, +} + +public static class StickerSizeExtensions +{ + public static float GetSizeModifier(this StickerSize size) + { + return size switch + { + StickerSize.Jarret => 0.125f, + StickerSize.Bean => 0.2f, + StickerSize.Smol => 0.25f, + StickerSize.ChonkLite => 0.5f, + StickerSize.Chonk => 1f, + StickerSize.HeckinChonk => 2f, + StickerSize.DoubleHeckinChonk => 4f, + StickerSize.TripleCursedUnit => 8f, + StickerSize.RealityTearingAbomination => 16f, + _ => 0.125f, + }; + } +} \ No newline at end of file diff --git a/Stickers/Stickers/Networking/ModNetwork.Constants.cs b/Stickers/Stickers/Networking/ModNetwork.Constants.cs index 5cc7a16..0515190 100644 --- a/Stickers/Stickers/Networking/ModNetwork.Constants.cs +++ b/Stickers/Stickers/Networking/ModNetwork.Constants.cs @@ -6,7 +6,7 @@ public static partial class ModNetwork internal const int MaxTextureSize = 1024 * 256; // 256KB - private const string NetworkVersion = "1.0.3"; // change each time network protocol changes + internal const string NetworkVersion = "1.0.3"; // change each time network protocol changes private const string ModId = $"MelonMod.NAK.Stickers_v{NetworkVersion}"; private const int ChunkSize = 1024; // roughly 1KB per ModNetworkMessage private const int MaxChunkCount = MaxTextureSize / ChunkSize; diff --git a/Stickers/Stickers/Networking/ModNetwork.Inbound.cs b/Stickers/Stickers/Networking/ModNetwork.Inbound.cs index 57b355c..2e65fcb 100644 --- a/Stickers/Stickers/Networking/ModNetwork.Inbound.cs +++ b/Stickers/Stickers/Networking/ModNetwork.Inbound.cs @@ -110,6 +110,8 @@ public static partial class ModNetwork msg.Read(out Vector3 position); msg.Read(out Vector3 forward); msg.Read(out Vector3 up); + msg.Read(out int size); + msg.Read(out float opacity); if (!StickerSystem.Instance.HasTextureHash(msg.Sender, textureHash)) { @@ -117,7 +119,7 @@ public static partial class ModNetwork StickerSystem.Instance.ClearStickersForPlayer(msg.Sender, stickerSlot); // Ensure no exploit } - StickerSystem.Instance.OnStickerPlaceReceived(msg.Sender, stickerSlot, position, forward, up); + StickerSystem.Instance.OnStickerPlaceReceived(msg.Sender, stickerSlot, position, forward, up, (StickerSize)size, opacity); } private static void HandleClearSticker(ModNetworkMessage msg) diff --git a/Stickers/Stickers/Networking/ModNetwork.Outbound.cs b/Stickers/Stickers/Networking/ModNetwork.Outbound.cs index 241f566..44e4ce3 100644 --- a/Stickers/Stickers/Networking/ModNetwork.Outbound.cs +++ b/Stickers/Stickers/Networking/ModNetwork.Outbound.cs @@ -36,7 +36,7 @@ public static partial class ModNetwork #region Outbound Methods - public static void SendPlaceSticker(int stickerSlot, Vector3 position, Vector3 forward, Vector3 up) + public static void SendPlaceSticker(int stickerSlot, Vector3 position, Vector3 forward, Vector3 up, StickerSize size, float opacity) { if (!_isSubscribedToModNetwork) return; @@ -51,6 +51,8 @@ public static partial class ModNetwork modMsg.Write(position); modMsg.Write(forward); modMsg.Write(up); + modMsg.Write((int)size); + modMsg.Write(opacity); modMsg.Send(); LoggerOutbound($"PlaceSticker: Slot: {stickerSlot}, Hash: {_textureStorage[stickerSlot].textureHash}, Position: {position}, Forward: {forward}, Up: {up}"); diff --git a/Stickers/Stickers/StickerData.cs b/Stickers/Stickers/StickerData.cs index 2ca96bd..3565a19 100644 --- a/Stickers/Stickers/StickerData.cs +++ b/Stickers/Stickers/StickerData.cs @@ -1,5 +1,4 @@ using ABI_RC.Core; -using ABI_RC.Core.IO; using UnityEngine; using Object = UnityEngine.Object; @@ -118,7 +117,7 @@ namespace NAK.Stickers _previewMaterial.mainTexture = texture; } - public void Place(RaycastHit hit, Vector3 forwardDirection, Vector3 upDirection, int spawnerIndex = 0) + public void Place(RaycastHit hit, Vector3 forwardDirection, Vector3 upDirection, int spawnerIndex = 0, StickerSize size = StickerSize.Chonk, float opacity = 1f) { if (spawnerIndex < 0 || spawnerIndex >= _decalSpawners.Length) { @@ -138,12 +137,14 @@ namespace NAK.Stickers _lastPlacedPosition = hit.point; LastPlacedTime = Time.time; - + + float sizeScale = size.GetSizeModifier(); + // Add decal to the specified spawner _decalSpawners[spawnerIndex].AddDecal( _lastPlacedPosition, Quaternion.LookRotation(forwardDirection, upDirection), hitGO, - DECAL_SIZE, DECAL_SIZE, 1f, 1f, 0f, rootObject); + DECAL_SIZE * sizeScale, DECAL_SIZE * sizeScale, 1f, opacity, 0f, rootObject); } public void Clear() @@ -233,7 +234,7 @@ namespace NAK.Stickers private int _previewSpawnerIndex = -1; private float _flashTime; - public void PlacePreview(RaycastHit hit, Vector3 forwardDirection, Vector3 upDirection, int spawnerIndex = 0) + public void PlacePreview(RaycastHit hit, Vector3 forwardDirection, Vector3 upDirection, int spawnerIndex = 0, StickerSize size = StickerSize.Chonk) { if (spawnerIndex < 0 || spawnerIndex >= _decalSpawners.Length) { @@ -252,10 +253,12 @@ namespace NAK.Stickers || hitGO.GetComponentInParent() != null) // movable rootObject = hitGO.transform; + float sizeScale = size.GetSizeModifier(); + _previewDecalSpawner.AddDecal( hit.point, Quaternion.LookRotation(forwardDirection, upDirection), hitGO, - DECAL_SIZE, DECAL_SIZE, 1f, 1f, 0f, rootObject); + DECAL_SIZE * sizeScale, DECAL_SIZE * sizeScale, 1f, 1f, 0f, rootObject); } public void UpdatePreview(int spawnerIndex) diff --git a/Stickers/Stickers/StickerSystem.Main.cs b/Stickers/Stickers/StickerSystem.Main.cs index 9cd8fcf..b377ccb 100644 --- a/Stickers/Stickers/StickerSystem.Main.cs +++ b/Stickers/Stickers/StickerSystem.Main.cs @@ -2,13 +2,9 @@ using ABI_RC.Core.Networking.IO.Instancing; using ABI_RC.Core.UI; using ABI_RC.Systems.GameEventSystem; -using JetBrains.Annotations; using NAK.Stickers.Networking; using NAK.Stickers.Utilities; -using System.EnterpriseServices; -using UnityEngine; -using MelonLoader; -using UnityEngine.ProBuilder.MeshOperations; +using ABI.CCK.Components; using NAK.Stickers.Integrations; namespace NAK.Stickers; @@ -50,7 +46,7 @@ public partial class StickerSystem CVRGameEventSystem.Player.OnJoinEntity.AddListener(Instance.OnPlayerJoined); CVRGameEventSystem.Player.OnLeaveEntity.AddListener(Instance.OnPlayerLeft); - SchedulerSystem.AddJob(Instance.OnUpdate, 10f, -1); + BetterScheduleSystem.AddJob(Instance.OnUpdate, 10f, -1); LoadAllImagesAtStartup(); } @@ -66,7 +62,8 @@ public partial class StickerSystem private void OnWorldLoad() { - IsRestrictedInstance = GameObject.Find("[DisableStickers]") != null; + CVRDataStore worldDS = CVRWorld.Instance.DataStore; + // IsRestrictedInstance = worldDS && worldDS.GetValue("StickersMod-ForceDisable"); if (IsRestrictedInstance) StickerMod.Logger.Msg("Stickers are restricted by the world author."); BTKUIAddon.OnStickerRestrictionUpdated(IsRestrictedInstance); } diff --git a/Stickers/Stickers/StickerSystem.PlayerCallbacks.cs b/Stickers/Stickers/StickerSystem.PlayerCallbacks.cs index f2b5dd3..3bec706 100644 --- a/Stickers/Stickers/StickerSystem.PlayerCallbacks.cs +++ b/Stickers/Stickers/StickerSystem.PlayerCallbacks.cs @@ -64,8 +64,8 @@ public partial class StickerSystem #region Sticker Callbacks - public void OnStickerPlaceReceived(string playerId, int stickerSlot, Vector3 position, Vector3 forward, Vector3 up) - => AttemptPlaceSticker(playerId, position, forward, up, alignWithNormal: true, stickerSlot); + public void OnStickerPlaceReceived(string playerId, int stickerSlot, Vector3 position, Vector3 forward, Vector3 up, StickerSize size, float opacity) + => AttemptPlaceSticker(playerId, size, opacity, position, forward, up, alignWithNormal: true, stickerSlot); public void OnStickerClearReceived(string playerId, int stickerSlot) => ClearStickersForPlayer(playerId, stickerSlot); diff --git a/Stickers/Stickers/StickerSystem.StickerLifecycle.cs b/Stickers/Stickers/StickerSystem.StickerLifecycle.cs index 5f350dd..bab30b5 100644 --- a/Stickers/Stickers/StickerSystem.StickerLifecycle.cs +++ b/Stickers/Stickers/StickerSystem.StickerLifecycle.cs @@ -51,15 +51,15 @@ public partial class StickerSystem private bool PlaceStickerSelf(Vector3 position, Vector3 forward, Vector3 up, bool alignWithNormal = true) { - if (!AttemptPlaceSticker(PlayerLocalId, position, forward, up, alignWithNormal, SelectedStickerSlot)) + if (!AttemptPlaceSticker(PlayerLocalId, ModSettings.Entry_StickerSize.Value, ModSettings.Entry_StickerOpacity.Value, position, forward, up, alignWithNormal, SelectedStickerSlot)) return false; // failed // placed, now network - ModNetwork.SendPlaceSticker(SelectedStickerSlot, position, forward, up); + ModNetwork.SendPlaceSticker(SelectedStickerSlot, position, forward, up, ModSettings.Entry_StickerSize.Value, ModSettings.Entry_StickerOpacity.Value); return true; } - private bool AttemptPlaceSticker(string playerId, Vector3 position, Vector3 forward, Vector3 up, bool alignWithNormal = true, int stickerSlot = 0, bool isPreview = false) + private bool AttemptPlaceSticker(string playerId, StickerSize size, float opacity, Vector3 position, Vector3 forward, Vector3 up, bool alignWithNormal = true, int stickerSlot = 0, bool isPreview = false) { // if the world contained a gameobject with the [DisableStickers] name and restricted the instance disable stickers! if (IsRestrictedInstance) @@ -81,11 +81,11 @@ public partial class StickerSystem if (isPreview) { - stickerData.PlacePreview(hit, alignWithNormal ? -hit.normal : forward, up, stickerSlot); + stickerData.PlacePreview(hit, alignWithNormal ? -hit.normal : forward, up, stickerSlot, size); return true; } - stickerData.Place(hit, alignWithNormal ? -hit.normal : forward, up, stickerSlot); + stickerData.Place(hit, alignWithNormal ? -hit.normal : forward, up, stickerSlot, size, opacity); stickerData.PlayAudio(); return true; } @@ -173,7 +173,7 @@ public partial class StickerSystem public void PlaceStickerPreview(Vector3 position, Vector3 forward, Vector3 up) { - AttemptPlaceSticker(PlayerLocalId, position, forward, up, true, SelectedStickerSlot, true); + AttemptPlaceSticker(PlayerLocalId, ModSettings.Entry_StickerSize.Value, ModSettings.Entry_StickerOpacity.Value, position, forward, up, true, SelectedStickerSlot, true); } public void UpdateStickerPreview() diff --git a/Stickers/Stickers/Utilities/StickerCache.cs b/Stickers/Stickers/Utilities/StickerCache.cs index 3d4c2a2..edc54b6 100644 --- a/Stickers/Stickers/Utilities/StickerCache.cs +++ b/Stickers/Stickers/Utilities/StickerCache.cs @@ -1,8 +1,6 @@ using BTKUILib.UIObjects.Components; -using MTJobSystem; using NAK.Stickers.Integrations; using System.Collections.Concurrent; -using BTKUILib; using UnityEngine; namespace NAK.Stickers.Utilities; diff --git a/Stickers/format.json b/Stickers/format.json index 2d2cab5..9c9a1c8 100644 --- a/Stickers/format.json +++ b/Stickers/format.json @@ -1,11 +1,11 @@ { "_id": 232, "name": "Stickers", - "modversion": "1.0.9", - "gameversion": "2025r179", - "loaderversion": "0.6.1", + "modversion": "1.1.1", + "gameversion": "2025r181", + "loaderversion": "0.7.2", "modtype": "Mod", - "author": "NotAKidoS, SketchFoxsky", + "author": "NotAKidoS", "description": "Stickers! Allows you to place small images on any surface. Requires both users to have the mod installed. Synced over Mod Network.\n\nLimitations:\n- Image should be under 256KB in size.\n- Image dimensions should be a power of 2 (e.g. 512x512, 1024x1024).\n - If the image exceeds the size limit or is not a power of 2 the mod will automatically resize it.\n - The automatic resizing may result in loss of quality (or may just fail), so it is recommended to resize the image yourself before placing it in the `UserData/Stickers/` folder.\n\n-# More information can be found on the [README](https://github.com/NotAKidoS/NAK_CVR_Mods/blob/main/Stickers/README.md).", "searchtags": [ "stickers", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/Stickers.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/Stickers.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/Stickers/", - "changelog": "- Fixes for 2025r179\n- Fixed placing stickers when Cohtml text input fields were focused\n- Fixed scrolling cycling selected sticker slot despite not being in placement mode", + "changelog": "- Rebuilt for CVR 2025r181\n- Reworked disabling system", "embedcolor": "#f61963" } \ No newline at end of file diff --git a/ThirdPerson/Patches.cs b/ThirdPerson/Patches.cs index 02a60db..a05dc1a 100644 --- a/ThirdPerson/Patches.cs +++ b/ThirdPerson/Patches.cs @@ -12,11 +12,11 @@ internal static class Patches internal static void Apply(HarmonyLib.Harmony harmony) { harmony.Patch( - typeof(CVRWorld).GetMethod(nameof(CVRWorld.SetDefaultCamValues), BindingFlags.NonPublic | BindingFlags.Instance), + typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.SetDefaultCamValues), BindingFlags.Public | BindingFlags.Instance), postfix: typeof(Patches).GetMethod(nameof(OnPostWorldStart), BindingFlags.NonPublic | BindingFlags.Static).ToNewHarmonyMethod() ); harmony.Patch( - typeof(CVRWorld).GetMethod(nameof(CVRWorld.CopyRefCamValues), BindingFlags.NonPublic | BindingFlags.Instance), + typeof(PlayerSetup).GetMethod(nameof(PlayerSetup.CopyRefCamValues), BindingFlags.Public | BindingFlags.Instance), postfix: typeof(Patches).GetMethod(nameof(OnPostWorldStart), BindingFlags.NonPublic | BindingFlags.Static).ToNewHarmonyMethod() ); harmony.Patch( diff --git a/ThirdPerson/Properties/AssemblyInfo.cs b/ThirdPerson/Properties/AssemblyInfo.cs index 85d8bfa..1964e57 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.3"; + public const string Version = "1.1.5"; public const string Author = "Davi & NotAKidoS"; } \ No newline at end of file diff --git a/ThirdPerson/format.json b/ThirdPerson/format.json index ff4c491..d6a81de 100644 --- a/ThirdPerson/format.json +++ b/ThirdPerson/format.json @@ -2,8 +2,8 @@ { "_id": 16, "name": "ThirdPerson", - "modversion": "1.1.3", - "gameversion": "2025r180", + "modversion": "1.1.5", + "gameversion": "2025r181", "loaderversion": "0.7.2", "modtype": "Mod", "author": "Davi & NotAKidoS", @@ -14,9 +14,9 @@ "third person" ], "requirements": [], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/ThirdPerson.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/ThirdPerson.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/ThirdPerson", - "changelog": "- Fixes for 2025r180", + "changelog": "- Rebuilt for CVR 2025r181", "embedcolor": "#F61961" } ] \ No newline at end of file diff --git a/Tinyboard/Main.cs b/Tinyboard/Main.cs index 540d150..fe641f3 100644 --- a/Tinyboard/Main.cs +++ b/Tinyboard/Main.cs @@ -1,5 +1,7 @@ using System.Reflection; +using ABI_RC.Core; using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Networking.API; using ABI_RC.Core.Savior; using ABI_RC.Core.UI; using ABI_RC.Core.UI.UIRework.Managers; @@ -200,7 +202,7 @@ public class TinyboardMod : MelonMod if (__instance is not CVRKeyboardPositionHelper { IsMenuOpen: true }) return; // Check if the open source was an open menu - KeyboardManager.OpenSource? openSource = KeyboardManager.Instance._keyboardOpenSource; + KeyboardManager.OpenSource? openSource = KeyboardManager.Instance.KeyboardOpenSource; MenuPositionHelperBase menuPositionHelper; switch (openSource) diff --git a/Tinyboard/Properties/AssemblyInfo.cs b/Tinyboard/Properties/AssemblyInfo.cs index b3048a5..e8ac525 100644 --- a/Tinyboard/Properties/AssemblyInfo.cs +++ b/Tinyboard/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.Tinyboard.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/Tinyboard/format.json b/Tinyboard/format.json index da65a56..3dda9a3 100644 --- a/Tinyboard/format.json +++ b/Tinyboard/format.json @@ -1,8 +1,8 @@ { - "_id": -1, + "_id": 264, "name": "Tinyboard", - "modversion": "1.0.0", - "gameversion": "2025r180", + "modversion": "1.0.1", + "gameversion": "2025r181", "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/Tinyboard.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/Tinyboard.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/Tinyboard/", - "changelog": "- Initial release", + "changelog": "- Rebuilt for CVR 2025r181", "embedcolor": "#f61963" } \ No newline at end of file diff --git a/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs b/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs index ee47977..6942477 100644 --- a/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs +++ b/YouAreMyPropNowWeAreHavingSoftTacosLater/Main.cs @@ -269,7 +269,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.BroadcastMessage("OnHavingSoftTacosNow", SendMessageOptions.DontRequireReceiver); // support with RelativeSyncJitterFix newPropData.Wrapper.name = $"p+{newPropData.ObjectId}~{newPropData.InstanceId}"; // Copy sync values diff --git a/YouAreMyPropNowWeAreHavingSoftTacosLater/Properties/AssemblyInfo.cs b/YouAreMyPropNowWeAreHavingSoftTacosLater/Properties/AssemblyInfo.cs index fa1864b..b6220ad 100644 --- a/YouAreMyPropNowWeAreHavingSoftTacosLater/Properties/AssemblyInfo.cs +++ b/YouAreMyPropNowWeAreHavingSoftTacosLater/Properties/AssemblyInfo.cs @@ -27,6 +27,6 @@ using System.Reflection; namespace NAK.YouAreMyPropNowWeAreHavingSoftTacosLater.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/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json b/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json index 8e68782..5390a52 100644 --- a/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json +++ b/YouAreMyPropNowWeAreHavingSoftTacosLater/format.json @@ -1,8 +1,8 @@ { "_id": 262, "name": "YouAreMyPropNowWeAreHavingSoftTacosLater", - "modversion": "1.0.0", - "gameversion": "2025r180", + "modversion": "1.0.1", + "gameversion": "2025r181", "loaderversion": "0.7.2", "modtype": "Mod", "author": "NotAKidoS", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r47/YouAreMyPropNowWeAreHavingSoftTacosLater.dll", + "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/YouAreMyPropNowWeAreHavingSoftTacosLater.dll", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/YouAreMyPropNowWeAreHavingSoftTacosLater/", - "changelog": "- Initial release", + "changelog": "- Updated for CVR 2025r181", "embedcolor": "#f61963" } \ No newline at end of file