using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using DimmingFlashlights.NetcodePatcher; using DimmingFlashlights.Network; using DimmingFlashlights.Patches; using DimmingFlashlights.Utils; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("DimmingFlashlights")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("0.0.9.0")] [assembly: AssemblyInformationalVersion("0.0.9")] [assembly: AssemblyProduct("DimmingFlashlights")] [assembly: AssemblyTitle("DimmingFlashlights")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.9.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace DimmingFlashlights { internal static class ConfigManager { internal static ConfigEntry MinimumBrightnessScale { get; private set; } internal static ConfigEntry BatteryThreshold { get; private set; } internal static void Bind(ConfigFile config) { MinimumBrightnessScale = config.Bind("Settings", "Minimum brightness scale", 0.15f, "Lowest possible brightness multiplier when the battery is near empty. Default is 15% brightness"); BatteryThreshold = config.Bind("Settings", "Battery Threshold", 0.6f, "Battery level at which full brightness stops and dimming begins. Default is 60% battery"); } } [BepInPlugin("MrHat.DimmingFlashlights", "DimmingFlashlights", "0.0.9")] internal class Plugin : BaseUnityPlugin { internal const string modGUID = "MrHat.DimmingFlashlights"; internal const string modName = "DimmingFlashlights"; internal const string modVersion = "0.0.9"; private Harmony _harmony; internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ConfigManager.Bind(((BaseUnityPlugin)this).Config); InitialiseNetworkSerialisation(); _harmony = new Harmony("MrHat.DimmingFlashlights"); _harmony.PatchAll(typeof(NetworkManagerPatches)); _harmony.PatchAll(typeof(FlashlightItemPatches)); _harmony.PatchAll(typeof(PlayerControllerBPatches)); _harmony.PatchAll(typeof(StartOfRoundPatches)); Log.LogInfo((object)"DimmingFlashlights loaded"); } private static void InitialiseNetworkSerialisation() { MethodInfo methodInfo = typeof(Plugin).Assembly.GetType("__GEN.NetworkVariableSerializationHelper")?.GetMethod("InitializeSerialization", BindingFlags.Static | BindingFlags.NonPublic); if (methodInfo == null) { Log.LogFatal((object)"DimmingFlashlights serialisation method was not found, flashlights will probably break the game"); return; } methodInfo.Invoke(null, null); Log.LogDebug((object)"DimmingFlashlights serialisation initialised"); } } public static class MyPluginInfo { public const string PLUGIN_GUID = "DimmingFlashlights"; public const string PLUGIN_NAME = "DimmingFlashlights"; public const string PLUGIN_VERSION = "0.0.9"; } } namespace DimmingFlashlights.Utils { internal static class FlashlightDimming { private const float MessageInterval = 1.2f; private static readonly Dictionary OriginalHelmetIntensities = new Dictionary(); private static readonly Dictionary NextFlashlightMessages = new Dictionary(); private static readonly HashSet FlashlightsThatDimmed = new HashSet(); internal static void Clear() { OriginalHelmetIntensities.Clear(); NextFlashlightMessages.Clear(); FlashlightsThatDimmed.Clear(); } internal static bool FlashlightMessageDue(ulong networkObjectId, float currentTime) { if (NextFlashlightMessages.TryGetValue(networkObjectId, out var value) && currentTime < value) { return false; } NextFlashlightMessages[networkObjectId] = currentTime + 1.2f; return true; } internal static bool DimmingLogDue(ulong networkObjectId, float charge) { float num = Mathf.Clamp01(ConfigManager.BatteryThreshold.Value); return Mathf.Clamp01(charge) < num && FlashlightsThatDimmed.Add(networkObjectId); } internal static bool HelmetIntensitiesKnown(ulong clientId) { return OriginalHelmetIntensities.ContainsKey(clientId); } internal static void RememberHelmetIntensities(ulong clientId, float[] intensities) { OriginalHelmetIntensities[clientId] = intensities; } internal static float OriginalHelmetIntensity(ulong clientId, int index) { if (OriginalHelmetIntensities.TryGetValue(clientId, out float[] value) && index >= 0 && index < value.Length) { return value[index]; } return 0f; } internal static void DimFlashlight(FlashlightItem flashlight, float charge) { Light flashlightBulb = flashlight.flashlightBulb; flashlightBulb.intensity *= Brightness(charge); } internal static float Brightness(float charge) { float num = Mathf.Clamp01(ConfigManager.BatteryThreshold.Value); float num2 = Mathf.Clamp01(ConfigManager.MinimumBrightnessScale.Value); charge = Mathf.Clamp01(charge); if (num <= 0f || charge >= num) { return 1f; } float num3 = Mathf.Clamp01(charge / num); return Mathf.Clamp01(num2 + (1f - num2) * num3); } } } namespace DimmingFlashlights.Patches { internal static class FlashlightItemPatches { [HarmonyPostfix] [HarmonyPatch(typeof(FlashlightItem), "Update")] private static void UpdatePostfix(FlashlightItem __instance) { if (((GrabbableObject)__instance).insertedBattery == null || (Object)(object)((NetworkBehaviour)__instance).NetworkObject == (Object)null) { return; } float num = Mathf.Clamp01(((GrabbableObject)__instance).insertedBattery.charge); ulong networkObjectId = ((NetworkBehaviour)__instance).NetworkObject.NetworkObjectId; if (((NetworkBehaviour)__instance).IsOwner && FlashlightDimming.FlashlightMessageDue(networkObjectId, Time.time)) { DimmingFlashlightsNetwork.PublishFlashlightCharge(networkObjectId, num); } float charge = (((NetworkBehaviour)__instance).IsOwner ? num : DimmingFlashlightsNetwork.FlashlightChargeFor(networkObjectId, num)); if (FlashlightDimming.DimmingLogDue(networkObjectId, charge)) { string text = ((GrabbableObject)__instance).itemProperties?.itemName ?? "Flashlight"; string text2 = ((GrabbableObject)__instance).playerHeldBy?.playerUsername; if (string.IsNullOrEmpty(text2)) { Plugin.Log.LogDebug((object)(text + " started dimming whilst held by no one")); } else { Plugin.Log.LogDebug((object)(text + " started dimming whilst held by " + text2)); } } FlashlightDimming.DimFlashlight(__instance, charge); } } internal static class NetworkManagerPatches { private static GameObject? dimmingFlashlightsPrefab; private static NetworkManager? networkManager; [HarmonyPostfix] [HarmonyPatch(typeof(NetworkManager), "SetSingleton")] private static void SetSingletonPostfix() { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || (Object)(object)singleton == (Object)(object)networkManager) { return; } if ((Object)(object)networkManager != (Object)null) { networkManager.OnServerStarted -= SpawnDimmingFlashlightsNetwork; } if ((Object)(object)dimmingFlashlightsPrefab == (Object)null) { GameObject val = new GameObject("MrHat.DimmingFlashlights.Network"); ((Object)val).hideFlags = (HideFlags)(((Object)val).hideFlags | 0x3D); Object.DontDestroyOnLoad((Object)(object)val); NetworkObject obj = val.AddComponent(); val.AddComponent(); FieldInfo field = typeof(NetworkObject).GetField("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { Plugin.Log.LogError((object)"DimmingFlashlights network prefab hash field was not found, networking will not work for DimmingFlashlights"); Object.Destroy((Object)(object)val); return; } uint num = 17u; string text = "MrHat.DimmingFlashlights"; foreach (char c in text) { num = (num * 31) ^ c; } field.SetValue(obj, num); dimmingFlashlightsPrefab = val; } singleton.PrefabHandler.AddNetworkPrefab(dimmingFlashlightsPrefab); singleton.OnServerStarted += SpawnDimmingFlashlightsNetwork; networkManager = singleton; Plugin.Log.LogDebug((object)"DimmingFlashlights network prefab loaded"); } private static void SpawnDimmingFlashlightsNetwork() { NetworkManager? obj = networkManager; if (obj != null && obj.IsServer && !((Object)(object)DimmingFlashlightsNetwork.Instance != (Object)null)) { GameObject val = Object.Instantiate(dimmingFlashlightsPrefab); ((Object)val).name = "MrHat.DimmingFlashlights.Network"; Object.DontDestroyOnLoad((Object)(object)val); val.GetComponent().Spawn(false); Plugin.Log.LogDebug((object)"DimmingFlashlights network values spawned"); } } } internal static class PlayerControllerBPatches { [HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")] [HarmonyPostfix] private static void LateUpdatePostfix(PlayerControllerB __instance) { Light[] allHelmetLights = __instance.allHelmetLights; if (allHelmetLights.Length == 0) { return; } ulong ownerClientId = ((NetworkBehaviour)__instance).OwnerClientId; if (!FlashlightDimming.HelmetIntensitiesKnown(ownerClientId)) { float[] array = new float[allHelmetLights.Length]; for (int i = 0; i < allHelmetLights.Length; i++) { array[i] = allHelmetLights[i].intensity; } FlashlightDimming.RememberHelmetIntensities(ownerClientId, array); } float num = 1f; GrabbableObject pocketedFlashlight = __instance.pocketedFlashlight; if (pocketedFlashlight?.insertedBattery != null) { num = Mathf.Clamp01(pocketedFlashlight.insertedBattery.charge); if (!((NetworkBehaviour)__instance).IsOwner && (Object)(object)((NetworkBehaviour)pocketedFlashlight).NetworkObject != (Object)null) { num = DimmingFlashlightsNetwork.FlashlightChargeFor(((NetworkBehaviour)pocketedFlashlight).NetworkObject.NetworkObjectId, num); } } float num2 = FlashlightDimming.Brightness(num); for (int j = 0; j < allHelmetLights.Length; j++) { float num3 = FlashlightDimming.OriginalHelmetIntensity(ownerClientId, j); allHelmetLights[j].intensity = num3 * num2; } } } internal static class StartOfRoundPatches { [HarmonyPatch(typeof(StartOfRound), "OnDestroy")] [HarmonyPostfix] private static void OnDestroyPostfix() { Stopwatch stopwatch = Stopwatch.StartNew(); FlashlightDimming.Clear(); DimmingFlashlightsNetwork.DespawnNetworkValues(); Plugin.Log.LogInfo((object)$"Cleanup complete in {stopwatch.Elapsed.TotalMilliseconds:F3} ms"); } } } namespace DimmingFlashlights.Network { internal struct FlashlightCharge : INetworkSerializable, IEquatable { internal ulong NetworkObjectId; internal float Charge; internal FlashlightCharge(ulong networkObjectId, float charge) { NetworkObjectId = networkObjectId; Charge = charge; } public bool Equals(FlashlightCharge other) { return NetworkObjectId == other.NetworkObjectId && Charge.Equals(other.Charge); } public unsafe void NetworkSerialize(BufferSerializer serializer) where T : IReaderWriter { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) ((BufferSerializer*)(&serializer))->SerializeValue(ref NetworkObjectId, default(ForPrimitives)); ((BufferSerializer*)(&serializer))->SerializeValue(ref Charge, default(ForPrimitives)); } } internal class DimmingFlashlightsNetwork : NetworkBehaviour { private NetworkList flashlightCharges = new NetworkList(); internal static DimmingFlashlightsNetwork? Instance { get; private set; } public override void OnNetworkSpawn() { ((NetworkBehaviour)this).OnNetworkSpawn(); Instance = this; Plugin.Log.LogDebug((object)"DimmingFlashlights network started"); } public override void OnNetworkDespawn() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } Plugin.Log.LogDebug((object)"DimmingFlashlights network despawned"); ((NetworkBehaviour)this).OnNetworkDespawn(); } public override void OnDestroy() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } ((NetworkBehaviour)this).OnDestroy(); } internal static void DespawnNetworkValues() { DimmingFlashlightsNetwork instance = Instance; if (!((Object)(object)instance == (Object)null)) { Instance = null; NetworkObject networkObject = ((NetworkBehaviour)instance).NetworkObject; NetworkManager networkManager = networkObject.NetworkManager; if ((Object)(object)networkManager == (Object)null) { Object.Destroy((Object)(object)((Component)instance).gameObject); } else if (((NetworkBehaviour)instance).IsServer && ((NetworkBehaviour)instance).IsSpawned && !networkManager.ShutdownInProgress && networkManager.SpawnManager != null) { networkObject.Despawn(true); } else { Object.Destroy((Object)(object)((Component)instance).gameObject); } } } internal static void PublishFlashlightCharge(ulong networkObjectId, float charge) { DimmingFlashlightsNetwork instance = Instance; if (instance != null && ((NetworkBehaviour)instance).IsSpawned) { instance.PublishFlashlightChargeRpc(networkObjectId, Mathf.Clamp01(charge)); } } internal static float FlashlightChargeFor(ulong networkObjectId, float fallbackCharge) { DimmingFlashlightsNetwork instance = Instance; if (instance == null || !((NetworkBehaviour)instance).IsSpawned) { return fallbackCharge; } for (int i = 0; i < instance.flashlightCharges.Count; i++) { FlashlightCharge flashlightCharge = instance.flashlightCharges[i]; if (flashlightCharge.NetworkObjectId == networkObjectId) { return flashlightCharge.Charge; } } return fallbackCharge; } [Rpc(/*Could not decode attribute arguments.*/)] private void PublishFlashlightChargeRpc(ulong networkObjectId, float charge) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Invalid comparison between Unknown and I4 //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 1) { RpcAttributeParams val = new RpcAttributeParams { RequireOwnership = false }; RpcParams val3 = default(RpcParams); FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendRpc(1962553790u, val3, val, (SendTo)2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val2, networkObjectId); ((FastBufferWriter)(ref val2)).WriteValueSafe(ref charge, default(ForPrimitives)); ((NetworkBehaviour)this).__endSendRpc(ref val2, 1962553790u, val3, val, (SendTo)2, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage != 1) { return; } base.__rpc_exec_stage = (__RpcExecStage)0; charge = Mathf.Clamp01(charge); for (int i = 0; i < flashlightCharges.Count; i++) { if (flashlightCharges[i].NetworkObjectId == networkObjectId) { if (!flashlightCharges[i].Charge.Equals(charge)) { flashlightCharges[i] = new FlashlightCharge(networkObjectId, charge); } return; } } flashlightCharges.Add(new FlashlightCharge(networkObjectId, charge)); if (!((NetworkBehaviour)this).NetworkManager.SpawnManager.SpawnedObjects.TryGetValue(networkObjectId, out var value)) { Plugin.Log.LogWarning((object)"A flashlight battery charge was received before its flashlight spawned on the network"); return; } FlashlightItem component = ((Component)value).GetComponent(); string text = ((GrabbableObject)component).itemProperties.itemName ?? "Flashlight"; string text2 = ((GrabbableObject)component).playerHeldBy?.playerUsername; if (string.IsNullOrEmpty(text2)) { Plugin.Log.LogDebug((object)(text + " found, held by nobody")); } else { Plugin.Log.LogDebug((object)(text + " held by " + text2)); } } protected override void __initializeVariables() { if (flashlightCharges == null) { throw new Exception("DimmingFlashlightsNetwork.flashlightCharges cannot be null. All NetworkVariableBase instances must be initialized."); } ((NetworkVariableBase)flashlightCharges).Initialize((NetworkBehaviour)(object)this); ((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)flashlightCharges, "flashlightCharges"); base.NetworkVariableFields.Add((NetworkVariableBase)(object)flashlightCharges); ((NetworkBehaviour)this).__initializeVariables(); } protected override void __initializeRpcs() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown ((NetworkBehaviour)this).__registerRpc(1962553790u, new RpcReceiveHandler(__rpc_handler_1962553790), "PublishFlashlightChargeRpc"); ((NetworkBehaviour)this).__initializeRpcs(); } private static void __rpc_handler_1962553790(NetworkBehaviour? target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { ulong networkObjectId = default(ulong); ByteUnpacker.ReadValueBitPacked(reader, ref networkObjectId); float charge = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref charge, default(ForPrimitives)); target.__rpc_exec_stage = (__RpcExecStage)1; ((DimmingFlashlightsNetwork)(object)target).PublishFlashlightChargeRpc(networkObjectId, charge); target.__rpc_exec_stage = (__RpcExecStage)0; } } protected internal override string? __getTypeName() { return "DimmingFlashlightsNetwork"; } } } namespace __GEN { internal class NetworkVariableSerializationHelper { [RuntimeInitializeOnLoadMethod] internal static void InitializeSerialization() { NetworkVariableSerializationTypes.InitializeSerializer_UnmanagedINetworkSerializable(); NetworkVariableSerializationTypes.InitializeEqualityChecker_UnmanagedIEquatable(); } } } namespace DimmingFlashlights.NetcodePatcher { [AttributeUsage(AttributeTargets.Module)] internal class NetcodePatchedAssemblyAttribute : Attribute { } }