Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of TightBeam v2.1.1
TightBeam.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppScheduleOne; using Il2CppScheduleOne.AvatarFramework; using Il2CppScheduleOne.AvatarFramework.Equipping; using Il2CppScheduleOne.DevUtilities; using Il2CppScheduleOne.Equipping; using Il2CppScheduleOne.Networking; using Il2CppScheduleOne.PlayerScripts; using Il2CppScheduleOne.Tools; using Il2CppScheduleOne.UI.Phone; using Il2CppSteamworks; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using TightBeam; using TightBeam.Bridge; using TightBeam.Config; using TightBeam.Lighting; using TightBeam.Net; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(Core), "TightBeam", "2.1.1", "DooDesch", "https://github.com/DooDesch-Mods/ScheduleOne-TightBeam")] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("DooDesch")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © DooDesch")] [assembly: AssemblyFileVersion("2.1.1.0")] [assembly: AssemblyInformationalVersion("2.1.1+6a27b2537a99a676ae7a40dc3b689df274b26d72")] [assembly: AssemblyProduct("TightBeam")] [assembly: AssemblyTitle("TightBeam")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: AssemblyVersion("2.1.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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 TightBeam { public sealed class Core : MelonMod { private bool _inMain; private bool _patched; private bool _wasEnabled = true; public static Instance Log { get; private set; } public override void OnInitializeMelon() { //IL_0065: Unknown result type (might be due to invalid IL or missing references) Log = ((MelonBase)this).LoggerInstance; TightBeamPreferences.Initialize(); FlashlightController.Instance.InitFromPrefs(); BridgeHost.Install(); BeamPostBuilder.Start(); Log.Msg($"TightBeam initialized. Enabled={TightBeamPreferences.Enabled}. On/off follows the game flashlight; hold {TightBeamPreferences.FocusModifierKey} + mouse wheel = focus/Pegel."); } public override void OnSceneWasInitialized(int buildIndex, string sceneName) { _inMain = sceneName == "Main"; if (_inMain && !_patched) { ((MelonBase)this).HarmonyInstance.PatchAll(typeof(Core).Assembly); _patched = true; Log.Msg("TightBeam: hotbar ALT+scroll guard applied."); } BeamBoard.EndSession(); RemoteBeams.NewSession(); } public override void OnUpdate() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (!TightBeamPreferences.Enabled || !_inMain) { return; } FlashlightController instance = FlashlightController.Instance; instance.SyncOnFromGame(); if (instance.IsOn) { if (Input.GetKey(TightBeamPreferences.FocusModifierKey)) { instance.UpdateFocusScroll(GameInput.MouseScrollDelta, Time.deltaTime); } else { instance.ResetFocusScrollVelocity(); } } } public override void OnLateUpdate() { FlashlightController instance = FlashlightController.Instance; if (!TightBeamPreferences.Enabled) { if (_wasEnabled) { _wasEnabled = false; instance.DisableRig(); RemoteBeams.DisableAll(); } BeamBoard.Tick(modEnabled: false); return; } _wasEnabled = true; if (!_inMain) { instance.DisableRig(); RemoteBeams.DisableAll(); BeamBoard.Tick(modEnabled: false); } else { instance.EnsureRig(); instance.Follow(); instance.Tick(Time.deltaTime); BeamBoard.Tick(modEnabled: true); RemoteBeams.Tick(Time.deltaTime); } } } } namespace TightBeam.Patches { [HarmonyPatch(typeof(PlayerInventory), "UpdateHotbarSelection")] internal static class HotbarScrollGuard { private static bool Prefix() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) if (!TightBeamPreferences.Enabled) { return true; } if (Input.GetKey(TightBeamPreferences.FocusModifierKey) && GameInput.MouseScrollDelta != 0f) { return false; } return true; } } } namespace TightBeam.Net { internal static class BeamBoard { private const float PublishDebounce = 0.2f; private const float SweepWhenCallbackUnproven = 1f; private const float SweepWhenCallbackWorks = 5f; private static readonly Dictionary<ulong, BeamPost> _posts = new Dictionary<ulong, BeamPost>(); private static Callback<LobbyDataUpdate_t> _dataCallback; private static Action _onLobbyChange; private static BeamPost _lastPublished; private static bool _hasPublished; private static bool _withdrawPending; private static float _nextPublishAt; private static float _nextRescanAt; private static float _writeBackoff; private static float _writeDelay; private static bool _warnedWrite; private static ulong _boundLobby; private static bool _callbackProven; private static bool _verifiedWrite; private const float BackoffMin = 0.5f; private const float BackoffMax = 15f; private static readonly ulong[] _noIds = new ulong[0]; private static readonly HashSet<ulong> _seen = new HashSet<ulong>(); private static readonly List<ulong> _gone = new List<ulong>(); internal static int KnownCount => _posts.Count; internal static int ReadCount { get; private set; } internal static int WriteCount { get; private set; } private static ulong LobbyId { get { try { Lobby instance = Singleton<Lobby>.Instance; if ((Object)(object)instance == (Object)null || !instance.IsInLobby) { return 0uL; } return instance.LobbyID; } catch { return 0uL; } } } internal static bool Available => LobbyId != 0; internal static void Tick(bool modEnabled) { ulong lobbyId = LobbyId; if (lobbyId == 0L) { if (_boundLobby != 0L) { Reset(); } return; } if (lobbyId != _boundLobby) { Reset(); _boundLobby = lobbyId; Bind(); ReadAll(lobbyId); } if (modEnabled && TightBeamPreferences.SyncMyBeam) { _withdrawPending = false; Publish(lobbyId); } else if (_hasPublished || _withdrawPending) { Withdraw(lobbyId); } if (modEnabled && Time.time >= _nextRescanAt) { _nextRescanAt = Time.time + (_callbackProven ? 5f : 1f); ReadAll(lobbyId); } } private static void Bind() { if (_dataCallback == null) { try { _dataCallback = Callback<LobbyDataUpdate_t>.Create(DispatchDelegate<LobbyDataUpdate_t>.op_Implicit((Action<LobbyDataUpdate_t>)OnLobbyData)); Instance log = Core.Log; if (log != null) { log.Msg("[board] lobby-data callback registered."); } } catch (Exception ex) { Instance log2 = Core.Log; if (log2 != null) { log2.Warning("[board] no lobby-data callback on this build (" + ex.GetType().Name + "); beam updates come from the periodic sweep instead."); } } } if (_onLobbyChange != null) { return; } try { Lobby instance = Singleton<Lobby>.Instance; if ((Object)(object)instance != (Object)null) { _onLobbyChange = OnLobbyChange; instance.OnLobbyChange += Action.op_Implicit(_onLobbyChange); } } catch (Exception ex2) { Instance log3 = Core.Log; if (log3 != null) { log3.Warning("[board] lobby-change hook failed: " + ex2.Message); } } } internal static void EndSession() { _posts.Clear(); if (_hasPublished) { _withdrawPending = true; } } internal static void Reset() { _posts.Clear(); _hasPublished = false; _withdrawPending = false; _verifiedWrite = false; _nextPublishAt = 0f; _nextRescanAt = 0f; _writeBackoff = 0f; _writeDelay = 0f; _boundLobby = 0uL; _warnedWrite = false; } internal static bool TryGet(ulong steamId, out BeamPost post) { return _posts.TryGetValue(steamId, out post); } internal static ulong[] PostedIds() { if (_posts.Count == 0) { return _noIds; } ulong[] array = new ulong[_posts.Count]; _posts.Keys.CopyTo(array, 0); return array; } private static void OnLobbyChange() { ulong lobbyId = LobbyId; if (lobbyId != 0L) { ReadAll(lobbyId); } } private static void OnLobbyData(LobbyDataUpdate_t e) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) try { if (!_callbackProven) { _callbackProven = true; Instance log = Core.Log; if (log != null) { log.Msg("[board] lobby-data callback is live; sweeping less often now."); } } if (e.m_ulSteamIDLobby == _boundLobby && e.m_ulSteamIDMember != e.m_ulSteamIDLobby) { ReadOne(e.m_ulSteamIDLobby, e.m_ulSteamIDMember); } } catch { } } private static void ReadAll(ulong lobby) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) try { CSteamID val = default(CSteamID); ((CSteamID)(ref val))..ctor(lobby); _seen.Clear(); int numLobbyMembers = SteamMatchmaking.GetNumLobbyMembers(val); for (int i = 0; i < numLobbyMembers; i++) { CSteamID lobbyMemberByIndex = SteamMatchmaking.GetLobbyMemberByIndex(val, i); _seen.Add(lobbyMemberByIndex.m_SteamID); ReadOne(lobby, lobbyMemberByIndex.m_SteamID); } _gone.Clear(); foreach (ulong key in _posts.Keys) { if (!_seen.Contains(key)) { _gone.Add(key); } } for (int j = 0; j < _gone.Count; j++) { _posts.Remove(_gone[j]); } } catch (Exception ex) { Instance log = Core.Log; if (log != null) { log.Warning("[board] read failed: " + ex.Message); } } } private static void ReadOne(ulong lobby, ulong member) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) try { if (member == PlayerIdentity.LocalSteamId()) { _posts.Remove(member); return; } string lobbyMemberData = SteamMatchmaking.GetLobbyMemberData(new CSteamID(lobby), new CSteamID(member), "doodesch_tightbeam"); ReadCount++; BeamPost p; if (string.IsNullOrEmpty(lobbyMemberData)) { _posts.Remove(member); } else if (BeamWire.TryDecode(lobbyMemberData, out p)) { _posts[member] = p; } else { _posts.Remove(member); } } catch { } } private static void Publish(ulong lobby) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) if (Time.time < _nextPublishAt) { return; } BeamPost beamPost = BeamPostBuilder.Current(); if (_hasPublished && beamPost.SameAs(_lastPublished)) { return; } string value = BeamWire.Encode(beamPost); if (!Write(lobby, value)) { return; } _lastPublished = beamPost; _hasPublished = true; _nextPublishAt = Time.time + 0.2f; if (_verifiedWrite) { return; } _verifiedWrite = true; try { if (string.IsNullOrEmpty(SteamMatchmaking.GetLobbyMemberData(new CSteamID(lobby), new CSteamID(PlayerIdentity.LocalSteamId()), "doodesch_tightbeam"))) { Instance log = Core.Log; if (log != null) { log.Warning("[board] our beam did not stick in the lobby - another mod may have used up the member-data slots. Others will see default cones."); } } } catch { } } private static void Withdraw(ulong lobby) { _withdrawPending = true; if (Write(lobby, "")) { _hasPublished = false; _withdrawPending = false; } } private static bool Write(ulong lobby, string value) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (Time.time < _writeBackoff) { return false; } try { SteamMatchmaking.SetLobbyMemberData(new CSteamID(lobby), "doodesch_tightbeam", value); if (_warnedWrite) { _warnedWrite = false; Instance log = Core.Log; if (log != null) { log.Msg("[board] beam sharing recovered."); } } _writeBackoff = 0f; _writeDelay = 0f; WriteCount++; return true; } catch (Exception ex) { _writeDelay = ((_writeDelay <= 0f) ? 0.5f : Mathf.Min(15f, _writeDelay * 2f)); _writeBackoff = Time.time + _writeDelay; if (!_warnedWrite) { _warnedWrite = true; Instance log2 = Core.Log; if (log2 != null) { log2.Warning("[board] beam write failed, backing off: " + ex.Message); } } return false; } } } internal static class BeamPostBuilder { private static int _fxSeq; private static FxKind _fxKind; private static int _fxA; private static int _fxB; private static int _fxC; private static int _fxSeed; private static bool _hooked; internal static void Start() { if (!_hooked) { _hooked = true; FlashlightController.Instance.FxRaised += OnFxRaised; } } internal static BeamPost Current() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) FlashlightController instance = FlashlightController.Instance; Color wireColor = instance.WireColor; return new BeamPost { On = instance.IsOn, I100 = Mathf.RoundToInt(Mathf.Max(0f, instance.WireIntensity) * 100f), R10 = Mathf.RoundToInt(Mathf.Clamp(instance.WireRange, 2f, 60f) * 10f), A10 = Mathf.RoundToInt(Mathf.Clamp(instance.WireSpotAngle, 8f, 90f) * 10f), Rgb24 = ((Byte(wireColor.r) << 16) | (Byte(wireColor.g) << 8) | Byte(wireColor.b)), FxSeq = _fxSeq, Fx = _fxKind, FxA = _fxA, FxB = _fxB, FxC = _fxC, FxSeed = _fxSeed }; } private static void OnFxRaised(char code, float a, float b, float c) { FxKind fxKind; switch (code) { default: return; case 'F': fxKind = FxKind.Flicker; break; case 'f': fxKind = FxKind.StopFlicker; break; case 'P': fxKind = FxKind.Pulse; break; case 'p': fxKind = FxKind.StopPulse; break; case 'B': fxKind = FxKind.Blink; break; } _fxSeq++; _fxKind = fxKind; _fxA = BeamWire.Q(a); _fxB = BeamWire.Q(b); _fxC = BeamWire.Q(c); _fxSeed = BeamWire.Q(FlashlightController.Instance.CurrentFxSeed); } private static int Byte(float v) { return Mathf.Clamp(Mathf.RoundToInt(v * 255f), 0, 255); } } internal enum FxKind { None, Flicker, StopFlicker, Pulse, StopPulse, Blink } internal struct BeamPost { public bool On; public int I100; public int R10; public int A10; public int Rgb24; public int FxSeq; public FxKind Fx; public int FxA; public int FxB; public int FxC; public int FxSeed; public float Intensity => (float)I100 / 100f; public float Range => (float)R10 / 10f; public float Angle => (float)A10 / 10f; public float R => (float)((Rgb24 >> 16) & 0xFF) / 255f; public float G => (float)((Rgb24 >> 8) & 0xFF) / 255f; public float B => (float)(Rgb24 & 0xFF) / 255f; public bool SameAs(BeamPost o) { if (On == o.On && I100 == o.I100 && R10 == o.R10 && A10 == o.A10 && Rgb24 == o.Rgb24) { return FxSeq == o.FxSeq; } return false; } } internal static class BeamWire { internal const string Prefix = "TB1|"; internal const string Key = "doodesch_tightbeam"; internal const int MaxPayloadChars = 128; private const int MinFields = 12; private const int MaxFields = 24; private static readonly CultureInfo Inv = CultureInfo.InvariantCulture; internal const int Endless = int.MaxValue; private const int MaxFinite = 60000; internal static string Encode(BeamPost p) { string[] obj = new string[22] { "TB1|", p.On ? "1" : "0", "|", p.I100.ToString(Inv), "|", p.R10.ToString(Inv), "|", p.A10.ToString(Inv), "|", (p.Rgb24 & 0xFFFFFF).ToString("X6", Inv), "|", p.FxSeq.ToString(Inv), "|", null, null, null, null, null, null, null, null, null }; int fx = (int)p.Fx; obj[13] = fx.ToString(Inv); obj[14] = "|"; obj[15] = p.FxA.ToString(Inv); obj[16] = "|"; obj[17] = p.FxB.ToString(Inv); obj[18] = "|"; obj[19] = p.FxC.ToString(Inv); obj[20] = "|"; obj[21] = p.FxSeed.ToString(Inv); return string.Concat(obj); } internal static bool TryDecode(string raw, out BeamPost p) { p = default(BeamPost); if (raw == null || raw.Length > 128) { return false; } if (!raw.StartsWith("TB1|", StringComparison.Ordinal)) { return false; } string[] array = raw.Split('|'); if (array.Length < 12 || array.Length > 24) { return false; } if (!TryInt(array[1], out var v) || !TryInt(array[2], out p.I100) || !TryInt(array[3], out p.R10) || !TryInt(array[4], out p.A10)) { return false; } if (!TryHex(array[5], out p.Rgb24)) { return false; } if (!TryInt(array[6], out p.FxSeq) || !TryInt(array[7], out var v2) || !TryInt(array[8], out p.FxA) || !TryInt(array[9], out p.FxB) || !TryInt(array[10], out p.FxC) || !TryInt(array[11], out p.FxSeed)) { return false; } if (v2 < 0 || v2 > 5) { return false; } p.On = v != 0; p.Fx = (FxKind)v2; p.I100 = Mathf.Clamp(p.I100, 0, 10000); p.R10 = Mathf.Clamp(p.R10, 20, 600); p.A10 = Mathf.Clamp(p.A10, 80, 900); p.Rgb24 &= 16777215; p.FxA = ClampFx(p.FxA); p.FxB = ClampFx(p.FxB); p.FxC = ClampFx(p.FxC); p.FxSeed = Mathf.Clamp(p.FxSeed, 0, 1000000); return true; } internal static int Q(float v) { if (float.IsNaN(v)) { return 0; } if (float.IsPositiveInfinity(v)) { return int.MaxValue; } double num = (double)v * 1000.0; if (num >= 2147483647.0) { return int.MaxValue; } if (num < 0.0) { return 0; } return (int)num; } internal static float Dq(int q) { if (q != int.MaxValue) { return (float)q / 1000f; } return float.PositiveInfinity; } private static int ClampFx(int q) { if (q != int.MaxValue) { return Mathf.Clamp(q, 0, 60000); } return int.MaxValue; } private static bool TryInt(string s, out int v) { return int.TryParse(s, NumberStyles.Integer, Inv, out v); } private static bool TryHex(string s, out int v) { v = 0; if (string.IsNullOrEmpty(s) || s.Length > 6) { return false; } for (int i = 0; i < s.Length; i++) { int num = HexDigit(s[i]); if (num < 0) { return false; } v = (v << 4) | num; } return true; } private static int HexDigit(char c) { if (c >= '0' && c <= '9') { return c - 48; } if (c >= 'A' && c <= 'F') { return c - 65 + 10; } if (c >= 'a' && c <= 'f') { return c - 97 + 10; } return -1; } } internal static class PlayerIdentity { internal static ulong SteamIdOf(Player p) { if ((Object)(object)p == (Object)null) { return 0uL; } try { string playerCode = p.PlayerCode; if (!string.IsNullOrEmpty(playerCode) && ulong.TryParse(playerCode, out var result)) { return result; } } catch { } return 0uL; } internal static ulong LocalSteamId() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) try { ulong steamID = SteamUser.GetSteamID().m_SteamID; if (steamID != 0L) { return steamID; } } catch { } try { return SteamIdOf(Player.Local); } catch { return 0uL; } } } } namespace TightBeam.Lighting { internal struct BeamFx { private enum Mode { None, Flicker, Pulse } private Mode _mode; private float _strength; private float _freq; private float _amp; private float _period; private float _end; private float _seed; private int _blinkLeft; private float _blinkInterval; private float _blinkNext; private bool _blinkDark; public const int MaxBlinks = 20; public float Seed => _seed; public void Flicker(float strength01, float durationSeconds, float freqHz, float seed) { _mode = Mode.Flicker; _strength = Mathf.Clamp01(strength01); _freq = Mathf.Max(0.1f, freqHz); _end = Time.time + Mathf.Max(0.05f, durationSeconds); _seed = seed; } public void Pulse(float amp01, float periodSeconds, float durationSeconds, float seed) { _mode = Mode.Pulse; _amp = Mathf.Clamp01(amp01); _period = Mathf.Max(0.1f, periodSeconds); _end = (float.IsInfinity(durationSeconds) ? float.MaxValue : (Time.time + Mathf.Max(0.05f, durationSeconds))); _seed = seed; } public bool StopFlicker() { if (_mode != Mode.Flicker) { return false; } _mode = Mode.None; return true; } public bool StopPulse() { if (_mode != Mode.Pulse) { return false; } _mode = Mode.None; return true; } public void Blink(int times, float intervalSeconds) { if (times > 0) { _blinkLeft = Mathf.Min(times, 20) * 2; _blinkInterval = Mathf.Max(0.02f, intervalSeconds); _blinkNext = Time.time; _blinkDark = false; } } public void Clear() { _mode = Mode.None; _blinkLeft = 0; _blinkDark = false; } public float Multiplier() { float num = 1f; if (_mode == Mode.Flicker) { if (Time.time >= _end) { _mode = Mode.None; } else { float num2 = Mathf.PerlinNoise(Time.time * _freq + _seed, _seed * 0.37f); num *= Mathf.Lerp(1f - _strength, 1f, num2); } } else if (_mode == Mode.Pulse) { if (Time.time >= _end) { _mode = Mode.None; } else { num *= 1f + _amp * Mathf.Sin(Time.time * ((float)Math.PI * 2f / Mathf.Max(0.05f, _period)) + _seed); } } if (_blinkLeft > 0) { if (Time.time >= _blinkNext) { _blinkDark = !_blinkDark; _blinkLeft--; _blinkNext = Time.time + _blinkInterval; } if (_blinkDark) { num *= 0.04f; } } return Mathf.Max(0f, num); } } internal sealed class FlashlightController { private sealed class Ov { public int Token; public string Owner; public float? I; public float? R; public float? A; public Color? C; public float Expiry; } private GameObject _go; private Light _light; private Camera _cam; private bool _isOn; private float _focus; private float _focusTarget; private float _scrollVelEma; private float _intensity; private Color _color = Color.white; private float? _manualRange; private float? _manualAngle; private readonly List<Ov> _overrides = new List<Ov>(); private int _nextToken = 1; private BeamFx _fx; private float _wireIntensity; private float _wireRange; private float _wireAngle; private Color _wireColor = Color.white; public static FlashlightController Instance { get; } = new FlashlightController(); public bool IsOn => _isOn; public bool HasLight => (Object)(object)_light != (Object)null; public float WireIntensity => _wireIntensity; public float WireRange => _wireRange; public float WireSpotAngle => _wireAngle; public Color WireColor => _wireColor; public float Focus => _focus; public float CurrentIntensity { get { if (!((Object)(object)_light != (Object)null)) { return 0f; } return _light.intensity; } } public float CurrentRange { get { if (!((Object)(object)_light != (Object)null)) { return 0f; } return _light.range; } } public float CurrentSpotAngle { get { if (!((Object)(object)_light != (Object)null)) { return 0f; } return _light.spotAngle; } } public Color CurrentColor { get { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_light != (Object)null)) { return Color.black; } return _light.color; } } public float CurrentFxSeed => _fx.Seed; public event Action<bool> Toggled; public event Action<char, float, float, float> FxRaised; public void InitFromPrefs() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) _focus = TightBeamPreferences.DefaultFocus; _focusTarget = _focus; _scrollVelEma = 0f; _intensity = TightBeamPreferences.DefaultIntensity; _color = TightBeamPreferences.Color; } public void EnsureRig() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown if ((Object)(object)_light == (Object)null) { _go = new GameObject("TightBeamLight"); Object.DontDestroyOnLoad((Object)(object)_go); _light = _go.AddComponent<Light>(); _light.type = (LightType)0; _light.renderMode = (LightRenderMode)0; _light.shadows = (LightShadows)(TightBeamPreferences.CastShadows ? 2 : 0); _light.shadowBias = 0.05f; _light.shadowNormalBias = 0.4f; ((Behaviour)_light).enabled = false; } if ((Object)(object)_cam == (Object)null) { _cam = Camera.main; } } public void DisableRig() { if ((Object)(object)_light != (Object)null) { ((Behaviour)_light).enabled = false; } VanillaLightSync.Restore(); } public void Follow() { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_light == (Object)null || !_isOn) { return; } if ((Object)(object)_cam == (Object)null) { _cam = Camera.main; if ((Object)(object)_cam == (Object)null) { return; } } Transform transform = ((Component)_cam).transform; _go.transform.position = transform.position + transform.forward * 0.25f + transform.right * 0.15f - transform.up * 0.2f; _go.transform.rotation = transform.rotation; } public void Tick(float dt) { //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_light == (Object)null) { return; } if (!_isOn) { if (((Behaviour)_light).enabled) { ((Behaviour)_light).enabled = false; VanillaLightSync.Apply(dark: false); } return; } float num = 1f - Mathf.Exp((0f - dt) / TightBeamPreferences.FocusEaseTau); _focus = Mathf.Lerp(_focus, _focusTarget, num); if (Mathf.Abs(_focusTarget - _focus) < 0.0005f) { _focus = _focusTarget; } float num2 = _manualRange ?? Mathf.Lerp(TightBeamPreferences.RangeNarrow, TightBeamPreferences.RangeWide, _focus); float num3 = _manualAngle ?? Mathf.Lerp(TightBeamPreferences.AngleNarrow, TightBeamPreferences.AngleWide, _focus); float intensity = _intensity; Color color = _color; PruneOverrides(); float num4 = num2; float num5 = num3; float num6 = intensity; Color val = color; for (int num7 = _overrides.Count - 1; num7 >= 0; num7--) { Ov ov = _overrides[num7]; if (ov.I.HasValue && num6 == intensity) { num6 = ov.I.Value; } if (ov.R.HasValue && num4 == num2) { num4 = ov.R.Value; } if (ov.A.HasValue && num5 == num3) { num5 = ov.A.Value; } if (ov.C.HasValue && val == color) { val = ov.C.Value; } } _wireIntensity = num6; _wireRange = num4; _wireAngle = num5; _wireColor = val; num6 *= _fx.Multiplier(); _light.intensity = Mathf.Max(0f, num6); _light.range = Mathf.Clamp(num4, 2f, 60f); _light.spotAngle = Mathf.Clamp(num5, 8f, 90f); _light.innerSpotAngle = _light.spotAngle * 0.6f; _light.color = val; ((Behaviour)_light).enabled = _isOn; VanillaLightSync.Apply(_isOn); } private void PruneOverrides() { for (int num = _overrides.Count - 1; num >= 0; num--) { if (_overrides[num].Expiry > 0f && Time.time > _overrides[num].Expiry) { _overrides.RemoveAt(num); } } } public void SyncOnFromGame() { bool flag = false; try { if (PlayerSingleton<Phone>.InstanceExists) { GameObject phoneFlashlight = PlayerSingleton<Phone>.Instance.PhoneFlashlight; flag = (Object)(object)phoneFlashlight != (Object)null && phoneFlashlight.activeSelf; } } catch { return; } if (flag != _isOn) { _isOn = flag; try { this.Toggled?.Invoke(flag); } catch { } } } public void SetOn(bool on) { try { if (PlayerSingleton<Phone>.InstanceExists && PlayerSingleton<Phone>.Instance.FlashlightOn != on) { PlayerSingleton<Phone>.Instance.ToggleFlashlight(); } } catch { } } public void Toggle() { try { if (PlayerSingleton<Phone>.InstanceExists) { PlayerSingleton<Phone>.Instance.ToggleFlashlight(); } } catch { } } private void MoveFocusTarget(float delta) { _focusTarget = Mathf.Clamp01(_focusTarget + delta); _manualRange = null; _manualAngle = null; } private void SnapFocusTarget(float value) { _focusTarget = Mathf.Clamp01(value); _manualRange = null; _manualAngle = null; } public void NudgeFocus(float delta) { MoveFocusTarget(delta); } public void UpdateFocusScroll(float scrollDelta, float dt) { if (Mathf.Abs(scrollDelta) > 0.0001f) { float num = Mathf.Abs(scrollDelta) / Mathf.Max(dt, 0.004166667f); float num2 = 1f - Mathf.Exp((0f - dt) / TightBeamPreferences.FocusVelAttackTau); _scrollVelEma = Mathf.Lerp(_scrollVelEma, num, num2); float focusVelocityRefRate = TightBeamPreferences.FocusVelocityRefRate; float num3 = focusVelocityRefRate * TightBeamPreferences.FocusFlickRateMultiplier; float num4 = (TightBeamPreferences.InvertFocusScroll ? (-1f) : 1f); float num5 = Mathf.Sign(scrollDelta) * num4; if (_scrollVelEma >= num3) { SnapFocusTarget((num5 > 0f) ? 1f : 0f); return; } float num6 = Mathf.Clamp01((_scrollVelEma - focusVelocityRefRate) / Mathf.Max(0.0001f, num3 - focusVelocityRefRate)); float num7 = Mathf.Lerp(TightBeamPreferences.FocusSensitivity, TightBeamPreferences.FocusMaxStep, Mathf.Pow(num6, TightBeamPreferences.FocusVelocityGamma)); MoveFocusTarget(num5 * num7); } else { float num8 = 1f - Mathf.Exp((0f - dt) / TightBeamPreferences.FocusVelDecayTau); _scrollVelEma = Mathf.Lerp(_scrollVelEma, 0f, num8); } } public void ResetFocusScrollVelocity() { _scrollVelEma = 0f; } public void SetIntensity(float v) { _intensity = Mathf.Clamp(v, TightBeamPreferences.MinIntensity, TightBeamPreferences.MaxIntensity); } public void SetColor(Color c) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) _color = c; } public void SetBaseRange(float v) { _manualRange = Mathf.Clamp(v, 2f, 60f); } public void SetBaseSpotAngle(float v) { _manualAngle = Mathf.Clamp(v, 8f, 90f); } public int BeginOverride(string owner) { Ov ov = new Ov { Token = _nextToken++, Owner = owner }; _overrides.Add(ov); return ov.Token; } public void EndOverride(int token) { for (int i = 0; i < _overrides.Count; i++) { if (_overrides[i].Token == token) { _overrides.RemoveAt(i); break; } } } private Ov Find(int token) { for (int i = 0; i < _overrides.Count; i++) { if (_overrides[i].Token == token) { return _overrides[i]; } } return null; } public void OverrideIntensity(int token, float v) { Ov ov = Find(token); if (ov != null) { ov.I = v; } } public void OverrideRange(int token, float v) { Ov ov = Find(token); if (ov != null) { ov.R = v; } } public void OverrideSpotAngle(int token, float v) { Ov ov = Find(token); if (ov != null) { ov.A = v; } } public void OverrideColor(int token, Color c) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) Ov ov = Find(token); if (ov != null) { ov.C = c; } } public void ClearOverrideIntensity(int token) { Ov ov = Find(token); if (ov != null) { ov.I = null; } } public void ClearOverrideRange(int token) { Ov ov = Find(token); if (ov != null) { ov.R = null; } } public void ClearOverrideSpotAngle(int token) { Ov ov = Find(token); if (ov != null) { ov.A = null; } } public void ClearOverrideColor(int token) { Ov ov = Find(token); if (ov != null) { ov.C = null; } } public void TemporaryIntensity(float v, float seconds) { _overrides.Add(new Ov { Token = _nextToken++, Owner = "$temp", I = v, Expiry = Time.time + Mathf.Max(0.05f, seconds) }); } public void TemporaryColor(float r, float g, float b, float a, float seconds) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) _overrides.Add(new Ov { Token = _nextToken++, Owner = "$temp", C = new Color(r, g, b, a), Expiry = Time.time + Mathf.Max(0.05f, seconds) }); } public void Flicker(float strength01, float durationSeconds, float freqHz) { _fx.Flicker(strength01, durationSeconds, freqHz, Random.value * 100f); RaiseFx('F', Mathf.Clamp01(strength01), durationSeconds, Mathf.Max(0.1f, freqHz)); } public void Pulse(float amp01, float periodSeconds, float durationSeconds) { _fx.Pulse(amp01, periodSeconds, durationSeconds, Random.value * 6.28f); RaiseFx('P', Mathf.Clamp01(amp01), Mathf.Max(0.1f, periodSeconds), durationSeconds); } public void StopFlicker() { if (_fx.StopFlicker()) { RaiseFx('f', 0f, 0f, 0f); } } public void StopPulse() { if (_fx.StopPulse()) { RaiseFx('p', 0f, 0f, 0f); } } public void Blink(int times, float intervalSeconds) { if (_isOn && times > 0) { _fx.Blink(times, intervalSeconds); RaiseFx('B', times, Mathf.Max(0.02f, intervalSeconds), 0f); } } private void RaiseFx(char code, float a, float b, float c) { try { this.FxRaised?.Invoke(code, a, b, c); } catch { } } } internal static class RemoteBeams { private sealed class Entry { public Player Owner; public ulong SteamId; public Transform Anchor; public bool Lit; public bool ToggleOwed; public Vector3 Pos; public Quaternion Rot; public bool PoseInit; public float Intensity; public float Range; public float Angle; public Color Color; public bool ParamsInit; public bool HasPost; public BeamPost Post; public BeamFx Fx; public float FxMul = 1f; public int LastFxSeq; public bool LastVanillaActive; public bool SawVanillaTransition; public OptimizedLight SupThird; public OptimizedLight SupEquip; public bool SupThirdTaken; public bool SupEquipTaken; public int Rig = -1; public bool Selected; public float Dist2; } private const float RosterInterval = 0.2f; private const float SelectInterval = 0.1f; private static readonly Vector3 HandOffset = new Vector3(0.15f, -0.2f, 0.25f); private static readonly Dictionary<ulong, Entry> _byId = new Dictionary<ulong, Entry>(); private static readonly List<Entry> _entries = new List<Entry>(); private static readonly List<Entry> _pending = new List<Entry>(); private static readonly Il2CppStructArray<Plane> _frustum = new Il2CppStructArray<Plane>(6L); private static GameObject[] _rigGo; private static Light[] _rigLight; private static Entry[] _winners; private static int _winnerCount; private static float _nextRoster; private static float _nextSelect; private static bool _broken; private static readonly List<Action<ulong, bool>> _toggledListeners = new List<Action<ulong, bool>>(); private static readonly ulong[] _noIds = new ulong[0]; internal static int ActiveCount { get; private set; } internal static int CandidateCount { get; private set; } internal static int TrackedCount => _entries.Count; public static void Tick(float dt) { if (_broken) { return; } try { TickInner(dt); } catch (Exception ex) { _broken = true; Instance log = Core.Log; if (log != null) { log.Error("RemoteBeams disabled for this session after an error: " + ex); } try { DisableAll(); } catch { } } } private static void TickInner(float dt) { int maxRemoteBeams = TightBeamPreferences.MaxRemoteBeams; bool num = TightBeamPreferences.RemoteBeams && maxRemoteBeams > 0; if (Time.time >= _nextRoster) { _nextRoster = Time.time + 0.2f; RefreshRoster(); } bool flag = Time.time >= _nextSelect; if (flag) { _nextSelect = Time.time + 0.1f; } if (!num) { if (flag) { Evaluate(); } ReleaseAll(); CandidateCount = 0; return; } Camera main = Camera.main; if ((Object)(object)main == (Object)null) { if (flag) { Evaluate(); } ReleaseAll(); return; } if (_entries.Count == 0) { ReleaseAll(); CandidateCount = 0; return; } EnsurePool(maxRemoteBeams); if (flag) { Evaluate(); Select(main, maxRemoteBeams); } int remoteShadowNearest = TightBeamPreferences.RemoteShadowNearest; for (int i = 0; i < _winnerCount; i++) { Entry entry = _winners[i]; if (entry != null && entry.Selected) { entry.FxMul = entry.Fx.Multiplier(); if (!ResolveAnchor(entry)) { Release(entry); } else { Render(entry, i, i < remoteShadowNearest, dt); } } } ActiveCount = _winnerCount; } private static void Evaluate() { for (int i = 0; i < _entries.Count; i++) { Entry entry = _entries[i]; PullPost(entry); bool flag = IsLit(entry); if (flag != entry.Lit) { entry.Lit = flag; RaiseToggled(entry); } } } private static void Select(Camera cam, int cap) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: 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_0097: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) GeometryUtility.CalculateFrustumPlanes(cam, _frustum); Vector3 position = ((Component)cam).transform.position; float remoteBeamMaxDistance = TightBeamPreferences.RemoteBeamMaxDistance; float num = remoteBeamMaxDistance * remoteBeamMaxDistance; int num2 = 0; int num3 = 0; for (int i = 0; i < _entries.Count; i++) { Entry entry = _entries[i]; entry.Selected = false; if (!entry.Lit) { Release(entry); continue; } if (!entry.HasPost && !TightBeamPreferences.RemoteBeamsForUnmoddedPlayers) { Release(entry); continue; } if (!ResolveAnchor(entry)) { Release(entry); continue; } Vector3 position2 = entry.Anchor.position; Vector3 val = position2 - position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude > num) { Release(entry); continue; } float range = entry.Range; if (!entry.ParamsInit) { TargetParams(entry, out var _, out range, out var _, out var _); } if (!ConeVisible(position2, entry.Anchor.forward, range)) { Release(entry); continue; } num2++; entry.Dist2 = sqrMagnitude; if (num3 < cap) { _winners[num3++] = entry; continue; } int num4 = 0; for (int j = 1; j < cap; j++) { if (_winners[j].Dist2 > _winners[num4].Dist2) { num4 = j; } } if (_winners[num4].Dist2 <= sqrMagnitude) { Release(entry); continue; } Release(_winners[num4]); _winners[num4] = entry; } CandidateCount = num2; SortWinners(num3); for (int k = 0; k < num3; k++) { _winners[k].Selected = true; } for (int l = num3; l < _rigGo.Length; l++) { SetRigActive(l, on: false); } _winnerCount = num3; } private static void RefreshRoster() { try { List<Player> playerList = Player.PlayerList; if (playerList == null) { return; } for (int num = _entries.Count - 1; num >= 0; num--) { Entry entry = _entries[num]; if (!((Object)(object)entry.Owner != (Object)null)) { Forget(entry, num); } } for (int i = 0; i < playerList.Count; i++) { Player val = playerList[i]; if ((Object)(object)val == (Object)null) { continue; } bool isLocalPlayer; try { isLocalPlayer = val.IsLocalPlayer; } catch { continue; } if (isLocalPlayer) { continue; } ulong num2 = PlayerIdentity.SteamIdOf(val); Entry entry2 = ((num2 != 0L && _byId.TryGetValue(num2, out var value)) ? value : FindPending(val)); if (entry2 == null) { entry2 = new Entry { Owner = val, SteamId = num2 }; _entries.Add(entry2); if (num2 != 0L) { _byId[num2] = entry2; } else { _pending.Add(entry2); } continue; } entry2.Owner = val; if (entry2.SteamId == 0L && num2 != 0L) { entry2.SteamId = num2; _byId[num2] = entry2; _pending.Remove(entry2); if (entry2.ToggleOwed) { RaiseToggled(entry2); } } } for (int num3 = _entries.Count - 1; num3 >= 0; num3--) { Entry entry3 = _entries[num3]; bool flag = false; for (int j = 0; j < playerList.Count; j++) { if (playerList[j] == entry3.Owner) { flag = true; break; } } if (!flag) { Forget(entry3, num3); } } } catch (Exception ex) { Instance log = Core.Log; if (log != null) { log.Warning("RemoteBeams roster failed: " + ex.Message); } } } private static Entry FindPending(Player p) { for (int i = 0; i < _pending.Count; i++) { if (_pending[i].Owner == p) { return _pending[i]; } } return null; } private static void Forget(Entry e, int index) { Release(e); _entries.RemoveAt(index); _pending.Remove(e); if (e.SteamId != 0L) { _byId.Remove(e.SteamId); } } private static void PullPost(Entry e) { if (e.SteamId == 0L) { return; } bool hasPost = e.HasPost; e.HasPost = BeamBoard.TryGet(e.SteamId, out var post); if (!e.HasPost) { if (hasPost) { e.Fx.Clear(); } return; } e.Post = post; if (!hasPost) { e.LastFxSeq = post.FxSeq; } else if (post.FxSeq != e.LastFxSeq) { e.LastFxSeq = post.FxSeq; ApplyFx(e, post); } } private static void ApplyFx(Entry e, BeamPost p) { float num = BeamWire.Dq(p.FxA); float num2 = BeamWire.Dq(p.FxB); float num3 = BeamWire.Dq(p.FxC); float seed = (float)p.FxSeed / 1000f; switch (p.Fx) { case FxKind.Flicker: e.Fx.Flicker(num, num2, num3, seed); break; case FxKind.StopFlicker: e.Fx.StopFlicker(); break; case FxKind.Pulse: e.Fx.Pulse(num, num2, num3, seed); break; case FxKind.StopPulse: e.Fx.StopPulse(); break; case FxKind.Blink: e.Fx.Blink(Mathf.RoundToInt(num), num2); break; } } private static bool IsLit(Entry e) { try { if ((Object)(object)e.Owner == (Object)null) { return false; } OptimizedLight thirdPersonFlashlight = e.Owner.ThirdPersonFlashlight; bool flag = (Object)(object)thirdPersonFlashlight != (Object)null && ((Component)thirdPersonFlashlight).gameObject.activeSelf; if (flag != e.LastVanillaActive) { e.LastVanillaActive = flag; e.SawVanillaTransition = true; } return ((e.SawVanillaTransition || !e.HasPost) ? flag : e.Post.On) && !e.Owner.IsInVehicle; } catch { return false; } } private static bool ResolveAnchor(Entry e) { try { if ((Object)(object)e.Owner == (Object)null) { return false; } Transform val = e.Owner.MimicCamera; if ((Object)(object)val == (Object)null) { Avatar avatar = e.Owner.Avatar; if ((Object)(object)avatar != (Object)null && (Object)(object)avatar.Eyes != (Object)null) { val = ((Component)avatar.Eyes).transform; } if ((Object)(object)val == (Object)null && (Object)(object)e.Owner.ThirdPersonFlashlight != (Object)null) { val = ((Component)e.Owner.ThirdPersonFlashlight).transform; } if ((Object)(object)val == (Object)null) { val = ((Component)e.Owner).transform; } } e.Anchor = val; return (Object)(object)val != (Object)null; } catch { return false; } } internal static void AddToggledListener(Action<ulong, bool> cb) { if (cb != null) { _toggledListeners.Add(cb); } } private static void RaiseToggled(Entry e) { if (e.SteamId == 0L) { e.ToggleOwed = true; return; } e.ToggleOwed = false; for (int i = 0; i < _toggledListeners.Count; i++) { try { _toggledListeners[i](e.SteamId, e.Lit); } catch { } } } internal static bool InMultiplayer() { try { List<Player> playerList = Player.PlayerList; return playerList != null && playerList.Count > 1; } catch { return false; } } internal static ulong[] RemoteIds() { ulong[] array = BeamBoard.PostedIds(); if (_byId.Count == 0) { return array; } List<ulong> list = new List<ulong>(array); foreach (ulong key in _byId.Keys) { if (!list.Contains(key)) { list.Add(key); } } if (list.Count != 0) { return list.ToArray(); } return _noIds; } internal static bool HasSyncedBeam(ulong steamId) { BeamPost post; return BeamBoard.TryGet(steamId, out post); } internal static float[] BeamOf(ulong steamId) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) if (_byId.TryGetValue(steamId, out var value)) { float intensity; float range; float angle; Color color; if (value.ParamsInit) { intensity = value.Intensity; range = value.Range; angle = value.Angle; color = value.Color; } else { TargetParams(value, out intensity, out range, out angle, out color); } return new float[8] { value.Lit ? 1f : 0f, Mathf.Max(0f, intensity * value.FxMul), range, angle, color.r, color.g, color.b, color.a }; } if (!BeamBoard.TryGet(steamId, out var post)) { return null; } return new float[8] { post.On ? 1f : 0f, Mathf.Min(post.Intensity, TightBeamPreferences.MaxIntensity), post.Range, post.Angle, post.R, post.G, post.B, 1f }; } internal static float[] PoseOf(ulong steamId) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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_007b: Unknown result type (might be due to invalid IL or missing references) if (!_byId.TryGetValue(steamId, out var value) || !value.PoseInit) { return null; } Vector3 val = value.Pos + value.Rot * HandOffset; Vector3 val2 = value.Rot * Vector3.forward; return new float[6] { val.x, val.y, val.z, val2.x, val2.y, val2.z }; } internal static bool IsRendered(ulong steamId) { if (_byId.TryGetValue(steamId, out var value)) { return value.Rig >= 0; } return false; } private static void Render(Entry e, int slot, bool shadows, float dt) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: 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) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) e.Rig = slot; Vector3 position = e.Anchor.position; Quaternion rotation = e.Anchor.rotation; if (!e.PoseInit) { e.Pos = position; e.Rot = rotation; e.PoseInit = true; } else { float num = 1f - Mathf.Exp((0f - dt) / TightBeamPreferences.RemoteSmoothingTau); e.Pos = Vector3.Lerp(e.Pos, position, num); e.Rot = Quaternion.Slerp(e.Rot, rotation, num); } ResolveParams(e, dt); GameObject val = _rigGo[slot]; Light obj = _rigLight[slot]; val.transform.position = e.Pos + e.Rot * HandOffset; val.transform.rotation = e.Rot; obj.intensity = Mathf.Max(0f, e.Intensity * e.FxMul); obj.range = Mathf.Clamp(e.Range, 2f, 60f); obj.spotAngle = Mathf.Clamp(e.Angle, 8f, 90f); obj.innerSpotAngle = obj.spotAngle * 0.6f; obj.color = e.Color; obj.shadows = (LightShadows)(shadows ? 2 : 0); if (!val.activeSelf) { val.SetActive(true); } ((Behaviour)obj).enabled = true; Suppress(e); } private static void TargetParams(Entry e, out float intensity, out float range, out float angle, out Color color) { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) if (e.HasPost) { intensity = Mathf.Min(e.Post.Intensity, TightBeamPreferences.MaxIntensity); range = e.Post.Range; angle = e.Post.Angle; color = new Color(e.Post.R, e.Post.G, e.Post.B, 1f); } else { float defaultFocus = TightBeamPreferences.DefaultFocus; intensity = TightBeamPreferences.DefaultIntensity; range = Mathf.Lerp(TightBeamPreferences.RangeNarrow, TightBeamPreferences.RangeWide, defaultFocus); angle = Mathf.Lerp(TightBeamPreferences.AngleNarrow, TightBeamPreferences.AngleWide, defaultFocus); color = TightBeamPreferences.Color; } } private static void ResolveParams(Entry e, float dt) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: 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_009a: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) TargetParams(e, out var intensity, out var range, out var angle, out var color); if (!e.ParamsInit) { e.Intensity = intensity; e.Range = range; e.Angle = angle; e.Color = color; e.ParamsInit = true; } else { float num = 1f - Mathf.Exp((0f - dt) / TightBeamPreferences.FocusEaseTau); e.Intensity = Mathf.Lerp(e.Intensity, intensity, num); e.Range = Mathf.Lerp(e.Range, range, num); e.Angle = Mathf.Lerp(e.Angle, angle, num); e.Color = Color.Lerp(e.Color, color, num); } } private static bool ConeVisible(Vector3 origin, Vector3 forward, float range) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) Vector3 val = origin + forward * (range * 0.5f); float num = range * 0.55f; for (int i = 0; i < 6; i++) { Plane val2 = ((Il2CppArrayBase<Plane>)(object)_frustum)[i]; if (((Plane)(ref val2)).GetDistanceToPoint(val) < 0f - num) { return false; } } return true; } private static void SortWinners(int count) { for (int i = 1; i < count; i++) { Entry entry = _winners[i]; int num = i - 1; while (num >= 0 && _winners[num].Dist2 > entry.Dist2) { _winners[num + 1] = _winners[num]; num--; } _winners[num + 1] = entry; } } private static void EnsurePool(int cap) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown if (_rigGo != null && _rigGo.Length >= cap) { if (_winners == null || _winners.Length < cap) { _winners = new Entry[cap]; } return; } GameObject[] array = (GameObject[])(object)new GameObject[cap]; Light[] array2 = (Light[])(object)new Light[cap]; int num = ((_rigGo != null) ? _rigGo.Length : 0); for (int i = 0; i < num; i++) { array[i] = _rigGo[i]; array2[i] = _rigLight[i]; } for (int j = num; j < cap; j++) { array[j] = new GameObject("TightBeamRemote" + j); Object.DontDestroyOnLoad((Object)(object)array[j]); array2[j] = array[j].AddComponent<Light>(); array2[j].type = (LightType)0; array2[j].renderMode = (LightRenderMode)0; array2[j].shadows = (LightShadows)0; array2[j].shadowBias = 0.05f; array2[j].shadowNormalBias = 0.4f; ((Behaviour)array2[j]).enabled = false; array[j].SetActive(false); } _rigGo = array; _rigLight = array2; _winners = new Entry[cap]; } private static void SetRigActive(int slot, bool on) { if (_rigGo != null && slot >= 0 && slot < _rigGo.Length && !((Object)(object)_rigGo[slot] == (Object)null)) { if ((Object)(object)_rigLight[slot] != (Object)null) { ((Behaviour)_rigLight[slot]).enabled = on; } if (_rigGo[slot].activeSelf != on) { _rigGo[slot].SetActive(on); } } } private static void Suppress(Entry e) { if (!TightBeamPreferences.SuppressRemoteVanillaLights) { Restore(e); return; } try { OptimizedLight val = (((Object)(object)e.Owner != (Object)null) ? e.Owner.ThirdPersonFlashlight : null); if (val != e.SupThird) { Give(e.SupThird, e.SupThirdTaken); e.SupThird = val; e.SupThirdTaken = false; } if (Take(e.SupThird)) { e.SupThirdTaken = true; } OptimizedLight val2 = null; Avatar val3 = (((Object)(object)e.Owner != (Object)null) ? e.Owner.Avatar : null); if ((Object)(object)val3 != (Object)null) { AvatarEquippable currentEquippable = val3.CurrentEquippable; if ((Object)(object)currentEquippable != (Object)null) { FlashlightAvatarEquippable val4 = ((Il2CppObjectBase)currentEquippable).TryCast<FlashlightAvatarEquippable>(); if ((Object)(object)val4 != (Object)null) { val2 = val4.Light; } } } if (val2 != e.SupEquip) { Give(e.SupEquip, e.SupEquipTaken); e.SupEquip = val2; e.SupEquipTaken = false; } if (Take(e.SupEquip)) { e.SupEquipTaken = true; } } catch (Exception ex) { Instance log = Core.Log; if (log != null) { log.Warning("RemoteBeams suppress failed: " + ex.Message); } } } private static void Restore(Entry e) { Give(e.SupThird, e.SupThirdTaken); e.SupThird = null; e.SupThirdTaken = false; Give(e.SupEquip, e.SupEquipTaken); e.SupEquip = null; e.SupEquipTaken = false; } private static bool Take(OptimizedLight ol) { try { if ((Object)(object)ol != (Object)null && ol.Enabled) { ol.Enabled = false; ol.UpdateLightState(); return true; } } catch { } return false; } private static void Give(OptimizedLight ol, bool weTurnedItOff) { if (!weTurnedItOff) { return; } try { if ((Object)(object)ol != (Object)null && !ol.Enabled) { ol.Enabled = true; ol.UpdateLightState(); } } catch { } } public static void NewSession() { _broken = false; try { DisableAll(); } catch { } _nextRoster = 0f; _nextSelect = 0f; } public static void DisableAll() { ReleaseAll(); _entries.Clear(); _byId.Clear(); _pending.Clear(); ActiveCount = 0; CandidateCount = 0; } private static void Release(Entry e) { e.Rig = -1; e.Selected = false; Restore(e); e.PoseInit = false; e.ParamsInit = false; } private static void ReleaseAll() { for (int i = 0; i < _entries.Count; i++) { Release(_entries[i]); } if (_rigGo != null) { for (int j = 0; j < _rigGo.Length; j++) { SetRigActive(j, on: false); } } _winnerCount = 0; ActiveCount = 0; } } internal static class VanillaLightSync { private static readonly List<OptimizedLight> _opt = new List<OptimizedLight>(); private static readonly List<Light> _bare = new List<Light>(); private static bool _dark; private static float _nextRescan; public static void Apply(bool dark) { if (dark) { if (!_dark) { _dark = true; _nextRescan = 0f; } ReassertDisabled(); if (Time.time >= _nextRescan) { _nextRescan = Time.time + 0.1f; Capture(); } } else if (_dark) { Restore(); } } private static void ReassertDisabled() { for (int i = 0; i < _opt.Count; i++) { OptimizedLight val = _opt[i]; if ((Object)(object)val != (Object)null && val.Enabled) { val.Enabled = false; val.UpdateLightState(); } } for (int j = 0; j < _bare.Count; j++) { Light val2 = _bare[j]; if ((Object)(object)val2 != (Object)null && ((Behaviour)val2).enabled) { ((Behaviour)val2).enabled = false; } } } private static void Capture() { try { if (PlayerSingleton<PlayerInventory>.InstanceExists) { Equippable equippable = PlayerSingleton<PlayerInventory>.Instance.Equippable; if ((Object)(object)equippable != (Object)null && (Object)(object)((Il2CppObjectBase)equippable).TryCast<Flashlight>() != (Object)null) { DisableUnder(((Component)equippable).gameObject); } } if (PlayerSingleton<Phone>.InstanceExists) { GameObject phoneFlashlight = PlayerSingleton<Phone>.Instance.PhoneFlashlight; if ((Object)(object)phoneFlashlight != (Object)null) { DisableUnder(phoneFlashlight); } } } catch (Exception ex) { Instance log = Core.Log; if (log != null) { log.Warning("VanillaLightSync capture failed: " + ex.Message); } } } private static void DisableUnder(GameObject root) { foreach (OptimizedLight componentsInChild in root.GetComponentsInChildren<OptimizedLight>(true)) { if (!((Object)(object)componentsInChild == (Object)null) && componentsInChild.Enabled) { componentsInChild.Enabled = false; componentsInChild.UpdateLightState(); _opt.Add(componentsInChild); } } foreach (Light componentsInChild2 in root.GetComponentsInChildren<Light>(true)) { if (!((Object)(object)componentsInChild2 == (Object)null) && ((Behaviour)componentsInChild2).enabled && !((Object)(object)((Component)componentsInChild2).GetComponent<OptimizedLight>() != (Object)null)) { ((Behaviour)componentsInChild2).enabled = false; _bare.Add(componentsInChild2); } } } public static void Restore() { _dark = false; foreach (OptimizedLight item in _opt) { try { if ((Object)(object)item != (Object)null) { item.Enabled = true; item.UpdateLightState(); } } catch { } } foreach (Light item2 in _bare) { try { if ((Object)(object)item2 != (Object)null) { ((Behaviour)item2).enabled = true; } } catch { } } _opt.Clear(); _bare.Clear(); } } } namespace TightBeam.Config { internal static class TightBeamPreferences { private static MelonPreferences_Category _cat; private static MelonPreferences_Entry<bool> _enabled; private static MelonPreferences_Entry<string> _focusModifierKey; private static MelonPreferences_Entry<float> _defaultIntensity; private static MelonPreferences_Entry<float> _minIntensity; private static MelonPreferences_Entry<float> _maxIntensity; private static MelonPreferences_Entry<float> _defaultFocus; private static MelonPreferences_Entry<float> _focusSensitivity; private static MelonPreferences_Entry<float> _focusEaseTau; private static MelonPreferences_Entry<float> _focusMaxStep; private static MelonPreferences_Entry<float> _focusVelocityGamma; private static MelonPreferences_Entry<float> _focusVelocityRefRate; private static MelonPreferences_Entry<float> _focusFlickRateMultiplier; private static MelonPreferences_Entry<float> _focusVelAttackTau; private static MelonPreferences_Entry<float> _focusVelDecayTau; private static MelonPreferences_Entry<bool> _invertFocusScroll; private static MelonPreferences_Entry<float> _rangeWide; private static MelonPreferences_Entry<float> _rangeNarrow; private static MelonPreferences_Entry<float> _angleWide; private static MelonPreferences_Entry<float> _angleNarrow; private static MelonPreferences_Entry<string> _colorHex; private static MelonPreferences_Entry<bool> _castShadows; private static MelonPreferences_Entry<bool> _remoteBeams; private static MelonPreferences_Entry<int> _maxRemoteBeams; private static MelonPreferences_Entry<float> _remoteBeamMaxDistance; private static MelonPreferences_Entry<int> _remoteShadowNearest; private static MelonPreferences_Entry<float> _remoteSmoothingTau; private static MelonPreferences_Entry<bool> _suppressRemoteVanillaLights; private static MelonPreferences_Entry<bool> _remoteBeamsForUnmoddedPlayers; private static MelonPreferences_Entry<bool> _syncMyBeam; public static bool Enabled { get { return _enabled.Value; } set { _enabled.Value = value; } } public static KeyCode FocusModifierKey => ParseKey(_focusModifierKey.Value, (KeyCode)308); public static float DefaultIntensity => Mathf.Clamp(_defaultIntensity.Value, MinIntensity, MaxIntensity); public static float MinIntensity => Mathf.Max(0.05f, _minIntensity.Value); public static float MaxIntensity => Mathf.Max(MinIntensity + 0.1f, _maxIntensity.Value); public static float DefaultFocus => Mathf.Clamp01(_defaultFocus.Value); public static float FocusSensitivity => Mathf.Clamp(_focusSensitivity.Value, 0.005f, 1f); public static float FocusEaseTau => Mathf.Clamp(_focusEaseTau.Value, 0.02f, 0.15f); public static float FocusMaxStep => Mathf.Clamp(_focusMaxStep.Value, FocusSensitivity, 1f); public static float FocusVelocityGamma => Mathf.Clamp(_focusVelocityGamma.Value, 1f, 4f); public static float FocusVelocityRefRate => Mathf.Clamp(_focusVelocityRefRate.Value, 0.5f, 30f); public static float FocusFlickRateMultiplier => Mathf.Clamp(_focusFlickRateMultiplier.Value, 1.5f, 10f); public static float FocusVelAttackTau => Mathf.Clamp(_focusVelAttackTau.Value, 0.01f, 0.2f); public static float FocusVelDecayTau => Mathf.Clamp(_focusVelDecayTau.Value, 0.05f, 0.4f); public static bool InvertFocusScroll => _invertFocusScroll.Value; public static float RangeWide => Mathf.Clamp(_rangeWide.Value, 3f, 25f); public static float RangeNarrow => Mathf.Clamp(_rangeNarrow.Value, 15f, 45f); public static float AngleWide => Mathf.Clamp(_angleWide.Value, 40f, 90f); public static float AngleNarrow => Mathf.Clamp(_angleNarrow.Value, 8f, 35f); public static Color Color => ParseColor(_colorHex.Value, new Color(0.9f, 0.95f, 1f)); public static bool CastShadows => _castShadows.Value; public static bool RemoteBeams => _remoteBeams.Value; public static int MaxRemoteBeams => Mathf.Clamp(_maxRemoteBeams.Value, 0, 16); public static float RemoteBeamMaxDistance => Mathf.Clamp(_remoteBeamMaxDistance.Value, 10f, 250f); public static int RemoteShadowNearest => Mathf.Clamp(_remoteShadowNearest.Value, 0, 4); public static float RemoteSmoothingTau => Mathf.Clamp(_remoteSmoothingTau.Value, 0.02f, 0.3f); public static bool SuppressRemoteVanillaLights => _suppressRemoteVanillaLights.Value; public static bool RemoteBeamsForUnmoddedPlayers => _remoteBeamsForUnmoddedPlayers.Value; public static bool SyncMyBeam => _syncMyBeam.Value; public static void Initialize() { _cat = MelonPreferences.CreateCategory("TightBeam"); _enabled = _cat.CreateEntry<bool>("Enabled", true, (string)null, "Master switch for the whole mod.", false, false, (ValueValidator)null, (string)null); _focusModifierKey = _cat.CreateEntry<string>("FocusModifierKey", "LeftAlt", (string)null, "Hold this key and scroll the mouse wheel to adjust FOCUS (Pegel): wide near flood <-> narrow far throw.", false, false, (ValueValidator)null, (string)null); _defaultIntensity = _cat.CreateEntry<float>("DefaultIntensity", 7f, (string)null, "Base beam brightness the flashlight rests at (clamped to Min/Max). Not player-adjustable in-game; mods can drive it via the API.", false, false, (ValueValidator)null, (string)null); _minIntensity = _cat.CreateEntry<float>("MinIntensity", 1f, (string)null, "Hard floor for brightness (also clamps mod/API overrides).", false, false, (ValueValidator)null, (string)null); _maxIntensity = _cat.CreateEntry<float>("MaxIntensity", 20f, (string)null, "Hard ceiling for brightness (also clamps mod/API overrides, so nothing can blind the screen).", false, false, (ValueValidator)null, (string)null); _defaultFocus = _cat.CreateEntry<float>("DefaultFocus", 0.5f, (string)null, "Starting focus/Pegel 0..1. 1 = wide short-range flood, 0 = narrow long-range throw, 0.5 = a balanced ~mid beam.", false, false, (ValueValidator)null, (string)null); _focusSensitivity = _cat.CreateEntry<float>("FocusSensitivity", 0.08f, (string)null, "Focus change per notch at SLOW/precise scroll speed (the fine-adjustment floor step).", false, false, (ValueValidator)null, (string)null); _focusEaseTau = _cat.CreateEntry<float>("FocusEaseTau", 0.05f, (string)null, "Seconds for the displayed beam to ease toward the target focus after a scroll (settle ~4x this). 0.02 = near-instant/steppy, 0.15 = very smooth.", false, false, (ValueValidator)null, (string)null); _focusMaxStep = _cat.CreateEntry<float>("FocusMaxStep", 0.35f, (string)null, "Largest per-notch focus step from a fast (but not flick-threshold) scroll.", false, false, (ValueValidator)null, (string)null); _focusVelocityGamma = _cat.CreateEntry<float>("FocusVelocityGamma", 2f, (string)null, "Curve exponent shaping how step size ramps up with scroll speed (higher = more ease-in, slow stays fine longer).", false, false, (ValueValidator)null, (string)null); _focusVelocityRefRate = _cat.CreateEntry<float>("FocusVelocityRefRate", 5f, (string)null, "Scroll rate (units/sec) at/below which focus changes by plain FocusSensitivity per notch (slow single ticks read ~2-4).", false, false, (ValueValidator)null, (string)null); _focusFlickRateMultiplier = _cat.CreateEntry<float>("FocusFlickRateMultiplier", 2f, (string)null, "Flick threshold = FocusVelocityRefRate * this (default 5*2=10); crossing it races focus to the nearest extreme. Fast flicks read ~27+.", false, false, (ValueValidator)null, (string)null); _focusVelAttackTau = _cat.CreateEntry<float>("FocusVelAttackTau", 0.05f, (string)null, "How quickly the scroll-speed estimate reacts to a new, faster scroll.", false, false, (ValueValidator)null, (string)null); _focusVelDecayTau = _cat.CreateEntry<float>("FocusVelDecayTau", 0.15f, (string)null, "How quickly the scroll-speed estimate cools down once scrolling pauses/stops.", false, false, (ValueValidator)null, (string)null); _invertFocusScroll = _cat.CreateEntry<bool>("InvertFocusScroll", false, (string)null, "Flip which scroll direction widens the beam.", false, false, (ValueValidator)null, (string)null); _rangeWide = _cat.CreateEntry<float>("RangeWide", 8f, (string)null, "Beam range (m) at full WIDE focus - a short near flood.", false, false, (ValueValidator)null, (string)null); _rangeNarrow = _cat.CreateEntry<float>("RangeNarrow", 34f, (string)null, "Beam range (m) at full NARROW focus - a long far throw.", false, false, (ValueValidator)null, (string)null); _angleWide = _cat.CreateEntry<float>("AngleWide", 66f, (string)null, "Cone angle (deg) at full WIDE focus.", false, false, (ValueValidator)null, (string)null); _angleNarrow = _cat.CreateEntry<float>("AngleNarrow", 16f, (string)null, "Cone angle (deg) at full NARROW focus.", false, false, (ValueValidator)null, (string)null); _colorHex = _cat.CreateEntry<string>("ColorHex", "#E6F2FF", (string)null, "Beam colour (hex). Cool white by default so it reads against warm/sickly environments.", false, false, (ValueValidator)null, (string)null); _castShadows = _cat.CreateEntry<bool>("CastShadows", true, (string)null, "Cast soft shadows so the beam is blocked by walls (turn off on low-end machines).", false, false, (ValueValidator)null, (string)null); _remoteBeams = _cat.CreateEntry<bool>("RemoteBeams", true, (string)null, "In co-op, show other players' flashlights as proper TightBeam cones instead of the game's small point light.", false, false, (ValueValidator)null, (string)null); _maxRemoteBeams = _cat.CreateEntry<int>("MaxRemoteBeams", 4, (string)null, "Most other players' beams drawn at once (nearest first). 0 turns remote beams off.", false, false, (ValueValidator)null, (string)null); _remoteBeamMaxDistance = _cat.CreateEntry<float>("RemoteBeamMaxDistance", 70f, (string)null, "Metres beyond which another player's beam is not drawn.", false, false, (ValueValidator)null, (string)null); _remoteShadowNearest = _cat.CreateEntry<int>("RemoteShadowNearest", 0, (string)null, "How many of the nearest remote beams may cast shadows. 0 = none, which keeps a full lobby smooth.", false, false, (ValueValidator)null, (string)null); _remoteSmoothingTau = _cat.CreateEntry<float>("RemoteSmoothingTau", 0.08f, (string)null, "Smoothing on another player's beam aim. The game replicates their camera about 10x/sec, so without this the cone steps visibly.", false, false, (ValueValidator)null, (string)null); _suppressRemoteVanillaLights = _cat.CreateEntry<bool>("SuppressRemoteVanillaLights", true, (string)null, "Turn off another player's vanilla flashlight lights while their TightBeam cone is shown, so you never see both at once.", false, false, (ValueValidator)null, (string)null); _remoteBeamsForUnmoddedPlayers = _cat.CreateEntry<bool>("RemoteBeamsForUnmoddedPlayers", true, (string)null, "Also draw a cone for players who do not have TightBeam, using your own default settings. Turn off to leave their vanilla flashlight alone.", false, false, (ValueValidator)null, (string)null); _syncMyBeam = _cat.CreateEntry<bool>("SyncMyBeam", true, (string)null, "Share your beam's shape, colour and effects with the other players, so they see your flashlight the way you do.", false, false, (ValueValidator)null, (string)null); } private static KeyCode ParseKey(string s, KeyCode fallback) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) if (!Enum.TryParse<KeyCode>(s, ignoreCase: true, out KeyCode result)) { return fallback; } return result; } private static Color ParseColor(string input, Color fallback) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(input)) { return fallback; } Color result = default(Color); if (ColorUtility.TryParseHtmlString(input.StartsWith("#") ? input : ("#" + input), ref result)) { return result; } return fallback; } } } namespace TightBeam.Bridge { internal static class BridgeHost { private static readonly List<Action<bool>> _toggleListeners = new List<Action<bool>>(); public static void Install() { FlashlightController c = FlashlightController.Instance; FlashlightBridge.IsOn = () => c.IsOn; FlashlightBridge.GetIntensity = () => c.CurrentIntensity; FlashlightBridge.GetRange = () => c.CurrentRange; FlashlightBridge.GetSpotAngle = () => c.CurrentSpotAngle; FlashlightBridge.GetColor = delegate { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) Color currentColor = c.CurrentColor; return new float[4] { currentColor.r, currentColor.g, currentColor.b, currentColor.a }; }; FlashlightBridge.SetOn = delegate(bool on) { c.SetOn(on); }; FlashlightBridge.Toggle = delegate { c.Toggle(); }; FlashlightBridge.SetIntensity = delegate(float v) { c.SetIntensity(v); }; FlashlightBridge.SetRange = delegate(float v) { c.SetBaseRange(v); }; FlashlightBridge.SetSpotAngle = delegate(float v) { c.SetBaseSpotAngle(v); }; FlashlightBridge.SetColor = delegate(float r, float g, float b, float a) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) c.SetColor(new Color(r, g, b, a)); }; FlashlightBridge.Blink = delegate(int t, float i) { c.Blink(t, i); }; FlashlightBridge.Flicker = delegate(float s, float d, float f) { c.Flicker(s, d, f); }; FlashlightBridge.StopFlicker = delegate { c.StopFlicker(); }; FlashlightBridge.Pulse = delegate(float a, float p, float d) { c.Pulse(a, p, d); }; FlashlightBridge.StopPulse = delegate { c.StopPulse(); }; FlashlightBridge.TempIntensity = delegate(float v, float s) { c.TemporaryIntensity(v, s); }; FlashlightBridge.TempColor = delegate(float r, float g, float b, float a, float s) { c.TemporaryColor(r, g, b, a, s); }; FlashlightBridge.BeginOverride = (string owner) => c.BeginOverride(owner); FlashlightBridge.EndOverride = delegate(int tok) { c.EndOverride(tok); }; FlashlightBridge.OvIntensity = delegate(int tok, float v) { c.OverrideIntensity(tok, v); }; FlashlightBridge.OvRange = delegate(int tok, float v) { c.OverrideRange(tok, v); }; FlashlightBridge.OvSpotAngle = delegate(int tok, float v) { c.OverrideSpotAngle(tok, v); }; FlashlightBridge.OvColor = delegate(int tok, float r, float g, float b, float a) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) c.OverrideColor(tok, new Color(r, g, b, a)); }; FlashlightBridge.ClrIntensity = delegate(int tok) { c.ClearOverrideIntensity(tok); }; FlashlightBridge.ClrRange = delegate(int tok) { c.ClearOverrideRange(tok); }; FlashlightBridge.ClrSpotAngle = delegate(int tok) { c.ClearOverrideSpotAngle(tok); }; FlashlightBridge.ClrColor = delegate(int tok) { c.ClearOverrideColor(tok); }; FlashlightBridge.RegisterToggledListener = delegate(Action<bool> cb) { if (cb != null) { _toggleListeners.Add(cb); } }; c.Toggled += delegate(bool on) { for (int i = 0; i < _toggleListeners.Count; i++) { try { _toggleListeners[i](on); } catch { } } }; FlashlightBridge.IsMultiplayer = () => RemoteBeams.InMultiplayer(); FlashlightBridge.GetLocalSteamId = () => PlayerIdentity.LocalSteamId(); FlashlightBridge.GetRemoteBeamIds = () => RemoteBeams.RemoteIds(); FlashlightBridge.RemoteHasTightBeam = (ulong id) => RemoteBeams.HasSyncedBeam(id); FlashlightBridge.GetRemoteBeam = (ulong id) => RemoteBeams.BeamOf(id); FlashlightBridge.GetRemoteBeamPose = (ulong id) => RemoteBeams.PoseOf(id); FlashlightBridge.IsRemoteBeamRendered = (ulong id) => RemoteBeams.IsRendered(id); FlashlightBridge.RegisterRemoteToggledListener = delegate(Action<ulong, bool> cb) { RemoteBeams.AddToggledListener(cb); }; } } public static class FlashlightBridge { public const int AbiVersion = 2; public static Func<bool> IsOn; public static Func<float> GetIntensity; public static Func<float> GetRange; public static Func<float> GetSpotAngle; public static Func<float[]> GetColor; public static Action<bool> SetOn; public static Action Toggle; public static Action<float> SetIntensity; public static Action<float> SetRange; public static Action<float> SetSpotAngle; public static Action<float, float, float, float> SetColor; public static Action<int, float> Blink; public static Action<float, float, float> Flicker; public static Action StopFlicker; public static Action<float, float, float> Pulse; public static Action StopPulse; public static Action<float, float> TempIntensity; public static Action<float, float, float, float, float> TempColor; public static Func<string, int> BeginOverride; public static Action<int> EndOverride; public static Action<int, float> OvIntensity; public static Action<int, float> OvRange; public static Action<int, float> OvSpotAngle; public static Action<int, float, float, float, float> OvColor; public static Action<int> ClrIntensity; public static Action<int> ClrRange; public static Action<int> ClrSpotAngle; public static Action<int> ClrColor; public static Action<Action<bool>> RegisterToggledListener; public static Func<bool> IsMultiplayer; public static Func<ulong> GetLocalSteamId; public static Func<ulong[]> GetRemoteBeamIds; public static Func<ulong, bool> RemoteHasTightBeam; public static Func<ulong, float[]> GetRemoteBeam; public static Func<ulong, float[]> GetRemoteBeamPose; public static Func<ulong, bool> IsRemoteBeamRendered; public static Action<Action<ulong, bool>> RegisterRemoteToggledListener; } }