mirror of
https://github.com/NotAKidoS/NAK_CVR_Mods.git
synced 2025-09-01 13:59:22 +00:00
Merge remote-tracking branch 'Blackout/main'
Merged Blackout
This commit is contained in:
commit
ad2da17f48
14 changed files with 1041 additions and 0 deletions
95
Blackout/AssetHandler.cs
Normal file
95
Blackout/AssetHandler.cs
Normal file
|
@ -0,0 +1,95 @@
|
|||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NAK.Melons.Blackout;
|
||||
|
||||
/*
|
||||
|
||||
Kindly stolen from SDraw's leap motion mod. (MIT)
|
||||
https://github.com/SDraw/ml_mods_cvr/blob/master/ml_lme/AssetsHandler.cs
|
||||
|
||||
*thank u sdraw, i wont be murderer now*
|
||||
|
||||
*/
|
||||
|
||||
|
||||
static class AssetsHandler
|
||||
{
|
||||
static readonly List<string> ms_assets = new List<string>()
|
||||
{
|
||||
"blackout_controller.asset"
|
||||
};
|
||||
|
||||
static Dictionary<string, AssetBundle> ms_loadedAssets = new Dictionary<string, AssetBundle>();
|
||||
static Dictionary<string, GameObject> ms_loadedObjects = new Dictionary<string, GameObject>();
|
||||
|
||||
public static void Load()
|
||||
{
|
||||
Assembly l_assembly = Assembly.GetExecutingAssembly();
|
||||
string l_assemblyName = l_assembly.GetName().Name;
|
||||
|
||||
foreach (string l_assetName in ms_assets)
|
||||
{
|
||||
try
|
||||
{
|
||||
Stream l_assetStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + l_assetName);
|
||||
if (l_assetStream != null)
|
||||
{
|
||||
MemoryStream l_memorySteam = new MemoryStream((int)l_assetStream.Length);
|
||||
l_assetStream.CopyTo(l_memorySteam);
|
||||
AssetBundle l_assetBundle = AssetBundle.LoadFromMemory(l_memorySteam.ToArray(), 0);
|
||||
if (l_assetBundle != null)
|
||||
{
|
||||
l_assetBundle.hideFlags |= HideFlags.DontUnloadUnusedAsset;
|
||||
ms_loadedAssets.Add(l_assetName, l_assetBundle);
|
||||
}
|
||||
else
|
||||
MelonLoader.MelonLogger.Warning("Unable to load bundled '" + l_assetName + "' asset");
|
||||
}
|
||||
else
|
||||
MelonLoader.MelonLogger.Warning("Unable to get bundled '" + l_assetName + "' asset stream");
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
MelonLoader.MelonLogger.Warning("Unable to load bundled '" + l_assetName + "' asset, reason: " + e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static GameObject GetAsset(string p_name)
|
||||
{
|
||||
GameObject l_result = null;
|
||||
if (ms_loadedObjects.ContainsKey(p_name))
|
||||
{
|
||||
l_result = UnityEngine.Object.Instantiate(ms_loadedObjects[p_name]);
|
||||
l_result.SetActive(true);
|
||||
l_result.hideFlags |= HideFlags.DontUnloadUnusedAsset;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var l_pair in ms_loadedAssets)
|
||||
{
|
||||
if (l_pair.Value.Contains(p_name))
|
||||
{
|
||||
GameObject l_bundledObject = (GameObject)l_pair.Value.LoadAsset(p_name, typeof(GameObject));
|
||||
if (l_bundledObject != null)
|
||||
{
|
||||
ms_loadedObjects.Add(p_name, l_bundledObject);
|
||||
l_result = UnityEngine.Object.Instantiate(l_bundledObject);
|
||||
l_result.SetActive(true);
|
||||
l_result.hideFlags |= HideFlags.DontUnloadUnusedAsset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return l_result;
|
||||
}
|
||||
|
||||
public static void Unload()
|
||||
{
|
||||
foreach (var l_pair in ms_loadedAssets)
|
||||
UnityEngine.Object.Destroy(l_pair.Value);
|
||||
ms_loadedAssets.Clear();
|
||||
}
|
||||
}
|
84
Blackout/Blackout.csproj
Normal file
84
Blackout/Blackout.csproj
Normal file
|
@ -0,0 +1,84 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="resources\blackout_controller.asset" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="resources\blackout_controller.asset" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\MelonLoader\0Harmony.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp-firstpass">
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="BTKUILib">
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\BTKUILib.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Cohtml.Runtime">
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Giamoz">
|
||||
<HintPath>..\..\Giamoz\Giamoz\bin\Debug\net472\Giamoz.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MelonLoader">
|
||||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\MelonLoader\MelonLoader.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SteamVR">
|
||||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\SteamVR.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UIExpansionKit">
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\UIExpansionKit.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.AnimationModule">
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.AssetBundleModule">
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AssetBundleModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.InputLegacyModule">
|
||||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.InputLegacyModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.PhysicsModule">
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Resource1.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resource1.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Resource1.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resource1.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="Deploy" AfterTargets="Build">
|
||||
<Copy SourceFiles="$(TargetPath)" DestinationFolder="C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\" />
|
||||
<Message Text="Copied $(TargetPath) to C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\" Importance="high" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
25
Blackout/Blackout.sln
Normal file
25
Blackout/Blackout.sln
Normal file
|
@ -0,0 +1,25 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.2.32630.192
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blackout", "Blackout.csproj", "{1D5ABEE5-ACFA-4B0C-9195-968FA3DFEECD}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{1D5ABEE5-ACFA-4B0C-9195-968FA3DFEECD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1D5ABEE5-ACFA-4B0C-9195-968FA3DFEECD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1D5ABEE5-ACFA-4B0C-9195-968FA3DFEECD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1D5ABEE5-ACFA-4B0C-9195-968FA3DFEECD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {698498B4-20BF-45AF-A7A3-2F8091D6AE7E}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
323
Blackout/BlackoutController.cs
Normal file
323
Blackout/BlackoutController.cs
Normal file
|
@ -0,0 +1,323 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Savior;
|
||||
using ABI_RC.Core.UI;
|
||||
using MelonLoader;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NAK.Melons.Blackout;
|
||||
|
||||
/*
|
||||
|
||||
Functionality heavily inspired by VRSleeper on Booth: https://booth.pm/ja/items/2151940
|
||||
|
||||
There are three states of "blackout":
|
||||
|
||||
0 - Awake (no effect)
|
||||
1 - Drowsy (partial effect)
|
||||
2 - Sleep (full effect)
|
||||
|
||||
After staying still for DrowsyModeTimer (minutes), you enter DrowsyMode.
|
||||
This mode dims the screen to your selected dimming strength.
|
||||
After continuing to stay still for SleepModeTimer (seconds), you enter SleepMode.
|
||||
This mode overrenders mostly everything with black.
|
||||
|
||||
Slight movement while in SleepMode will place you in DrowsyMode until SleepModeTimer is reached again.
|
||||
Hard movement once entering DrowsyMode will fully wake you and return complete vision.
|
||||
|
||||
*/
|
||||
|
||||
public class BlackoutController : MonoBehaviour
|
||||
{
|
||||
public static BlackoutController Instance;
|
||||
|
||||
// The current state of the player's consciousness.
|
||||
public BlackoutState CurrentState = BlackoutState.Awake;
|
||||
|
||||
// Should the states automatically change based on time?
|
||||
public bool AutomaticStateChange = true;
|
||||
// Should the sleep state be automatically transitioned to? Some may prefer drowsy state only due to dimming.
|
||||
public bool AutoSleepState = true;
|
||||
|
||||
// The minimum amount of movement required to partially restore vision.
|
||||
public float drowsyThreshold = 2f;
|
||||
// The minimum amount of movement required to fully restore vision.
|
||||
public float wakeThreshold = 4f;
|
||||
|
||||
// The amount of time the player must remain still to enter drowsy state (in minutes).
|
||||
public float DrowsyModeTimer = 3f;
|
||||
// The amount of time the player must remain in drowsy state before entering sleep state (in seconds).
|
||||
public float SleepModeTimer = 10f;
|
||||
|
||||
// The amount by which DrowsyMode affects the screen.
|
||||
public float DrowsyDimStrength = 0.6f;
|
||||
// Should DrowsyDimStrength be affected by velocity?
|
||||
public bool DrowsyVelocityMultiplier = true;
|
||||
|
||||
// Whether to display HUD messages.
|
||||
public bool HudMessages = true;
|
||||
|
||||
// Whether to lower the frame rate while in sleep mode.
|
||||
public bool DropFPSOnSleep = false;
|
||||
|
||||
// The available states of consciousness.
|
||||
public enum BlackoutState
|
||||
{
|
||||
Awake = 0,
|
||||
Drowsy,
|
||||
Sleeping,
|
||||
}
|
||||
|
||||
private Camera activeModeCam;
|
||||
private Vector3 headVelocity = Vector3.zero;
|
||||
private Vector3 lastHeadPos = Vector3.zero;
|
||||
private float curTime = 0f;
|
||||
private float lastAwakeTime = 0f;
|
||||
private Animator blackoutAnimator;
|
||||
private int targetFPS;
|
||||
|
||||
public void ChangeBlackoutStateFromInt(int state) => ChangeBlackoutState((BlackoutState)state);
|
||||
|
||||
// Changes the player's state of consciousness.
|
||||
public void ChangeBlackoutState(BlackoutState newState)
|
||||
{
|
||||
if (!blackoutAnimator) return;
|
||||
if (newState == CurrentState) return;
|
||||
|
||||
lastAwakeTime = curTime;
|
||||
|
||||
// Update the blackout animator based on the new state.
|
||||
switch (newState)
|
||||
{
|
||||
case BlackoutState.Awake:
|
||||
blackoutAnimator.SetBool("BlackoutState.Drowsy", false);
|
||||
blackoutAnimator.SetBool("BlackoutState.Sleeping", false);
|
||||
drowsyMagnitude = 0f;
|
||||
break;
|
||||
case BlackoutState.Drowsy:
|
||||
blackoutAnimator.SetBool("BlackoutState.Drowsy", true);
|
||||
blackoutAnimator.SetBool("BlackoutState.Sleeping", false);
|
||||
drowsyMagnitude = 0f;
|
||||
break;
|
||||
case BlackoutState.Sleeping:
|
||||
blackoutAnimator.SetBool("BlackoutState.Drowsy", false);
|
||||
blackoutAnimator.SetBool("BlackoutState.Sleeping", true);
|
||||
drowsyMagnitude = 1f;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Update the current state and send a HUD message if enabled.
|
||||
BlackoutState prevState = CurrentState;
|
||||
CurrentState = newState;
|
||||
SendHUDMessage($"Exiting {prevState} and entering {newState} state.");
|
||||
ChangeTargetFPS();
|
||||
}
|
||||
|
||||
public void AdjustDrowsyDimStrength(float multiplier = 1f)
|
||||
{
|
||||
blackoutAnimator.SetFloat("BlackoutSetting.DrowsyStrength", DrowsyDimStrength * multiplier);
|
||||
}
|
||||
|
||||
// Initialize the BlackoutInstance object.
|
||||
void Start()
|
||||
{
|
||||
Instance = this;
|
||||
|
||||
// Get the blackout asset and instantiate it.
|
||||
GameObject blackoutAsset = AssetsHandler.GetAsset("Assets/BundledAssets/Blackout/Blackout.prefab");
|
||||
GameObject blackoutGO = Instantiate(blackoutAsset, new Vector3(0, 0, 0), Quaternion.identity);
|
||||
blackoutGO.name = "BlackoutInstance";
|
||||
|
||||
// Get the blackout animator component.
|
||||
blackoutAnimator = blackoutGO.GetComponent<Animator>();
|
||||
if (!blackoutAnimator)
|
||||
{
|
||||
MelonLogger.Error("Blackout: Could not find blackout animator component!");
|
||||
return;
|
||||
}
|
||||
|
||||
SetupBlackoutInstance();
|
||||
|
||||
//we dont want this to ever disable
|
||||
Camera.onPreRender += OnPreRender;
|
||||
Camera.onPostRender += OnPostRender;
|
||||
}
|
||||
|
||||
//Automatic State Change
|
||||
void Update()
|
||||
{
|
||||
//get the current position of the player's head
|
||||
Vector3 curHeadPos = activeModeCam.transform.position;
|
||||
//calculate the player's head velocity by taking the difference in position
|
||||
headVelocity = (curHeadPos - lastHeadPos) / Time.deltaTime;
|
||||
//store the current head position for use in the next frame
|
||||
lastHeadPos = curHeadPos;
|
||||
|
||||
if (AutomaticStateChange)
|
||||
{
|
||||
curTime = Time.time;
|
||||
//handle current state
|
||||
switch (CurrentState)
|
||||
{
|
||||
case BlackoutState.Awake:
|
||||
HandleAwakeState();
|
||||
break;
|
||||
case BlackoutState.Drowsy:
|
||||
HandleDrowsyState();
|
||||
break;
|
||||
case BlackoutState.Sleeping:
|
||||
HandleSleepingState();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CalculateDimmingMultiplier();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnEnable()
|
||||
{
|
||||
curTime = Time.time;
|
||||
lastAwakeTime = curTime;
|
||||
}
|
||||
|
||||
public void OnDisable()
|
||||
{
|
||||
ChangeBlackoutState(BlackoutState.Awake);
|
||||
}
|
||||
|
||||
void OnPreRender(Camera cam)
|
||||
{
|
||||
if (cam == activeModeCam) return;
|
||||
blackoutAnimator.transform.localScale = Vector3.zero;
|
||||
}
|
||||
|
||||
void OnPostRender(Camera cam)
|
||||
{
|
||||
blackoutAnimator.transform.localScale = Vector3.one;
|
||||
}
|
||||
|
||||
public void SetupBlackoutInstance()
|
||||
{
|
||||
activeModeCam = PlayerSetup.Instance.GetActiveCamera().GetComponent<Camera>();
|
||||
blackoutAnimator.transform.parent = activeModeCam.transform;
|
||||
blackoutAnimator.transform.localPosition = Vector3.zero;
|
||||
blackoutAnimator.transform.localRotation = Quaternion.identity;
|
||||
blackoutAnimator.transform.localScale = Vector3.one;
|
||||
}
|
||||
|
||||
private float GetNextStateTimer()
|
||||
{
|
||||
switch (CurrentState)
|
||||
{
|
||||
case BlackoutState.Awake:
|
||||
return (lastAwakeTime + DrowsyModeTimer * 60 - curTime);
|
||||
case BlackoutState.Drowsy:
|
||||
return (lastAwakeTime + SleepModeTimer - curTime);
|
||||
case BlackoutState.Sleeping:
|
||||
return 0f;
|
||||
default:
|
||||
return 0f;
|
||||
}
|
||||
}
|
||||
|
||||
//broken, needs to run next frame
|
||||
private void SendHUDMessage(string message)
|
||||
{
|
||||
MelonLogger.Msg(message);
|
||||
if (!CohtmlHud.Instance || !HudMessages) return;
|
||||
|
||||
StringBuilder secondmessage = new StringBuilder();
|
||||
if (AutomaticStateChange)
|
||||
{
|
||||
if (CurrentState == BlackoutState.Drowsy && !AutoSleepState)
|
||||
{
|
||||
secondmessage = new StringBuilder("AutoSleepState is disabled. Staying in Drowsy State.");
|
||||
}
|
||||
else
|
||||
{
|
||||
secondmessage = new StringBuilder(GetNextStateTimer().ToString() + " seconds till next state change.");
|
||||
}
|
||||
}
|
||||
|
||||
CohtmlHud.Instance.ViewDropTextImmediate("Blackout", message, secondmessage.ToString());
|
||||
}
|
||||
|
||||
private void ChangeTargetFPS()
|
||||
{
|
||||
if (!DropFPSOnSleep) return;
|
||||
|
||||
//store target FPS to restore, i check each time just in case it changed
|
||||
targetFPS = MetaPort.Instance.settings.GetSettingInt("GraphicsFramerateTarget", 0);
|
||||
|
||||
Application.targetFrameRate = (CurrentState == BlackoutState.Sleeping) ? 5 : targetFPS;
|
||||
}
|
||||
|
||||
private void HandleAwakeState()
|
||||
{
|
||||
//small movement should reset sleep timer
|
||||
if (headVelocity.magnitude > drowsyThreshold)
|
||||
{
|
||||
lastAwakeTime = curTime;
|
||||
}
|
||||
//enter drowsy mode after few minutes
|
||||
if (curTime > lastAwakeTime + DrowsyModeTimer * 60)
|
||||
{
|
||||
ChangeBlackoutState(BlackoutState.Drowsy);
|
||||
}
|
||||
}
|
||||
|
||||
public float fadeSpeed = 0.8f; // The speed at which the value fades back to 0 or increases
|
||||
public float minimumThreshold = 0.5f; // The minimum value that the drowsy magnitude can have
|
||||
public float drowsyMagnitude = 0f;
|
||||
|
||||
private void CalculateDimmingMultiplier()
|
||||
{
|
||||
if (!DrowsyVelocityMultiplier)
|
||||
{
|
||||
AdjustDrowsyDimStrength();
|
||||
return;
|
||||
}
|
||||
|
||||
float normalizedMagnitude = headVelocity.magnitude / wakeThreshold;
|
||||
float targetMagnitude = 1f - normalizedMagnitude;
|
||||
targetMagnitude = Mathf.Max(targetMagnitude, minimumThreshold);
|
||||
drowsyMagnitude = Mathf.Lerp(drowsyMagnitude, targetMagnitude, fadeSpeed * Time.deltaTime);
|
||||
AdjustDrowsyDimStrength(drowsyMagnitude);
|
||||
}
|
||||
|
||||
private void HandleDrowsyState()
|
||||
{
|
||||
//hard movement should exit drowsy state
|
||||
if (headVelocity.magnitude > wakeThreshold)
|
||||
{
|
||||
ChangeBlackoutState(BlackoutState.Awake);
|
||||
return;
|
||||
}
|
||||
//small movement should reset sleep timer
|
||||
if (headVelocity.magnitude > drowsyThreshold)
|
||||
{
|
||||
lastAwakeTime = curTime;
|
||||
}
|
||||
//enter full sleep mode
|
||||
if (AutoSleepState && curTime > lastAwakeTime + SleepModeTimer)
|
||||
{
|
||||
ChangeBlackoutState(BlackoutState.Sleeping);
|
||||
}
|
||||
CalculateDimmingMultiplier();
|
||||
}
|
||||
|
||||
private void HandleSleepingState()
|
||||
{
|
||||
//small movement should enter drowsy state
|
||||
if (headVelocity.magnitude > drowsyThreshold)
|
||||
{
|
||||
ChangeBlackoutState(BlackoutState.Drowsy);
|
||||
}
|
||||
}
|
||||
}
|
24
Blackout/HarmonyPatches.cs
Normal file
24
Blackout/HarmonyPatches.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Savior;
|
||||
using HarmonyLib;
|
||||
using MelonLoader;
|
||||
|
||||
namespace NAK.Melons.Blackout.HarmonyPatches;
|
||||
|
||||
[HarmonyPatch]
|
||||
internal class HarmonyPatches
|
||||
{
|
||||
//Support for changing VRMode during runtime.
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(PlayerSetup), "CalibrateAvatar")]
|
||||
private static void CheckVRModeOnSwitch()
|
||||
{
|
||||
if (Blackout.inVR != MetaPort.Instance.isUsingVr)
|
||||
{
|
||||
MelonLogger.Msg("VRMode change detected! Reinitializing Blackout Instance...");
|
||||
Blackout.inVR = MetaPort.Instance.isUsingVr;
|
||||
BlackoutController.Instance.SetupBlackoutInstance();
|
||||
BlackoutController.Instance.ChangeBlackoutState(BlackoutController.BlackoutState.Awake);
|
||||
}
|
||||
}
|
||||
}
|
63
Blackout/Integrations/BTKUIAddon.cs
Normal file
63
Blackout/Integrations/BTKUIAddon.cs
Normal file
|
@ -0,0 +1,63 @@
|
|||
using BTKUILib;
|
||||
using BTKUILib.UIObjects;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace NAK.Melons.Blackout;
|
||||
|
||||
public static class BTKUIAddon
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static void Init()
|
||||
{
|
||||
//Add myself to the Misc Menu
|
||||
Page miscPage = QuickMenuAPI.MiscTabPage;
|
||||
Category miscCategory = miscPage.AddCategory(Blackout.SettingsCategory);
|
||||
|
||||
AddMelonToggle(ref miscCategory, Blackout.m_entryEnabled);
|
||||
|
||||
//Add my own page to not clog up Misc Menu
|
||||
|
||||
Page blackoutPage = miscCategory.AddPage("Blackout Settings", "", "Configure the settings for Blackout.", "Blackout");
|
||||
blackoutPage.MenuTitle = "Blackout Settings";
|
||||
blackoutPage.MenuSubtitle = "Dim screen after set time of sitting still, or configure with manual control. Should be nice for VR sleeping.";
|
||||
|
||||
Category blackoutCategory = blackoutPage.AddCategory("Blackout");
|
||||
|
||||
AddMelonToggle(ref blackoutCategory, Blackout.m_entryEnabled);
|
||||
|
||||
//manual state changing
|
||||
var state_Awake = blackoutCategory.AddButton("Awake State", null, "Enter the Awake State.");
|
||||
state_Awake.OnPress += () => BlackoutController.Instance?.ChangeBlackoutState(BlackoutController.BlackoutState.Awake);
|
||||
var state_Drowsy = blackoutCategory.AddButton("Drowsy State", null, "Enter the Drowsy State.");
|
||||
state_Drowsy.OnPress += () => BlackoutController.Instance?.ChangeBlackoutState(BlackoutController.BlackoutState.Drowsy);
|
||||
var state_Sleeping = blackoutCategory.AddButton("Sleeping State", null, "Enter the Sleeping State.");
|
||||
state_Sleeping.OnPress += () => BlackoutController.Instance?.ChangeBlackoutState(BlackoutController.BlackoutState.Sleeping);
|
||||
|
||||
//dimming strength
|
||||
AddMelonSlider(ref blackoutPage, Blackout.m_entryDrowsyDimStrength, 0f, 1f);
|
||||
|
||||
//velocity dim multiplier
|
||||
AddMelonToggle(ref blackoutCategory, Blackout.m_entryDrowsyVelocityMultiplier);
|
||||
|
||||
//hud messages
|
||||
AddMelonToggle(ref blackoutCategory, Blackout.m_entryHudMessages);
|
||||
|
||||
//lower fps while sleep (desktop)
|
||||
AddMelonToggle(ref blackoutCategory, Blackout.m_entryDropFPSOnSleep);
|
||||
|
||||
//auto sleep state
|
||||
AddMelonToggle(ref blackoutCategory, Blackout.m_entryAutoSleepState);
|
||||
|
||||
//i will add the rest of the settings once BTKUILib supports int input
|
||||
}
|
||||
|
||||
private static void AddMelonToggle(ref Category category, MelonLoader.MelonPreferences_Entry<bool> entry)
|
||||
{
|
||||
category.AddToggle(entry.DisplayName, entry.Description, entry.Value).OnValueUpdated += b => entry.Value = b;
|
||||
}
|
||||
|
||||
private static void AddMelonSlider(ref Page page, MelonLoader.MelonPreferences_Entry<float> entry, float min, float max)
|
||||
{
|
||||
page.AddSlider(entry.DisplayName, entry.Description, entry.Value, min, max).OnValueUpdated += f => entry.Value = f;
|
||||
}
|
||||
}
|
29
Blackout/Integrations/UIExpansionKitAddon.cs
Normal file
29
Blackout/Integrations/UIExpansionKitAddon.cs
Normal file
|
@ -0,0 +1,29 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
using UIExpansionKit.API;
|
||||
|
||||
namespace NAK.Melons.Blackout;
|
||||
public static class UIExpansionKitAddon
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static void Init()
|
||||
{
|
||||
/**
|
||||
ive spent hours debugging this, and no matter what the buttons wont actually call the actions
|
||||
from logging shit to straight up closing the game, nothing
|
||||
|
||||
implementing btkuilib support, but gonna leave this shit as a reminder why to not use uiexpansionkit
|
||||
also because it **used to work**... a game update broke it and uiexpansionkit hasnt updated since
|
||||
|
||||
what pisses me off more, is that DesktopVRSwitch works, and that was originally copied from Blackout -_-
|
||||
https://github.com/NotAKidOnSteam/DesktopVRSwitch/blob/main/DesktopVRSwitch/UIExpansionKitAddon.cs
|
||||
**/
|
||||
var settings = ExpansionKitApi.GetSettingsCategory(Blackout.SettingsCategory);
|
||||
settings.AddSimpleButton("Awake State", AwakeState);
|
||||
settings.AddSimpleButton("Drowsy State", DrowsyState);
|
||||
settings.AddSimpleButton("Sleep State", SleepingState);
|
||||
}
|
||||
//UIExpansionKit actions
|
||||
internal static void AwakeState() => BlackoutController.Instance?.ChangeBlackoutState(BlackoutController.BlackoutState.Awake);
|
||||
internal static void DrowsyState() => BlackoutController.Instance?.ChangeBlackoutState(BlackoutController.BlackoutState.Drowsy);
|
||||
internal static void SleepingState() => BlackoutController.Instance?.ChangeBlackoutState(BlackoutController.BlackoutState.Sleeping);
|
||||
}
|
111
Blackout/Main.cs
Normal file
111
Blackout/Main.cs
Normal file
|
@ -0,0 +1,111 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Savior;
|
||||
using MelonLoader;
|
||||
|
||||
namespace NAK.Melons.Blackout;
|
||||
|
||||
public class Blackout : MelonMod
|
||||
{
|
||||
internal static bool inVR;
|
||||
internal const string SettingsCategory = "Blackout";
|
||||
|
||||
internal static MelonPreferences_Category m_categoryBlackout;
|
||||
internal static MelonPreferences_Entry<bool>
|
||||
m_entryEnabled,
|
||||
m_entryAutoSleepState,
|
||||
m_entryHudMessages,
|
||||
m_entryDropFPSOnSleep,
|
||||
m_entryDrowsyVelocityMultiplier;
|
||||
internal static MelonPreferences_Entry<float>
|
||||
m_entryDrowsyThreshold, m_entryAwakeThreshold,
|
||||
m_entryDrowsyModeTimer, m_entrySleepModeTimer,
|
||||
m_entryDrowsyDimStrength;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
m_categoryBlackout = MelonPreferences.CreateCategory(SettingsCategory);
|
||||
m_entryEnabled = m_categoryBlackout.CreateEntry<bool>("Automatic State Change", true, description: "Should the screen automatically dim if head is still for enough time?");
|
||||
m_entryEnabled.OnEntryValueChangedUntyped.Subscribe(OnUpdateEnabled);
|
||||
m_entryHudMessages = m_categoryBlackout.CreateEntry<bool>("Hud Messages", true, description: "Notify on state change.");
|
||||
m_entryDropFPSOnSleep = m_categoryBlackout.CreateEntry<bool>("Limit FPS While Sleep", false, description: "Limits FPS to 5 while in Sleep State. This only works in Desktop, as SteamVR/HMD handles VR FPS.");
|
||||
m_entryDrowsyVelocityMultiplier = m_categoryBlackout.CreateEntry<bool>("Drowsy Velocity Multiplier", true, description: "Should head velocity act as a multiplier to Drowsy Dim Strength?");
|
||||
m_entryAutoSleepState = m_categoryBlackout.CreateEntry<bool>("Auto Sleep State", true, description: "Should the sleep state be used during Automatic State Change?");
|
||||
m_entryDrowsyThreshold = m_categoryBlackout.CreateEntry<float>("Drowsy Threshold", 2f, description: "Velocity to return partial vision.");
|
||||
m_entryAwakeThreshold = m_categoryBlackout.CreateEntry<float>("Awake Threshold", 4f, description: "Velocity to return full vision.");
|
||||
m_entryDrowsyModeTimer = m_categoryBlackout.CreateEntry<float>("Enter Drowsy Time (Minutes)", 3f, description: "How many minutes without movement until enter drowsy mode.");
|
||||
m_entrySleepModeTimer = m_categoryBlackout.CreateEntry<float>("Enter Sleep Time (Seconds)", 10f, description: "How many seconds without movement until enter sleep mode.");
|
||||
m_entryDrowsyDimStrength = m_categoryBlackout.CreateEntry<float>("Drowsy Dim Strength", 0.6f, description: "How strong of a dimming effect should drowsy mode have.");
|
||||
|
||||
foreach (var setting in m_categoryBlackout.Entries)
|
||||
{
|
||||
if (!setting.OnEntryValueChangedUntyped.GetSubscribers().Any())
|
||||
setting.OnEntryValueChangedUntyped.Subscribe(OnUpdateSettings);
|
||||
}
|
||||
|
||||
//UIExpansionKit addon
|
||||
if (MelonMod.RegisteredMelons.Any(it => it.Info.Name == "UI Expansion Kit"))
|
||||
{
|
||||
MelonLogger.Msg("Initializing UIExpansionKit support.");
|
||||
UIExpansionKitAddon.Init();
|
||||
}
|
||||
|
||||
//BTKUILib addon
|
||||
if (MelonMod.RegisteredMelons.Any(it => it.Info.Name == "BTKUILib"))
|
||||
{
|
||||
MelonLogger.Msg("Initializing BTKUILib support.");
|
||||
BTKUIAddon.Init();
|
||||
}
|
||||
|
||||
MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator WaitForLocalPlayer()
|
||||
{
|
||||
//load blackout_controller.asset
|
||||
AssetsHandler.Load();
|
||||
|
||||
while (PlayerSetup.Instance == null)
|
||||
yield return null;
|
||||
|
||||
inVR = MetaPort.Instance.isUsingVr;
|
||||
PlayerSetup.Instance.gameObject.AddComponent<BlackoutController>();
|
||||
|
||||
//update BlackoutController settings after it initializes
|
||||
while (BlackoutController.Instance == null)
|
||||
yield return null;
|
||||
|
||||
UpdateAllSettings();
|
||||
OnEnabled();
|
||||
}
|
||||
|
||||
private void OnEnabled()
|
||||
{
|
||||
if (!BlackoutController.Instance) return;
|
||||
if (m_entryEnabled.Value)
|
||||
{
|
||||
BlackoutController.Instance.OnEnable();
|
||||
}
|
||||
else
|
||||
{
|
||||
BlackoutController.Instance.OnDisable();
|
||||
}
|
||||
BlackoutController.Instance.AutomaticStateChange = m_entryEnabled.Value;
|
||||
}
|
||||
|
||||
private void UpdateAllSettings()
|
||||
{
|
||||
if (!BlackoutController.Instance) return;
|
||||
BlackoutController.Instance.HudMessages = m_entryHudMessages.Value;
|
||||
BlackoutController.Instance.AutoSleepState = m_entryAutoSleepState.Value;
|
||||
BlackoutController.Instance.DropFPSOnSleep = m_entryDropFPSOnSleep.Value;
|
||||
BlackoutController.Instance.drowsyThreshold = m_entryDrowsyThreshold.Value;
|
||||
BlackoutController.Instance.wakeThreshold = m_entryAwakeThreshold.Value;
|
||||
BlackoutController.Instance.DrowsyModeTimer = m_entryDrowsyModeTimer.Value;
|
||||
BlackoutController.Instance.SleepModeTimer = m_entrySleepModeTimer.Value;
|
||||
BlackoutController.Instance.DrowsyDimStrength = m_entryDrowsyDimStrength.Value;
|
||||
BlackoutController.Instance.DrowsyVelocityMultiplier = m_entryDrowsyVelocityMultiplier.Value;
|
||||
}
|
||||
|
||||
private void OnUpdateEnabled(object arg1, object arg2) => OnEnabled();
|
||||
private void OnUpdateSettings(object arg1, object arg2) => UpdateAllSettings();
|
||||
}
|
31
Blackout/Properties/AssemblyInfo.cs
Normal file
31
Blackout/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
using NAK.Melons.Blackout.Properties;
|
||||
using MelonLoader;
|
||||
using System.Reflection;
|
||||
|
||||
|
||||
[assembly: AssemblyVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyTitle(nameof(NAK.Melons.Blackout))]
|
||||
[assembly: AssemblyCompany(AssemblyInfoParams.Author)]
|
||||
[assembly: AssemblyProduct(nameof(NAK.Melons.Blackout))]
|
||||
|
||||
[assembly: MelonInfo(
|
||||
typeof(NAK.Melons.Blackout.Blackout),
|
||||
nameof(NAK.Melons.Blackout),
|
||||
AssemblyInfoParams.Version,
|
||||
AssemblyInfoParams.Author,
|
||||
downloadLink: "https://github.com/NotAKidOnSteam/Blackout"
|
||||
)]
|
||||
|
||||
[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")]
|
||||
[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||
[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
||||
[assembly: MelonOptionalDependencies("UIExpansionKit", "BTKUILib")]
|
||||
|
||||
namespace NAK.Melons.Blackout.Properties;
|
||||
internal static class AssemblyInfoParams
|
||||
{
|
||||
public const string Version = "2.0.0";
|
||||
public const string Author = "NotAKidoS";
|
||||
}
|
73
Blackout/Resource1.Designer.cs
generated
Normal file
73
Blackout/Resource1.Designer.cs
generated
Normal file
|
@ -0,0 +1,73 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace NAK.Melons.Blackout {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resource1 {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resource1() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Blackout.Resource1", typeof(Resource1).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] blackout_controller {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("blackout_controller", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
124
Blackout/Resource1.resx
Normal file
124
Blackout/Resource1.resx
Normal file
|
@ -0,0 +1,124 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="blackout_controller" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>Resources\blackout_controller.asset;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
</root>
|
24
Blackout/format.json
Normal file
24
Blackout/format.json
Normal file
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"_id": 106,
|
||||
"name": "Blackout",
|
||||
"modversion": "2.0.0",
|
||||
"gameversion": "2022r170",
|
||||
"loaderversion": "0.5.7",
|
||||
"modtype": "Mod",
|
||||
"author": "NotAKidoS",
|
||||
"description": "Dim screen after set time of sitting still. Should be nice for VR sleeping.\n\nNotable Options:\n Cap FPS while sleeping.\nManual control via BTKUILib\nConfigurable dimming strength.",
|
||||
"searchtags": [
|
||||
"black",
|
||||
"dimmer",
|
||||
"sleeping",
|
||||
"sleeper"
|
||||
],
|
||||
"requirements": [
|
||||
"BTKUILib",
|
||||
"UIExpansionKit"
|
||||
],
|
||||
"downloadlink": "https://github.com/NotAKidOnSteam/Blackout/releases/download/v2.0.0/Blackout.dll",
|
||||
"sourcelink": "https://github.com/NotAKidOnSteam/Blackout/",
|
||||
"changelog": "- Added BTKUILib support.\n- Added dimming strength velocity multiplier option.\n- Added option to not use Automatic Sleep State.\n- Dimming strengh now updates in realtime when configuring.",
|
||||
"embedcolor": "#161b22"
|
||||
}
|
BIN
Blackout/resources/blackout_controller.asset
Normal file
BIN
Blackout/resources/blackout_controller.asset
Normal file
Binary file not shown.
35
README.md
35
README.md
|
@ -30,6 +30,41 @@ Simple mod to clear hud notifications when joining an online instance. Can also
|
|||
|
||||
There is no native method to clear notifications, so I force an immediate notification to clear the buffer.
|
||||
|
||||
# Blackout
|
||||
|
||||
Functionality heavily inspired by VRSleeper on Booth: https://booth.pm/ja/items/2151940
|
||||
|
||||
There are three states of "blackout":
|
||||
|
||||
0 - Awake (no effect)
|
||||
1 - Drowsy (partial effect)
|
||||
2 - Sleep (full effect)
|
||||
|
||||
After staying still for DrowsyModeTimer (minutes), you enter DrowsyMode.
|
||||
This mode dims the screen to your selected dimming strength.
|
||||
After continuing to stay still for SleepModeTimer (seconds), you enter SleepMode.
|
||||
This mode over renders mostly everything with black.
|
||||
|
||||
Slight movement while in SleepMode will place you in DrowsyMode until SleepModeTimer is reached again.
|
||||
Hard movement once entering DrowsyMode will fully wake you and return complete vision.
|
||||
|
||||
Auto state changing can be disabled. This allows you to use UIExpansionKit to manually change Blackout states.
|
||||
|
||||
Supports DesktopVRSwitch~ if that releases.
|
||||
|
||||
**Settings**
|
||||
|
||||
* Hud Messages - Sends hud notification on state change.
|
||||
* Lower FPS While Sleep - Caps FPS to 5 while in Sleep State.
|
||||
* Drowsy Dim Strength - How strong of a dimming effect should drowsy mode have.
|
||||
|
||||
//Automatic State Change related stuff
|
||||
* Automatic State Change - Dim screen when there is no movement for a while.
|
||||
* Drowsy Threshold - Degrees of movement to return partial vision.
|
||||
* Awake Threshold - Degrees of movement to return full vision.
|
||||
* Enter Drowsy Time - How many minutes without movement until enter drowsy mode.
|
||||
* Enter Sleep Time - How many seconds without movement until enter sleep mode.
|
||||
|
||||
---
|
||||
|
||||
Here is the block of text where I tell you this mod is not affiliated or endorsed by ABI.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue