mirror of
https://github.com/NotAKidoS/NAK_CVR_Mods.git
synced 2025-09-02 14:29:25 +00:00
Testing Phase
Basics are implemented. Needs playtesting before potential rewrite and implementation of avatar parameters & manual control.
This commit is contained in:
parent
c049d93d55
commit
d033d3750e
8 changed files with 541 additions and 82 deletions
95
Blackout/AssetHandler.cs
Normal file
95
Blackout/AssetHandler.cs
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace 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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,14 @@
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="resources\blackout_controller.asset" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="resources\blackout_controller.asset" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="0Harmony">
|
<Reference Include="0Harmony">
|
||||||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\MelonLoader\0Harmony.dll</HintPath>
|
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\MelonLoader\0Harmony.dll</HintPath>
|
||||||
|
@ -47,6 +55,21 @@
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</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">
|
<Target Name="Deploy" AfterTargets="Build">
|
||||||
<Copy SourceFiles="$(TargetPath)" DestinationFolder="C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\" />
|
<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" />
|
<Message Text="Copied $(TargetPath) to C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\" Importance="high" />
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
using ABI.CCK.Components;
|
using ABI_RC.Core.Player;
|
||||||
using ABI_RC.Core.Player;
|
using ABI_RC.Core.UI;
|
||||||
using ABI_RC.Systems.IK;
|
|
||||||
using ABI_RC.Systems.IK.SubSystems;
|
|
||||||
using HarmonyLib;
|
|
||||||
using MelonLoader;
|
using MelonLoader;
|
||||||
using RootMotion.FinalIK;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Events;
|
|
||||||
|
|
||||||
namespace Blackout;
|
namespace Blackout;
|
||||||
|
|
||||||
|
@ -20,11 +15,21 @@ namespace Blackout;
|
||||||
1 - Drowsy (partial effect)
|
1 - Drowsy (partial effect)
|
||||||
2 - Sleep (full 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 class BlackoutController : MonoBehaviour
|
||||||
{
|
{
|
||||||
public int BlackoutState = 0;
|
public static BlackoutController Instance;
|
||||||
|
|
||||||
|
public BlackoutState CurrentState = BlackoutState.Awake;
|
||||||
|
|
||||||
//degrees of movement to give partial vision
|
//degrees of movement to give partial vision
|
||||||
public float drowsyThreshold = 1f;
|
public float drowsyThreshold = 1f;
|
||||||
|
@ -32,81 +37,190 @@ public class BlackoutController : MonoBehaviour
|
||||||
public float wakeThreshold = 12f;
|
public float wakeThreshold = 12f;
|
||||||
|
|
||||||
//how long without movement until the screen dims
|
//how long without movement until the screen dims
|
||||||
public float enterSleepTime = 3f; // MINUTES
|
public float DrowsyModeTimer = 3f; // MINUTES
|
||||||
//how long should the wake state last before return
|
//how long should the wake state last before return
|
||||||
public float returnSleepTime = 10f; // SECONDS
|
public float SleepModeTimer = 10f; // SECONDS
|
||||||
|
|
||||||
|
//how much does DrowsyMode affect the screen
|
||||||
|
public float DrowsyDimStrength = 0.5f;
|
||||||
|
|
||||||
|
//this is uh, not work well- might rewrite now that i know how this should work
|
||||||
|
public bool HudMessages = false;
|
||||||
|
|
||||||
|
public enum BlackoutState
|
||||||
|
{
|
||||||
|
Awake = 0,
|
||||||
|
Drowsy,
|
||||||
|
Sleeping,
|
||||||
|
}
|
||||||
|
|
||||||
//private BlackoutController instance;
|
|
||||||
private Quaternion oldHeadRotation = Quaternion.identity;
|
private Quaternion oldHeadRotation = Quaternion.identity;
|
||||||
|
private float angularMovement = 0f;
|
||||||
|
private float curTime = 0f;
|
||||||
private float lastAwakeTime = 0f;
|
private float lastAwakeTime = 0f;
|
||||||
private int nextUpdate = 1;
|
private int nextUpdate = 1;
|
||||||
|
private Animator blackoutAnimator;
|
||||||
|
|
||||||
|
public void ChangeBlackoutState(BlackoutState newState)
|
||||||
|
{
|
||||||
|
if (!blackoutAnimator) return;
|
||||||
|
if (newState == CurrentState) return;
|
||||||
|
|
||||||
|
lastAwakeTime = curTime;
|
||||||
|
|
||||||
|
switch (newState)
|
||||||
|
{
|
||||||
|
case BlackoutState.Awake:
|
||||||
|
blackoutAnimator.SetBool("BlackoutState.Drowsy", false);
|
||||||
|
blackoutAnimator.SetBool("BlackoutState.Sleeping", false);
|
||||||
|
blackoutAnimator.SetFloat("BlackoutSetting.DrowsyPartial", DrowsyDimStrength);
|
||||||
|
break;
|
||||||
|
case BlackoutState.Drowsy:
|
||||||
|
blackoutAnimator.SetBool("BlackoutState.Drowsy", true);
|
||||||
|
blackoutAnimator.SetBool("BlackoutState.Sleeping", false);
|
||||||
|
blackoutAnimator.SetFloat("BlackoutSetting.DrowsyPartial", DrowsyDimStrength);
|
||||||
|
break;
|
||||||
|
case BlackoutState.Sleeping:
|
||||||
|
blackoutAnimator.SetBool("BlackoutState.Drowsy", false);
|
||||||
|
blackoutAnimator.SetBool("BlackoutState.Sleeping", true);
|
||||||
|
blackoutAnimator.SetFloat("BlackoutSetting.DrowsyPartial", DrowsyDimStrength);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
BlackoutState prevState = CurrentState;
|
||||||
|
CurrentState = newState;
|
||||||
|
SendHUDMessage($"Exiting {prevState} and entering {newState} state.");
|
||||||
|
}
|
||||||
|
|
||||||
void Update()
|
void Update()
|
||||||
{
|
{
|
||||||
//only run once a second, angularMovement is "smoothed out" at high FPS otherwise
|
//only run once a second, angularMovement is "smoothed out" at high FPS otherwise
|
||||||
float curTime = Time.time;
|
//for the sake of responsivness while user is in a sleepy state, this might be removed to prevent confusion...
|
||||||
|
curTime = Time.time;
|
||||||
if (!(curTime >= nextUpdate)) return;
|
if (!(curTime >= nextUpdate)) return;
|
||||||
nextUpdate = Mathf.FloorToInt(curTime) + 1;
|
nextUpdate = Mathf.FloorToInt(curTime) + 1;
|
||||||
|
|
||||||
//get difference between last frame rotation and current rotation
|
//get difference between last frame rotation and current rotation
|
||||||
Quaternion currentHeadRotation = PlayerSetup.Instance.GetActiveCamera().transform.rotation;
|
Quaternion currentHeadRotation = PlayerSetup.Instance.GetActiveCamera().transform.rotation;
|
||||||
float angularMovement = Quaternion.Angle(oldHeadRotation, currentHeadRotation);
|
angularMovement = Quaternion.Angle(oldHeadRotation, currentHeadRotation);
|
||||||
oldHeadRotation = currentHeadRotation;
|
oldHeadRotation = currentHeadRotation;
|
||||||
|
|
||||||
// These are SOFT movements
|
//handle current state
|
||||||
|
switch (CurrentState)
|
||||||
|
{
|
||||||
|
case BlackoutState.Awake:
|
||||||
|
HandleAwakeState();
|
||||||
|
break;
|
||||||
|
case BlackoutState.Drowsy:
|
||||||
|
HandleDrowsyState();
|
||||||
|
break;
|
||||||
|
case BlackoutState.Sleeping:
|
||||||
|
HandleSleepingState();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//debug
|
||||||
|
//MelonLogger.Msg("curTime " + curTime);
|
||||||
|
//MelonLogger.Msg("lastAwakeTime " + lastAwakeTime);
|
||||||
|
//MelonLogger.Msg("timeleft " + GetNextStateTimer());
|
||||||
|
//MelonLogger.Msg("current state " + CurrentState);
|
||||||
|
}
|
||||||
|
|
||||||
|
//initialize BlackoutInstance object
|
||||||
|
void Start()
|
||||||
|
{
|
||||||
|
Instance = this;
|
||||||
|
|
||||||
|
GameObject blackoutAsset = AssetsHandler.GetAsset("Assets/BundledAssets/Blackout/Blackout.prefab");
|
||||||
|
GameObject blackoutGO = Instantiate(blackoutAsset, new Vector3(0, 0, 0), Quaternion.identity);
|
||||||
|
|
||||||
|
if (blackoutGO != null)
|
||||||
|
{
|
||||||
|
blackoutGO.name = "BlackoutInstance";
|
||||||
|
blackoutAnimator = blackoutGO.GetComponent<Animator>();
|
||||||
|
SetupBlackoutInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnEnabled()
|
||||||
|
{
|
||||||
|
if (!blackoutAnimator) return;
|
||||||
|
blackoutAnimator.gameObject.SetActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnDisabled()
|
||||||
|
{
|
||||||
|
ChangeBlackoutState(BlackoutState.Awake);
|
||||||
|
if (!blackoutAnimator) return;
|
||||||
|
blackoutAnimator.gameObject.SetActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetupBlackoutInstance()
|
||||||
|
{
|
||||||
|
blackoutAnimator.transform.parent = PlayerSetup.Instance.GetActiveCamera().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;
|
||||||
|
CohtmlHud.Instance.ViewDropTextImmediate("Blackout", message, GetNextStateTimer().ToString() + " seconds till next state change.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleAwakeState()
|
||||||
|
{
|
||||||
|
//small movement should reset sleep timer
|
||||||
if (angularMovement > drowsyThreshold)
|
if (angularMovement > drowsyThreshold)
|
||||||
{
|
{
|
||||||
lastAwakeTime = curTime;
|
lastAwakeTime = curTime;
|
||||||
if (BlackoutState == 2)
|
|
||||||
{
|
|
||||||
BlackoutState = 1;
|
|
||||||
MelonLogger.Msg("Exited Sleep state and entered Drowsy state.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
//enter drowsy mode after few minutes
|
||||||
// These are HARD movements
|
if (curTime > lastAwakeTime + DrowsyModeTimer * 60)
|
||||||
|
{
|
||||||
|
ChangeBlackoutState(BlackoutState.Drowsy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void HandleDrowsyState()
|
||||||
|
{
|
||||||
|
//hard movement should exit drowsy state
|
||||||
if (angularMovement > wakeThreshold)
|
if (angularMovement > wakeThreshold)
|
||||||
{
|
{
|
||||||
lastAwakeTime = curTime;
|
ChangeBlackoutState(BlackoutState.Awake);
|
||||||
|
|
||||||
if (BlackoutState == 0) return;
|
|
||||||
BlackoutState = 0;
|
|
||||||
MelonLogger.Msg("Exited anystate and entered Awake state.");
|
|
||||||
}
|
}
|
||||||
|
//enter full sleep mode
|
||||||
MelonLogger.Msg($"BlackoutState " + BlackoutState);
|
if (curTime > lastAwakeTime + SleepModeTimer)
|
||||||
MelonLogger.Msg($"curTime " + curTime);
|
|
||||||
MelonLogger.Msg($"lastAwakeTime " + lastAwakeTime);
|
|
||||||
|
|
||||||
if (BlackoutState == 2) return;
|
|
||||||
|
|
||||||
//check if we should enter/return to sleep mode
|
|
||||||
if (curTime > lastAwakeTime + (BlackoutState == 0 ? enterSleepTime * 60 : returnSleepTime))
|
|
||||||
{
|
{
|
||||||
BlackoutState = 2;
|
ChangeBlackoutState(BlackoutState.Sleeping);
|
||||||
MelonLogger.Msg("Entered sleep state.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private void HandleSleepingState()
|
||||||
void Start()
|
|
||||||
{
|
{
|
||||||
MelonLogger.Msg(Application.streamingAssetsPath);
|
//small movement should enter drowsy state
|
||||||
|
if (angularMovement > drowsyThreshold)
|
||||||
var myLoadedAssetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, "blackoutfader"));
|
|
||||||
if (myLoadedAssetBundle == null)
|
|
||||||
{
|
{
|
||||||
Debug.Log("Failed to load AssetBundle!");
|
ChangeBlackoutState(BlackoutState.Drowsy);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var prefab = myLoadedAssetBundle.LoadAsset<GameObject>("MyObject");
|
|
||||||
Instantiate(prefab);
|
|
||||||
|
|
||||||
myLoadedAssetBundle.Unload(false);
|
|
||||||
|
|
||||||
prefab.transform.parent = PlayerSetup.Instance.GetActiveCamera().transform;
|
|
||||||
prefab.transform.localPosition = Vector3.zero;
|
|
||||||
prefab.transform.localRotation = Quaternion.identity;
|
|
||||||
prefab.transform.localScale = Vector3.zero;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,59 +1,89 @@
|
||||||
using ABI.CCK.Components;
|
using ABI_RC.Core.Player;
|
||||||
using ABI_RC.Core.Player;
|
|
||||||
using ABI_RC.Systems.IK;
|
|
||||||
using ABI_RC.Systems.IK.SubSystems;
|
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using MelonLoader;
|
using MelonLoader;
|
||||||
using RootMotion.FinalIK;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Events;
|
|
||||||
|
|
||||||
namespace Blackout;
|
namespace Blackout;
|
||||||
|
|
||||||
public class Blackout : MelonMod
|
public class Blackout : MelonMod
|
||||||
{
|
{
|
||||||
BlackoutController m_blackoutController = null;
|
private static bool inVR;
|
||||||
|
|
||||||
private static MelonPreferences_Category m_categoryBlackout;
|
private static MelonPreferences_Category m_categoryBlackout;
|
||||||
private static MelonPreferences_Entry<bool> m_entryEnabled;
|
private static MelonPreferences_Entry<bool> m_entryEnabled, m_entryHudMessages;
|
||||||
private static MelonPreferences_Entry<float> m_entryDrowsyThreshold;
|
//private static MelonPreferences_Entry<bool> m_entryVROnly;
|
||||||
private static MelonPreferences_Entry<float> m_entryAwakeThreshold;
|
private static MelonPreferences_Entry<float>
|
||||||
private static MelonPreferences_Entry<float> m_entryEnterSleepTime;
|
m_entryDrowsyThreshold, m_entryAwakeThreshold,
|
||||||
private static MelonPreferences_Entry<float> m_entryReturnSleepTime;
|
m_entryDrowsyModeTimer, m_entrySleepModeTimer,
|
||||||
|
m_entryDrowsyDimStrength;
|
||||||
|
|
||||||
public override void OnApplicationStart()
|
public override void OnApplicationStart()
|
||||||
{
|
{
|
||||||
m_categoryBlackout = MelonPreferences.CreateCategory(nameof(Blackout));
|
m_categoryBlackout = MelonPreferences.CreateCategory(nameof(Blackout));
|
||||||
m_entryEnabled = m_categoryBlackout.CreateEntry<bool>("Enabled", true, description: "Dim screen when sleeping.");
|
m_entryEnabled = m_categoryBlackout.CreateEntry<bool>("Enabled", true, description: "Dim screen when sleeping.");
|
||||||
|
m_entryHudMessages = m_categoryBlackout.CreateEntry<bool>("Hud Messages", false, description: "Notify on state change.");
|
||||||
m_entryDrowsyThreshold = m_categoryBlackout.CreateEntry<float>("Drowsy Threshold", 1f, description: "Degrees of movement to return partial vision.");
|
m_entryDrowsyThreshold = m_categoryBlackout.CreateEntry<float>("Drowsy Threshold", 1f, description: "Degrees of movement to return partial vision.");
|
||||||
m_entryAwakeThreshold = m_categoryBlackout.CreateEntry<float>("Awake Threshold", 12f, description: "Degrees of movement to return full vision.");
|
m_entryAwakeThreshold = m_categoryBlackout.CreateEntry<float>("Awake Threshold", 12f, description: "Degrees of movement to return full vision.");
|
||||||
m_entryEnterSleepTime = m_categoryBlackout.CreateEntry<float>("Enter Sleep Time", 3f, description: "How many minutes without movement until enter sleep mode.");
|
m_entryDrowsyModeTimer = m_categoryBlackout.CreateEntry<float>("Enter Drowsy Time", 3f, description: "How many minutes without movement until enter drowsy mode.");
|
||||||
m_entryReturnSleepTime = m_categoryBlackout.CreateEntry<float>("Return Sleep Time", 10f, description: "How many seconds should the wake state last before return.");
|
m_entrySleepModeTimer = m_categoryBlackout.CreateEntry<float>("Enter Sleep Time", 10f, description: "How many seconds without movement until enter sleep mode.");
|
||||||
|
m_entryDrowsyDimStrength = m_categoryBlackout.CreateEntry<float>("Drowsy Dim Strength", 0.5f, description: "How strong of a dimming effect should drowsy mode have.");
|
||||||
|
//m_entryVROnly = m_categoryBlackout.CreateEntry<bool>("VR Only", false, description: "Only enable mod in VR.");
|
||||||
m_categoryBlackout.SaveToFile(false);
|
m_categoryBlackout.SaveToFile(false);
|
||||||
|
|
||||||
m_entryEnabled.OnValueChangedUntyped += OnEnabled;
|
m_entryEnabled.OnValueChangedUntyped += OnEnabled;
|
||||||
|
m_entryHudMessages.OnValueChangedUntyped += OnUpdateSettings;
|
||||||
|
m_entryDrowsyThreshold.OnValueChangedUntyped += OnUpdateSettings;
|
||||||
|
m_entryAwakeThreshold.OnValueChangedUntyped += OnUpdateSettings;
|
||||||
|
m_entryDrowsyModeTimer.OnValueChangedUntyped += OnUpdateSettings;
|
||||||
|
m_entrySleepModeTimer.OnValueChangedUntyped += OnUpdateSettings;
|
||||||
|
m_entryDrowsyDimStrength.OnValueChangedUntyped += OnUpdateSettings;
|
||||||
|
//m_entryVROnly.OnValueChangedUntyped += OnUpdateSettings;
|
||||||
MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
|
MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer());
|
||||||
}
|
}
|
||||||
|
|
||||||
System.Collections.IEnumerator WaitForLocalPlayer()
|
System.Collections.IEnumerator WaitForLocalPlayer()
|
||||||
{
|
{
|
||||||
|
//load blackout_controller.asset
|
||||||
|
AssetsHandler.Load();
|
||||||
|
|
||||||
while (PlayerSetup.Instance == null)
|
while (PlayerSetup.Instance == null)
|
||||||
yield return null;
|
yield return null;
|
||||||
|
|
||||||
m_blackoutController = PlayerSetup.Instance.gameObject.AddComponent<BlackoutController>();
|
inVR = PlayerSetup.Instance._inVr;
|
||||||
|
PlayerSetup.Instance.gameObject.AddComponent<BlackoutController>();
|
||||||
|
|
||||||
|
//update BlackoutController settings after it initializes
|
||||||
|
yield return new WaitForEndOfFrame();
|
||||||
|
OnUpdateSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnEnabled()
|
private void OnEnabled()
|
||||||
{
|
{
|
||||||
if (!m_blackoutController) return;
|
if (!BlackoutController.Instance) return;
|
||||||
m_blackoutController.enabled = m_entryEnabled.Value;
|
BlackoutController.Instance.enabled = m_entryEnabled.Value;
|
||||||
}
|
}
|
||||||
public void OnUpdateSettings()
|
private void OnUpdateSettings()
|
||||||
{
|
{
|
||||||
if (!m_blackoutController) return;
|
if (!BlackoutController.Instance) return;
|
||||||
m_blackoutController.drowsyThreshold = m_entryDrowsyThreshold.Value;
|
BlackoutController.Instance.drowsyThreshold = m_entryDrowsyThreshold.Value;
|
||||||
m_blackoutController.wakeThreshold = m_entryAwakeThreshold.Value;
|
BlackoutController.Instance.wakeThreshold = m_entryAwakeThreshold.Value;
|
||||||
m_blackoutController.enterSleepTime = m_entryEnterSleepTime.Value;
|
BlackoutController.Instance.DrowsyModeTimer = m_entryDrowsyModeTimer.Value;
|
||||||
m_blackoutController.returnSleepTime = m_entryReturnSleepTime.Value;
|
BlackoutController.Instance.SleepModeTimer = m_entrySleepModeTimer.Value;
|
||||||
|
BlackoutController.Instance.DrowsyDimStrength = m_entryDrowsyDimStrength.Value;
|
||||||
|
BlackoutController.Instance.HudMessages = m_entryHudMessages.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Support for changing VRMode during runtime.
|
||||||
|
[HarmonyPatch]
|
||||||
|
private class HarmonyPatches
|
||||||
|
{
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(PlayerSetup), "CalibrateAvatar")]
|
||||||
|
private static void CheckVRModeSwitch()
|
||||||
|
{
|
||||||
|
if (inVR != PlayerSetup.Instance._inVr)
|
||||||
|
{
|
||||||
|
BlackoutController.Instance.SetupBlackoutInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
using MelonLoader;
|
using Blackout.Properties;
|
||||||
|
using MelonLoader;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Blackout.Properties;
|
|
||||||
|
|
||||||
|
|
||||||
[assembly: AssemblyVersion(AssemblyInfoParams.Version)]
|
[assembly: AssemblyVersion(AssemblyInfoParams.Version)]
|
||||||
|
|
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 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>
|
BIN
Blackout/resources/blackout_controller.asset
Normal file
BIN
Blackout/resources/blackout_controller.asset
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue