Move many mods to Deprecated folder, fix spelling

This commit is contained in:
NotAKidoS 2025-04-03 02:57:35 -05:00
parent 5e822cec8d
commit 0042590aa6
539 changed files with 7475 additions and 3120 deletions

View file

@ -0,0 +1,69 @@
using System.Collections;
using UnityEngine;
using System.Text;
using MelonLoader;
namespace NAK.LegacyContentMitigation.Debug;
public class CameraCallbackLogger
{
private static CameraCallbackLogger instance;
private readonly List<string> frameCallbacks = new();
private bool isListening;
private readonly StringBuilder logBuilder = new();
public static CameraCallbackLogger Instance => instance ??= new CameraCallbackLogger();
private void RegisterCallbacks()
{
Camera.onPreCull += (cam) => LogCallback(cam, "OnPreCull");
Camera.onPreRender += (cam) => LogCallback(cam, "OnPreRender");
Camera.onPostRender += (cam) => LogCallback(cam, "OnPostRender");
}
private void UnregisterCallbacks()
{
Camera.onPreCull -= (cam) => LogCallback(cam, "OnPreCull");
Camera.onPreRender -= (cam) => LogCallback(cam, "OnPreRender");
Camera.onPostRender -= (cam) => LogCallback(cam, "OnPostRender");
}
public void LogCameraEvents()
{
MelonCoroutines.Start(LoggingCoroutine());
}
private IEnumerator LoggingCoroutine()
{
yield return null; // idk at what point in frame start occurs
// First frame: Register and listen
RegisterCallbacks();
isListening = true;
yield return null;
// Second frame: Log and cleanup
isListening = false;
PrintFrameLog();
UnregisterCallbacks();
}
private void LogCallback(Camera camera, string callbackName)
{
if (!isListening) return;
frameCallbacks.Add($"{camera.name} - {callbackName} (Depth: {camera.depth})");
}
private void PrintFrameLog()
{
logBuilder.Clear();
logBuilder.AppendLine("\nCamera Callbacks for Frame:");
foreach (var callback in frameCallbacks)
logBuilder.AppendLine(callback);
LegacyContentMitigationMod.Logger.Msg(logBuilder.ToString());
frameCallbacks.Clear();
}
}

View file

@ -0,0 +1,100 @@
using ABI_RC.Core;
using ABI_RC.Core.Player;
using ABI_RC.Core.Savior;
using NAK.LegacyContentMitigation;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.XR;
namespace LegacyContentMitigation.Components;
public class FaceMirror : MonoBehaviour
{
private Camera _parentCamera;
private Camera _camera;
public Rect shiftRect;
private CommandBuffer _viewportBuffer;
private void Start() {
_parentCamera = GetComponent<Camera>();
_camera = new GameObject("Face Mirror").AddComponent<Camera>();
_camera.transform.parent = transform;
_camera.CopyFrom(_parentCamera);
_camera.ResetReplacementShader();
_camera.depth = 99;
_camera.clearFlags = CameraClearFlags.Depth;
_camera.transform.position += transform.forward * 0.5f;
_camera.transform.rotation *= Quaternion.Euler(0, 180, 0);
// View only CVRLayers.PlayerLocal
_camera.cullingMask = 1 << CVRLayers.PlayerLocal;
// Create and cache the command buffer
_viewportBuffer = new CommandBuffer();
_viewportBuffer.SetViewport(shiftRect);
_camera.AddCommandBuffer(CameraEvent.BeforeDepthTexture, _viewportBuffer);
_camera.AddCommandBuffer(CameraEvent.BeforeForwardOpaque, _viewportBuffer);
_camera.AddCommandBuffer(CameraEvent.BeforeForwardAlpha, _viewportBuffer);
_camera.AddCommandBuffer(CameraEvent.BeforeImageEffects, _viewportBuffer);
}
private void Update()
{
if (ModSettings.EntryUseFaceMirror.Value == false)
{
_camera.enabled = false;
return;
}
_camera.enabled = true;
// Update camera distance
_camera.transform.localPosition = Vector3.forward * ModSettings.EntryFaceMirrorDistance.Value;
// Get the display resolution based on VR status
int displayWidth, displayHeight;
if (MetaPort.Instance.isUsingVr)
{
displayWidth = XRSettings.eyeTextureWidth;
displayHeight = XRSettings.eyeTextureHeight;
}
else
{
displayWidth = Screen.width;
displayHeight = Screen.height;
}
// Calculate pixel sizes first
float pixelSizeX = ModSettings.EntryFaceMirrorSizeX.Value * displayWidth;
float pixelSizeY = ModSettings.EntryFaceMirrorSizeY.Value * displayHeight;
// Calculate offsets from center
float pixelOffsetX = (ModSettings.EntryFaceMirrorOffsetX.Value * displayWidth) - (pixelSizeX * 0.5f) + (displayWidth * 0.5f);
float pixelOffsetY = (ModSettings.EntryFaceMirrorOffsetY.Value * displayHeight) - (pixelSizeY * 0.5f) + (displayHeight * 0.5f);
_camera.transform.localScale = Vector3.one * ModSettings.EntryFaceMirrorCameraScale.Value;
Vector3 playerup = PlayerSetup.Instance.transform.up;
Vector3 cameraForward = _parentCamera.transform.forward;
// Check if playerup and cameraForward are nearly aligned
if (Mathf.Abs(Vector3.Dot(playerup, cameraForward)) <= Mathf.Epsilon) {
playerup = -_parentCamera.transform.forward;
cameraForward = _parentCamera.transform.up;
}
_camera.transform.rotation = Quaternion.LookRotation(-cameraForward, playerup);
// Create viewport rect with pixel values
shiftRect = new Rect(
pixelOffsetX,
pixelOffsetY,
pixelSizeX,
pixelSizeY
);
// Update the cached buffer's viewport
_viewportBuffer.Clear();
_viewportBuffer.SetViewport(shiftRect);
}
}

View file

@ -0,0 +1,230 @@
using ABI_RC.Core;
using ABI_RC.Core.Player;
using ABI_RC.Systems.UI;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.XR;
namespace NAK.LegacyContentMitigation;
public class FakeMultiPassHack : MonoBehaviour
{
private static readonly int s_WorldSpaceCameraPos = Shader.PropertyToID("_WorldSpaceCameraPos");
public static Action<bool> OnMultiPassActiveChanged;
#region Properties
public static FakeMultiPassHack Instance { get; set; }
public bool IsActive => IsEnabled && isActiveAndEnabled;
public bool IsEnabled { get; private set; }
public Camera.MonoOrStereoscopicEye RenderingEye { get; private set; }
#endregion
#region Private Fields
private Camera _mainCamera;
private Camera _leftEye;
private Camera _rightEye;
private GameObject _leftEyeObject;
private GameObject _rightEyeObject;
private RenderTexture _leftTexture;
private RenderTexture _rightTexture;
private CommandBuffer _shaderGlobalBuffer;
private CommandBuffer _leftEyeBuffer;
private int CachedCullingMask;
private bool _isInitialized;
#endregion
#region Unity Lifecycle
private void OnEnable()
{
Camera.onPreRender += OnPreRenderCallback;
if (IsEnabled) _mainCamera.cullingMask = 0;
}
private void OnDisable()
{
Camera.onPreRender -= OnPreRenderCallback;
if (IsEnabled) _mainCamera.cullingMask = CachedCullingMask;
}
private void OnDestroy()
{
if (_leftEye != null) RemoveCameraFromWorldTransitionSystem(_leftEye);
if (_rightEye != null) RemoveCameraFromWorldTransitionSystem(_rightEye);
if (_leftTexture != null) _leftTexture.Release();
if (_rightTexture != null) _rightTexture.Release();
_shaderGlobalBuffer?.Release();
_leftEyeBuffer?.Release();
if (_leftEyeObject != null) Destroy(_leftEyeObject);
if (_rightEyeObject != null) Destroy(_rightEyeObject);
return;
void RemoveCameraFromWorldTransitionSystem(Camera cam)
{
if (cam.TryGetComponent(out WorldTransitionCamera effectCam)) Destroy(effectCam);
WorldTransitionSystem.Cameras.Remove(cam);
}
}
#endregion
#region Public Methods
public void SetMultiPassActive(bool active)
{
if (active == IsEnabled) return;
IsEnabled = active;
if (active && !_isInitialized) DoInitialSetup();
_mainCamera.cullingMask = IsActive ? 0 : CachedCullingMask;
OnMultiPassActiveChanged?.Invoke(active);
}
public void OnMainCameraChanged()
{
if (!_isInitialized) return;
CachedCullingMask = _mainCamera.cullingMask;
if (IsActive) _mainCamera.cullingMask = 0;
CVRTools.CopyToDestCam(_mainCamera, _leftEye);
CVRTools.CopyToDestCam(_mainCamera, _rightEye);
}
#endregion
#region Initialization
private void DoInitialSetup()
{
_mainCamera = GetComponent<Camera>();
CachedCullingMask = _mainCamera.cullingMask;
_shaderGlobalBuffer = new CommandBuffer();
_leftEyeBuffer = new CommandBuffer();
SetupEye("Left Eye", out _leftEyeObject, out _leftEye, _leftEyeBuffer);
SetupEye("Right Eye", out _rightEyeObject, out _rightEye, null);
_isInitialized = true;
return;
void SetupEye(string camName, out GameObject eyeObj, out Camera eye, CommandBuffer eyeBuffer)
{
eyeObj = new GameObject(camName);
eyeObj.transform.parent = transform;
eyeObj.transform.localScale = Vector3.one;
eye = eyeObj.AddComponent<Camera>();
eye.enabled = false;
// Correct camera world space pos (nameplate shader)
eye.AddCommandBuffer(CameraEvent.BeforeDepthTexture, _shaderGlobalBuffer);
eye.AddCommandBuffer(CameraEvent.BeforeForwardOpaque, _shaderGlobalBuffer);
eye.AddCommandBuffer(CameraEvent.BeforeForwardAlpha, _shaderGlobalBuffer);
// normalizedViewport parameter is ignored, so we cannot draw mesh on right eye :)
if (eyeBuffer != null)
{
eye.AddCommandBuffer(CameraEvent.BeforeDepthTexture, eyeBuffer);
eye.AddCommandBuffer(CameraEvent.BeforeForwardOpaque, eyeBuffer);
eye.AddCommandBuffer(CameraEvent.BeforeForwardAlpha, eyeBuffer);
// notice how we pass fucked param vs UnityEngine.Rendering.XRUtils
eyeBuffer.DrawOcclusionMesh(new RectInt(0, 0, 0, 0));
}
WorldTransitionSystem.AddCamera(eye);
CVRTools.CopyToDestCam(_mainCamera, eye);
}
}
#endregion
#region Rendering
private void OnPreRenderCallback(Camera cam)
{
if (!IsEnabled || !_isInitialized) return;
if (cam.CompareTag("MainCamera"))
{
EnsureRenderTexturesCreated();
RenderEyePair();
}
}
private void EnsureRenderTexturesCreated()
{
int eyeWidth = XRSettings.eyeTextureWidth;
int eyeHeight = XRSettings.eyeTextureHeight;
bool needsUpdate = _leftTexture == null || _rightTexture == null ||
_leftTexture.width != eyeWidth || _leftTexture.height != eyeHeight;
if (!needsUpdate) return;
if (_leftTexture != null) _leftTexture.Release();
if (_rightTexture != null) _rightTexture.Release();
_leftTexture = new RenderTexture(eyeWidth, eyeHeight, 24, RenderTextureFormat.ARGBHalf);
_rightTexture = new RenderTexture(eyeWidth, eyeHeight, 24, RenderTextureFormat.ARGBHalf);
}
private void RenderEyePair()
{
_shaderGlobalBuffer.Clear();
_shaderGlobalBuffer.SetGlobalVector(s_WorldSpaceCameraPos, _mainCamera.transform.position);
Camera realVRCamera = PlayerSetup.Instance.vrCam;
RenderingEye = Camera.MonoOrStereoscopicEye.Left;
PlayerSetup.Instance.vrCam = _leftEye; // so we trigger head hiding
RenderEye(_leftEye, _leftTexture, Camera.StereoscopicEye.Left);
RenderingEye = Camera.MonoOrStereoscopicEye.Right;
PlayerSetup.Instance.vrCam = _rightEye; // so we trigger head hiding
RenderEye(_rightEye, _rightTexture, Camera.StereoscopicEye.Right);
RenderingEye = Camera.MonoOrStereoscopicEye.Mono; // bleh
PlayerSetup.Instance.vrCam = realVRCamera; // reset back to real cam
return;
void RenderEye(Camera eyeCamera, RenderTexture targetTexture, Camera.StereoscopicEye eye)
{
eyeCamera.CopyFrom(_mainCamera);
eyeCamera.targetTexture = targetTexture;
eyeCamera.cullingMask = CachedCullingMask;
eyeCamera.stereoTargetEye = StereoTargetEyeMask.None;
eyeCamera.cullingMatrix = _mainCamera.cullingMatrix;
eyeCamera.projectionMatrix = _mainCamera.GetStereoProjectionMatrix(eye);
eyeCamera.worldToCameraMatrix = _mainCamera.GetStereoViewMatrix(eye);
eyeCamera.Render();
eyeCamera.ResetCullingMatrix();
}
}
private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if (!IsEnabled || !_isInitialized || _leftTexture == null || _rightTexture == null)
{
Graphics.Blit(source, destination);
return;
}
Graphics.CopyTexture(_leftTexture, 0, destination, 0);
Graphics.CopyTexture(_rightTexture, 0, destination, 1);
}
#endregion
}

View file

@ -0,0 +1,86 @@
using ABI_RC.Core.InteractionSystem;
using ABI_RC.Core.Networking.API.Responses;
using ABI.CCK.Components;
using BTKUILib;
using BTKUILib.UIObjects;
using BTKUILib.UIObjects.Components;
using NAK.LegacyContentMitigation.Debug;
namespace NAK.LegacyContentMitigation.Integrations;
public static class BtkUiAddon
{
private static ToggleButton _currentModState;
public static void Initialize()
{
// Create menu late to ensure we at bottom.
// Doing this cause these settings are "Advanced" & mostly for debugging.
QuickMenuAPI.OnMenuGenerated += SetupCategory;
}
private static void SetupCategory(CVR_MenuManager _)
{
QuickMenuAPI.OnMenuGenerated -= SetupCategory;
Category category = QuickMenuAPI.MiscTabPage.AddCategory(ModSettings.LCM_SettingsCategory, ModSettings.ModName, true, true, true);
ToggleButton autoButton = category.AddMelonToggle(ModSettings.EntryAutoForLegacyWorlds);
autoButton.OnValueUpdated += (_) =>
{
if (CVRWorld.CompatibilityVersion == CompatibilityVersions.NotSpi)
QuickMenuAPI.ShowNotice("Legacy World Notice",
"You must reload this World Bundle for Shader Replacement to be undone / applied. " +
"Load into a different world and then rejoin.");
};
_currentModState = category.AddToggle(string.Empty, string.Empty, false);
_currentModState.OnValueUpdated += OnCurrentStateToggled;
Button printCameraCallbacksButton = category.AddButton("DEBUG LOG CAMERAS",
string.Empty, "Records Camera events & logs them next frame. Useful for determining camera render order shenanigans.");
printCameraCallbacksButton.OnPress += () => CameraCallbackLogger.Instance.LogCameraEvents();
OnMultiPassActiveChanged(FakeMultiPassHack.Instance.IsEnabled);
FakeMultiPassHack.OnMultiPassActiveChanged += OnMultiPassActiveChanged;
}
private static void OnCurrentStateToggled(bool state)
{
if (state)
{
_currentModState.ToggleValue = false; // dont visually update
QuickMenuAPI.ShowConfirm("Legacy Mitigation Warning",
"This will change how the main VR view is rendered and cause a noticeable performance hit. " +
"It is recommended to only enable this within Worlds that require it (Legacy Content/Broken Shaders). " +
"Shader Replacement will not occur for ALL content that is loaded while enabled. " +
"If this World is Legacy and already Shader Replaced, you must enable Auto For Legacy Worlds instead, " +
"load a different World, and then join back.",
() =>
{
FakeMultiPassHack.Instance.SetMultiPassActive(true);
OnMultiPassActiveChanged(true);
});
}
else
{
FakeMultiPassHack.Instance.SetMultiPassActive(false);
OnMultiPassActiveChanged(false);
}
}
private static void OnMultiPassActiveChanged(bool state)
{
_currentModState.ToggleValue = state;
if (state)
{
_currentModState.ToggleName = "Currently Active";
_currentModState.ToggleTooltip = "Fake Multi Pass is currently active.";
}
else
{
_currentModState.ToggleName = "Currently Inactive";
_currentModState.ToggleTooltip = "Fake Multi Pass is inactive.";
}
}
}

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net48</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Reference Include="BTKUILib">
<HintPath>..\.ManagedLibs\BTKUILib.dll</HintPath>
</Reference>
<Reference Include="TheClapper">
<HintPath>..\.ManagedLibs\TheClapper.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View file

@ -0,0 +1,68 @@
using ABI_RC.Core.InteractionSystem;
using MelonLoader;
using UnityEngine;
namespace NAK.LegacyContentMitigation;
public class LegacyContentMitigationMod : MelonMod
{
internal static MelonLogger.Instance Logger;
#region Melon Preferences
// private static readonly MelonPreferences_Category Category =
// MelonPreferences.CreateCategory(nameof(LegacyContentMitigationMod));
//
// private static readonly MelonPreferences_Entry<bool> EntryEnabled =
// Category.CreateEntry(
// "use_legacy_mitigation",
// true,
// "Enabled",
// description: "Enable legacy content camera hack when in Legacy worlds.");
#endregion Melon Preferences
#region Melon Events
public override void OnInitializeMelon()
{
Logger = LoggerInstance;
ApplyPatches(typeof(Patches.PlayerSetup_Patches)); // add MultiPassCamera to VR camera
ApplyPatches(typeof(Patches.SceneLoaded_Patches)); // enable / disable in legacy worlds
ApplyPatches(typeof(Patches.CVRWorld_Patches)); // post processing shit
ApplyPatches(typeof(Patches.CVRTools_Patches)); // prevent shader replacement when fix is active
ApplyPatches(typeof(Patches.HeadHiderManager_Patches)); // prevent main cam triggering early head hide
ApplyPatches(typeof(Patches.CVRMirror_Patches));
InitializeIntegration("BTKUILib", Integrations.BtkUiAddon.Initialize); // quick menu options
}
#endregion Melon Events
#region Melon Mod Utilities
private static void InitializeIntegration(string modName, Action integrationAction)
{
if (RegisteredMelons.All(it => it.Info.Name != modName))
return;
Logger.Msg($"Initializing {modName} integration.");
integrationAction.Invoke();
}
private void ApplyPatches(Type type)
{
try
{
HarmonyInstance.PatchAll(type);
}
catch (Exception e)
{
LoggerInstance.Msg($"Failed while patching {type.Name}!");
LoggerInstance.Error(e);
}
}
#endregion Melon Mod Utilities
}

View file

@ -0,0 +1,52 @@
using MelonLoader;
namespace NAK.LegacyContentMitigation;
internal static class ModSettings
{
#region Constants
internal const string ModName = nameof(LegacyContentMitigation);
internal const string LCM_SettingsCategory = "Legacy Content Mitigation";
#endregion Constants
#region Melon Preferences
private static readonly MelonPreferences_Category Category =
MelonPreferences.CreateCategory(ModName);
internal static readonly MelonPreferences_Entry<bool> EntryAutoForLegacyWorlds =
Category.CreateEntry("auto_for_legacy_worlds", true,
"Auto For Legacy Worlds", description: "Should Legacy View be auto enabled for detected Legacy worlds?");
internal static readonly MelonPreferences_Entry<float> EntryFaceMirrorDistance =
Category.CreateEntry("face_mirror_distance", 0.5f,
"Face Mirror Distance", description: "Distance from the camera to place the face mirror.");
internal static readonly MelonPreferences_Entry<float> EntryFaceMirrorOffsetX =
Category.CreateEntry("face_mirror_offset_x", 0f,
"Face Mirror Offset X", description: "Offset the face mirror on the X axis.");
internal static readonly MelonPreferences_Entry<float> EntryFaceMirrorOffsetY =
Category.CreateEntry("face_mirror_offset_y", 0f,
"Face Mirror Offset Y", description: "Offset the face mirror on the Y axis.");
internal static readonly MelonPreferences_Entry<float> EntryFaceMirrorSizeX =
Category.CreateEntry("face_mirror_size_x", 0.5f,
"Face Mirror Size X", description: "Size of the face mirror on the X axis.");
internal static readonly MelonPreferences_Entry<float> EntryFaceMirrorSizeY =
Category.CreateEntry("face_mirror_size_y", 0.5f,
"Face Mirror Size Y", description: "Size of the face mirror on the Y axis.");
internal static readonly MelonPreferences_Entry<float> EntryFaceMirrorCameraScale =
Category.CreateEntry("face_mirror_camera_scale", 1f,
"Face Mirror Camera Scale", description: "Scale of the face mirror camera.");
internal static readonly MelonPreferences_Entry<bool> EntryUseFaceMirror =
Category.CreateEntry("use_face_mirror", true,
"Use Face Mirror", description: "Should the face mirror be used?");
#endregion Melon Preferences
}

View file

@ -0,0 +1,145 @@
using ABI_RC.Core;
using ABI_RC.Core.Base;
using ABI_RC.Core.Base.Jobs;
using ABI_RC.Core.Networking.API.Responses;
using ABI_RC.Core.Player;
using ABI_RC.Core.Player.LocalClone;
using ABI_RC.Core.Player.TransformHider;
using ABI.CCK.Components;
using cohtml;
using cohtml.Net;
using HarmonyLib;
using LegacyContentMitigation.Components;
using UnityEngine;
using UnityEngine.Rendering.PostProcessing;
using UnityEngine.SceneManagement;
namespace NAK.LegacyContentMitigation.Patches;
internal static class PlayerSetup_Patches
{
[HarmonyPostfix]
[HarmonyPatch(typeof(PlayerSetup), nameof(PlayerSetup.Start))]
private static void Postfix_PlayerSetup_Start(ref PlayerSetup __instance)
{
__instance.vrCam.AddComponentIfMissing<FaceMirror>();
__instance.desktopCam.AddComponentIfMissing<FaceMirror>();
FakeMultiPassHack.Instance = __instance.vrCam.AddComponentIfMissing<FakeMultiPassHack>();
FakeMultiPassHack.Instance.enabled = ModSettings.EntryAutoForLegacyWorlds.Value;
}
}
internal static class SceneLoaded_Patches
{
[HarmonyPrefix]
[HarmonyPatch(typeof(SceneLoaded), nameof(SceneLoaded.OnSceneLoadedHandleJob))]
private static void Prefix_SceneLoaded_OnSceneLoadedHandleJob(Scene scene, LoadSceneMode mode)
{
if (mode == LoadSceneMode.Additive) return;
if (!ModSettings.EntryAutoForLegacyWorlds.Value)
{
LegacyContentMitigationMod.Logger.Msg("LegacyContentMitigationMod is disabled.");
FakeMultiPassHack.Instance.SetMultiPassActive(false);
return;
}
bool sceneIsNotSpi = CVRWorld.CompatibilityVersion == CompatibilityVersions.NotSpi;
string logText = sceneIsNotSpi
? "Legacy world detected, enabling legacy content mitigation."
: "Loaded scene is not considered Legacy content. Disabling if active.";
LegacyContentMitigationMod.Logger.Msg(logText);
FakeMultiPassHack.Instance.SetMultiPassActive(sceneIsNotSpi);
}
}
internal static class CVRWorld_Patches
{
// Third Person patches same methods:
// https://github.com/NotAKidoS/NAK_CVR_Mods/blob/3d6b1bbd59d23be19fe3594e104ad26e4ac0adcd/ThirdPerson/Patches.cs#L15-L22
[HarmonyPriority(Priority.Last)]
[HarmonyPostfix]
[HarmonyPatch(typeof(CVRWorld), nameof(CVRWorld.CopyRefCamValues))]
[HarmonyPatch(typeof(CVRWorld), nameof(CVRWorld.SetDefaultCamValues))]
private static void Postfix_CVRWorld_SetDefaultCamValues(ref CVRWorld __instance)
{
LegacyContentMitigationMod.Logger.Msg("Legacy world camera values updated.");
FakeMultiPassHack.Instance.OnMainCameraChanged();
}
[HarmonyPostfix]
[HarmonyPatch(typeof(CVRWorld), nameof(CVRWorld.UpdatePostProcessing))]
private static void Postfix_CVRWorld_UpdatePostProcessing(ref CVRWorld __instance)
{
if (!FakeMultiPassHack.Instance.IsActive) return;
foreach (PostProcessEffectSettings motionBlur in __instance._postProcessingMotionBlurList)
motionBlur.active = false; // force off cause its fucked and no one cares
}
}
internal static class CVRTools_Patches
{
[HarmonyPrefix]
[HarmonyPatch(typeof(CVRTools), nameof(CVRTools.ReplaceShaders), typeof(Material), typeof(string))]
private static bool Prefix_CVRTools_ReplaceShaders(Material material, string fallbackShaderName = "")
{
// When in a legacy world with the hack enabled, do not replace shaders
return !FakeMultiPassHack.Instance.IsActive;
}
}
internal static class HeadHiderManager_Patches
{
// despite the visual clone not being normally accessible, i fix it cause mod:
// https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/VisualCloneFix
[HarmonyPrefix]
[HarmonyPatch(typeof(TransformHiderManager), nameof(TransformHiderManager.OnPreRenderCallback))]
[HarmonyPatch(typeof(TransformHiderManager), nameof(TransformHiderManager.OnPreRenderCallback))]
[HarmonyPatch(typeof(LocalCloneManager), nameof(LocalCloneManager.OnPreRenderCallback))]
[HarmonyPatch(typeof(LocalCloneManager), nameof(LocalCloneManager.OnPostRenderCallback))]
private static bool Prefix_HeadHiderManagers_OnRenderCallbacks(Camera cam)
{
if (!FakeMultiPassHack.Instance.IsActive)
return true; // not active, no need
// dont let real camera trigger head hiding to occur or reset- leave it to the left/right eyes
return !cam.CompareTag("MainCamera"); // we spoof playersetup.activeCam, need check tag
}
[HarmonyPrefix]
[HarmonyPatch(typeof(TransformHiderManager), nameof(TransformHiderManager.OnPostRenderCallback))]
[HarmonyPatch(typeof(LocalCloneManager), nameof(LocalCloneManager.OnPostRenderCallback))]
private static void Prefix_HeadHiderManagers_OnPostRenderCallback(Camera cam, ref MonoBehaviour __instance)
{
if (!FakeMultiPassHack.Instance.IsActive) return;
if (FakeMultiPassHack.Instance.RenderingEye == Camera.MonoOrStereoscopicEye.Left)
SetResetAfterRenderFlag(__instance, true); // so right eye mirror sees head
if (FakeMultiPassHack.Instance.RenderingEye == Camera.MonoOrStereoscopicEye.Right)
SetResetAfterRenderFlag(__instance, !TransformHiderManager.s_UseCloneToCullUi); // dont undo if ui culling
return;
void SetResetAfterRenderFlag(MonoBehaviour headHiderManager, bool flag)
{
if (headHiderManager is LocalCloneManager localCloneManager)
localCloneManager._resetAfterThisRender = flag;
else if (headHiderManager is TransformHiderManager transformHiderManager)
transformHiderManager._resetAfterThisRender = flag;
}
}
}
internal static class CVRMirror_Patches
{
[HarmonyPostfix]
[HarmonyPatch(typeof(CVRMirror), nameof(CVRMirror.CopyCameraProperties))]
private static void Postfix_CVRMirror_CopyCameraProperties(ref CVRMirror __instance)
{
__instance.m_ReflectionCamera.ResetCullingMatrix();
}
}

