mirror of
https://github.com/NotAKidoS/NAK_CVR_Mods.git
synced 2026-02-24 22:16:11 +00:00
mass commit of laziness
This commit is contained in:
parent
ce992c70ee
commit
6d4fc549d9
167 changed files with 5471 additions and 675 deletions
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk" />
|
||||
42
.Deprecated/AvatarQueueSystemTweaks/Main.cs
Normal file
42
.Deprecated/AvatarQueueSystemTweaks/Main.cs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
using MelonLoader;
|
||||
using NAK.AvatarQueueSystemTweaks.Patches;
|
||||
|
||||
namespace NAK.AvatarQueueSystemTweaks;
|
||||
|
||||
public class AvatarQueueSystemTweaksMod : MelonMod
|
||||
{
|
||||
public static readonly MelonPreferences_Category Category =
|
||||
MelonPreferences.CreateCategory(nameof(AvatarQueueSystemTweaks));
|
||||
|
||||
public static readonly MelonPreferences_Entry<bool> EntryPrioritizeSelf =
|
||||
Category.CreateEntry("prioritize_self", true, "Prioritize Self", description: "Prioritize loading of your own avatar over others.");
|
||||
|
||||
public static readonly MelonPreferences_Entry<bool> EntryPrioritizeFriends =
|
||||
Category.CreateEntry("prioritize_friends", true, "Prioritize Friends", description: "Prioritize loading of friends avatars over others.");
|
||||
|
||||
public static readonly MelonPreferences_Entry<bool> EntryLoadByDistance =
|
||||
Category.CreateEntry("load_by_distance", true, "Load By Distance", description: "Prioritize loading of avatars by distance.");
|
||||
|
||||
// public static readonly MelonPreferences_Entry<bool> EntryChokeInstantiation =
|
||||
// Category.CreateEntry("choke_instantiation", false, "Choke Instantiation",
|
||||
// description: "Chokes the instantiation queue by waiting 0.2s");
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
//ApplyPatches(typeof(CVRObjectLoaderPatches));
|
||||
ApplyPatches(typeof(AvatarQueueSystemPatches));
|
||||
}
|
||||
|
||||
private void ApplyPatches(Type type)
|
||||
{
|
||||
try
|
||||
{
|
||||
HarmonyInstance.PatchAll(type);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LoggerInstance.Msg($"Failed while patching {type.Name}!");
|
||||
LoggerInstance.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
116
.Deprecated/AvatarQueueSystemTweaks/Patches.cs
Normal file
116
.Deprecated/AvatarQueueSystemTweaks/Patches.cs
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
using ABI_RC.Core;
|
||||
using ABI_RC.Core.IO;
|
||||
using ABI_RC.Core.Networking.IO.Social;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Util;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NAK.AvatarQueueSystemTweaks.Patches;
|
||||
|
||||
// internal static class CVRObjectLoaderPatches
|
||||
// {
|
||||
// private static readonly YieldInstruction _yieldInstruction = new WaitForSeconds(0.2f);
|
||||
//
|
||||
// [HarmonyPostfix]
|
||||
// [HarmonyPatch(typeof(CVRObjectLoader), nameof(CVRObjectLoader.InstantiateAvatarFromBundle))]
|
||||
// [HarmonyPatch(typeof(CVRObjectLoader), nameof(CVRObjectLoader.InstantiateSpawnableFromBundle))]
|
||||
// //[HarmonyPatch(typeof(CVRObjectLoader), nameof(CVRObjectLoader.InstantiateAvatarFromExistingPrefab))]
|
||||
// //[HarmonyPatch(typeof(CVRObjectLoader), nameof(CVRObjectLoader.InstantiateSpawnableFromExistingPrefab))]
|
||||
// private static IEnumerator MyWrapper(IEnumerator result)
|
||||
// {
|
||||
// while (result.MoveNext())
|
||||
// yield return result.Current;
|
||||
//
|
||||
// if (AvatarQueueSystemTweaksMod.EntryChokeInstantiation.Value)
|
||||
// yield return _yieldInstruction;
|
||||
// }
|
||||
// }
|
||||
|
||||
internal static class AvatarQueueSystemPatches
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(AvatarQueueSystem.CoroutineHandle), nameof(AvatarQueueSystem.CoroutineHandle.RunManagedCoroutine))]
|
||||
private static bool Prefix_AvatarQueueSystem_CoroutineHandle_RunManagedCoroutine(AvatarQueueSystem.CoroutineHandle __instance)
|
||||
{
|
||||
AvatarQueueSystem.Instance.jobIsActive = true;
|
||||
|
||||
// difference from original: doesn't immediately call CheckAvailability on same frame of completion
|
||||
|
||||
__instance._activeCoroutine = AvatarQueueSystem.Instance.StartCoroutine(CoroutineUtil.RunThrowingIterator(__instance._function, delegate(Exception exception)
|
||||
{
|
||||
CommonTools.Log(CommonTools.LogLevelType_t.Error, string.Format("[CVRGame => {0}] Avatar loading job has failed!\n{1}", __instance.GetType().Name, exception), "A0108");
|
||||
__instance.CleanCurrentJob();
|
||||
var onException = __instance._onException;
|
||||
onException?.Invoke(exception);
|
||||
}, delegate
|
||||
{
|
||||
CommonTools.Log(CommonTools.LogLevelType_t.Info, "[CVRGame => " + __instance.GetType().Name + "] Avatar loading job has completed successfully.", "A0107");
|
||||
__instance.CleanCurrentJob();
|
||||
Action onSuccess = __instance._onSuccess;
|
||||
onSuccess?.Invoke();
|
||||
}));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(AvatarQueueSystem), nameof(AvatarQueueSystem.CheckAvailability))]
|
||||
private static bool Prefix_AvatarQueueSystem_CheckAvailability(AvatarQueueSystem __instance)
|
||||
{
|
||||
if (__instance.JobIsActive
|
||||
|| __instance.activeCoroutines.Count == 0)
|
||||
return false;
|
||||
|
||||
bool prioritizeSelf = AvatarQueueSystemTweaksMod.EntryPrioritizeSelf.Value;
|
||||
bool prioritizeFriends = AvatarQueueSystemTweaksMod.EntryPrioritizeFriends.Value;
|
||||
bool loadByDistance = AvatarQueueSystemTweaksMod.EntryLoadByDistance.Value;
|
||||
|
||||
bool foundFriend = false;
|
||||
float nearestDistance = float.MaxValue;
|
||||
AvatarQueueSystem.CoroutineHandle nextCoroutine = null;
|
||||
Vector3 playerPosition = PlayerSetup.Instance.activeCam.transform.position;
|
||||
|
||||
foreach (AvatarQueueSystem.CoroutineHandle coroutine in __instance.activeCoroutines)
|
||||
{
|
||||
if (prioritizeSelf && coroutine.player == "_PLAYERLOCAL") // prioritize local player if setting is enabled
|
||||
{
|
||||
nextCoroutine = coroutine;
|
||||
break;
|
||||
}
|
||||
|
||||
CVRPlayerManager.Instance.GetPlayerPuppetMaster(coroutine.player, out PuppetMaster puppetMaster);
|
||||
if (puppetMaster == null)
|
||||
continue;
|
||||
|
||||
if (prioritizeFriends)
|
||||
{
|
||||
switch (foundFriend)
|
||||
{
|
||||
// attempt find first friend
|
||||
case false when Friends.FriendsWith(coroutine.player):
|
||||
foundFriend = true;
|
||||
nearestDistance = float.MaxValue;
|
||||
nextCoroutine = coroutine;
|
||||
if (!loadByDistance) break; // no reason to continue loop
|
||||
continue;
|
||||
// found a friend, filtering will now only respect friends for this iteration
|
||||
case true when !Friends.FriendsWith(coroutine.player):
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// filtering by distance
|
||||
if (!loadByDistance) continue;
|
||||
|
||||
float distance = Vector3.Distance(playerPosition, puppetMaster.transform.position);
|
||||
if (!(distance < nearestDistance)) continue; // update nearest coroutine if closer
|
||||
|
||||
nearestDistance = distance;
|
||||
nextCoroutine = coroutine;
|
||||
}
|
||||
|
||||
nextCoroutine?.RunManagedCoroutine();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
using MelonLoader;
|
||||
using NAK.AvatarQueueSystemTweaks.Properties;
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyTitle(nameof(NAK.AvatarQueueSystemTweaks))]
|
||||
[assembly: AssemblyCompany(AssemblyInfoParams.Author)]
|
||||
[assembly: AssemblyProduct(nameof(NAK.AvatarQueueSystemTweaks))]
|
||||
|
||||
[assembly: MelonInfo(
|
||||
typeof(NAK.AvatarQueueSystemTweaks.AvatarQueueSystemTweaksMod),
|
||||
nameof(NAK.AvatarQueueSystemTweaks),
|
||||
AssemblyInfoParams.Version,
|
||||
AssemblyInfoParams.Author,
|
||||
downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/AvatatQueueSystemTweaks"
|
||||
)]
|
||||
|
||||
[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.AvatarQueueSystemTweaks.Properties;
|
||||
internal static class AssemblyInfoParams
|
||||
{
|
||||
public const string Version = "1.0.1";
|
||||
public const string Author = "NotAKidoS";
|
||||
}
|
||||
18
.Deprecated/AvatarQueueSystemTweaks/README.md
Normal file
18
.Deprecated/AvatarQueueSystemTweaks/README.md
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# AvatarQueueSystemTweaks
|
||||
|
||||
Small tweaks to the Avatar Queue System.
|
||||
|
||||
- Prioritize loading own avatar over others.
|
||||
- Prioritize loading friends' avatars over others.
|
||||
- Load avatars by distance from player.
|
||||
|
||||
---
|
||||
|
||||
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.
|
||||
24
.Deprecated/AvatarQueueSystemTweaks/format.json
Normal file
24
.Deprecated/AvatarQueueSystemTweaks/format.json
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"_id": 226,
|
||||
"name": "AvatarQueueSystemTweaks",
|
||||
"modversion": "1.0.1",
|
||||
"gameversion": "2025r179",
|
||||
"loaderversion": "0.6.1",
|
||||
"modtype": "Mod",
|
||||
"author": "NotAKidoS",
|
||||
"description": "Small tweaks to the Avatar Queue System.\n\n- Prioritize loading own avatar over others.\n- Prioritize loading friends' avatars over others.\n- Load avatars by distance from player.",
|
||||
"searchtags": [
|
||||
"avatar",
|
||||
"load",
|
||||
"queue",
|
||||
"initialize",
|
||||
"download"
|
||||
],
|
||||
"requirements": [
|
||||
"None"
|
||||
],
|
||||
"downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/AvatarQueueSystemTweaks.dll",
|
||||
"sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/AvatarQueueSystemTweaks/",
|
||||
"changelog": "- Recompiled for 2025r179",
|
||||
"embedcolor": "#f61963"
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk" />
|
||||
109
.Deprecated/BufferParticleFixer/Main.cs
Normal file
109
.Deprecated/BufferParticleFixer/Main.cs
Normal file
|
|
@ -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<bool> 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;
|
||||
}
|
||||
}
|
||||
32
.Deprecated/BufferParticleFixer/Properties/AssemblyInfo.cs
Normal file
32
.Deprecated/BufferParticleFixer/Properties/AssemblyInfo.cs
Normal file
|
|
@ -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";
|
||||
}
|
||||
14
.Deprecated/BufferParticleFixer/README.md
Normal file
14
.Deprecated/BufferParticleFixer/README.md
Normal file
|
|
@ -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.
|
||||
23
.Deprecated/BufferParticleFixer/format.json
Normal file
23
.Deprecated/BufferParticleFixer/format.json
Normal file
|
|
@ -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"
|
||||
}
|
||||
|
|
@ -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)]
|
||||
|
||||
|
|
|
|||
9
.Deprecated/ChatBoxTweaks/ChatBoxTweaks.csproj
Normal file
9
.Deprecated/ChatBoxTweaks/ChatBoxTweaks.csproj
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<RootNamespace>PlayerCloneAttachment</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Resources\playercloneattachment.assets" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
92
.Deprecated/ChatBoxTweaks/Main.cs
Normal file
92
.Deprecated/ChatBoxTweaks/Main.cs
Normal file
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
32
.Deprecated/ChatBoxTweaks/Properties/AssemblyInfo.cs
Normal file
32
.Deprecated/ChatBoxTweaks/Properties/AssemblyInfo.cs
Normal file
|
|
@ -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";
|
||||
}
|
||||
22
.Deprecated/ChatBoxTweaks/README.md
Normal file
22
.Deprecated/ChatBoxTweaks/README.md
Normal file
|
|
@ -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.
|
||||
23
.Deprecated/ChatBoxTweaks/format.json
Normal file
23
.Deprecated/ChatBoxTweaks/format.json
Normal file
|
|
@ -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"
|
||||
}
|
||||
6
.Deprecated/ChatBubbles/ChatBubbles.csproj
Normal file
6
.Deprecated/ChatBubbles/ChatBubbles.csproj
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<RootNamespace>YouAreMineNow</RootNamespace>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
236
.Deprecated/ChatBubbles/Main.cs
Normal file
236
.Deprecated/ChatBubbles/Main.cs
Normal file
|
|
@ -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<KeyCode> EntryChatBubblesKey =
|
||||
Category.CreateEntry("keyboard_bind", KeyCode.Y, display_name: "Chat Bubbles Key",
|
||||
description: "Key to open chat bubble input.");
|
||||
|
||||
private static readonly MelonPreferences_Entry<float> 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<float> 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<int> 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<Color> 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<ChatBubble> _chatBubblePool = [];
|
||||
private readonly List<ChatBubble> _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<ChatBubble>(_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
|
||||
}
|
||||
32
.Deprecated/ChatBubbles/Properties/AssemblyInfo.cs
Normal file
32
.Deprecated/ChatBubbles/Properties/AssemblyInfo.cs
Normal file
|
|
@ -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";
|
||||
}
|
||||
19
.Deprecated/ChatBubbles/README.md
Normal file
19
.Deprecated/ChatBubbles/README.md
Normal file
|
|
@ -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.
|
||||
23
.Deprecated/ChatBubbles/format.json
Normal file
23
.Deprecated/ChatBubbles/format.json
Normal file
|
|
@ -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"
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<RootNamespace>PlayerCloneAttachment</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Resources\playercloneattachment.assets" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
169
.Deprecated/ControlToUnlockEyes/Main.cs
Normal file
169
.Deprecated/ControlToUnlockEyes/Main.cs
Normal file
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
32
.Deprecated/ControlToUnlockEyes/Properties/AssemblyInfo.cs
Normal file
32
.Deprecated/ControlToUnlockEyes/Properties/AssemblyInfo.cs
Normal file
|
|
@ -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";
|
||||
}
|
||||
22
.Deprecated/ControlToUnlockEyes/README.md
Normal file
22
.Deprecated/ControlToUnlockEyes/README.md
Normal file
|
|
@ -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.
|
||||
23
.Deprecated/ControlToUnlockEyes/format.json
Normal file
23
.Deprecated/ControlToUnlockEyes/format.json
Normal file
|
|
@ -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"
|
||||
}
|
||||
6
.Deprecated/FuckCameras/FuckCameras.csproj
Normal file
6
.Deprecated/FuckCameras/FuckCameras.csproj
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<RootNamespace>YouAreMineNow</RootNamespace>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
228
.Deprecated/FuckCameras/Main.cs
Normal file
228
.Deprecated/FuckCameras/Main.cs
Normal file
|
|
@ -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<FuckCameraComponent>();
|
||||
|
||||
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<CameraPoolManager>();
|
||||
DontDestroyOnLoad(obj);
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<GameObject> _cameraObjects = new();
|
||||
|
||||
public Camera CreatePooledCamera(Camera source)
|
||||
{
|
||||
var go = new GameObject("PooledCamera");
|
||||
go.SetActive(false);
|
||||
var camera = go.AddComponent<Camera>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
32
.Deprecated/FuckCameras/Properties/AssemblyInfo.cs
Normal file
32
.Deprecated/FuckCameras/Properties/AssemblyInfo.cs
Normal file
|
|
@ -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";
|
||||
}
|
||||
19
.Deprecated/FuckCameras/README.md
Normal file
19
.Deprecated/FuckCameras/README.md
Normal file
|
|
@ -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.
|
||||
23
.Deprecated/FuckCameras/format.json
Normal file
23
.Deprecated/FuckCameras/format.json
Normal file
|
|
@ -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"
|
||||
}
|
||||
6
.Deprecated/FuckCohtml2/FuckCohtml2.csproj
Normal file
6
.Deprecated/FuckCohtml2/FuckCohtml2.csproj
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<RootNamespace>YouAreMineNow</RootNamespace>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
57
.Deprecated/FuckCohtml2/Main.cs
Normal file
57
.Deprecated/FuckCohtml2/Main.cs
Normal file
|
|
@ -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<bool> 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<bool> 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;
|
||||
}
|
||||
}
|
||||
32
.Deprecated/FuckCohtml2/Properties/AssemblyInfo.cs
Normal file
32
.Deprecated/FuckCohtml2/Properties/AssemblyInfo.cs
Normal file
|
|
@ -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";
|
||||
}
|
||||
19
.Deprecated/FuckCohtml2/README.md
Normal file
19
.Deprecated/FuckCohtml2/README.md
Normal file
|
|
@ -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.
|
||||
23
.Deprecated/FuckCohtml2/format.json
Normal file
23
.Deprecated/FuckCohtml2/format.json
Normal file
|
|
@ -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"
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<RootNamespace>YouAreMineNow</RootNamespace>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
39
.Deprecated/IFUCKINGHATECAMERAS/Main.cs
Normal file
39
.Deprecated/IFUCKINGHATECAMERAS/Main.cs
Normal file
|
|
@ -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<bool> 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
|
||||
}
|
||||
}
|
||||
32
.Deprecated/IFUCKINGHATECAMERAS/Properties/AssemblyInfo.cs
Normal file
32
.Deprecated/IFUCKINGHATECAMERAS/Properties/AssemblyInfo.cs
Normal file
|
|
@ -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";
|
||||
}
|
||||
19
.Deprecated/IFUCKINGHATECAMERAS/README.md
Normal file
19
.Deprecated/IFUCKINGHATECAMERAS/README.md
Normal file
|
|
@ -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.
|
||||
23
.Deprecated/IFUCKINGHATECAMERAS/format.json
Normal file
23
.Deprecated/IFUCKINGHATECAMERAS/format.json
Normal file
|
|
@ -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"
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<RootNamespace>LoadedObjectHack</RootNamespace>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
34
.Deprecated/KeepVelocityOnExitFlight/Main.cs
Normal file
34
.Deprecated/KeepVelocityOnExitFlight/Main.cs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
using System.Reflection;
|
||||
using ABI_RC.Systems.Movement;
|
||||
using HarmonyLib;
|
||||
using MelonLoader;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NAK.KeepVelocityOnExitFlight;
|
||||
|
||||
public class KeepVelocityOnExitFlightMod : MelonMod
|
||||
{
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
HarmonyInstance.Patch(
|
||||
typeof(BetterBetterCharacterController).GetMethod(nameof(BetterBetterCharacterController.ChangeFlight),
|
||||
BindingFlags.Public | BindingFlags.Instance),
|
||||
prefix: new HarmonyMethod(typeof(KeepVelocityOnExitFlightMod).GetMethod(nameof(Prefix_OnChangeFlight),
|
||||
BindingFlags.NonPublic | BindingFlags.Static)),
|
||||
postfix: new HarmonyMethod(typeof(KeepVelocityOnExitFlightMod).GetMethod(nameof(Postfix_OnChangeFlight),
|
||||
BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
}
|
||||
|
||||
// ReSharper disable once RedundantAssignment
|
||||
private static void Prefix_OnChangeFlight(ref BetterBetterCharacterController __instance, ref Vector3 __state)
|
||||
{
|
||||
__state = __instance.GetVelocity();
|
||||
}
|
||||
|
||||
private static void Postfix_OnChangeFlight(ref BetterBetterCharacterController __instance, ref Vector3 __state)
|
||||
{
|
||||
if (__instance.FlightAllowedInWorld && !__instance.IsFlying())
|
||||
__instance.SetVelocity(__state);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
using MelonLoader;
|
||||
using NAK.KeepVelocityOnExitFlight.Properties;
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyTitle(nameof(NAK.KeepVelocityOnExitFlight))]
|
||||
[assembly: AssemblyCompany(AssemblyInfoParams.Author)]
|
||||
[assembly: AssemblyProduct(nameof(NAK.KeepVelocityOnExitFlight))]
|
||||
|
||||
[assembly: MelonInfo(
|
||||
typeof(NAK.KeepVelocityOnExitFlight.KeepVelocityOnExitFlightMod),
|
||||
nameof(NAK.KeepVelocityOnExitFlight),
|
||||
AssemblyInfoParams.Version,
|
||||
AssemblyInfoParams.Author,
|
||||
downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/KeepVelocityOnExitFlight"
|
||||
)]
|
||||
|
||||
[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.KeepVelocityOnExitFlight.Properties;
|
||||
internal static class AssemblyInfoParams
|
||||
{
|
||||
public const string Version = "1.0.1";
|
||||
public const string Author = "NotAKidoS";
|
||||
}
|
||||
14
.Deprecated/KeepVelocityOnExitFlight/README.md
Normal file
14
.Deprecated/KeepVelocityOnExitFlight/README.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# KeepVelocityOnExitFlight
|
||||
|
||||
Keeps the player's velocity when exiting flight mode. Makes it possible to fling yourself like in Garry's Mod.
|
||||
|
||||
---
|
||||
|
||||
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.
|
||||
24
.Deprecated/KeepVelocityOnExitFlight/format.json
Normal file
24
.Deprecated/KeepVelocityOnExitFlight/format.json
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"_id": 222,
|
||||
"name": "KeepVelocityOnExitFlight",
|
||||
"modversion": "1.0.1",
|
||||
"gameversion": "2025r179",
|
||||
"loaderversion": "0.6.1",
|
||||
"modtype": "Mod",
|
||||
"author": "NotAKidoS",
|
||||
"description": "Keeps the player's velocity when exiting flight mode. Makes it possible to fling yourself like in Garry's Mod.",
|
||||
"searchtags": [
|
||||
"flight",
|
||||
"mode",
|
||||
"velocity",
|
||||
"flying",
|
||||
"fly"
|
||||
],
|
||||
"requirements": [
|
||||
"None"
|
||||
],
|
||||
"downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/KeepVelocityOnExitFlight.dll",
|
||||
"sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/KeepVelocityOnExitFlight/",
|
||||
"changelog": "- Recompiled for 2025r179",
|
||||
"embedcolor": "#f61963"
|
||||
}
|
||||
6
.Deprecated/LazyPrune/LazyPrune.csproj
Normal file
6
.Deprecated/LazyPrune/LazyPrune.csproj
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<RootNamespace>LoadedObjectHack</RootNamespace>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
214
.Deprecated/LazyPrune/Main.cs
Normal file
214
.Deprecated/LazyPrune/Main.cs
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
using System.Reflection;
|
||||
using ABI_RC.Core.EventSystem;
|
||||
using ABI_RC.Core.IO;
|
||||
using ABI_RC.Core.Networking.API.Responses;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Savior;
|
||||
using ABI_RC.Systems.GameEventSystem;
|
||||
using HarmonyLib;
|
||||
using MelonLoader;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NAK.LazyPrune;
|
||||
|
||||
public class LazyPrune : MelonMod
|
||||
{
|
||||
private static MelonLogger.Instance Logger;
|
||||
|
||||
private const int MAX_OBJECTS_UNLOADED_AT_ONCE = 3; // just to alleviate hitch on mass destruction
|
||||
private const float OBJECT_CACHE_TIMEOUT = 2f; // minutes
|
||||
private static readonly Dictionary<CVRObjectLoader.LoadedObject, float> _loadedObjects = new();
|
||||
|
||||
private static string _lastLoadedWorld;
|
||||
private static bool _isInitialized;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
Logger = LoggerInstance;
|
||||
|
||||
// listen for world load
|
||||
CVRGameEventSystem.World.OnLoad.AddListener(OnWorldLoaded);
|
||||
|
||||
// listen for local avatar bundle load
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRObjectLoader).GetMethod(nameof(CVRObjectLoader.InstantiateAvatarFromExistingPrefab),
|
||||
BindingFlags.Public | BindingFlags.Instance), // earliest callback (why the fuck are you public)
|
||||
prefix: new HarmonyMethod(typeof(LazyPrune).GetMethod(nameof(OnInstantiateAvatarFromExistingPrefab),
|
||||
BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
|
||||
// listen for prop bundle load
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRObjectLoader).GetMethod(nameof(CVRObjectLoader.InstantiateSpawnableFromExistingPrefab),
|
||||
BindingFlags.NonPublic | BindingFlags.Instance), // earliest callback
|
||||
prefix: new HarmonyMethod(typeof(LazyPrune).GetMethod(nameof(OnInstantiateSpawnableFromExistingPrefab),
|
||||
BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
|
||||
// listen for object destruction
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRObjectLoader).GetMethod(nameof(CVRObjectLoader.CheckForDestruction),
|
||||
BindingFlags.Public | BindingFlags.Instance), // earliest callback
|
||||
prefix: new HarmonyMethod(typeof(LazyPrune).GetMethod(nameof(OnObjectDestroyed),
|
||||
BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
|
||||
// nuke qm debug method as there is a race condition that locks up download queue
|
||||
HarmonyInstance.Patch(
|
||||
typeof(CVRDownloadManager).GetMethod(nameof(CVRDownloadManager.UpdateUiDownloadStatus),
|
||||
BindingFlags.Public | BindingFlags.Instance),
|
||||
prefix: new HarmonyMethod(typeof(LazyPrune).GetMethod(nameof(OnUpdateUiDownloadStatus),
|
||||
BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
|
||||
// another race condition that causes instantiation queue to lock up
|
||||
HarmonyInstance.Patch(
|
||||
typeof(PuppetMaster).GetMethod(nameof(PuppetMaster.AvatarInstantiated),
|
||||
BindingFlags.Public | BindingFlags.Instance),
|
||||
prefix: new HarmonyMethod(typeof(LazyPrune).GetMethod(nameof(OnAvatarInstantiated),
|
||||
BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
}
|
||||
|
||||
#region Game Fixes
|
||||
|
||||
private static bool OnUpdateUiDownloadStatus() => false;
|
||||
|
||||
private static bool OnAvatarInstantiated(ref GameObject ___avatarObject)
|
||||
{
|
||||
if (___avatarObject != null) return true; // instantiate coroutine is try-catch'd, so purposefully throw to have it catch
|
||||
Logger.Warning("Caught null avatar object in PuppetMaster.AvatarInstantiated. Throwing exception so ObjectLoader can catch.");
|
||||
throw new Exception("LazyPrune: PuppetMaster Avatar instantiated with null object!");
|
||||
}
|
||||
|
||||
#endregion Game Fixes
|
||||
|
||||
#region Game Events
|
||||
|
||||
private static void OnInstantiateAvatarFromExistingPrefab(string objectId, string instantiationTarget,
|
||||
GameObject prefabObject,
|
||||
ref CVRObjectLoader.LoadedObject loadedObject, string blockReason, AssetManagement.AvatarTags? avatarTags,
|
||||
bool shouldFilter, bool isBlocked,
|
||||
CompatibilityVersions compatibilityVersion)
|
||||
{
|
||||
if (prefabObject == MetaPort.Instance.blockedAvatarPrefab)
|
||||
{
|
||||
Logger.Msg($"Blocked avatar prefab is loading. Ignoring...");
|
||||
return;
|
||||
}
|
||||
|
||||
OnObjectCreated(ref loadedObject);
|
||||
}
|
||||
|
||||
private static void OnInstantiateSpawnableFromExistingPrefab(string objectId, string instantiationTarget,
|
||||
GameObject prefabObject, CVRObjectLoader.LoadedObject loadedObject, AssetManagement.PropTags propTags,
|
||||
CompatibilityVersions compatibilityVersion)
|
||||
{
|
||||
if (prefabObject == MetaPort.Instance.blockedSpawnablePrefab)
|
||||
{
|
||||
Logger.Msg($"Blocked spawnable prefab is loading. Ignoring...");
|
||||
return;
|
||||
}
|
||||
|
||||
OnObjectCreated(ref loadedObject);
|
||||
}
|
||||
|
||||
private static void OnWorldLoaded(string guid)
|
||||
{
|
||||
if (!_isInitialized)
|
||||
{
|
||||
// every minute, check for objects to prune
|
||||
SchedulerSystem.AddJob(CheckForObjectsToPrune, 1f, 10f, -1);
|
||||
_isInitialized = true;
|
||||
}
|
||||
|
||||
if (_lastLoadedWorld != guid)
|
||||
ForcePrunePendingObjects();
|
||||
|
||||
_lastLoadedWorld = guid;
|
||||
}
|
||||
|
||||
private static void OnObjectCreated(ref CVRObjectLoader.LoadedObject ___loadedObject)
|
||||
{
|
||||
if (___loadedObject == null)
|
||||
{
|
||||
Logger.Error("Avatar/Prop created with no backed LoadedObject.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_loadedObjects.ContainsKey(___loadedObject))
|
||||
{
|
||||
_loadedObjects[___loadedObject] = -1; // mark as ineligible for pruning
|
||||
return;
|
||||
}
|
||||
|
||||
___loadedObject.refCount++; // increment ref count
|
||||
_loadedObjects.Add(___loadedObject, -1); // mark as ineligible for pruning
|
||||
}
|
||||
|
||||
private static void OnObjectDestroyed(CVRObjectLoader.LoadedObject loadedObject)
|
||||
{
|
||||
if (loadedObject == null)
|
||||
{
|
||||
Logger.Error("Avatar/Prop destroyed with no backed LoadedObject.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (loadedObject.refCount > 1)
|
||||
return;
|
||||
|
||||
if (_loadedObjects.ContainsKey(loadedObject))
|
||||
_loadedObjects[loadedObject] = Time.time + OBJECT_CACHE_TIMEOUT * 60f;
|
||||
}
|
||||
|
||||
#endregion Game Events
|
||||
|
||||
#region Lazy Pruning
|
||||
|
||||
private static void ForcePrunePendingObjects()
|
||||
{
|
||||
for (int i = _loadedObjects.Count - 1; i >= 0; i--)
|
||||
{
|
||||
(CVRObjectLoader.LoadedObject loadedObject, var killTime) = _loadedObjects.ElementAt(i);
|
||||
if (killTime > 0) AttemptPruneObject(loadedObject);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckForObjectsToPrune()
|
||||
{
|
||||
int unloaded = 0;
|
||||
float time = Time.time;
|
||||
for (int i = _loadedObjects.Count - 1; i >= 0; i--)
|
||||
{
|
||||
(CVRObjectLoader.LoadedObject loadedObject, var killTime) = _loadedObjects.ElementAt(i);
|
||||
if (!(killTime < time) || killTime < 0) continue;
|
||||
AttemptPruneObject(loadedObject);
|
||||
if (unloaded++ >= MAX_OBJECTS_UNLOADED_AT_ONCE) break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void AttemptPruneObject(CVRObjectLoader.LoadedObject loadedObject)
|
||||
{
|
||||
if (loadedObject == null)
|
||||
{
|
||||
Logger.Error("Attempted to prune null object. This happens on initial load sometimes.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (loadedObject.refCount > 1)
|
||||
{
|
||||
Logger.Error($"Object {loadedObject.prefabName} has ref count {loadedObject.refCount}, expected 1");
|
||||
_loadedObjects[loadedObject] = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
Logger.Msg($"Pruning object {loadedObject.prefabName}");
|
||||
_loadedObjects.Remove(loadedObject);
|
||||
|
||||
loadedObject.refCount--;
|
||||
if (CVRObjectLoader.Instance != null)
|
||||
CVRObjectLoader.Instance.CheckForDestruction(loadedObject);
|
||||
}
|
||||
|
||||
#endregion Lazy Pruning
|
||||
}
|
||||
32
.Deprecated/LazyPrune/Properties/AssemblyInfo.cs
Normal file
32
.Deprecated/LazyPrune/Properties/AssemblyInfo.cs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
using MelonLoader;
|
||||
using NAK.LazyPrune.Properties;
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyTitle(nameof(NAK.LazyPrune))]
|
||||
[assembly: AssemblyCompany(AssemblyInfoParams.Author)]
|
||||
[assembly: AssemblyProduct(nameof(NAK.LazyPrune))]
|
||||
|
||||
[assembly: MelonInfo(
|
||||
typeof(NAK.LazyPrune.LazyPrune),
|
||||
nameof(NAK.LazyPrune),
|
||||
AssemblyInfoParams.Version,
|
||||
AssemblyInfoParams.Author,
|
||||
downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/LazyPrune"
|
||||
)]
|
||||
|
||||
[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")]
|
||||
[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||
[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
||||
[assembly: MelonColor(255, 246, 25, 99)] // red-pink
|
||||
[assembly: MelonAuthorColor(255, 158, 21, 32)] // red
|
||||
[assembly: HarmonyDontPatchAll]
|
||||
|
||||
namespace NAK.LazyPrune.Properties;
|
||||
internal static class AssemblyInfoParams
|
||||
{
|
||||
public const string Version = "1.0.3";
|
||||
public const string Author = "NotAKidoS";
|
||||
}
|
||||
16
.Deprecated/LazyPrune/README.md
Normal file
16
.Deprecated/LazyPrune/README.md
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# LazyPrune
|
||||
|
||||
Prevents loaded objects from immediately unloading on destruction. Should prevent needlessly unloading & reloading all avatars/props on world rejoin or GS reconnection.
|
||||
|
||||
Unused objects are pruned after 3 minutes, or when loading into a different world.
|
||||
|
||||
---
|
||||
|
||||
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.
|
||||
24
.Deprecated/LazyPrune/format.json
Normal file
24
.Deprecated/LazyPrune/format.json
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"_id": 214,
|
||||
"name": "LazyPrune",
|
||||
"modversion": "1.0.3",
|
||||
"gameversion": "2025r179",
|
||||
"loaderversion": "0.6.1",
|
||||
"modtype": "Mod",
|
||||
"author": "NotAKidoS",
|
||||
"description": "Prevents loaded objects from immediately unloading on destruction. Should prevent needlessly unloading & reloading all avatars/props on world rejoin or GS reconnection.\n\nUnused objects are pruned after 3 minutes, or when loading into a different world.",
|
||||
"searchtags": [
|
||||
"cache",
|
||||
"prune",
|
||||
"bundle",
|
||||
"download",
|
||||
"load"
|
||||
],
|
||||
"requirements": [
|
||||
"None"
|
||||
],
|
||||
"downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r46/LazyPrune.dll",
|
||||
"sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/LazyPrune/",
|
||||
"changelog": "- Recompiled for 2025r179",
|
||||
"embedcolor": "#1c75f1"
|
||||
}
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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<CVRPlayerInputHandler>();
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
/// Register a custom tool mode
|
||||
/// </summary>
|
||||
public void RegisterCustomToolMode(System.Action<CVRHand, CVRRaycastResult, InputState> callback)
|
||||
{
|
||||
_inputHandler.RegisterCustomTool(callback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unregister the current custom tool mode
|
||||
/// </summary>
|
||||
public void UnregisterCustomToolMode()
|
||||
{
|
||||
_inputHandler.UnregisterCustomTool();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the interaction mode
|
||||
/// </summary>
|
||||
public void SetInteractionMode(CVRPlayerInputHandler.InteractionMode mode)
|
||||
{
|
||||
_inputHandler.SetInteractionMode(mode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the raycast result for a specific hand
|
||||
/// </summary>
|
||||
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
|
||||
}
|
||||
}
|
||||
// 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<CVRPlayerInputHandler>();
|
||||
// }
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Register a custom tool mode
|
||||
// /// </summary>
|
||||
// public void RegisterCustomToolMode(System.Action<CVRHand, CVRRaycastResult, InputState> callback)
|
||||
// {
|
||||
// _inputHandler.RegisterCustomTool(callback);
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Unregister the current custom tool mode
|
||||
// /// </summary>
|
||||
// public void UnregisterCustomToolMode()
|
||||
// {
|
||||
// _inputHandler.UnregisterCustomTool();
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Set the interaction mode
|
||||
// /// </summary>
|
||||
// public void SetInteractionMode(CVRPlayerInputHandler.InteractionMode mode)
|
||||
// {
|
||||
// _inputHandler.SetInteractionMode(mode);
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Get the raycast result for a specific hand
|
||||
// /// </summary>
|
||||
// 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
|
||||
// }
|
||||
// }
|
||||
|
|
@ -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<RaycastResult> _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<RectTransform>();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
_graphicsRaycaster = _canvas.gameObject.AddComponent<GraphicRaycaster>();
|
||||
_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
|
||||
}
|
||||
}
|
||||
// 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<RaycastResult> _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<RectTransform>();
|
||||
// }
|
||||
//
|
||||
// private void Start()
|
||||
// {
|
||||
// _graphicsRaycaster = _canvas.gameObject.AddComponent<GraphicRaycaster>();
|
||||
// _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
|
||||
// }
|
||||
// }
|
||||
1871
.Deprecated/SuperAwesomeMod/Interaction/ControllerRay.cs
Normal file
1871
.Deprecated/SuperAwesomeMod/Interaction/ControllerRay.cs
Normal file
File diff suppressed because it is too large
Load diff
85
.Deprecated/SuperAwesomeMod/Interaction/Input/CustomInput.cs
Normal file
85
.Deprecated/SuperAwesomeMod/Interaction/Input/CustomInput.cs
Normal file
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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<CustomBaseInput>();
|
||||
|
||||
// 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>();
|
||||
EventSystem[] systems = FindObjectsOfType<EventSystem>();
|
||||
foreach (EventSystem system in systems)
|
||||
{
|
||||
if (system.gameObject.name == "UniverseLibCanvas") continue;
|
||||
if (system != thisEventSystem)
|
||||
{
|
||||
system.enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace ABI_RC.Core.Player.Interaction.RaycastImpl
|
||||
|
|
|
|||
|
|
@ -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<UEMenuHelper>();
|
||||
Instance.menuTransform = contentTransform;
|
||||
// Instance._offsetTransform = offsetTransform; // Got in MenuPositionHelperBase.Start
|
||||
|
||||
// Apply the component filters done in worlds
|
||||
// foreach (Component c in _universeLibCanvas.GetComponentsInChildren<Component>(true))
|
||||
// SetupCollidersOnUnityUi(c);
|
||||
|
||||
CVRCanvasWrapper.AddForCanvas(_universeLibCanvas.GetComponent<Canvas>(), 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<Canvas>(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<BoxCollider>();
|
||||
col.isTrigger = true;
|
||||
var rectTransform = go.GetComponent<RectTransform>();
|
||||
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<BoxCollider>();
|
||||
col.isTrigger = true;
|
||||
var rectTransform = go.GetComponent<RectTransform>();
|
||||
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<RectTransform>();
|
||||
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<BoxCollider>();
|
||||
var rectTransform = go.GetComponent<RectTransform>();
|
||||
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<BoxCollider>();
|
||||
var rectTransform = go.GetComponent<RectTransform>();
|
||||
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<BoxCollider>();
|
||||
col.isTrigger = true;
|
||||
var rectTransform = go.GetComponent<RectTransform>();
|
||||
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<BoxCollider>();
|
||||
col.isTrigger = true;
|
||||
var rectTransform = go.GetComponent<RectTransform>();
|
||||
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<BoxCollider>();
|
||||
col.isTrigger = true;
|
||||
var rectTransform = go.GetComponent<RectTransform>();
|
||||
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<BoxCollider>();
|
||||
|
||||
var rectTransform = go.GetComponent<RectTransform>();
|
||||
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
|
||||
}
|
||||
|
|
@ -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<Task> 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<CVRCanvasWrapper>();
|
||||
|
||||
if (c is InputField input)
|
||||
{
|
||||
input.AddComponentIfMissing<InputFocusIntentDetector>();
|
||||
}
|
||||
|
||||
if (c is TMPro.TMP_InputField tmpInput)
|
||||
{
|
||||
tmpInput.AddComponentIfMissing<InputFocusIntentDetector>();
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnProcessCanvas(string collectionId, Canvas canvas)
|
||||
public class InputFocusIntentDetector : MonoBehaviour, IPointerClickHandler
|
||||
{
|
||||
canvas.gameObject.AddComponent<CVRCanvasWrapper>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<RootNamespace>ASTExtension</RootNamespace>
|
||||
<RootNamespace>SuperAwesomeMod</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="BTKUILib">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue