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.
|
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.
|
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