View file

@ -0,0 +1,32 @@
using NAK.LegacyContentMitigation.Properties;
using MelonLoader;
using System.Reflection;
[assembly: AssemblyVersion(AssemblyInfoParams.Version)]
[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)]
[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)]
[assembly: AssemblyTitle(nameof(NAK.LegacyContentMitigation))]
[assembly: AssemblyCompany(AssemblyInfoParams.Author)]
[assembly: AssemblyProduct(nameof(NAK.LegacyContentMitigation))]
[assembly: MelonInfo(
typeof(NAK.LegacyContentMitigation.LegacyContentMitigationMod),
nameof(NAK.LegacyContentMitigation),
AssemblyInfoParams.Version,
AssemblyInfoParams.Author,
downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/LegacyContentMitigation"
)]
[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.LegacyContentMitigation.Properties;
internal static class AssemblyInfoParams
{
public const string Version = "1.0.2";
public const string Author = "Exterrata & NotAKidoS";
}

View file

@ -0,0 +1,18 @@
# LegacyContentMitigation
Experimental mod that manually renders both VR eyes separately while in Legacy Worlds.
The mod will automatically kick-in when loading NonSpi Worlds & prevent Shader Replacement for all content while active. You can also manually toggle it within the BTKUI Misc tab for experimenting.
-# There is an obvious performance penalty with rendering the world 2x & toggling the head hiding per eye, so enabling the mod outside of Legacy Worlds is not recommended.
---
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.

View file

@ -0,0 +1,23 @@
{
"_id": 247,
"name": "LegacyContentMitigation",
"modversion": "1.0.2",
"gameversion": "2024r177",
"loaderversion": "0.6.1",
"modtype": "Mod",
"author": "Exterrata, NotAKidoS",
"description": "Experimental mod that manually renders both VR eyes separately while in Legacy Worlds.\n\nThe mod will automatically kick-in when loading NonSpi Worlds & prevent Shader Replacement for all content while active. You can also manually toggle it within the BTKUI Misc tab for experimenting.\n\n-# There is an obvious performance penalty with rendering the world 2x & toggling the head hiding per eye, so enabling the mod outside of Legacy Worlds is not recommended.",
"searchtags": [
"legacy",
"content",
"spi",
"shaders"
],
"requirements": [
"BTKUILib"
],
"downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r44/LegacyContentMitigation.dll",
"sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/LegacyContentMitigation/",
"changelog": "- Initial release",
"embedcolor": "#f61963"
}