using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Linq; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ConnectorLib.JSON; using CrowdControl.Delegates.Effects; using CrowdControl.Delegates.Metadata; using Extensions; using HarmonyLib; using Microsoft.CodeAnalysis; using Mirror; using Newtonsoft.Json; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class ParamCollectionAttribute : Attribute { } [CompilerGenerated] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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 CrowdControl { internal static class CasinoBetMaxPusher { private static readonly FieldInfo? s_canBetField = typeof(GameBase).GetField("canBet", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo? sRouletteBets = typeof(Roulette).GetField("_bets", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo? sRouletteButtons = typeof(Roulette).GetField("buttons", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly MethodInfo? sRouletteRpcTotalText = typeof(Roulette).GetMethod("RpcSetTotalBetText", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly MethodInfo? sKeypadApplyInput = typeof(Keypad).GetMethod("ApplyInput", BindingFlags.Instance | BindingFlags.NonPublic); private static bool ReadCanBet(GameBase gb) { if (s_canBetField == null) { return !gb.isPlaying; } object value = s_canBetField.GetValue(gb); bool flag = default(bool); int num; if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } public static int PushAllTablesToAffordableMax() { if (!NetworkServer.active) { return 0; } MoneyManager instance = NetworkSingleton.Instance; if ((Object)(object)instance == (Object)null) { return 0; } long balance = instance.balance; int num = 0; GameBase[] array = CasinoTimedOdds.FindAllGameBasesInScene(); for (int i = 0; i < array.Length; i++) { if (TryPushSingleTableToAffordableMax(array[i], balance)) { num = checked(num + 1); } } return num; } internal static bool TryPushSingleTableToAffordableMax(GameBase gb, long? balanceOverride = null) { if (!NetworkServer.active || (Object)(object)gb == (Object)null || !Object.op_Implicit((Object)(object)gb) || (Object)(object)gb.Keypad == (Object)null) { return false; } MoneyManager instance = NetworkSingleton.Instance; if ((Object)(object)instance == (Object)null) { return false; } long num = balanceOverride ?? instance.balance; if (!ReadCanBet(gb) || gb.isPlaying) { return false; } Roulette val = (Roulette)(object)((gb is Roulette) ? gb : null); if (val != null) { return TryPushRoulette(val, num); } long maxBet = gb.MaxBet; long minBet = gb.MinBet; if (maxBet < minBet) { return false; } long num2 = Math.Min(maxBet, Math.Max(minBet, num)); if (gb.isGoldenChipApplied) { num2 = maxBet; } if (num2 == gb.currentBet) { return false; } TryApplyBetThroughKeypad(gb, num2); return true; } private static void TryApplyBetThroughKeypad(GameBase gb, long target) { if ((Object)(object)gb.Keypad != (Object)null && sKeypadApplyInput != null) { sKeypadApplyInput.Invoke(gb.Keypad, new object[2] { target.ToString(), false }); } else { gb.ServerSetBet(target); } } private static bool TryPushRoulette(Roulette r, long balance) { if (sRouletteBets == null || sRouletteRpcTotalText == null) { return false; } long maxBet = ((GameBase)r).MaxBet; long minBet = ((GameBase)r).MinBet; if (maxBet < minBet) { return false; } long num = Math.Min(maxBet, Math.Max(minBet, balance)); if (((GameBase)r).isGoldenChipApplied) { num = maxBet; } Dictionary dictionary = (Dictionary)sRouletteBets.GetValue(r); long num2 = 0L; foreach (long value2 in dictionary.Values) { num2 = checked(num2 + value2); } if (num2 == num) { return false; } dictionary.Clear(); RouletteButton[] array = sRouletteButtons?.GetValue(r) as RouletteButton[]; string key = "Red"; if (array != null && array.Length != 0 && !string.IsNullOrEmpty(((Object)array[0]).name)) { key = ((Object)array[0]).name; } dictionary[key] = num; ((GameBase)r).ServerSetBet(num); sRouletteRpcTotalText.Invoke(r, new object[1] { MoneyFormatter.FormatWithDollar(num, false) }); if (array != null) { RouletteButton[] array2 = array; foreach (RouletteButton val in array2) { if (!((Object)(object)val == (Object)null)) { long value; long num3 = (dictionary.TryGetValue(((Object)val).name, out value) ? value : 0); val.ServerSetBets(((GameBase)r).MaxBet, num3); } } } return true; } } internal static class CasinoOopsMaxBetsGate { private static int _sessions; private static bool _inServerSetBetPostfix; private static bool IsSessionActive => Volatile.Read(ref _sessions) > 0; internal static void BeginSession() { Interlocked.Increment(ref _sessions); } internal static void EndSession() { if (Interlocked.Decrement(ref _sessions) < 0) { Interlocked.Exchange(ref _sessions, 0); } } internal static bool IsActive() { return IsSessionActive; } internal static void AfterServerSetBet(GameBase gb) { if (!NetworkServer.active || !IsSessionActive || _inServerSetBetPostfix) { return; } _inServerSetBetPostfix = true; try { CasinoBetMaxPusher.TryPushSingleTableToAffordableMax(gb); } finally { _inServerSetBetPostfix = false; } } } internal static class CasinoTimedOdds { private static readonly FieldInfo s_estimatedValueField = typeof(GameBase).GetField("estimatedValue", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly Dictionary> s_estimatedSessions = new Dictionary>(); private static readonly Dictionary> s_maxBetSessions = new Dictionary>(); public static float ReadEstimatedValue(GameBase gameBase) { return (float)s_estimatedValueField.GetValue(gameBase); } private static GameBase[] FindAllGameBases() { return Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); } internal static GameBase[] FindAllGameBasesInScene() { return FindAllGameBases(); } public static void BeginEstimatedUniformSession(uint crowdControlRequestId, float uniformValue) { Dictionary dictionary = new Dictionary(); GameBase[] array = FindAllGameBases(); foreach (GameBase val in array) { if (Object.op_Implicit((Object)(object)val)) { int instanceID = ((Object)((Component)val).gameObject).GetInstanceID(); dictionary[instanceID] = ReadEstimatedValue(val); val.SetEstimatedValue(uniformValue); } } s_estimatedSessions[crowdControlRequestId] = dictionary; } public static void BeginEstimatedScaleSession(uint crowdControlRequestId, float scale, float maxValue) { Dictionary dictionary = new Dictionary(); GameBase[] array = FindAllGameBases(); foreach (GameBase val in array) { if (Object.op_Implicit((Object)(object)val)) { int instanceID = ((Object)((Component)val).gameObject).GetInstanceID(); float num2 = (dictionary[instanceID] = ReadEstimatedValue(val)); val.SetEstimatedValue(Mathf.Min(num2 * scale, maxValue)); } } s_estimatedSessions[crowdControlRequestId] = dictionary; } public static void RestoreEstimatedSession(uint crowdControlRequestId) { if (!s_estimatedSessions.TryGetValue(crowdControlRequestId, out Dictionary value)) { return; } GameBase[] array = FindAllGameBases(); foreach (GameBase val in array) { if (Object.op_Implicit((Object)(object)val) && value.TryGetValue(((Object)((Component)val).gameObject).GetInstanceID(), out var value2)) { val.SetEstimatedValue(value2); } } s_estimatedSessions.Remove(crowdControlRequestId); } public static void BeginMaxBetScaleSession(uint crowdControlRequestId, double factor, double maxMultiplier) { Dictionary dictionary = new Dictionary(); GameBase[] array = FindAllGameBases(); foreach (GameBase val in array) { if (Object.op_Implicit((Object)(object)val)) { int instanceID = ((Object)((Component)val).gameObject).GetInstanceID(); double num = (dictionary[instanceID] = val.MaxBetOverrideMultiplier); val.MaxBetOverrideMultiplier = Math.Min(num * factor, maxMultiplier); } } s_maxBetSessions[crowdControlRequestId] = dictionary; } public static void RestoreMaxBetSession(uint crowdControlRequestId) { if (!s_maxBetSessions.TryGetValue(crowdControlRequestId, out Dictionary value)) { return; } GameBase[] array = FindAllGameBases(); foreach (GameBase val in array) { if (Object.op_Implicit((Object)(object)val) && value.TryGetValue(((Object)((Component)val).gameObject).GetInstanceID(), out var value2)) { val.MaxBetOverrideMultiplier = value2; } } s_maxBetSessions.Remove(crowdControlRequestId); } internal static bool HasAnyEstimatedSession() { return s_estimatedSessions.Count > 0; } internal static bool HasAnyMaxBetSession() { return s_maxBetSessions.Count > 0; } } public sealed class CrowdControlEffectHud : MonoBehaviour { private sealed class ActiveTimed { public TimedEffectState Tracker; public string Title = ""; public string Summary = ""; } private sealed class MirrorTimed { public float EndRealtimeSinceStartup; public string Title = ""; public string Summary = ""; } private CrowdControlMod? _mod; private Texture2D? _white; private Font? _gameFont; private static bool s_loggedMissingGameFont; private int _fontResolveAttempts; private readonly Dictionary _activeTimed = new Dictionary(); private readonly Dictionary _mirrorTimed = new Dictionary(); private readonly List<(float until, string text)> _toasts = new List<(float, string)>(); private GUIStyle? _body; private GUIStyle? _bodyBold; public static CrowdControlEffectHud? Instance { get; private set; } private void Awake() { Instance = this; } private void OnDestroy() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } if ((Object)(object)_white != (Object)null) { Object.Destroy((Object)(object)_white); } } internal void Init(CrowdControlMod mod) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_0026: Unknown result type (might be due to invalid IL or missing references) _mod = mod; TryLoadGameFont(mod, logOnFailure: false); _white = new Texture2D(1, 1, (TextureFormat)4, false); _white.SetPixel(0, 0, Color.white); _white.Apply(); } private void DrawSolidToastFrame(Rect r, float scale) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_white == (Object)null)) { Color val = default(Color); ((Color)(ref val))..ctor(0.96f, 0.96f, 1f, 1f); Color val2 = default(Color); ((Color)(ref val2))..ctor(0.12f, 0.12f, 0.15f, 1f); float num = Mathf.Max(2f, 2.75f * scale); GUI.DrawTexture(r, (Texture)(object)_white, (ScaleMode)0, false, 0f, val, 0f, 0f); Rect val3 = default(Rect); ((Rect)(ref val3))..ctor(((Rect)(ref r)).x + num, ((Rect)(ref r)).y + num, ((Rect)(ref r)).width - 2f * num, ((Rect)(ref r)).height - 2f * num); if (((Rect)(ref val3)).width > 0f && ((Rect)(ref val3)).height > 0f) { GUI.DrawTexture(val3, (Texture)(object)_white, (ScaleMode)0, false, 0f, val2, 0f, 0f); } } } private void TryLoadGameFont(CrowdControlMod mod, bool logOnFailure) { _gameFont = Resources.Load("Fonts/Bungee-Regular"); if ((Object)(object)_gameFont == (Object)null) { Font[] array = Resources.FindObjectsOfTypeAll(); foreach (Font val in array) { if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(((Object)val).name) && ((Object)val).name.IndexOf("Bungee", StringComparison.OrdinalIgnoreCase) >= 0) { _gameFont = val; break; } } } if ((Object)(object)_gameFont == (Object)null && logOnFailure && !s_loggedMissingGameFont) { s_loggedMissingGameFont = true; mod.Logger.LogInfo((object)"Crowd Control HUD: no Bungee font found; using skin default (try after load if still wrong)."); } if ((Object)(object)_gameFont != (Object)null) { InvalidateStyles(); } } private void MaybeResolveFontAgain() { if (!((Object)(object)_gameFont != (Object)null) && !((Object)(object)_mod == (Object)null) && _fontResolveAttempts < 12) { checked { _fontResolveAttempts++; } if (_fontResolveAttempts % 3 == 0) { TryLoadGameFont(_mod, _fontResolveAttempts >= 12); } } } private void InvalidateStyles() { _body = (_bodyBold = null); } private void Update() { if ((Object)(object)_mod == (Object)null || !_mod.ConfigShowEffectHud.Value) { return; } float unscaledTime = Time.unscaledTime; List list; checked { for (int num = _toasts.Count - 1; num >= 0; num--) { if (_toasts[num].until <= unscaledTime) { _toasts.RemoveAt(num); } } list = null; } foreach (KeyValuePair item in _activeTimed) { TimedEffectState.EffectState state = item.Value.Tracker.State; if ((uint)(state - 3) <= 1u) { (list ?? (list = new List())).Add(item.Key); } } if (list != null) { foreach (uint item2 in list) { _activeTimed.Remove(item2); } } float realtimeSinceStartup = Time.realtimeSinceStartup; List list2 = null; foreach (KeyValuePair item3 in _mirrorTimed) { if (realtimeSinceStartup >= item3.Value.EndRealtimeSinceStartup) { (list2 ?? (list2 = new List())).Add(item3.Key); } } if (list2 == null) { return; } foreach (uint item4 in list2) { _mirrorTimed.Remove(item4); } } internal static void NotifyInstant(string? code, EffectResponse response) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Instance?._mod == (Object)null) && Instance._mod.ConfigShowEffectHud.Value && (int)response.status == 0) { CrowdControlEffectPresentation.TryGet(code, out string title, out string _); float item = Time.unscaledTime + Instance._mod.ConfigEffectToastSeconds.Value; Instance._toasts.Add((item, title)); while (Instance._toasts.Count > 8) { Instance._toasts.RemoveAt(0); } } } internal static void NotifyTimedStarted(TimedEffectState state, EffectResponse response) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Instance?._mod == (Object)null) && Instance._mod.ConfigShowEffectHud.Value && (int)response.status == 0 && state.State == TimedEffectState.EffectState.Running) { CrowdControlEffectPresentation.TryGet(state.Request.code, out string title, out string summary); uint id = ((SimpleJSONRequest)state.Request).id; Instance._activeTimed[id] = new ActiveTimed { Tracker = state, Title = title, Summary = summary }; float num = Mathf.Min(2.25f, Instance._mod.ConfigEffectToastSeconds.Value); Instance._toasts.Add((Time.unscaledTime + num, title)); while (Instance._toasts.Count > 8) { Instance._toasts.RemoveAt(0); } } } internal static void NotifyTimedEnded(uint requestId) { if (!((Object)(object)Instance == (Object)null)) { Instance._activeTimed.Remove(requestId); Instance._mirrorTimed.Remove(requestId); } } internal static void NotifyMirrorTimedEnded(uint requestId) { if (!((Object)(object)Instance == (Object)null)) { Instance._mirrorTimed.Remove(requestId); } } internal static void NotifyNetworkTimed(string code, uint requestId, float durationSeconds) { if (!((Object)(object)Instance?._mod == (Object)null) && Instance._mod.ConfigShowEffectHud.Value) { CrowdControlEffectPresentation.TryGet(code, out string title, out string summary); float endRealtimeSinceStartup = Time.realtimeSinceStartup + Mathf.Max(0.05f, durationSeconds); Instance._mirrorTimed[requestId] = new MirrorTimed { EndRealtimeSinceStartup = endRealtimeSinceStartup, Title = title, Summary = summary }; float num = Mathf.Min(2.25f, Instance._mod.ConfigEffectToastSeconds.Value); Instance._toasts.Add((Time.unscaledTime + num, title)); while (Instance._toasts.Count > 8) { Instance._toasts.RemoveAt(0); } } } private void OnGUI() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Invalid comparison between Unknown and I4 //IL_04bc: Unknown result type (might be due to invalid IL or missing references) //IL_04d8: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_031e: Unknown result type (might be due to invalid IL or missing references) //IL_0516: Unknown result type (might be due to invalid IL or missing references) //IL_054e: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_mod == (Object)null || !_mod.ConfigShowEffectHud.Value || (Object)(object)_white == (Object)null || (int)Event.current.type != 7) { return; } MaybeResolveFontAgain(); int depth = GUI.depth; GUI.depth = -2000; float num = Mathf.Clamp((float)Screen.height / 1080f * _mod.ConfigEffectHudScale.Value, 0.55f, 2.2f); float num2 = (float)Screen.height / 1080f; Mathf.RoundToInt(8f * num); float gap = Mathf.Max(4f, 5f * num); float num3 = Mathf.Max(0f, _mod.ConfigTimedHudTopOffsetPx.Value * num2); if (_activeTimed.Count > 0 || _mirrorTimed.Count > 0) { float num4 = _mod.ConfigTimedHudTicketStripLeftPx.Value * num2; num4 = Mathf.Max(num4, 4f * num + 36f * num); float num5 = Mathf.Max(20f, 24f * num); GUIStyle st = StyleBodyBold(num, timed: true); TextInfo textInfo = CultureInfo.InvariantCulture.TextInfo; float num6 = TimedRowHeight(num5, gap); float num7 = num3; float num8 = (float)Screen.width - num4 - Mathf.Max(2f, 4f * num); foreach (ActiveTimed value in _activeTimed.Values) { string text = ((value.Tracker.State == TimedEffectState.EffectState.Paused) ? " (PAUSED)" : ""); double num9 = Math.Max(0.0, value.Tracker.TimeRemaining.TotalSeconds); string arg = textInfo.ToUpper(value.Title); string text2 = (string.IsNullOrEmpty(text) ? $"{arg} - {num9:F0}S" : $"{arg} - {num9:F0}S{text}"); DrawLabelSoftShadow(new Rect(num4, num7, num8, num5 * 1.1f), text2, st, num, rich: true); num7 += num6; } foreach (KeyValuePair item in _mirrorTimed) { if (!_activeTimed.ContainsKey(item.Key)) { float num10 = Mathf.Max(0f, item.Value.EndRealtimeSinceStartup - Time.realtimeSinceStartup); double num11 = ((!(num10 <= 0f)) ? Mathf.CeilToInt(num10) : 0); string arg2 = textInfo.ToUpper(item.Value.Title); string text3 = $"{arg2} - {num11:F0}S"; DrawLabelSoftShadow(new Rect(num4, num7, num8, num5 * 1.1f), text3, st, num, rich: true); num7 += num6; } } GUI.color = Color.white; } if (_toasts.Count == 0) { GUI.depth = depth; return; } GUIStyle val = StyleBody(num); val.fontSize = Mathf.RoundToInt(16.5f * num); float num12 = Mathf.RoundToInt(10f * num); float num13 = Mathf.RoundToInt(7f * num); float shadowD = ToastShadowOffset(num); float num14 = 0f; checked { for (int i = 0; i < _toasts.Count; i++) { num14 = Mathf.Max(num14, MeasureToastContentWidth(val, _toasts[i].text, shadowD, num)); } float num15 = Mathf.Min(num14 + num12 * 2f, (float)Screen.width * 0.52f); num15 = Mathf.Max(num15, num12 * 2f + 4f * num); float num16 = Mathf.Max(1f, num15 - num12 * 2f); float[] array = new float[_toasts.Count]; float num17 = 0f; for (int j = 0; j < _toasts.Count; j++) { array[j] = MeasureToastRowHeight(val, _toasts[j].text, num16, shadowD, num); num17 += array[j]; } float num18 = num13 * 2f + num17; float num19 = _mod.ConfigToastBottomMarginPx.Value * num2; float num20 = (float)Screen.width - num15; float num21 = (float)Screen.height - num18 - num19; Rect r = default(Rect); ((Rect)(ref r))..ctor(num20, num21, num15, num18); DrawSolidToastFrame(r, num); GUI.color = new Color(0.95f, 0.96f, 0.98f, 1f); float num22 = ((Rect)(ref r)).y + num13; for (int num23 = _toasts.Count - 1; num23 >= 0; num23--) { float num24 = array[num23]; DrawLabelSoftShadow(new Rect(((Rect)(ref r)).x + num12, num22, num16, num24), _toasts[num23].text, val, num, val.richText); num22 += num24; } GUI.color = Color.white; GUI.depth = depth; } } private static float TimedRowHeight(float line, float gap) { return line * 1.06f + gap; } private static float ToastShadowOffset(float scale) { return Mathf.Max(1f, scale * 0.45f); } private static float MeasureToastContentWidth(GUIStyle st, string text, float shadowD, float scale) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_0009: Unknown result type (might be due to invalid IL or missing references) GUIContent val = new GUIContent(text); float num = Mathf.Ceil(st.CalcSize(val).x); float num2 = default(float); float num3 = default(float); st.CalcMinMaxWidth(val, ref num2, ref num3); num = Mathf.Max(new float[3] { num, Mathf.Ceil(num2), Mathf.Ceil(num3) }); num += shadowD * 2f + Mathf.Max(6f * scale, 4f); return num + Mathf.Ceil((float)st.fontSize * 0.22f); } private static float MeasureToastRowHeight(GUIStyle st, string text, float textW, float shadowD, float scale) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown return Mathf.Max(Mathf.Ceil(st.CalcHeight(new GUIContent(text), textW)), Mathf.Ceil((float)st.fontSize * 1.34f)) + Mathf.Ceil(shadowD + 2f); } private static void DrawLabelSoftShadow(Rect r, string text, GUIStyle st, float scale, bool rich) { //IL_000f: 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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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) st.richText = rich; float num = ToastShadowOffset(scale); Color color = GUI.color; GUI.color = new Color(0f, 0f, 0f, 0.42f); GUI.Label(new Rect(((Rect)(ref r)).x + num, ((Rect)(ref r)).y + num, ((Rect)(ref r)).width, ((Rect)(ref r)).height), text, st); GUI.Label(new Rect(((Rect)(ref r)).x - num, ((Rect)(ref r)).y + num, ((Rect)(ref r)).width, ((Rect)(ref r)).height), text, st); GUI.color = color; GUI.Label(r, text, st); } private GUIStyle StyleBody(float scale) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown if (_body == null) { _body = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)0, wordWrap = true, richText = true }; if ((Object)(object)_gameFont != (Object)null) { _body.font = _gameFont; } } _body.fontSize = Mathf.RoundToInt(12.5f * scale); return _body; } private GUIStyle StyleBodyBold(float scale, bool timed) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_0026: 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) //IL_0039: Expected O, but got Unknown if (_bodyBold == null) { _bodyBold = new GUIStyle(GUI.skin.label) { fontStyle = (FontStyle)0, alignment = (TextAnchor)0, wordWrap = true, richText = true }; if ((Object)(object)_gameFont != (Object)null) { _bodyBold.font = _gameFont; } } _bodyBold.fontSize = Mathf.RoundToInt((timed ? 17f : 12f) * scale); return _bodyBold; } } internal static class CrowdControlEffectPresentation { private static readonly Dictionary s_map = new Dictionary { ["add_cash_50"] = ("+$50", "Shared cash."), ["add_cash_100"] = ("+$100", "Shared cash."), ["add_cash_500"] = ("+$500", "Shared cash."), ["add_cash_1000"] = ("+$1000", "Shared cash."), ["remove_cash_50"] = ("−$50", "Shared cash if affordable."), ["remove_cash_100"] = ("−$100", "Shared cash if affordable."), ["remove_cash_500"] = ("−$500", "Shared cash if affordable."), ["remove_cash_1000"] = ("−$1000", "Shared cash if affordable."), ["add_tickets_1"] = ("+1 ticket", "Shared tickets."), ["add_tickets_2"] = ("+2 tickets", "Shared tickets."), ["add_tickets_5"] = ("+5 tickets", "Shared tickets."), ["remove_tickets_1"] = ("−1 ticket", "Shared tickets if possible."), ["remove_tickets_2"] = ("−2 tickets", "Shared tickets if possible."), ["remove_tickets_5"] = ("−5 tickets", "Shared tickets if possible."), ["grant_auxiliary_money"] = ("Auxiliary payout", "Quota-day auxiliary cash (host applies)."), ["add_day_time"] = ("+Day time", "Shared day timer."), ["remove_day_time"] = ("−Day time", "Shared day timer."), ["casino_house_crush"] = ("Cold tables", "Payouts crash toward zero on every table (whole group)."), ["casino_hot_table"] = ("Hot tables", "Better table payouts (whole group)."), ["casino_maxbet_surge"] = ("Double Cap on Bets", "Doubles max-bet limits on every table (whole group)."), ["casino_oops_max_bets"] = ("Opps, all max bets!", "Snaps open tables to max wager (whole group)."), ["luck_tipsy_surge"] = ("Tipsy fortune ↑", "Better win slice for you."), ["luck_tipsy_hangover"] = ("Tipsy fortune ↓", "Worse win slice for you."), ["buff_drink_tipsy"] = ("Drunk", "Drink-style buff on streamer: fortune up, more profit while drunk (includes short wobble voice effect)."), ["buff_immunity"] = ("Immunity aura", "Holy Statue–style: block losses for you and nearby players."), ["buff_inspiring_melody"] = ("Inspiring melody", "Mic-style buff: profit boost for nearby players while active."), ["upgrade_insurance_boost"] = ("Insurance ↑", "Softer losses on payouts."), ["upgrade_bonus_draw_boost"] = ("Bonus Draw ↑", "Extra ticket chance on wins."), ["upgrade_stakeholder_boost"] = ("Stakeholder ↑", "Stronger drink / tipsy scaling."), ["upgrade_gamblers_confidence_nerf"] = ("Confidence ↓", "Small GC tick down."), ["upgrade_gamblers_confidence_boost"] = ("Confidence ↑", "Small GC tick up."), ["upgrade_reset_run"] = ("Reset upgrades", "Your run upgrades to default."), ["reset_balances"] = ("Reset balances", "Money & tickets to defaults."), ["player_movement_fast"] = ("Fast movement", "Higher move speed."), ["player_movement_slow"] = ("Slow movement", "Lower move speed."), ["player_movement_very_slow"] = ("Very slow", "Much lower move speed."), ["spawn_bat"] = ("Spawn bat", "Bat pickup in front of you."), ["spawn_drink"] = ("Spawn drink", "Drink bottle: tipsy fortune + drunk profit."), ["spawn_immunity_cross"] = ("Spawn Holy Statue", "Immunity cross / statue pickup."), ["spawn_microphone"] = ("Spawn mic", "Microphone: Inspiring Melody for allies."), ["spawn_coordinator"] = ("Spawn coordinator", "Coordinator camera pickup."), ["spawn_golden_chip"] = ("Spawn golden chip", "Golden chip pickup."), ["spawn_devils_reel"] = ("Spawn Devil's Reel", "Pickup."), ["spawn_angels_reel"] = ("Spawn Angel's Reel", "Pickup."), ["spawn_time_machine"] = ("Spawn time machine", "Pickup."), ["spawn_taser"] = ("Spawn taser", "Pickup."), ["spawn_quota_gun"] = ("Spawn quota gun", "Pickup."), ["spawn_mystery_box"] = ("Spawn mystery box", "Pickup."), ["spawn_upgrade_stakeholder"] = ("Spawn Stakeholder upgrade", "Upgrade pickup."), ["spawn_upgrade_insurance"] = ("Spawn Insurance upgrade", "Upgrade pickup."), ["spawn_upgrade_bonus_draw"] = ("Spawn Bonus Draw upgrade", "Upgrade pickup."), ["spawn_upgrade_gamblers_confidence"] = ("Spawn Gambler's Confidence", "Upgrade pickup near you."), ["spawn_holy_statue"] = ("Spawn Holy Statue", "Same immunity-cross pickup as spawn_immunity_cross in this build (catalog id 10)."), ["spawn_voice_wand"] = ("Spawn voice wand", "Toy that cycles voice effects while held."), ["spawn_gacha_sphere"] = ("Spawn gacha sphere", "Cosmetic capsule (catalog “Cosmetic Item”, id 1)."), ["spawn_basketball"] = ("Spawn basketball", "Ball pickup if prefab is registered (e.g. hoop minigame assets loaded)."), ["spawn_sledding_frog"] = ("Spawn sledding frog", "Plush from Mirror spawn list or loaded prefab prototypes."), ["spawn_bongo"] = ("Spawn bongos", "From spawn prefabs / prototypes when available."), ["spawn_dice"] = ("Spawn dice", "From spawn prefabs / prototypes when available."), ["spawn_chess_piece"] = ("Spawn chess piece", "From spawn prefabs / prototypes when available."), ["spawn_bingbong"] = ("Spawn Bing Bong", "Plush whose name hints match bing/bong in spawn data."), ["spawn_debt_bag"] = ("Spawn debt bag", "From DebtBagMachine prefab or spawn list when that scene exists."), ["cosmetic_random_piece"] = ("Random cosmetic", "Random piece on you."), ["cosmetic_reset_outfit"] = ("Reset outfit", "Default outfit."), ["cosmetic_clear_hats"] = ("Clear hats", "Hat slot cleared."), ["voice_low"] = ("Low voice effect", "Low pitch on your outgoing voice."), ["voice_wobble"] = ("Wobble voice effect", "Wobble filter on your outgoing voice."), ["voice_radio"] = ("Radio voice effect", "Radio-style filter on your outgoing voice."), ["voice_no_mouth_on"] = ("No-mouth on", "Voice appearance filter on."), ["voice_no_mouth_off"] = ("No-mouth off", "Voice appearance filter off."), ["voice_reset"] = ("Reset voice effects", "Clear voice filters.") }; internal static bool TryGet(string? code, out string title, out string summary) { title = ""; summary = ""; if (string.IsNullOrEmpty(code)) { return false; } if (s_map.TryGetValue(code, out (string, string) value)) { (title, summary) = value; return true; } title = Humanize(code); summary = ""; return true; } private static string Humanize(string code) { return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(code.Replace('_', ' ')); } } internal static class CrowdControlGlobalHudMirror { internal static void Announce(string? code, uint requestId, float durationSeconds) { if (!string.IsNullOrEmpty(code) && CrowdControlGlobalHudMirrorCodes.CodesSet.Contains(code)) { if (NetworkServer.active) { NetworkConnection excludeConnection = (NetworkConnection)(object)((NetworkClient.active && NetworkServer.localConnection != null) ? NetworkServer.localConnection : null); CrowdControlGlobalTimedHud.ServerBroadcastByCode(requestId, code, durationSeconds, excludeConnection); } else { CrowdControlGlobalHudMirrorNetwork.ClientSendAnnounce(requestId, code, durationSeconds); } } } internal static void AnnounceEnd(uint requestId) { if (NetworkServer.active) { NetworkConnection excludeConnection = (NetworkConnection)(object)((NetworkClient.active && NetworkServer.localConnection != null) ? NetworkServer.localConnection : null); CrowdControlGlobalTimedHud.ServerBroadcastRemove(requestId, excludeConnection); } else { CrowdControlGlobalHudMirrorNetwork.ClientSendRemove(requestId); } } } internal static class CrowdControlGlobalHudMirrorCodes { internal static readonly HashSet CodesSet = new HashSet(StringComparer.Ordinal) { "buff_immunity", "buff_inspiring_melody", "buff_drink_tipsy", "luck_tipsy_surge", "luck_tipsy_hangover", "player_movement_fast", "player_movement_slow", "player_movement_very_slow", "voice_low", "voice_wobble", "voice_radio" }; } internal struct CrowdControlGlobalTimedHudCodeMsg : NetworkMessage { public uint RequestId; public string Code; public float DurationSeconds; } internal struct CrowdControlGlobalHudMirrorAnnounceFromClient : NetworkMessage { public uint RequestId; public string Code; public float DurationSeconds; } internal struct CrowdControlGlobalTimedHudRemoveMsg : NetworkMessage { public uint RequestId; } internal struct CrowdControlGlobalHudMirrorRemoveFromClient : NetworkMessage { public uint RequestId; } internal static class CrowdControlGlobalHudMirrorNetwork { private static bool _serverHandlerInstalled; internal static void InstallSerialization() { Writer.write = delegate(NetworkWriter w, CrowdControlGlobalTimedHudCodeMsg v) { NetworkWriterExtensions.WriteUInt(w, v.RequestId); NetworkWriterExtensions.WriteString(w, v.Code ?? string.Empty); NetworkWriterExtensions.WriteFloat(w, v.DurationSeconds); }; Reader.read = delegate(NetworkReader r) { CrowdControlGlobalTimedHudCodeMsg result4 = default(CrowdControlGlobalTimedHudCodeMsg); result4.RequestId = NetworkReaderExtensions.ReadUInt(r); result4.Code = NetworkReaderExtensions.ReadString(r); result4.DurationSeconds = NetworkReaderExtensions.ReadFloat(r); return result4; }; Writer.write = delegate(NetworkWriter w, CrowdControlGlobalHudMirrorAnnounceFromClient v) { NetworkWriterExtensions.WriteUInt(w, v.RequestId); NetworkWriterExtensions.WriteString(w, v.Code ?? string.Empty); NetworkWriterExtensions.WriteFloat(w, v.DurationSeconds); }; Reader.read = delegate(NetworkReader r) { CrowdControlGlobalHudMirrorAnnounceFromClient result3 = default(CrowdControlGlobalHudMirrorAnnounceFromClient); result3.RequestId = NetworkReaderExtensions.ReadUInt(r); result3.Code = NetworkReaderExtensions.ReadString(r); result3.DurationSeconds = NetworkReaderExtensions.ReadFloat(r); return result3; }; Writer.write = delegate(NetworkWriter w, CrowdControlGlobalTimedHudRemoveMsg v) { NetworkWriterExtensions.WriteUInt(w, v.RequestId); }; Reader.read = delegate(NetworkReader r) { CrowdControlGlobalTimedHudRemoveMsg result2 = default(CrowdControlGlobalTimedHudRemoveMsg); result2.RequestId = NetworkReaderExtensions.ReadUInt(r); return result2; }; Writer.write = delegate(NetworkWriter w, CrowdControlGlobalHudMirrorRemoveFromClient v) { NetworkWriterExtensions.WriteUInt(w, v.RequestId); }; Reader.read = delegate(NetworkReader r) { CrowdControlGlobalHudMirrorRemoveFromClient result = default(CrowdControlGlobalHudMirrorRemoveFromClient); result.RequestId = NetworkReaderExtensions.ReadUInt(r); return result; }; } internal static void RegisterServerHandlerIfNeeded() { InstallSerialization(); if (!_serverHandlerInstalled && NetworkServer.active) { NetworkServer.ReplaceHandler((Action)OnServerAnnounceFromClient, true); NetworkServer.ReplaceHandler((Action)OnServerRemoveFromClient, true); _serverHandlerInstalled = true; CrowdControlMod.Instance.Logger.LogInfo((object)"Crowd Control: registered global HUD mirror announce (client → host)."); } } internal static void UnregisterServerHandlerIfNeeded() { if (_serverHandlerInstalled) { NetworkServer.UnregisterHandler(); NetworkServer.UnregisterHandler(); _serverHandlerInstalled = false; } } private static void OnServerAnnounceFromClient(NetworkConnectionToClient conn, CrowdControlGlobalHudMirrorAnnounceFromClient msg) { if (conn != null && !string.IsNullOrEmpty(msg.Code) && CrowdControlGlobalHudMirrorCodes.CodesSet.Contains(msg.Code)) { CrowdControlGlobalTimedHud.ServerBroadcastByCode(msg.RequestId, msg.Code, msg.DurationSeconds, (NetworkConnection?)(object)conn); } } private static void OnServerRemoveFromClient(NetworkConnectionToClient conn, CrowdControlGlobalHudMirrorRemoveFromClient msg) { if (conn != null) { CrowdControlGlobalTimedHud.ServerBroadcastRemove(msg.RequestId, (NetworkConnection?)(object)conn); } } internal static bool ClientSendAnnounce(uint requestId, string code, float durationSeconds) { InstallSerialization(); if (!NetworkClient.isConnected) { return false; } if (NetworkClient.connection == null) { return false; } if (string.IsNullOrEmpty(code) || !CrowdControlGlobalHudMirrorCodes.CodesSet.Contains(code)) { return false; } CrowdControlGlobalHudMirrorAnnounceFromClient crowdControlGlobalHudMirrorAnnounceFromClient = default(CrowdControlGlobalHudMirrorAnnounceFromClient); crowdControlGlobalHudMirrorAnnounceFromClient.RequestId = requestId; crowdControlGlobalHudMirrorAnnounceFromClient.Code = code; crowdControlGlobalHudMirrorAnnounceFromClient.DurationSeconds = durationSeconds; NetworkClient.Send(crowdControlGlobalHudMirrorAnnounceFromClient, 0); return true; } internal static bool ClientSendRemove(uint requestId) { InstallSerialization(); if (!NetworkClient.isConnected) { return false; } if (NetworkClient.connection == null) { return false; } CrowdControlGlobalHudMirrorRemoveFromClient crowdControlGlobalHudMirrorRemoveFromClient = default(CrowdControlGlobalHudMirrorRemoveFromClient); crowdControlGlobalHudMirrorRemoveFromClient.RequestId = requestId; NetworkClient.Send(crowdControlGlobalHudMirrorRemoveFromClient, 0); return true; } } internal static class CrowdControlGlobalTimedHud { private static bool _clientHandlersInstalled; internal static void InstallClientHandlerIfNeeded() { if (!_clientHandlersInstalled) { CrowdControlGlobalHudMirrorNetwork.InstallSerialization(); NetworkClient.ReplaceHandler((Action)OnGlobalTimedHud, true); NetworkClient.ReplaceHandler((Action)OnGlobalTimedHudByCode, true); NetworkClient.ReplaceHandler((Action)OnGlobalTimedHudRemove, true); _clientHandlersInstalled = true; } } internal static void UninstallClientHandlerIfNeeded() { if (_clientHandlersInstalled) { NetworkClient.UnregisterHandler(); NetworkClient.UnregisterHandler(); NetworkClient.UnregisterHandler(); _clientHandlersInstalled = false; } } private static void OnGlobalTimedHud(CrowdControlGlobalTimedHudMsg msg) { string text = CrowdControlHostCcServerExecutor.CodeString((CrowdControlHostCcEffectCode)msg.EffectCode); if (!string.IsNullOrEmpty(text)) { CrowdControlEffectHud.NotifyNetworkTimed(text, msg.RequestId, msg.DurationSeconds); } } private static void OnGlobalTimedHudByCode(CrowdControlGlobalTimedHudCodeMsg msg) { if (!string.IsNullOrEmpty(msg.Code)) { CrowdControlEffectHud.NotifyNetworkTimed(msg.Code, msg.RequestId, msg.DurationSeconds); } } private static void OnGlobalTimedHudRemove(CrowdControlGlobalTimedHudRemoveMsg msg) { CrowdControlEffectHud.NotifyMirrorTimedEnded(msg.RequestId); } internal static void ServerBroadcast(uint requestId, CrowdControlHostCcEffectCode effectCode, float durationSeconds, NetworkConnection? excludeConnection) { if (!NetworkServer.active) { return; } CrowdControlGlobalTimedHudMsg crowdControlGlobalTimedHudMsg = default(CrowdControlGlobalTimedHudMsg); crowdControlGlobalTimedHudMsg.RequestId = requestId; crowdControlGlobalTimedHudMsg.EffectCode = (ushort)effectCode; crowdControlGlobalTimedHudMsg.DurationSeconds = durationSeconds; CrowdControlGlobalTimedHudMsg crowdControlGlobalTimedHudMsg2 = crowdControlGlobalTimedHudMsg; foreach (NetworkConnectionToClient value in NetworkServer.connections.Values) { NetworkConnectionToClient val = ((value is NetworkConnectionToClient) ? value : null); if (val != null && (excludeConnection == null || val != excludeConnection)) { ((NetworkConnection)val).Send(crowdControlGlobalTimedHudMsg2, 0); } } } internal static void ServerBroadcastByCode(uint requestId, string code, float durationSeconds, NetworkConnection? excludeConnection) { if (!NetworkServer.active) { return; } CrowdControlGlobalTimedHudCodeMsg crowdControlGlobalTimedHudCodeMsg = default(CrowdControlGlobalTimedHudCodeMsg); crowdControlGlobalTimedHudCodeMsg.RequestId = requestId; crowdControlGlobalTimedHudCodeMsg.Code = code; crowdControlGlobalTimedHudCodeMsg.DurationSeconds = durationSeconds; CrowdControlGlobalTimedHudCodeMsg crowdControlGlobalTimedHudCodeMsg2 = crowdControlGlobalTimedHudCodeMsg; foreach (NetworkConnectionToClient value in NetworkServer.connections.Values) { NetworkConnectionToClient val = ((value is NetworkConnectionToClient) ? value : null); if (val != null && (excludeConnection == null || val != excludeConnection)) { ((NetworkConnection)val).Send(crowdControlGlobalTimedHudCodeMsg2, 0); } } } internal static void ServerBroadcastRemove(uint requestId, NetworkConnection? excludeConnection) { if (!NetworkServer.active) { return; } CrowdControlGlobalTimedHudRemoveMsg crowdControlGlobalTimedHudRemoveMsg = default(CrowdControlGlobalTimedHudRemoveMsg); crowdControlGlobalTimedHudRemoveMsg.RequestId = requestId; CrowdControlGlobalTimedHudRemoveMsg crowdControlGlobalTimedHudRemoveMsg2 = crowdControlGlobalTimedHudRemoveMsg; foreach (NetworkConnectionToClient value in NetworkServer.connections.Values) { NetworkConnectionToClient val = ((value is NetworkConnectionToClient) ? value : null); if (val != null && (excludeConnection == null || val != excludeConnection)) { ((NetworkConnection)val).Send(crowdControlGlobalTimedHudRemoveMsg2, 0); } } } } internal enum CrowdControlHostCcEffectCode : ushort { None, AddDayTime, RemoveDayTime, GrantAuxiliaryMoney, CasinoHouseCrush, CasinoHotTable, CasinoMaxBetSurge, CasinoOopsMaxBets } internal enum CrowdControlHostCcKind : byte { Instant = 1, TimedStart, TimedStop } internal struct CrowdControlHostCcFromClient : NetworkMessage { public byte Kind; public ushort EffectCode; public uint RequestId; public float DurationSeconds; } internal struct CrowdControlHostCcToClient : NetworkMessage { public uint RequestId; public byte Status; public string Message; } internal struct CrowdControlGlobalTimedHudMsg : NetworkMessage { public uint RequestId; public ushort EffectCode; public float DurationSeconds; } internal static class CrowdControlHostCcRelay { internal const byte StatusOk = 0; internal const byte StatusFail = 1; internal const byte StatusConflict = 2; private static bool _serverHandlerInstalled; private static readonly Dictionary _pendingResults = new Dictionary(); private static bool RelayLogEnabled { get { if ((Object)(object)CrowdControlMod.Instance != (Object)null) { return CrowdControlMod.Instance.ConfigLogClientHostCcRelay.Value; } return false; } } private static void LogRelay(string line) { if (RelayLogEnabled) { CrowdControlMod.Instance.Logger.LogMessage((object)("[Crowd Control][HostCcRelay] " + line)); } } private static string FormatKind(byte kind) { return (CrowdControlHostCcKind)kind switch { CrowdControlHostCcKind.Instant => "Instant", CrowdControlHostCcKind.TimedStart => "TimedStart", CrowdControlHostCcKind.TimedStop => "TimedStop", _ => $"Unknown({kind})", }; } private static string FormatEffect(ushort effectCode) { CrowdControlHostCcEffectCode crowdControlHostCcEffectCode = (CrowdControlHostCcEffectCode)effectCode; string text = CrowdControlHostCcServerExecutor.CodeString(crowdControlHostCcEffectCode); if (!string.IsNullOrEmpty(text)) { return $"{crowdControlHostCcEffectCode} ({text})"; } return $"effectCode={effectCode}"; } private static int ConnectionLogId(NetworkConnection conn) { return ((NetworkConnectionToClient)(((conn is NetworkConnectionToClient) ? conn : null)?)).connectionId ?? (-1); } internal static bool TryConsumeResponse(uint requestId, out EffectResponse response) { if (!_pendingResults.TryGetValue(requestId, out (byte, string) value)) { response = null; return false; } _pendingResults.Remove(requestId); response = (EffectResponse)(value.Item1 switch { 0 => EffectResponse.Success(requestId, (string)null), 2 => EffectResponse.Failure(requestId, (StandardErrors)32768), _ => string.IsNullOrEmpty(value.Item2) ? EffectResponse.Failure(requestId, (StandardErrors)16384) : EffectResponse.Failure(requestId, value.Item2), }); return true; } internal static void ClearPending(uint requestId) { _pendingResults.Remove(requestId); } internal static void InstallSerialization() { Writer.write = delegate(NetworkWriter w, CrowdControlHostCcFromClient v) { w.WriteByte(v.Kind); NetworkWriterExtensions.WriteUInt(w, (uint)v.EffectCode); NetworkWriterExtensions.WriteUInt(w, v.RequestId); NetworkWriterExtensions.WriteFloat(w, v.DurationSeconds); }; Reader.read = delegate(NetworkReader r) { CrowdControlHostCcFromClient result3 = default(CrowdControlHostCcFromClient); result3.Kind = r.ReadByte(); result3.EffectCode = checked((ushort)NetworkReaderExtensions.ReadUInt(r)); result3.RequestId = NetworkReaderExtensions.ReadUInt(r); result3.DurationSeconds = NetworkReaderExtensions.ReadFloat(r); return result3; }; Writer.write = delegate(NetworkWriter w, CrowdControlHostCcToClient v) { NetworkWriterExtensions.WriteUInt(w, v.RequestId); w.WriteByte(v.Status); NetworkWriterExtensions.WriteString(w, v.Message ?? string.Empty); }; Reader.read = delegate(NetworkReader r) { CrowdControlHostCcToClient result2 = default(CrowdControlHostCcToClient); result2.RequestId = NetworkReaderExtensions.ReadUInt(r); result2.Status = r.ReadByte(); result2.Message = NetworkReaderExtensions.ReadString(r); return result2; }; Writer.write = delegate(NetworkWriter w, CrowdControlGlobalTimedHudMsg v) { NetworkWriterExtensions.WriteUInt(w, v.RequestId); NetworkWriterExtensions.WriteUInt(w, (uint)v.EffectCode); NetworkWriterExtensions.WriteFloat(w, v.DurationSeconds); }; Reader.read = delegate(NetworkReader r) { CrowdControlGlobalTimedHudMsg result = default(CrowdControlGlobalTimedHudMsg); result.RequestId = NetworkReaderExtensions.ReadUInt(r); result.EffectCode = checked((ushort)NetworkReaderExtensions.ReadUInt(r)); result.DurationSeconds = NetworkReaderExtensions.ReadFloat(r); return result; }; CrowdControlGlobalHudMirrorNetwork.InstallSerialization(); } internal static void RegisterServerHandlerIfNeeded() { InstallSerialization(); if (!_serverHandlerInstalled && NetworkServer.active) { NetworkServer.ReplaceHandler((Action)OnServerHostCcFromClient, true); _serverHandlerInstalled = true; CrowdControlMod.Instance.Logger.LogInfo((object)"Crowd Control: registered host CC relay (client → host)."); } } internal static void UnregisterServerHandlerIfNeeded() { if (_serverHandlerInstalled) { NetworkServer.UnregisterHandler(); _serverHandlerInstalled = false; } } private static void OnServerHostCcFromClient(NetworkConnectionToClient conn, CrowdControlHostCcFromClient msg) { //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Invalid comparison between Unknown and I4 //IL_014e: Unknown result type (might be due to invalid IL or missing references) if (conn == null) { return; } LogRelay($"Host received: connId={ConnectionLogId((NetworkConnection)(object)conn)} kind={FormatKind(msg.Kind)} {FormatEffect(msg.EffectCode)} requestId={msg.RequestId} durationSeconds={msg.DurationSeconds:F2}"); byte kind = msg.Kind; bool flag = (uint)(kind - 1) <= 1u; if (flag && GameStateManager.RequiresActiveCasinoPlay(CrowdControlHostCcServerExecutor.CodeString((CrowdControlHostCcEffectCode)msg.EffectCode))) { GameStateManager gameStateManager = CrowdControlMod.Instance?.GameStateManager; if (gameStateManager != null && !gameStateManager.IsStrictCasinoGamblingReady()) { ((NetworkConnection)conn).Send(new CrowdControlHostCcToClient { RequestId = msg.RequestId, Status = 1, Message = "This effect is not available in the current game state (need an active casino day / timer)." }, 0); return; } } CrowdControlHostCcToClient crowdControlHostCcToClient = default(CrowdControlHostCcToClient); crowdControlHostCcToClient.RequestId = msg.RequestId; crowdControlHostCcToClient.Status = 1; crowdControlHostCcToClient.Message = string.Empty; CrowdControlHostCcToClient crowdControlHostCcToClient2 = crowdControlHostCcToClient; switch ((CrowdControlHostCcKind)msg.Kind) { case CrowdControlHostCcKind.Instant: { EffectResponse val = CrowdControlHostCcServerExecutor.TryInstant((CrowdControlHostCcEffectCode)msg.EffectCode, msg.RequestId); crowdControlHostCcToClient2.Status = (((int)val.status > 0) ? ((byte)1) : ((byte)0)); crowdControlHostCcToClient2.Message = (((int)val.status == 0) ? string.Empty : (val.message ?? string.Empty)); break; } case CrowdControlHostCcKind.TimedStart: { CrowdControlHostCcEffectCode effectCode = (CrowdControlHostCcEffectCode)msg.EffectCode; if (!CrowdControlHostCcServerExecutor.TryTimedStart(effectCode, msg.RequestId, msg.DurationSeconds, out var conflict)) { crowdControlHostCcToClient2.Status = (byte)((!conflict) ? 1 : 2); break; } crowdControlHostCcToClient2.Status = 0; CrowdControlGlobalTimedHud.ServerBroadcast(msg.RequestId, effectCode, msg.DurationSeconds, (NetworkConnection?)(object)conn); break; } case CrowdControlHostCcKind.TimedStop: CrowdControlHostCcServerExecutor.TimedStop(msg.RequestId); crowdControlHostCcToClient2.Status = 0; break; } ((NetworkConnection)conn).Send(crowdControlHostCcToClient2, 0); } internal static bool ClientSendInstant(CrowdControlHostCcEffectCode code, uint requestId) { InstallSerialization(); if (!NetworkClient.isConnected) { return false; } NetworkConnection connection = (NetworkConnection)(object)NetworkClient.connection; if (connection == null) { return false; } CrowdControlHostCcFromClient crowdControlHostCcFromClient = default(CrowdControlHostCcFromClient); crowdControlHostCcFromClient.Kind = 1; crowdControlHostCcFromClient.EffectCode = (ushort)code; crowdControlHostCcFromClient.RequestId = requestId; crowdControlHostCcFromClient.DurationSeconds = 0f; CrowdControlHostCcFromClient crowdControlHostCcFromClient2 = crowdControlHostCcFromClient; LogRelay($"Client sending: connId={ConnectionLogId(connection)} kind=Instant {FormatEffect(crowdControlHostCcFromClient2.EffectCode)} requestId={requestId}"); NetworkClient.Send(crowdControlHostCcFromClient2, 0); return true; } internal static bool ClientSendTimedStart(CrowdControlHostCcEffectCode code, uint requestId, float durationSeconds) { InstallSerialization(); if (!NetworkClient.isConnected) { return false; } NetworkConnection connection = (NetworkConnection)(object)NetworkClient.connection; if (connection == null) { return false; } CrowdControlHostCcFromClient crowdControlHostCcFromClient = default(CrowdControlHostCcFromClient); crowdControlHostCcFromClient.Kind = 2; crowdControlHostCcFromClient.EffectCode = (ushort)code; crowdControlHostCcFromClient.RequestId = requestId; crowdControlHostCcFromClient.DurationSeconds = durationSeconds; CrowdControlHostCcFromClient crowdControlHostCcFromClient2 = crowdControlHostCcFromClient; LogRelay($"Client sending: connId={ConnectionLogId(connection)} kind=TimedStart {FormatEffect(crowdControlHostCcFromClient2.EffectCode)} requestId={requestId} durationSeconds={durationSeconds:F2}"); NetworkClient.Send(crowdControlHostCcFromClient2, 0); return true; } internal static void ClientSendTimedStop(uint requestId) { InstallSerialization(); if (NetworkClient.isConnected) { NetworkConnection connection = (NetworkConnection)(object)NetworkClient.connection; if (connection != null) { CrowdControlHostCcFromClient crowdControlHostCcFromClient = default(CrowdControlHostCcFromClient); crowdControlHostCcFromClient.Kind = 3; crowdControlHostCcFromClient.EffectCode = 0; crowdControlHostCcFromClient.RequestId = requestId; crowdControlHostCcFromClient.DurationSeconds = 0f; CrowdControlHostCcFromClient crowdControlHostCcFromClient2 = crowdControlHostCcFromClient; LogRelay($"Client sending: connId={ConnectionLogId(connection)} kind=TimedStop requestId={requestId}"); NetworkClient.Send(crowdControlHostCcFromClient2, 0); } } } private static void OnClientHostCcToClient(CrowdControlHostCcToClient msg) { _pendingResults[msg.RequestId] = (msg.Status, msg.Message ?? string.Empty); } internal static void RegisterClientResponseHandlerIfNeeded() { InstallSerialization(); NetworkClient.ReplaceHandler((Action)OnClientHostCcToClient, true); } internal static void UnregisterClientResponseHandlerIfNeeded() { NetworkClient.UnregisterHandler(); } internal static bool NeedsRelayHost(string code) { return CrowdControlHostOnlyEffectCodes.CodesSet.Contains(code); } internal static bool TryMapCode(string code, out CrowdControlHostCcEffectCode effectCode) { switch (code) { case "add_day_time": effectCode = CrowdControlHostCcEffectCode.AddDayTime; return true; case "remove_day_time": effectCode = CrowdControlHostCcEffectCode.RemoveDayTime; return true; case "grant_auxiliary_money": effectCode = CrowdControlHostCcEffectCode.GrantAuxiliaryMoney; return true; case "casino_house_crush": effectCode = CrowdControlHostCcEffectCode.CasinoHouseCrush; return true; case "casino_hot_table": effectCode = CrowdControlHostCcEffectCode.CasinoHotTable; return true; case "casino_maxbet_surge": effectCode = CrowdControlHostCcEffectCode.CasinoMaxBetSurge; return true; case "casino_oops_max_bets": effectCode = CrowdControlHostCcEffectCode.CasinoOopsMaxBets; return true; default: effectCode = CrowdControlHostCcEffectCode.None; return false; } } } internal static class CrowdControlHostCcServerExecutor { internal static EffectResponse TryInstant(CrowdControlHostCcEffectCode code, uint requestId) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_0019: Expected O, but got Unknown EffectRequest request = new EffectRequest { id = requestId, code = CodeString(code) }; return (EffectResponse)(code switch { CrowdControlHostCcEffectCode.AddDayTime => AddDayTimeCore(request), CrowdControlHostCcEffectCode.RemoveDayTime => RemoveDayTimeCore(request), CrowdControlHostCcEffectCode.GrantAuxiliaryMoney => GrantAuxiliaryMoneyCore(request), _ => EffectResponse.Failure(requestId, (StandardErrors)4097), }); } internal static string? CodeString(CrowdControlHostCcEffectCode code) { return code switch { CrowdControlHostCcEffectCode.AddDayTime => "add_day_time", CrowdControlHostCcEffectCode.RemoveDayTime => "remove_day_time", CrowdControlHostCcEffectCode.GrantAuxiliaryMoney => "grant_auxiliary_money", CrowdControlHostCcEffectCode.CasinoHouseCrush => "casino_house_crush", CrowdControlHostCcEffectCode.CasinoHotTable => "casino_hot_table", CrowdControlHostCcEffectCode.CasinoMaxBetSurge => "casino_maxbet_surge", CrowdControlHostCcEffectCode.CasinoOopsMaxBets => "casino_oops_max_bets", _ => null, }; } internal static EffectResponse AddDayTimeCore(EffectRequest request) { GameManager instance = NetworkSingleton.Instance; if ((Object)(object)instance == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } GameSettings val = Resources.Load("GameSettings"); if ((Object)(object)val == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } if (!GwyfDayTimerRules.CanAddRemainingSeconds(val, instance, 30f)) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, GwyfDayTimerRules.DescribeCannotAddTime(val, instance, 30f)); } instance.ServerAdjustTimer(-30f); GameStateManager.LogCrowdControl($"ServerAdjustTimer({-30f}) — ~30s more day time (host)."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } internal static EffectResponse RemoveDayTimeCore(EffectRequest request) { GameManager instance = NetworkSingleton.Instance; if ((Object)(object)instance == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } GameSettings val = Resources.Load("GameSettings"); if ((Object)(object)val == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } if (!GwyfDayTimerRules.CanRemoveRemainingSeconds(val, instance, 30f)) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, GwyfDayTimerRules.DescribeCannotRemoveTime(val, instance, 30f)); } instance.ServerAdjustTimer(30f); GameStateManager.LogCrowdControl($"ServerAdjustTimer(+{30f}) — day ends sooner (host)."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } internal static EffectResponse GrantAuxiliaryMoneyCore(EffectRequest request) { GameManager instance = NetworkSingleton.Instance; if ((Object)(object)instance == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } instance.ServerGetAuxiliaryMoney(); GameStateManager.LogCrowdControl("ServerGetAuxiliaryMoney (host)."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } internal static bool TryTimedStart(CrowdControlHostCcEffectCode code, uint requestId, float durationSeconds, out bool conflict) { conflict = false; if (CrowdControlHostTimedRelaySessions.HasConflict(code)) { conflict = true; return false; } switch (code) { case CrowdControlHostCcEffectCode.CasinoHouseCrush: CrowdControlHostTimedRelaySessions.RegisterHouseCrush(requestId, durationSeconds); return true; case CrowdControlHostCcEffectCode.CasinoHotTable: CrowdControlHostTimedRelaySessions.RegisterHotTable(requestId, durationSeconds); return true; case CrowdControlHostCcEffectCode.CasinoMaxBetSurge: CrowdControlHostTimedRelaySessions.RegisterMaxBetSurge(requestId, durationSeconds); return true; case CrowdControlHostCcEffectCode.CasinoOopsMaxBets: CrowdControlHostTimedRelaySessions.RegisterOopsMaxBets(requestId, durationSeconds); return true; default: return false; } } internal static void TimedStop(uint requestId) { CrowdControlHostTimedRelaySessions.Stop(requestId); } } internal static class CrowdControlHostOnlyEffectCodes { internal static readonly string[] Codes = new string[7] { "add_day_time", "remove_day_time", "grant_auxiliary_money", "casino_house_crush", "casino_hot_table", "casino_maxbet_surge", "casino_oops_max_bets" }; internal static readonly HashSet CodesSet = new HashSet(Codes, StringComparer.Ordinal); } internal static class CrowdControlHostTimedRelaySessions { private sealed class Session { public CrowdControlHostCcEffectCode Code; public uint RequestId; public float TimeLeft; public float OopsAccum; } private static readonly Dictionary Sessions = new Dictionary(); internal static bool HasConflict(CrowdControlHostCcEffectCode code) { foreach (Session value in Sessions.Values) { if (Conflicts(value.Code, code)) { return true; } } bool flag = code - 4 <= CrowdControlHostCcEffectCode.AddDayTime; if (flag && CasinoTimedOdds.HasAnyEstimatedSession()) { return true; } if (code - 6 <= CrowdControlHostCcEffectCode.AddDayTime) { if (CasinoTimedOdds.HasAnyMaxBetSession()) { return true; } if (CasinoOopsMaxBetsGate.IsActive()) { return true; } } return false; } private static bool Conflicts(CrowdControlHostCcEffectCode a, CrowdControlHostCcEffectCode b) { if (a == b) { return true; } if (a - 4 <= CrowdControlHostCcEffectCode.AddDayTime) { if (b - 4 <= CrowdControlHostCcEffectCode.AddDayTime) { return true; } return false; } if (a - 6 <= CrowdControlHostCcEffectCode.AddDayTime) { if (b - 6 <= CrowdControlHostCcEffectCode.AddDayTime) { return true; } return false; } return false; } internal static void RegisterHouseCrush(uint requestId, float duration) { CasinoTimedOdds.BeginEstimatedUniformSession(requestId, 0.04f); GameStateManager.LogCrowdControl($"Casino: house crush (~{0.04f} est) {duration:F0}s (host relay)."); AddSession(requestId, CrowdControlHostCcEffectCode.CasinoHouseCrush, duration); } internal static void RegisterHotTable(uint requestId, float duration) { CasinoTimedOdds.BeginEstimatedScaleSession(requestId, 2.15f, 3.25f); GameStateManager.LogCrowdControl($"Casino: hot table x{2.15f} (cap {3.25f}) {duration:F0}s (host relay)."); AddSession(requestId, CrowdControlHostCcEffectCode.CasinoHotTable, duration); } internal static void RegisterMaxBetSurge(uint requestId, float duration) { CasinoTimedOdds.BeginMaxBetScaleSession(requestId, 2.0, 4.0); GameStateManager.LogCrowdControl($"Casino: max-bet surge x{2.0} (cap {4.0}) {duration:F0}s (host relay)."); AddSession(requestId, CrowdControlHostCcEffectCode.CasinoMaxBetSurge, duration); } internal static void RegisterOopsMaxBets(uint requestId, float duration) { CasinoOopsMaxBetsGate.BeginSession(); int num = CasinoBetMaxPusher.PushAllTablesToAffordableMax(); GameStateManager.LogCrowdControl($"Casino: oops max bets — pushed {num} table(s) on start (host relay)."); Sessions[requestId] = new Session { Code = CrowdControlHostCcEffectCode.CasinoOopsMaxBets, RequestId = requestId, TimeLeft = duration, OopsAccum = 0.4f }; } private static void AddSession(uint requestId, CrowdControlHostCcEffectCode code, float duration) { Sessions[requestId] = new Session { Code = code, RequestId = requestId, TimeLeft = duration, OopsAccum = 0f }; } internal static void Stop(uint requestId) { if (Sessions.TryGetValue(requestId, out Session value)) { EndSession(value); Sessions.Remove(requestId); } } private static void EndSession(Session s) { switch (s.Code) { case CrowdControlHostCcEffectCode.CasinoHouseCrush: CasinoTimedOdds.RestoreEstimatedSession(s.RequestId); GameStateManager.LogCrowdControl("Casino: house crush ended (host relay)."); break; case CrowdControlHostCcEffectCode.CasinoHotTable: CasinoTimedOdds.RestoreEstimatedSession(s.RequestId); GameStateManager.LogCrowdControl("Casino: hot table ended (host relay)."); break; case CrowdControlHostCcEffectCode.CasinoMaxBetSurge: CasinoTimedOdds.RestoreMaxBetSession(s.RequestId); GameStateManager.LogCrowdControl("Casino: max-bet surge ended (host relay)."); break; case CrowdControlHostCcEffectCode.CasinoOopsMaxBets: CasinoOopsMaxBetsGate.EndSession(); GameStateManager.LogCrowdControl("Casino: oops max bets window ended (host relay)."); break; } } internal static void Tick(float dt) { if (!NetworkServer.active || Sessions.Count == 0) { return; } List list = null; foreach (KeyValuePair session in Sessions) { Session value = session.Value; value.TimeLeft -= dt; if (value.Code == CrowdControlHostCcEffectCode.CasinoOopsMaxBets) { value.OopsAccum += dt; if (value.OopsAccum >= 0.4f) { value.OopsAccum = 0f; CasinoBetMaxPusher.PushAllTablesToAffordableMax(); } } if (value.TimeLeft <= 0f) { (list ?? (list = new List())).Add(session.Key); } } if (list == null) { return; } foreach (uint item in list) { if (Sessions.TryGetValue(item, out Session value2)) { EndSession(value2); Sessions.Remove(item); } } } } public enum CrowdControlSpawnItemKind : byte { Bat = 1, Basketball = 2, Drink = 3, Microphone = 4, ImmunityCross = 5, CoordinatorCamera = 10, GoldenChip = 11, DevilsReel = 12, AngelsReel = 13, TimeMachine = 14, Taser = 15, QuotaGun = 16, MysteryBox = 17, UpgradeStakeholder = 20, UpgradeInsurance = 21, UpgradeBonusDraw = 22, UpgradeGamblersConfidence = 23, HolyStatue = 30, SleddingFrog = 31, VoiceWand = 32, GachaSphere = 33, Bongo = 34, Dice = 35, ChessPiece = 36, BingBong = 37, DebtBag = 38 } public struct CrowdControlItemGiveRequest : NetworkMessage { public CrowdControlSpawnItemKind Kind; } internal static class CrowdControlItemNetwork { private static bool _serverHandlerInstalled; internal static void InstallSerialization() { Writer.write = delegate(NetworkWriter w, CrowdControlItemGiveRequest v) { w.WriteByte((byte)v.Kind); }; Reader.read = delegate(NetworkReader r) { CrowdControlItemGiveRequest result = default(CrowdControlItemGiveRequest); result.Kind = (CrowdControlSpawnItemKind)r.ReadByte(); return result; }; } internal static void RegisterServerHandlerIfNeeded() { InstallSerialization(); if (!_serverHandlerInstalled && NetworkServer.active) { NetworkServer.ReplaceHandler((Action)OnServerItemGiveRequest, true); _serverHandlerInstalled = true; CrowdControlMod.Instance.Logger.LogInfo((object)"Crowd Control: registered server item-give handler (non-host clients can request items)."); } } internal static void UnregisterServerHandlerIfNeeded() { if (_serverHandlerInstalled) { NetworkServer.UnregisterHandler(); _serverHandlerInstalled = false; } } private static void OnServerItemGiveRequest(NetworkConnectionToClient conn, CrowdControlItemGiveRequest msg) { if ((Object)(object)((conn != null) ? ((NetworkConnection)conn).identity : null) == (Object)null) { return; } PlayerInventory component = ((Component)((NetworkConnection)conn).identity).GetComponent(); if ((Object)(object)component == (Object)null) { return; } if (!GwyfItemSpawnHelper.TrySpawnCrowdControlKindNearServer(component, msg.Kind, out Item _, out string errorMessage)) { if (!string.IsNullOrEmpty(errorMessage)) { CrowdControlMod.Instance.Logger.LogWarning((object)$"Crowd Control: item request failed ({msg.Kind}): {errorMessage}"); } } else { GameStateManager.LogCrowdControl($"Item (network): spawned kind {msg.Kind} near conn {conn.connectionId}."); } } internal static bool ClientSendItemRequest(CrowdControlSpawnItemKind kind) { InstallSerialization(); if (!NetworkClient.isConnected) { return false; } if (NetworkClient.connection == null) { return false; } CrowdControlItemGiveRequest crowdControlItemGiveRequest = default(CrowdControlItemGiveRequest); crowdControlItemGiveRequest.Kind = kind; NetworkClient.Send(crowdControlItemGiveRequest, 0); return true; } } internal static class CrowdControlMirrorWriterBootstrap { internal static void ApplyAllCustomMessageWriters() { CrowdControlHostCcRelay.InstallSerialization(); CrowdControlItemNetwork.InstallSerialization(); CrowdControlStreamerEffectNetwork.InstallSerialization(); CrowdControlGlobalHudMirrorNetwork.InstallSerialization(); } } [BepInPlugin("WarpWorld.CrowdControl.GambleWithYourFriends", "Crowd Control — Gamble With Your Friends", "1.0.0.0")] public class CrowdControlMod : BaseUnityPlugin { public const string MOD_GUID = "WarpWorld.CrowdControl.GambleWithYourFriends"; public const string MOD_NAME = "Crowd Control — Gamble With Your Friends"; public const string MOD_VERSION = "1.0.0.0"; private readonly Harmony harmony = new Harmony("WarpWorld.CrowdControl.GambleWithYourFriends"); private const float GAME_STATUS_UPDATE_INTERVAL = 1f; private float m_gameStatusUpdateTimer; private volatile bool m_pendingCrowdControlGameStateResync; public static float DeltaTime => Time.fixedDeltaTime / Time.timeScale; public ManualLogSource Logger => ((BaseUnityPlugin)this).Logger; internal static CrowdControlMod Instance { get; private set; } public GameStateManager GameStateManager { get; private set; } public EffectLoader EffectLoader { get; private set; } public bool ClientConnected => Client.Connected; public NetworkClient Client { get; private set; } public Scheduler Scheduler { get; private set; } internal ConfigEntry ConfigShowEffectHud { get; private set; } internal ConfigEntry ConfigEffectHudScale { get; private set; } internal ConfigEntry ConfigEffectToastSeconds { get; private set; } internal ConfigEntry ConfigEffectHudRightInset { get; private set; } internal ConfigEntry ConfigTimedHudTicketStripLeftPx { get; private set; } internal ConfigEntry ConfigToastBottomMarginPx { get; private set; } internal ConfigEntry ConfigTimedHudTopOffsetPx { get; private set; } internal ConfigEntry ConfigLogSpawnableCatalogHintsOnce { get; private set; } internal ConfigEntry ConfigLogClientHostCcRelay { get; private set; } internal void QueueCrowdControlGameStateResync() { m_pendingCrowdControlGameStateResync = true; } private void Awake() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Expected O, but got Unknown //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Expected O, but got Unknown //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Expected O, but got Unknown //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Expected O, but got Unknown //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Expected O, but got Unknown //IL_0259: Unknown result type (might be due to invalid IL or missing references) Instance = this; ConfigShowEffectHud = ((BaseUnityPlugin)this).Config.Bind("Effect UI", "ShowHud", true, "Show Crowd Control on-screen feedback (active timed effects + short toasts for instant effects)."); ConfigEffectHudScale = ((BaseUnityPlugin)this).Config.Bind("Effect UI", "HudScale", 1f, new ConfigDescription("Relative size of the overlay.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 2f), Array.Empty())); ConfigEffectToastSeconds = ((BaseUnityPlugin)this).Config.Bind("Effect UI", "ToastSeconds", 3.5f, new ConfigDescription("How long instant-effect toasts stay visible.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 12f), Array.Empty())); ConfigEffectHudRightInset = ((BaseUnityPlugin)this).Config.Bind("Effect UI", "RightEdgeInset", 320f, new ConfigDescription("Unused (legacy). Timed HUD is top-left; safe to ignore.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 600f), Array.Empty())); ConfigTimedHudTicketStripLeftPx = ((BaseUnityPlugin)this).Config.Bind("Effect UI", "TicketStripLeftPx", 100f, new ConfigDescription("Left edge of timed-effect text (1080p height ref). Lower = further left; raise if it overlaps the ticket UI.", (AcceptableValueBase)(object)new AcceptableValueRange(72f, 520f), Array.Empty())); ConfigToastBottomMarginPx = ((BaseUnityPlugin)this).Config.Bind("Effect UI", "ToastBottomMarginPx", 0f, new ConfigDescription("Lift toasts up from the bottom edge (1080p ref). 0 = flush bottom-right; increase only if they cover ping/emote UI.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 200f), Array.Empty())); ConfigTimedHudTopOffsetPx = ((BaseUnityPlugin)this).Config.Bind("Effect UI", "TimedHudTopOffsetPx", 0f, new ConfigDescription("Distance from the top of the screen for timed-effect text (1080p ref). Lower = higher on screen.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 120f), Array.Empty())); ConfigLogSpawnableCatalogHintsOnce = ((BaseUnityPlugin)this).Config.Bind("Debug", "LogSpawnableCatalogHintsOnce", false, "On startup, log once any SpawnableSettings row whose spawnableName contains: debt, chess, frog, bing, gacha, voice, sled, dice, bongo. Use BepInEx LogOutput to align name hints; set false to silence after tuning."); ConfigLogClientHostCcRelay = ((BaseUnityPlugin)this).Config.Bind("Debug", "LogClientHostCcRelay", false, "When true, logs each Crowd Control client→host relay message (instant/timed start/stop) on the sending client and when the host receives it (connection id, effect, request id). Enable only while troubleshooting; can be noisy."); Logger.LogInfo((object)"Loaded WarpWorld.CrowdControl.GambleWithYourFriends. Patching."); harmony.PatchAll(); CrowdControlMirrorWriterBootstrap.ApplyAllCustomMessageWriters(); Logger.LogInfo((object)"Initializing Crowd Control"); try { GameStateManager = new GameStateManager(this); Client = new NetworkClient(this); EffectLoader = new EffectLoader(this, Client); Scheduler = new Scheduler(this, Client); GameObject val = new GameObject("CrowdControlEffectHud"); Object.DontDestroyOnLoad((Object)val); ((Object)val).hideFlags = (HideFlags)61; val.AddComponent().Init(this); } catch (Exception arg) { Logger.LogError((object)$"Crowd Control Init Error: {arg}"); } GwyfItemSpawnHelper.LogCatalogHintMatchesOnceIfEnabled(Logger, ConfigLogSpawnableCatalogHintsOnce.Value); Logger.LogInfo((object)"Crowd Control Initialized"); } private void OnApplicationQuit() { try { Client?.Dispose(); } catch { } } private void OnDestroy() { try { Client?.Dispose(); } catch { } } private void OnApplicationFocus(bool hasFocus) { if (GameStateManager != null) { GameStateManager.UpdateGameState(force: true); } } private void FixedUpdate() { if (m_pendingCrowdControlGameStateResync) { m_pendingCrowdControlGameStateResync = false; GameStateManager.UpdateGameState(force: true); } m_gameStatusUpdateTimer += Time.fixedDeltaTime; if (m_gameStatusUpdateTimer >= 1f) { GameStateManager.UpdateGameState(); m_gameStatusUpdateTimer = 0f; } Scheduler?.Tick(); if (NetworkServer.active) { CrowdControlHostTimedRelaySessions.Tick(Time.fixedDeltaTime); } } } internal static class CrowdControlNetworkBootstrap { [RuntimeInitializeOnLoadMethod(/*Could not decode attribute arguments.*/)] private static void RegisterMirrorSerialization() { CrowdControlMirrorWriterBootstrap.ApplyAllCustomMessageWriters(); } } internal static class CrowdControlStreamerEffectExecutor { internal static bool TryExecute(NetworkIdentity id, CrowdControlStreamerEffectOp op, out string? error) { error = null; if ((Object)(object)id == (Object)null) { error = "Null identity."; return false; } if (!NetworkServer.active) { error = "Not server."; return false; } PlayerBuff component = ((Component)id).GetComponent(); PlayerProfile component2 = ((Component)id).GetComponent(); switch (op) { case CrowdControlStreamerEffectOp.LuckTipsySurge30s: if ((Object)(object)component == (Object)null || !((NetworkBehaviour)component).isServer) { error = "No server PlayerBuff."; return false; } component.ApplyBuff((PlayerBuffType)0, 0.65f, 30f); return true; case CrowdControlStreamerEffectOp.LuckTipsyHangover30s: if ((Object)(object)component == (Object)null || !((NetworkBehaviour)component).isServer) { error = "No server PlayerBuff."; return false; } component.ApplyBuff((PlayerBuffType)0, -0.45f, 30f); return true; case CrowdControlStreamerEffectOp.BuffDrinkTipsy15s: { if ((Object)(object)component == (Object)null || !((NetworkBehaviour)component).isServer) { error = "No server PlayerBuff."; return false; } component.ApplyBuff((PlayerBuffType)0, 0.38f, 15f); PlayerVoiceFX val = ((Component)id).GetComponent() ?? ((Component)id).GetComponentInChildren(true); if ((Object)(object)val != (Object)null) { val.CmdStartTimedVoiceFX((VoipFX)1, 15f, true); } return true; } case CrowdControlStreamerEffectOp.BuffImmunity15s: if ((Object)(object)component == (Object)null || !((NetworkBehaviour)component).isServer) { error = "No server PlayerBuff."; return false; } component.ApplyBuff((PlayerBuffType)2, 1f, 15f); return true; case CrowdControlStreamerEffectOp.BuffInspiringMelody15s: if ((Object)(object)component == (Object)null || !((NetworkBehaviour)component).isServer) { error = "No server PlayerBuff."; return false; } component.ApplyBuff((PlayerBuffType)1, 0.4f, 15f); return true; case CrowdControlStreamerEffectOp.UpgradeInsurance: case CrowdControlStreamerEffectOp.UpgradeBonusDraw: case CrowdControlStreamerEffectOp.UpgradeStakeholder: case CrowdControlStreamerEffectOp.UpgradeNerfGamblersConfidence: case CrowdControlStreamerEffectOp.UpgradeBuffGamblersConfidence: return TryUpgradeOp(op, component2, out error); case CrowdControlStreamerEffectOp.UpgradeResetRun: return TryResetUpgradesForProfile(component2, out error); default: error = $"Unknown op {(byte)op}."; return false; } } private static bool TryUpgradeOp(CrowdControlStreamerEffectOp op, PlayerProfile? profile, out string? error) { error = null; if ((Object)(object)profile == (Object)null || profile.steamId == 0L) { error = "No PlayerProfile / steam id."; return false; } UpgradeManager instance = NetworkSingleton.Instance; if ((Object)(object)instance == (Object)null) { error = "No UpgradeManager."; return false; } ulong steamId = profile.steamId; switch (op) { case CrowdControlStreamerEffectOp.UpgradeInsurance: instance.ChangeUpgradeData(steamId, (PlayerUpgradeType)1, 0.1f); return true; case CrowdControlStreamerEffectOp.UpgradeBonusDraw: instance.ChangeUpgradeData(steamId, (PlayerUpgradeType)3, 0.06f); return true; case CrowdControlStreamerEffectOp.UpgradeStakeholder: instance.ChangeUpgradeData(steamId, (PlayerUpgradeType)2, 0.18f); return true; case CrowdControlStreamerEffectOp.UpgradeNerfGamblersConfidence: if (instance.GetUpgradeData(steamId, (PlayerUpgradeType)0) - 0.1f < 0.35f) { error = "Gamblers Confidence already near floor."; return false; } instance.ChangeUpgradeData(steamId, (PlayerUpgradeType)0, -0.1f); return true; case CrowdControlStreamerEffectOp.UpgradeBuffGamblersConfidence: instance.ChangeUpgradeData(steamId, (PlayerUpgradeType)0, 0.12f); return true; default: error = "Not an upgrade op."; return false; } } private static bool TryResetUpgradesForProfile(PlayerProfile? profile, out string? error) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) error = null; if ((Object)(object)profile == (Object)null || profile.steamId == 0L) { error = "No PlayerProfile / steam id."; return false; } UpgradeManager instance = NetworkSingleton.Instance; if ((Object)(object)instance == (Object)null) { error = "No UpgradeManager."; return false; } ulong steamId = profile.steamId; PlayerUpgradeData val = new PlayerUpgradeData(); if (RunUpgradesMatchDefaults(instance, steamId, val)) { error = "Run upgrades are already at default values."; GameStateManager.LogCrowdControl($"Upgrades: skip reset for steamId {steamId} — already at run defaults (single streamer)."); return false; } foreach (KeyValuePair upgrade in val.Upgrades) { instance.SetUpgradeData(steamId, upgrade.Key, upgrade.Value); } foreach (PlayerUpgradeType key in val.Upgrades.Keys) { instance.ChangeUpgradeData(steamId, key, 0f); } GameStateManager.LogCrowdControl($"Upgrades: reset to defaults for steamId {steamId} (single streamer)."); return true; } private static bool RunUpgradesMatchDefaults(UpgradeManager um, ulong steamId, PlayerUpgradeData defaults) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) foreach (KeyValuePair upgrade in defaults.Upgrades) { if (Mathf.Abs(um.GetUpgradeData(steamId, upgrade.Key) - upgrade.Value) > 0.0005f) { return false; } } return true; } } internal static class CrowdControlStreamerEffectNetwork { private static bool _serverHandlerInstalled; internal static void InstallSerialization() { Writer.write = delegate(NetworkWriter w, CrowdControlStreamerEffectRequest v) { w.WriteByte((byte)v.Op); }; Reader.read = delegate(NetworkReader r) { CrowdControlStreamerEffectRequest result = default(CrowdControlStreamerEffectRequest); result.Op = (CrowdControlStreamerEffectOp)r.ReadByte(); return result; }; } internal static void RegisterServerHandlerIfNeeded() { InstallSerialization(); if (!_serverHandlerInstalled && NetworkServer.active) { NetworkServer.ReplaceHandler((Action)OnServerStreamerEffectRequest, true); _serverHandlerInstalled = true; CrowdControlMod.Instance.Logger.LogInfo((object)"Crowd Control: registered client-effect handler (client → host, single connection)."); } } internal static void UnregisterServerHandlerIfNeeded() { if (_serverHandlerInstalled) { NetworkServer.UnregisterHandler(); _serverHandlerInstalled = false; } } private static void OnServerStreamerEffectRequest(NetworkConnectionToClient conn, CrowdControlStreamerEffectRequest msg) { if ((Object)(object)((conn != null) ? ((NetworkConnection)conn).identity : null) == (Object)null) { return; } if (!CrowdControlStreamerEffectExecutor.TryExecute(((NetworkConnection)conn).identity, msg.Op, out string error)) { if (!string.IsNullOrEmpty(error)) { CrowdControlMod.Instance.Logger.LogWarning((object)$"Crowd Control: client effect {msg.Op} failed: {error}"); } } else { GameStateManager.LogCrowdControl($"Client effect {msg.Op} applied for conn {conn.connectionId}."); } } internal static bool TryRunForLocalStreamer(CrowdControlStreamerEffectOp op, out string? error) { error = null; if (!NetworkClient.isConnected || (Object)(object)NetworkClient.localPlayer == (Object)null) { error = "Not connected or no local player."; return false; } NetworkIdentity component = ((Component)NetworkClient.localPlayer).GetComponent(); if ((Object)(object)component == (Object)null) { error = "Local player has no NetworkIdentity."; return false; } if (NetworkServer.active) { if (!CrowdControlStreamerEffectExecutor.TryExecute(component, op, out error)) { return false; } return true; } InstallSerialization(); if (NetworkClient.connection == null) { error = "No client connection."; return false; } CrowdControlStreamerEffectRequest crowdControlStreamerEffectRequest = default(CrowdControlStreamerEffectRequest); crowdControlStreamerEffectRequest.Op = op; NetworkClient.Send(crowdControlStreamerEffectRequest, 0); return true; } internal static bool ClientSend(CrowdControlStreamerEffectOp op) { string error; return TryRunForLocalStreamer(op, out error); } } public enum CrowdControlStreamerEffectOp : byte { LuckTipsySurge30s = 1, LuckTipsyHangover30s = 2, BuffDrinkTipsy15s = 3, BuffImmunity15s = 4, BuffInspiringMelody15s = 5, UpgradeInsurance = 10, UpgradeBonusDraw = 11, UpgradeStakeholder = 12, UpgradeNerfGamblersConfidence = 13, UpgradeBuffGamblersConfidence = 14, UpgradeResetRun = 15 } public struct CrowdControlStreamerEffectRequest : NetworkMessage { public CrowdControlStreamerEffectOp Op; } internal static class CrowdControlTimedCasinoHud { internal static void AfterHostLocalTimedStart(string code, uint requestId, float durationSeconds) { if (NetworkServer.active && CrowdControlHostCcRelay.TryMapCode(code, out var effectCode)) { NetworkConnection localConnection = (NetworkConnection)(object)NetworkServer.localConnection; CrowdControlGlobalTimedHud.ServerBroadcast(requestId, effectCode, durationSeconds, localConnection); } } } public class DelimitedStreamReader : IDisposable { [CompilerGenerated] private NetworkStream P; private readonly MemoryStream _memory_stream; public DelimitedStreamReader(NetworkStream stream) { P = stream; _memory_stream = new MemoryStream(); base..ctor(); } ~DelimitedStreamReader() { Dispose(disposing: false); } public void Dispose() { Dispose(disposing: true); } protected virtual void Dispose(bool disposing) { if (!disposing) { return; } try { _memory_stream.Dispose(); } catch { } } public string ReadUntilNullTerminator() { int num; while ((num = P.ReadByte()) != -1 && num != 0) { _memory_stream.WriteByte(checked((byte)num)); } if (num == -1) { throw new EndOfStreamException("Reached end of stream without finding a null terminator."); } string @string = Encoding.UTF8.GetString(_memory_stream.ToArray()); _memory_stream.SetLength(0L); return @string; } } public class GameStateManager { [CompilerGenerated] private CrowdControlMod P; private const string CasinoSceneName = "CasinoScene"; private const string HomeSceneName = "HomeScene"; public const string CasinoPlayRequiredMessage = "Can only be used when in the Casino"; private static readonly HashSet PauseTimedOutsideCasinoRoundCodes = new HashSet(StringComparer.Ordinal) { "player_movement_fast", "player_movement_slow", "player_movement_very_slow" }; private static readonly HashSet LobbySessionOkEffectCodes = new HashSet(StringComparer.Ordinal) { "cosmetic_random_piece", "cosmetic_reset_outfit", "cosmetic_clear_hats", "spawn_bat", "spawn_drink", "spawn_immunity_cross", "spawn_microphone", "spawn_coordinator", "spawn_golden_chip", "spawn_devils_reel", "spawn_angels_reel", "spawn_time_machine", "spawn_taser", "spawn_quota_gun", "spawn_mystery_box", "spawn_upgrade_stakeholder", "spawn_upgrade_insurance", "spawn_upgrade_bonus_draw", "spawn_upgrade_gamblers_confidence", "spawn_holy_statue", "spawn_voice_wand", "spawn_gacha_sphere", "spawn_basketball", "spawn_sledding_frog", "spawn_bongo", "spawn_dice", "spawn_chess_piece", "spawn_bingbong", "spawn_debt_bag", "player_movement_fast", "player_movement_slow", "player_movement_very_slow", "voice_low", "voice_wobble", "voice_radio", "voice_no_mouth_on", "voice_no_mouth_off", "voice_reset" }; private GameState? _lastGameState; public GameStateManager(CrowdControlMod mod) { P = mod; base..ctor(); } public static void LogCrowdControl(string message) { CrowdControlMod instance = CrowdControlMod.Instance; if (instance != null) { instance.Logger.LogMessage((object)("[Crowd Control] " + message)); } } public string FormatCrowdControlSpawnSnapshot() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //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_0077: Unknown result type (might be due to invalid IL or missing references) try { GameState gameState = GetGameState(); Scene activeScene = SceneManager.GetActiveScene(); string name = ((Scene)(ref activeScene)).name; GameManager instance = NetworkSingleton.Instance; string text = (((Object)(object)instance == (Object)null) ? "(null)" : ((object)(GameState)(ref instance.state)).ToString()); float num = (((Object)(object)instance == (Object)null) ? (-1f) : instance.Network_timer); bool flag = (Object)(object)instance != (Object)null && instance.HasDayStarted; return $"CcGameState={gameState} scene=\"{name}\" vanillaGameState={text} Network_timer={num:F2}s HasDayStarted={flag} " + $"focused={Application.isFocused} host={NetworkServer.active} client={NetworkClient.isConnected} timeScale={Time.timeScale:0.###}"; } catch (Exception ex) { return "CcGameState snapshot error: " + ex.Message; } } public bool IsStrictCasinoGamblingReady() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Invalid comparison between Unknown and I4 try { if (!NetworkClient.isConnected) { return false; } Scene activeScene = SceneManager.GetActiveScene(); string name = ((Scene)(ref activeScene)).name; GameManager instance = NetworkSingleton.Instance; if ((Object)(object)instance == (Object)null) { return false; } if (Time.timeScale <= 0f) { return false; } if (name != "CasinoScene" || (int)instance.state != 1) { return false; } if (NetworkServer.active) { return instance.HasDayStarted; } return instance.Network_timer > 0.0001f; } catch { return false; } } public bool IsCasinoRoundPlayReady() { return IsStrictCasinoGamblingReady(); } public static bool RequiresActiveCasinoPlay(string? code) { if (!string.IsNullOrEmpty(code)) { return CrowdControlHostOnlyEffectCodes.CodesSet.Contains(code); } return false; } public bool ShouldRejectCasinoOnlyOutsidePlay(string? code, [NotNullWhen(true)] out string? message) { message = null; if (!RequiresActiveCasinoPlay(code)) { return false; } if (IsStrictCasinoGamblingReady()) { return false; } message = "Can only be used when in the Casino"; return true; } public static bool ShouldFreezeTimedOutsideCasinoRound(string code) { if (!string.IsNullOrEmpty(code)) { return PauseTimedOutsideCasinoRoundCodes.Contains(code); } return false; } public bool IsReady(string code = "") { //IL_0014: 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_0022: Unknown result type (might be due to invalid IL or missing references) if (!Application.isFocused) { return false; } if (IsStrictCasinoGamblingReady()) { return true; } GameState gameState = GetGameState(); if (IsLobbySessionOkEffect(code) && CanRunLobbySessionEffects(gameState)) { return true; } return false; } private static bool IsLobbySessionOkEffect(string code) { if (!string.IsNullOrEmpty(code)) { return LobbySessionOkEffectCodes.Contains(code); } return false; } private static bool CanRunLobbySessionEffects(GameState state) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Invalid comparison between Unknown and I4 //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 if ((state - -8 <= 3 || (int)state == -1) ? true : false) { return false; } if (!NetworkClient.isConnected) { return false; } return (Object)(object)NetworkSingleton.Instance != (Object)null; } public GameState GetGameState() { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_000f: 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_0009: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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) //IL_003a: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Invalid comparison between Unknown and I4 //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) try { if (!NetworkClient.isConnected) { return (GameState)(-8); } Scene activeScene = SceneManager.GetActiveScene(); string name = ((Scene)(ref activeScene)).name; GameManager instance = NetworkSingleton.Instance; if ((Object)(object)instance == (Object)null) { return (GameState)(-6); } if (!Application.isFocused) { return (GameState)(-5); } if (Time.timeScale <= 0f) { return (GameState)(-7); } if (name == "HomeScene" && (int)instance.state == 0) { return (GameState)1; } if (name == "CasinoScene" && (int)instance.state == 1) { return (GameState)1; } return (GameState)(-9); } catch (Exception arg) { CrowdControlMod.Instance.Logger.LogError((object)$"Crowd Control game state error: {arg}"); return (GameState)(-1); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool UpdateGameState(bool force = false) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return UpdateGameState(GetGameState(), force); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool UpdateGameState(GameState newState, bool force) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return UpdateGameState(newState, null, force); } public bool UpdateGameState(GameState newState, string? message = null, bool force = false) { //IL_002d: 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_0039: Expected O, but got Unknown //IL_000a: 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_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_003e: Unknown result type (might be due to invalid IL or missing references) if (!force && _lastGameState == (GameState?)newState) { return true; } if (!P.Client.Send((SimpleJSONResponse?)new GameUpdate(newState, message))) { return false; } _lastGameState = newState; return true; } } internal static class GwyfDayTimerRules { public const float MaxRemainingSeconds = 300f; public const float MinRemainingAfterRemoveSeconds = 5f; public static float GetRemainingSeconds(GameSettings gs, GameManager gm) { return Mathf.Max(0f, gs.dayDuration - gm.Network_timer); } public static float GetMaxAllowedRemainingSeconds(GameSettings gs) { return Mathf.Min(gs.dayDuration, 300f); } public static bool CanAddRemainingSeconds(GameSettings gs, GameManager gm, float addSeconds) { if (addSeconds <= 0f) { return true; } float remainingSeconds = GetRemainingSeconds(gs, gm); float maxAllowedRemainingSeconds = GetMaxAllowedRemainingSeconds(gs); return remainingSeconds + addSeconds <= maxAllowedRemainingSeconds + 0.01f; } public static bool CanRemoveRemainingSeconds(GameSettings gs, GameManager gm, float removeSeconds) { if (removeSeconds <= 0f) { return true; } return GetRemainingSeconds(gs, gm) >= removeSeconds + 5f - 0.01f; } public static string FormatMinutesSeconds(float totalSeconds) { totalSeconds = Mathf.Max(0f, totalSeconds); int num = Mathf.FloorToInt(totalSeconds + 0.5f); int num2 = num / 60; int num3 = num % 60; if (num2 <= 0) { return $"{num3}s"; } return $"{num2}:{num3:00}"; } public static string DescribeCannotAddTime(GameSettings gs, GameManager gm, float tryAddSeconds) { float remainingSeconds = GetRemainingSeconds(gs, gm); float maxAllowedRemainingSeconds = GetMaxAllowedRemainingSeconds(gs); return "Cannot add time: the day timer is already at the maximum allowed remaining time (~" + FormatMinutesSeconds(remainingSeconds) + " on the clock, cap ~" + FormatMinutesSeconds(maxAllowedRemainingSeconds) + "; adding ~" + FormatMinutesSeconds(tryAddSeconds) + " would exceed it)."; } public static string DescribeCannotRemoveTime(GameSettings gs, GameManager gm, float removeSeconds) { float remainingSeconds = GetRemainingSeconds(gs, gm); float totalSeconds = removeSeconds + 5f; return "Cannot remove time: the day timer is too low (~" + FormatMinutesSeconds(remainingSeconds) + " remaining). Need at least ~" + FormatMinutesSeconds(totalSeconds) + " on the clock to remove ~" + FormatMinutesSeconds(removeSeconds) + " while keeping ~" + FormatMinutesSeconds(5f) + " left."; } } internal static class GwyfItemSpawnHelper { private static bool s_catalogHintDumpDone; private static readonly string[] s_catalogHintKeywords = new string[9] { "debt", "chess", "frog", "bing", "gacha", "voice", "sled", "dice", "bongo" }; private const float SpawnForwardDistance = 1.35f; private const float SpawnRaycastUp = 3f; private const float SpawnRaycastDown = 8f; private const float GroundLift = 0.08f; private static void LogItemSpawnCcState(string channel, CrowdControlSpawnItemKind kind) { GameStateManager gameStateManager = CrowdControlMod.Instance?.GameStateManager; if (gameStateManager != null) { GameStateManager.LogCrowdControl($"Item spawn ({channel}) kind={kind} — {gameStateManager.FormatCrowdControlSpawnSnapshot()}"); } else { GameStateManager.LogCrowdControl($"Item spawn ({channel}) kind={kind} — (no GameStateManager)"); } } internal static void LogCatalogHintMatchesOnceIfEnabled(ManualLogSource log, bool enabled) { if (!enabled || s_catalogHintDumpDone || log == null) { return; } s_catalogHintDumpDone = true; SpawnableSettings val = Resources.Load("SpawnableSettings"); if (val?.spawnables == null) { log.LogWarning((object)"Crowd Control spawn debug: SpawnableSettings missing or has no spawnables list (Resources.Load)."); return; } int count = val.spawnables.Count; log.LogInfo((object)string.Format("Crowd Control spawn debug (one-time): scanning {0} spawnables for name substrings: {1}.", count, string.Join(", ", s_catalogHintKeywords))); int num = 0; foreach (SpawnableSO spawnable in val.spawnables) { if (!Object.op_Implicit((Object)(object)spawnable) || string.IsNullOrEmpty(spawnable.spawnableName)) { continue; } List list = new List(); string[] array = s_catalogHintKeywords; foreach (string text in array) { if (spawnable.spawnableName.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0) { list.Add(text); } } if (list.Count != 0) { num = checked(num + 1); string text2 = (Object.op_Implicit((Object)(object)spawnable.prefab) ? "yes" : "no"); log.LogInfo((object)string.Format("[CC spawn catalog] id={0} name=\"{1}\" matched=[{2}] prefab={3}", spawnable.spawnableID, spawnable.spawnableName, string.Join(", ", list), text2)); } } if (num == 0) { log.LogInfo((object)"Crowd Control spawn debug: no spawnableName contained those keywords (other toys may still match by prefab component)."); } else { log.LogInfo((object)$"Crowd Control spawn debug: keyword hits: {num} row(s)."); } log.LogInfo((object)"Crowd Control spawn debug: **full catalog** (only these rows exist for Resources SpawnableSettings — spawn_* effects cannot invent props not listed here):"); foreach (SpawnableSO spawnable2 in val.spawnables) { if (Object.op_Implicit((Object)(object)spawnable2)) { string text3 = (string.IsNullOrEmpty(spawnable2.spawnableName) ? "(empty name)" : spawnable2.spawnableName); string text4 = (Object.op_Implicit((Object)(object)spawnable2.prefab) ? "prefab=yes" : "prefab=no"); string text5 = SummarizeItemTypesOnPrefab(spawnable2.prefab); log.LogInfo((object)$"[CC spawn row] id={spawnable2.spawnableID} name=\"{text3}\" {text4} itemScripts=[{text5}]"); } } log.LogInfo((object)"Crowd Control spawn debug: end. Off-catalog toys also try Mirror spawn prefabs + scene machine refs (see GwyfOffCatalogPrefabDiscovery). Set Debug.LogSpawnableCatalogHintsOnce=false to silence."); } private static string SummarizeItemTypesOnPrefab(GameObject? prefab) { if (!Object.op_Implicit((Object)(object)prefab)) { return string.Empty; } Item[] componentsInChildren = prefab.GetComponentsInChildren(true); if (componentsInChildren == null || componentsInChildren.Length == 0) { return string.Empty; } HashSet hashSet = new HashSet(StringComparer.Ordinal); Item[] array = componentsInChildren; foreach (Item val in array) { if (Object.op_Implicit((Object)(object)val)) { hashSet.Add(((object)val).GetType().Name); } } if (hashSet.Count != 0) { return string.Join(", ", hashSet); } return string.Empty; } public static SpawnableSO? FindSpawnableByNameHints(params string[] nameSubstrings) { SpawnableSettings val = Resources.Load("SpawnableSettings"); if (val?.spawnables == null) { return null; } foreach (string value in nameSubstrings) { if (string.IsNullOrWhiteSpace(value)) { continue; } foreach (SpawnableSO spawnable in val.spawnables) { if (Object.op_Implicit((Object)(object)spawnable) && !string.IsNullOrEmpty(spawnable.spawnableName) && Object.op_Implicit((Object)(object)spawnable.prefab) && spawnable.spawnableName.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) { return spawnable; } } } return null; } private static SpawnableSO? FindSpawnableById(int spawnableId) { SpawnableSettings val = Resources.Load("SpawnableSettings"); if (val?.spawnables == null) { return null; } foreach (SpawnableSO spawnable in val.spawnables) { if (Object.op_Implicit((Object)(object)spawnable) && spawnable.spawnableID == spawnableId && Object.op_Implicit((Object)(object)spawnable.prefab)) { return spawnable; } } return null; } private static SpawnableSO? FindSpawnableWithPrefabComponent() where T : Component { SpawnableSettings val = Resources.Load("SpawnableSettings"); if (val?.spawnables == null) { return null; } foreach (SpawnableSO spawnable in val.spawnables) { if (Object.op_Implicit((Object)(object)spawnable) && Object.op_Implicit((Object)(object)spawnable.prefab) && (Object)(object)spawnable.prefab.GetComponentInChildren(true) != (Object)null) { return spawnable; } } return null; } private static SpawnableSO? FindSpawnableUpgradeConsumable(params string[] nameHintsInPriorityOrder) { SpawnableSettings val = Resources.Load("SpawnableSettings"); if (val?.spawnables == null) { return null; } foreach (string value in nameHintsInPriorityOrder) { if (string.IsNullOrWhiteSpace(value)) { continue; } foreach (SpawnableSO spawnable in val.spawnables) { if (Object.op_Implicit((Object)(object)spawnable) && !string.IsNullOrEmpty(spawnable.spawnableName) && Object.op_Implicit((Object)(object)spawnable.prefab) && spawnable.spawnableName.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0 && !((Object)(object)spawnable.prefab.GetComponentInChildren(true) == (Object)null)) { return spawnable; } } } return null; } internal static SpawnableSO? ResolveSpawnable(CrowdControlSpawnItemKind kind) { return (SpawnableSO?)(kind switch { CrowdControlSpawnItemKind.Bat => FindSpawnableByNameHints("Bat") ?? FindSpawnableWithPrefabComponent(), CrowdControlSpawnItemKind.Basketball => null, CrowdControlSpawnItemKind.Drink => FindSpawnableByNameHints("Drink") ?? FindSpawnableWithPrefabComponent(), CrowdControlSpawnItemKind.Microphone => FindSpawnableByNameHints("Microphone", "Mic") ?? FindSpawnableWithPrefabComponent(), CrowdControlSpawnItemKind.ImmunityCross => FindSpawnableById(10) ?? FindSpawnableByNameHints("ImmunityCross", "Immunity Cross", "Immunity", "Cross") ?? FindSpawnableWithPrefabComponent(), CrowdControlSpawnItemKind.CoordinatorCamera => FindSpawnableWithPrefabComponent() ?? FindSpawnableByNameHints("Coordinator", "Camera", "Capture"), CrowdControlSpawnItemKind.GoldenChip => FindSpawnableById(17) ?? FindSpawnableWithPrefabComponent() ?? FindSpawnableByNameHints("Golden", "Chip", "GoldenChip"), CrowdControlSpawnItemKind.DevilsReel => FindSpawnableById(12) ?? FindSpawnableWithPrefabComponent() ?? FindSpawnableByNameHints("Devil", "Reel", "DevilsReel"), CrowdControlSpawnItemKind.AngelsReel => FindSpawnableById(39) ?? FindSpawnableWithPrefabComponent() ?? FindSpawnableByNameHints("Angel", "Reel", "AngelsReel"), CrowdControlSpawnItemKind.TimeMachine => FindSpawnableWithPrefabComponent() ?? FindSpawnableByNameHints("Time Machine", "TimeMachine", "Time"), CrowdControlSpawnItemKind.Taser => FindSpawnableWithPrefabComponent() ?? FindSpawnableByNameHints("Taser"), CrowdControlSpawnItemKind.QuotaGun => FindSpawnableWithPrefabComponent() ?? FindSpawnableByNameHints("Quota", "Gun", "QuotaGun"), CrowdControlSpawnItemKind.MysteryBox => FindSpawnableWithPrefabComponent() ?? FindSpawnableByNameHints("Mystery", "Box", "MysteryBox"), CrowdControlSpawnItemKind.UpgradeStakeholder => FindSpawnableUpgradeConsumable("Stakeholder", "Stake Holder", "Stake"), CrowdControlSpawnItemKind.UpgradeInsurance => FindSpawnableUpgradeConsumable("Insurance"), CrowdControlSpawnItemKind.UpgradeBonusDraw => FindSpawnableUpgradeConsumable("Bonus Draw", "BonusDraw", "Bonus"), CrowdControlSpawnItemKind.UpgradeGamblersConfidence => FindSpawnableUpgradeConsumable("Gamblers Confidence", "GamblersConfidence", "Gambler"), CrowdControlSpawnItemKind.HolyStatue => FindSpawnableById(10) ?? FindSpawnableByNameHints("Holy Statue", "HolyStatue", "Holy", "Loss Statue") ?? FindSpawnableWithPrefabComponent(), CrowdControlSpawnItemKind.SleddingFrog => null, CrowdControlSpawnItemKind.VoiceWand => FindSpawnableById(35) ?? FindSpawnableWithPrefabComponent() ?? FindSpawnableByNameHints("Voice Manipulator", "VoiceManipulator", "Voice Wand", "Voice Toy"), CrowdControlSpawnItemKind.GachaSphere => FindSpawnableById(1) ?? FindSpawnableWithPrefabComponent() ?? FindSpawnableByNameHints("Cosmetic Item", "Cosmetic", "Gacha", "Gacha Sphere", "GachaSphere"), CrowdControlSpawnItemKind.Bongo => null, CrowdControlSpawnItemKind.Dice => null, CrowdControlSpawnItemKind.ChessPiece => null, CrowdControlSpawnItemKind.BingBong => null, CrowdControlSpawnItemKind.DebtBag => null, _ => null, }); } private static Item? ResolvePrimaryItem(GameObject instance) { NetworkIdentity val = instance.GetComponent() ?? instance.GetComponentInChildren(true); if ((Object)(object)val != (Object)null) { Item component = ((Component)val).GetComponent(); if ((Object)(object)component != (Object)null) { return component; } } return instance.GetComponent() ?? instance.GetComponentInChildren(true); } private static Transform GetFacingTransform(PlayerInventory inv) { PlayerController component = ((Component)inv).GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)component.head != (Object)null) { return ((Component)component.head).transform; } return ((Component)inv).transform; } private static bool TryComputeSpawnPose(PlayerInventory inv, out Vector3 worldPos, out Quaternion worldRot) { //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_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_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_0071: 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) //IL_0080: 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_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: 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) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) Vector3 val = Vector3.ProjectOnPlane(GetFacingTransform(inv).forward, Vector3.up); if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { val = Vector3.ProjectOnPlane(((Component)inv).transform.forward, Vector3.up); } if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { val = Vector3.forward; } ((Vector3)(ref val)).Normalize(); worldPos = ((Component)inv).transform.position + val * 1.35f + Vector3.up * 0.1f; worldRot = Quaternion.LookRotation(val, Vector3.up); RaycastHit val2 = default(RaycastHit); if (Physics.Raycast(worldPos + Vector3.up * 3f, Vector3.down, ref val2, 11f, -5, (QueryTriggerInteraction)1)) { worldPos = ((RaycastHit)(ref val2)).point + Vector3.up * 0.08f; } return true; } internal static bool ServerTrySpawnItemNearPlayer(PlayerInventory inv, SpawnableSO spawnable, out Item? spawnedItem, out string? errorMessage) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_009e: 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) spawnedItem = null; errorMessage = null; if (!NetworkServer.active) { errorMessage = "Internal: ServerTrySpawnItemNearPlayer requires an active server."; return false; } if (!Object.op_Implicit((Object)(object)spawnable.prefab)) { errorMessage = "SpawnableSO has no prefab."; return false; } if ((Object)(object)inv == (Object)null) { errorMessage = "PlayerInventory was null."; return false; } if (!TryComputeSpawnPose(inv, out var worldPos, out var worldRot)) { errorMessage = "Could not compute spawn position."; return false; } GameObject val = Object.Instantiate(spawnable.prefab, worldPos, worldRot); Item val2 = ResolvePrimaryItem(val); if ((Object)(object)val2 == (Object)null) { Object.Destroy((Object)(object)val); errorMessage = "Spawnable prefab has no Item usable for pickup."; return false; } Rigidbody val3 = ((Component)val2).GetComponent() ?? ((Component)val2).GetComponentInParent(); if ((Object)(object)val3 != (Object)null) { val3.linearVelocity = Vector3.zero; val3.angularVelocity = Vector3.zero; } NetworkServer.Spawn(val, (NetworkConnectionToClient)null); spawnedItem = val2; return true; } internal static bool ServerTrySpawnPrefabNearPlayer(PlayerInventory inv, GameObject prefabRoot, out Item? spawnedItem, out string? errorMessage) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_00a0: Unknown result type (might be due to invalid IL or missing references) spawnedItem = null; errorMessage = null; if (!NetworkServer.active) { errorMessage = "Internal: ServerTrySpawnPrefabNearPlayer requires an active server."; return false; } if (!Object.op_Implicit((Object)(object)prefabRoot)) { errorMessage = "Prefab root was null."; return false; } if ((Object)(object)inv == (Object)null) { errorMessage = "PlayerInventory was null."; return false; } if (!TryComputeSpawnPose(inv, out var worldPos, out var worldRot)) { errorMessage = "Could not compute spawn position."; return false; } GameObject val = Object.Instantiate(prefabRoot, worldPos, worldRot); Item val2 = ResolvePrimaryItem(val); if ((Object)(object)val2 == (Object)null) { Object.Destroy((Object)(object)val); errorMessage = "Prefab has no Item usable for pickup."; return false; } Rigidbody val3 = ((Component)val2).GetComponent() ?? ((Component)val2).GetComponentInParent(); if ((Object)(object)val3 != (Object)null) { val3.linearVelocity = Vector3.zero; val3.angularVelocity = Vector3.zero; } NetworkServer.Spawn(val, (NetworkConnectionToClient)null); spawnedItem = val2; return true; } internal static bool TrySpawnCrowdControlKindNearServer(PlayerInventory inv, CrowdControlSpawnItemKind kind, out Item? spawnedItem, out string? errorMessage) { spawnedItem = null; errorMessage = null; if (!NetworkServer.active) { errorMessage = "Internal: TrySpawnCrowdControlKindNearServer requires an active server."; return false; } SpawnableSO val = ResolveSpawnable(kind); if ((Object)(object)val != (Object)null) { if (!ServerTrySpawnItemNearPlayer(inv, val, out spawnedItem, out errorMessage)) { return false; } LogItemSpawnCcState("server/catalog-SO", kind); return true; } GameObject val2 = GwyfOffCatalogPrefabDiscovery.TryGetPrefabRootForKind(kind); if ((Object)(object)val2 == (Object)null) { errorMessage = $"No SpawnableSettings row and no discoverable prefab for {kind}."; return false; } if (!ServerTrySpawnPrefabNearPlayer(inv, val2, out spawnedItem, out errorMessage)) { return false; } LogItemSpawnCcState("server/off-catalog-prefab", kind); return true; } internal static bool TrySpawnByKindNearLocalStreamer(CrowdControlSpawnItemKind kind, out Item? spawnedItem, out string? errorMessage) { spawnedItem = null; errorMessage = null; if (!NetworkClient.isConnected || (Object)(object)NetworkClient.localPlayer == (Object)null) { errorMessage = "Not connected or no local player."; return false; } PlayerInventory component = ((Component)NetworkClient.localPlayer).GetComponent(); if ((Object)(object)component == (Object)null) { errorMessage = "Local player has no PlayerInventory."; return false; } SpawnableSO val = ResolveSpawnable(kind); if ((Object)(object)val != (Object)null) { return TrySpawnItemNearLocalStreamer(val, kind, out spawnedItem, out errorMessage); } if (NetworkServer.active) { return TrySpawnCrowdControlKindNearServer(component, kind, out spawnedItem, out errorMessage); } if (!CrowdControlItemNetwork.ClientSendItemRequest(kind)) { errorMessage = "Could not send item request to host (network not ready)."; return false; } LogItemSpawnCcState("by-kind/off-catalog/client-request-sent", kind); return true; } public static bool TrySpawnItemNearLocalStreamer(SpawnableSO spawnable, CrowdControlSpawnItemKind kind, out Item? spawnedItem, out string? errorMessage) { spawnedItem = null; errorMessage = null; if ((Object)(object)spawnable == (Object)null) { errorMessage = "SpawnableSO was null."; return false; } if (!NetworkClient.isConnected || (Object)(object)NetworkClient.localPlayer == (Object)null) { errorMessage = "Not connected or no local player."; return false; } PlayerInventory component = ((Component)NetworkClient.localPlayer).GetComponent(); if ((Object)(object)component == (Object)null) { errorMessage = "Local player has no PlayerInventory."; return false; } if (NetworkServer.active) { if (!ServerTrySpawnItemNearPlayer(component, spawnable, out spawnedItem, out errorMessage)) { return false; } LogItemSpawnCcState("local/catalog-SO/host", kind); return true; } if (!CrowdControlItemNetwork.ClientSendItemRequest(kind)) { errorMessage = "Could not send item request to host (network not ready)."; return false; } LogItemSpawnCcState("local/catalog-SO/client-request", kind); return true; } } internal static class GwyfLocalMovementSpeed { private readonly struct Baseline { internal readonly float MaxSpeed; internal readonly float SprintMaxSpeed; internal readonly float CrouchMaxSpeed; internal readonly float RollMaxSpeed; internal readonly float Acceleration; internal readonly float RollAcceleration; internal static Baseline From(PlayerSettings ps) { return new Baseline(ps.maxSpeed, ps.sprintMaxSpeed, ps.crouchMaxSpeed, ps.rollMaxSpeed, ps.acceleration, ps.rollAcceleration); } private Baseline(float maxSpeed, float sprintMaxSpeed, float crouchMaxSpeed, float rollMaxSpeed, float acceleration, float rollAcceleration) { MaxSpeed = maxSpeed; SprintMaxSpeed = sprintMaxSpeed; CrouchMaxSpeed = crouchMaxSpeed; RollMaxSpeed = rollMaxSpeed; Acceleration = acceleration; RollAcceleration = rollAcceleration; } internal void ApplyTo(PlayerSettings ps) { ps.maxSpeed = MaxSpeed; ps.sprintMaxSpeed = SprintMaxSpeed; ps.crouchMaxSpeed = CrouchMaxSpeed; ps.rollMaxSpeed = RollMaxSpeed; ps.acceleration = Acceleration; ps.rollAcceleration = RollAcceleration; } internal void ScaleInto(PlayerSettings ps, float multiplier) { ps.maxSpeed = MaxSpeed * multiplier; ps.sprintMaxSpeed = SprintMaxSpeed * multiplier; ps.crouchMaxSpeed = CrouchMaxSpeed * multiplier; ps.rollMaxSpeed = RollMaxSpeed * multiplier; ps.acceleration = Acceleration * Mathf.Sqrt(multiplier); ps.rollAcceleration = RollAcceleration * Mathf.Sqrt(multiplier); } } private static PlayerController? s_preparedController; private static PlayerSettings? s_dupSettings; private static Baseline s_baseline; private static bool s_hasBaseline; private static float? s_appliedMultiplier; internal static void PreparePrivatePlayerSettings(PlayerController pc) { if (!((Object)(object)pc == (Object)null) && ((NetworkBehaviour)pc).isLocalPlayer && (!((Object)(object)s_preparedController == (Object)(object)pc) || !((Object)(object)s_dupSettings != (Object)null))) { FieldInfo fieldInfo = AccessTools.Field(typeof(PlayerController), "_ps"); object? value = fieldInfo.GetValue(pc); PlayerSettings val = (PlayerSettings)((value is PlayerSettings) ? value : null); if (!((Object)(object)val == (Object)null)) { PlayerSettings val2 = Object.Instantiate(val); ((Object)val2).name = ((Object)val).name + " (CC local)"; s_baseline = Baseline.From(val2); s_hasBaseline = true; fieldInfo.SetValue(pc, val2); s_dupSettings = val2; s_preparedController = pc; } } } internal static bool TryApplySpeedMultiplier(float multiplier, out string? error) { error = null; if (!NetworkClient.isConnected || (Object)(object)NetworkClient.localPlayer == (Object)null) { error = "No local player."; return false; } PlayerController component = ((Component)NetworkClient.localPlayer).GetComponent(); if ((Object)(object)component == (Object)null) { error = "No PlayerController on local player."; return false; } PreparePrivatePlayerSettings(component); if ((Object)(object)s_dupSettings == (Object)null || !s_hasBaseline) { error = "Could not create private PlayerSettings copy."; return false; } s_baseline.ScaleInto(s_dupSettings, multiplier); s_appliedMultiplier = multiplier; return true; } internal static void RestoreBaseline() { if ((Object)(object)s_dupSettings != (Object)null && s_hasBaseline) { s_baseline.ApplyTo(s_dupSettings); } s_appliedMultiplier = null; } internal static void PauseHeldMultiplier() { if ((Object)(object)s_dupSettings != (Object)null && s_hasBaseline && s_appliedMultiplier.HasValue) { s_baseline.ApplyTo(s_dupSettings); } } internal static void ResumeHeldMultiplier() { if (!((Object)(object)s_dupSettings == (Object)null) && s_hasBaseline) { float? num = s_appliedMultiplier; if (num.HasValue) { float valueOrDefault = num.GetValueOrDefault(); s_baseline.ScaleInto(s_dupSettings, valueOrDefault); } } } } public static class GwyfMultiplayer { public static bool IsNetworkActive { get { if (!NetworkServer.active) { return NetworkClient.active; } return true; } } public static bool IsServer => NetworkServer.active; public static bool IsClientConnected => NetworkClient.isConnected; public static bool TryGetMoneyManager(out MoneyManager money) { money = NetworkSingleton.Instance; return Object.op_Implicit((Object)(object)money); } } internal static class GwyfOffCatalogPrefabDiscovery { internal static GameObject? TryGetPrefabRootForKind(CrowdControlSpawnItemKind kind) { return (GameObject?)(kind switch { CrowdControlSpawnItemKind.SleddingFrog => TryMirrorSpawnPrefabWithComponent() ?? TryLoadedPrefabPrototype(), CrowdControlSpawnItemKind.Basketball => TryMirrorSpawnPrefabWithComponent() ?? TrySerializeFieldComponentPrefab("basketballPrefab") ?? TryLoadedPrefabPrototype(), CrowdControlSpawnItemKind.Bongo => TryMirrorSpawnPrefabWithComponent() ?? TryLoadedPrefabPrototype(), CrowdControlSpawnItemKind.Dice => TryMirrorSpawnPrefabWithComponent() ?? TryLoadedPrefabPrototype(), CrowdControlSpawnItemKind.ChessPiece => TryMirrorSpawnPrefabWithComponent() ?? TryLoadedPrefabPrototype(), CrowdControlSpawnItemKind.BingBong => TryBingBongPlushPrefab(), CrowdControlSpawnItemKind.DebtBag => TryMirrorSpawnPrefabWithComponent() ?? TrySerializeFieldComponentPrefab("debtBagPrefab") ?? TryLoadedPrefabPrototype(), _ => null, }); } private static GameObject? TryMirrorSpawnPrefabWithComponent() where T : Component { NetworkManager singleton = NetworkManager.singleton; if (singleton?.spawnPrefabs == null) { return null; } foreach (GameObject spawnPrefab in singleton.spawnPrefabs) { if (Object.op_Implicit((Object)(object)spawnPrefab)) { T componentInChildren = spawnPrefab.GetComponentInChildren(true); if (Object.op_Implicit((Object)(object)componentInChildren)) { return GetNetworkIdentitySpawnRoot(spawnPrefab, (Component)(object)componentInChildren); } } } return null; } private static GameObject GetNetworkIdentitySpawnRoot(GameObject listEntry, Component hit) { if (Object.op_Implicit((Object)(object)listEntry.GetComponent())) { return listEntry; } NetworkIdentity componentInParent = hit.GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent)) { return ((Component)componentInParent).gameObject; } return ((Component)hit.transform.root).gameObject; } private static GameObject? TrySerializeFieldComponentPrefab(string fieldName) where TBehaviour : Component { FieldInfo field = typeof(TBehaviour).GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { return null; } TBehaviour[] array = Object.FindObjectsByType((FindObjectsInactive)1, (FindObjectsSortMode)0); foreach (TBehaviour val in array) { if (Object.op_Implicit((Object)(object)val)) { object? value = field.GetValue(val); Component val2 = (Component)((value is Component) ? value : null); if (val2 != null && Object.op_Implicit((Object)(object)val2)) { return GetNetworkIdentitySpawnRoot(val2.gameObject, val2); } } } return null; } private static GameObject? TryLoadedPrefabPrototype() where T : Component { //IL_002c: 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) T[] array = Resources.FindObjectsOfTypeAll(); foreach (T val in array) { if (Object.op_Implicit((Object)(object)val)) { GameObject gameObject = ((Component)val).gameObject; Scene scene = gameObject.scene; if (!((Scene)(ref scene)).IsValid()) { return GetNetworkIdentitySpawnRoot(gameObject, (Component)(object)val); } } } return null; } private static GameObject? TryBingBongPlushPrefab() { //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.singleton; Plush[] componentsInChildren; if (singleton?.spawnPrefabs != null) { foreach (GameObject spawnPrefab in singleton.spawnPrefabs) { if (!Object.op_Implicit((Object)(object)spawnPrefab)) { continue; } componentsInChildren = spawnPrefab.GetComponentsInChildren(true); foreach (Plush val in componentsInChildren) { if (Object.op_Implicit((Object)(object)val) && !(val is SleddingFrog)) { string name = ((Object)((Component)val).gameObject).name; if (name.IndexOf("bing", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("bong", StringComparison.OrdinalIgnoreCase) >= 0) { return GetNetworkIdentitySpawnRoot(spawnPrefab, (Component)(object)val); } } } } } componentsInChildren = Resources.FindObjectsOfTypeAll(); foreach (Plush val2 in componentsInChildren) { if (!Object.op_Implicit((Object)(object)val2) || val2 is SleddingFrog) { continue; } Scene scene = ((Component)val2).gameObject.scene; if (!((Scene)(ref scene)).IsValid()) { string name2 = ((Object)((Component)val2).gameObject).name; if (name2.IndexOf("bing", StringComparison.OrdinalIgnoreCase) >= 0 || name2.IndexOf("bong", StringComparison.OrdinalIgnoreCase) >= 0) { return GetNetworkIdentitySpawnRoot(((Component)val2).gameObject, (Component)(object)val2); } } } return null; } } public static class GwyfSceneHelpers { public static bool TryGetLocalPlayerVoiceFx(out PlayerVoiceFX? pv) { pv = null; if (!NetworkClient.active || (Object)(object)NetworkClient.localPlayer == (Object)null) { return false; } pv = ((Component)NetworkClient.localPlayer).GetComponent() ?? ((Component)NetworkClient.localPlayer).GetComponentInChildren(true); return (Object)(object)pv != (Object)null; } public static PlayerVoiceFX[] FindAllPlayerVoiceFx() { return Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); } public static PlayerProfile[] FindAllPlayerProfiles() { return Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); } public static PlayerCustomization[] FindAllPlayerCustomizations() { return Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); } } internal static class GwyfSpawnedBuffItemActivator { [CompilerGenerated] private sealed class d__6 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public float wait; public ImmunityCross cross; public List targets; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__6(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(wait); <>1__state = 1; return true; case 1: <>1__state = -1; if ((Object)(object)cross == (Object)null) { return false; } foreach (PlayerBuff target in targets) { if (Object.op_Implicit((Object)(object)target)) { target.ResetBuffArea((PlayerBuffType)2, (Item)(object)cross); } } ((ConsumableItem)cross).DestroyItem(); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public const float ImmunityCrossAuraSeconds = 15f; private static readonly MethodInfo? sDrinkOnDrank = typeof(Drink).GetMethod("OnDrank", BindingFlags.Instance | BindingFlags.NonPublic); public static void ActivateIfBuffItem(Item item) { if (!NetworkServer.active || (Object)(object)item == (Object)null) { return; } Drink val = (Drink)(object)((item is Drink) ? item : null); if (val == null) { ImmunityCross val2 = (ImmunityCross)(object)((item is ImmunityCross) ? item : null); if (val2 == null) { Microphone val3 = (Microphone)(object)((item is Microphone) ? item : null); if (val3 != null) { ActivateMicrophoneMelodyApproximation(val3, 0.4f, 15f); } } else { ActivateImmunityCrossAura(val2, 15f); } } else { ActivateDrink(val); } } private static void ActivateDrink(Drink drink) { if (sDrinkOnDrank != null) { sDrinkOnDrank.Invoke(drink, null); } else { FallbackDrinkOnDrank(drink); } } private static void FallbackDrinkOnDrank(Drink drink) { PlayerInventory networkHolder = ((Item)drink).NetworkHolder; if ((Object)(object)networkHolder == (Object)null) { return; } PlayerProfile component = ((Component)networkHolder).GetComponent(); PlayerBuff component2 = ((Component)networkHolder).GetComponent(); if (!((Object)(object)component2 == (Object)null) && !((Object)(object)component == (Object)null) && !((Object)(object)NetworkSingleton.Instance == (Object)null)) { float upgradeData = NetworkSingleton.Instance.GetUpgradeData(component.steamId, (PlayerUpgradeType)2); component2.ApplyBuff((PlayerBuffType)0, 1f * upgradeData, 30f); PlayerVoiceFX val = default(PlayerVoiceFX); if (((Component)networkHolder).TryGetComponent(ref val)) { val.RpcStartTimedVoiceFX((VoipFX)1, 30f, true); } ((ConsumableItem)drink).DestroyItem(); } } private static void ActivateImmunityCrossAura(ImmunityCross cross, float seconds) { //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_004c: 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_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown List list = new List(); PlayerBuff[] array = Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0); foreach (PlayerBuff val in array) { if (Object.op_Implicit((Object)(object)val) && ((NetworkBehaviour)val).isServer) { list.Add(val); } } BuffArea val2 = new BuffArea { Source = ((Component)cross).transform, Range = 500f, Amount = 1f, IsActive = true }; foreach (PlayerBuff item in list) { item.SetBuffArea((PlayerBuffType)2, (Item)(object)cross, val2); } ((MonoBehaviour)CrowdControlMod.Instance).StartCoroutine(ClearImmunityCrossAuraAndConsume(cross, list, seconds)); } [IteratorStateMachine(typeof(d__6))] private static IEnumerator ClearImmunityCrossAuraAndConsume(ImmunityCross cross, List targets, float wait) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__6(0) { cross = cross, targets = targets, wait = wait }; } private static void ActivateMicrophoneMelodyApproximation(Microphone mic, float melodyDelta, float seconds) { PlayerInventory networkHolder = ((Item)mic).NetworkHolder; PlayerBuff val = (((Object)(object)networkHolder != (Object)null) ? ((Component)networkHolder).GetComponent() : null); if ((Object)(object)val != (Object)null && ((NetworkBehaviour)val).isServer) { val.ApplyBuff((PlayerBuffType)1, melodyDelta, seconds); GameStateManager.LogCrowdControl($"Item: microphone spawned then removed — approx InspiringMelody +{melodyDelta} ({seconds}s) on holder only (real mic uses charge + proximity)."); } ((ConsumableItem)mic).DestroyItem(); } } public class NetworkClient : IDisposable { private const bool PROCESS_LOOKUP_FALLBACK = true; private static readonly SITimeSpan TIMEOUT_NO_PROCESS = 5.0; private static readonly SITimeSpan TIMEOUT_NO_CONNECTION = 2.0; public static readonly string CV_HOST = "127.0.0.1"; public static readonly int CV_PORT = 51337; private TcpClient? m_client; private DelimitedStreamReader? m_streamReader; private readonly CrowdControlMod m_mod; private readonly CancellationTokenSource m_quitting = new CancellationTokenSource(); private readonly object m_shutdownLock = new object(); private volatile bool m_disposed; private readonly Thread m_readLoop; private readonly Thread m_maintenanceLoop; private static readonly EmptyResponse KEEPALIVE = new EmptyResponse { type = (ResponseType)255 }; public bool Connected => m_client?.Connected ?? false; ~NetworkClient() { Dispose(disposing: false); } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!disposing) { return; } lock (m_shutdownLock) { if (m_disposed) { return; } m_disposed = true; } try { m_client?.Close(); m_client?.Dispose(); m_client = null; } catch { } try { m_quitting.Cancel(); } catch { } } private static bool IsBenignShutdownException(Exception e, bool quitting) { if (!quitting && !(e is ThreadAbortException) && !(e is ObjectDisposedException) && !(e is OperationCanceledException) && (!(e is IOException ex) || !(ex.InnerException is SocketException ex2) || !IsBenignSocketError(ex2.SocketErrorCode))) { if (e is SocketException ex3) { return IsBenignSocketError(ex3.SocketErrorCode); } return false; } return true; } private static bool IsBenignSocketError(SocketError code) { switch (code) { case SocketError.OperationAborted: case SocketError.Interrupted: case SocketError.ConnectionAborted: case SocketError.ConnectionReset: case SocketError.Shutdown: return true; default: return false; } } public NetworkClient(CrowdControlMod mod) { m_mod = mod; m_readLoop = new Thread(NetworkLoop) { IsBackground = true, Name = "CrowdControl.NetworkRead" }; m_maintenanceLoop = new Thread(MaintenanceLoop) { IsBackground = true, Name = "CrowdControl.NetworkMaintenance" }; m_readLoop.Start(); m_maintenanceLoop.Start(); } private void NetworkLoop() { Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; while (!m_quitting.IsCancellationRequested) { if (!IsCrowdControlSemaphorePresent() && !IsCrowdControlProcessRunning()) { CrowdControlMod.Instance.Logger.LogMessage((object)"No CrowdControl process found, skipping connection attempt..."); m_quitting.Token.WaitHandle.WaitOne((TimeSpan)TIMEOUT_NO_PROCESS); continue; } CrowdControlMod.Instance.Logger.LogInfo((object)"Attempting to connect to Crowd Control"); try { m_client = new TcpClient(); m_client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, optionValue: true); m_client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, optionValue: true); if (m_client.BeginConnect(CV_HOST, CV_PORT, null, null).AsyncWaitHandle.WaitOne(2000, exitContext: true) && m_client.Connected) { ClientLoop(); } else { CrowdControlMod.Instance.Logger.LogInfo((object)"Failed to connect to Crowd Control"); } } catch (Exception ex) { if (!IsBenignShutdownException(ex, m_quitting.IsCancellationRequested)) { CrowdControlMod.Instance.Logger.LogError((object)ex); CrowdControlMod.Instance.Logger.LogError((object)"Failed to connect to Crowd Control"); } } finally { try { m_client?.Close(); } catch { } } if (!m_quitting.IsCancellationRequested) { m_quitting.Token.WaitHandle.WaitOne((TimeSpan)TIMEOUT_NO_CONNECTION); continue; } break; } } private void MaintenanceLoop() { Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; while (!m_quitting.IsCancellationRequested) { try { if (!m_disposed) { TcpClient? client = m_client; if (client != null && client.Connected) { KeepAlive(); } } } catch { } m_quitting.Token.WaitHandle.WaitOne(2000); } } private void ClientLoop() { Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; try { m_streamReader = new DelimitedStreamReader(m_client.GetStream()); CrowdControlMod.Instance.Logger.LogInfo((object)"Connected to Crowd Control"); m_mod.QueueCrowdControlGameStateResync(); try { while (!m_quitting.IsCancellationRequested) { string text = m_streamReader.ReadUntilNullTerminator(); OnMessage(text.Trim()); } } catch (EndOfStreamException) { if (!m_quitting.IsCancellationRequested) { CrowdControlMod.Instance.Logger.LogInfo((object)"Disconnected from Crowd Control"); } } catch (Exception ex2) { if (!IsBenignShutdownException(ex2, m_quitting.IsCancellationRequested)) { CrowdControlMod.Instance.Logger.LogError((object)ex2); CrowdControlMod.Instance.Logger.LogError((object)"Disconnected from Crowd Control"); } } } finally { try { m_client?.Close(); } catch { } try { m_streamReader?.Dispose(); m_streamReader = null; } catch { } } } private void OnMessage(string message) { if (m_disposed || m_quitting.IsCancellationRequested || string.IsNullOrWhiteSpace(message)) { return; } try { SimpleJSONRequest request = default(SimpleJSONRequest); if (SimpleJSONRequest.TryParse(message, ref request)) { m_mod.Scheduler.ProcessRequest(request); } } catch (Exception ex) { CrowdControlMod.Instance.Logger.LogError((object)ex); } } private static bool IsCrowdControlSemaphorePresent() { Semaphore result; return Semaphore.TryOpenExisting("CrowdControl", out result); } private static bool IsCrowdControlProcessRunning() { checked { try { Process[] processes = Process.GetProcesses(); int num = 0; int num2 = 0; Process[] array = processes; foreach (Process process in array) { try { if (process.ProcessName.IndexOf("crowdcontrol", StringComparison.OrdinalIgnoreCase) >= 0) { CrowdControlMod.Instance.Logger.LogMessage((object)$"Found CrowdControl process: {process.ProcessName} (PID: {process.Id})"); return true; } num++; } catch (UnauthorizedAccessException) { num2++; } catch (Exception ex2) { CrowdControlMod.Instance.Logger.LogMessage((object)("Could not access process: " + ex2.Message)); num2++; } } if (num2 > 0) { CrowdControlMod.Instance.Logger.LogMessage((object)$"Found {num2} inaccessible processes (possibly running with different privileges). Attempting connection anyway."); return true; } return false; } catch (Exception ex3) { CrowdControlMod.Instance.Logger.LogMessage((object)("Error checking for CrowdControl processes: " + ex3.Message)); return true; } } } public bool Send(SimpleJSONResponse? response) { try { if (response == null || m_disposed || m_quitting.IsCancellationRequested) { return false; } if (!Connected) { return false; } byte[] bytes = Encoding.UTF8.GetBytes(((SimpleJSONMessage)response).Serialize()); int num = 0; byte[] array = new byte[1 + bytes.Length]; ReadOnlySpan readOnlySpan = new ReadOnlySpan(bytes); readOnlySpan.CopyTo(new Span(array).Slice(num, readOnlySpan.Length)); num += readOnlySpan.Length; array[num] = 0; byte[] array2 = array; m_client.GetStream().Write(array2, 0, array2.Length); return true; } catch (Exception ex) { if (!IsBenignShutdownException(ex, m_quitting.IsCancellationRequested)) { CrowdControlMod.Instance.Logger.LogError((object)$"Error sending a message to the Crowd Control client: {ex}"); } return false; } } public Task SendAsync(SimpleJSONResponse? response) { SimpleJSONResponse response2 = response; return Task.Run(() => Send(response2)); } public void Stop(string? message = null) { //IL_000f: 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_001a: 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_002b: Expected O, but got Unknown if (!m_disposed) { if (message != null) { Send((SimpleJSONResponse?)new MessageResponse { type = (ResponseType)254, message = message }); } m_client?.Close(); } } public Task StopAsync(string? message = null) { string message2 = message; return Task.Run(delegate { Stop(message2); }); } public bool KeepAlive() { return Send((SimpleJSONResponse?)(object)KEEPALIVE); } public Task KeepAliveAsync() { return Task.Run((Func)KeepAlive); } public void AttachMetadata(EffectResponse response) { response.metadata = new Dictionary(); string[] commonMetadata = MetadataDelegates.CommonMetadata; foreach (string text in commonMetadata) { if (MetadataLoader.Metadata.TryGetValue(text, out MetadataDelegate value)) { response.metadata.Add(text, value(m_mod)); } else { CrowdControlMod.Instance.Logger.LogError((object)("Metadata delegate \"" + text + "\" could not be found. Available delegates: " + string.Join(", ", MetadataLoader.Metadata.Keys))); } } } public bool ShowEffects(params string[] codes) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown return Send((SimpleJSONResponse?)new EffectUpdate(codes, (EffectStatus)128, (string)null)); } public bool ShowEffects([ParamCollection] IEnumerable codes) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown return Send((SimpleJSONResponse?)new EffectUpdate(codes, (EffectStatus)128, (string)null)); } public Task ShowEffectsAsync(params string[] codes) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown return SendAsync((SimpleJSONResponse?)new EffectUpdate(codes, (EffectStatus)128, (string)null)); } public Task ShowEffectsAsync([ParamCollection] IEnumerable codes) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown return SendAsync((SimpleJSONResponse?)new EffectUpdate(codes, (EffectStatus)128, (string)null)); } public bool ShowAllEffects() { return ShowEffects(m_mod.EffectLoader.Effects.Keys); } public Task ShowAllEffectsAsync() { return ShowEffectsAsync(m_mod.EffectLoader.Effects.Keys); } public bool HideEffects(params string[] codes) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown return Send((SimpleJSONResponse?)new EffectUpdate(codes, (EffectStatus)129, (string)null)); } public bool HideEffects([ParamCollection] IEnumerable codes) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown return Send((SimpleJSONResponse?)new EffectUpdate(codes, (EffectStatus)129, (string)null)); } public Task HideEffectsAsync(params string[] codes) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown return SendAsync((SimpleJSONResponse?)new EffectUpdate(codes, (EffectStatus)129, (string)null)); } public Task HideEffectsAsync([ParamCollection] IEnumerable codes) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown return SendAsync((SimpleJSONResponse?)new EffectUpdate(codes, (EffectStatus)129, (string)null)); } public bool HideAllEffects() { return HideEffects(m_mod.EffectLoader.Effects.Keys); } public Task HideAllEffectsAsync() { return HideEffectsAsync(m_mod.EffectLoader.Effects.Keys); } public bool EnableEffects(params string[] codes) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown return Send((SimpleJSONResponse?)new EffectUpdate(codes, (EffectStatus)130, (string)null)); } public bool EnableEffects([ParamCollection] IEnumerable codes) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown return Send((SimpleJSONResponse?)new EffectUpdate(codes, (EffectStatus)130, (string)null)); } public Task EnableEffectsAsync(params string[] codes) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown return SendAsync((SimpleJSONResponse?)new EffectUpdate(codes, (EffectStatus)130, (string)null)); } public Task EnableEffectsAsync([ParamCollection] IEnumerable codes) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown return SendAsync((SimpleJSONResponse?)new EffectUpdate(codes, (EffectStatus)130, (string)null)); } public bool EnableAllEffects() { return ShowEffects(m_mod.EffectLoader.Effects.Keys); } public Task EnableAllEffectsAsync() { return ShowEffectsAsync(m_mod.EffectLoader.Effects.Keys); } public bool DisableEffects(params string[] codes) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown return Send((SimpleJSONResponse?)new EffectUpdate(codes, (EffectStatus)131, (string)null)); } public bool DisableEffects([ParamCollection] IEnumerable codes) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown return Send((SimpleJSONResponse?)new EffectUpdate(codes, (EffectStatus)131, (string)null)); } public Task DisableEffectsAsync(params string[] codes) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown return SendAsync((SimpleJSONResponse?)new EffectUpdate(codes, (EffectStatus)131, (string)null)); } public Task DisableEffectsAsync([ParamCollection] IEnumerable codes) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown return SendAsync((SimpleJSONResponse?)new EffectUpdate(codes, (EffectStatus)131, (string)null)); } public bool DisableAllEffects() { return ShowEffects(m_mod.EffectLoader.Effects.Keys); } public Task DisableAllEffectsAsync() { return ShowEffectsAsync(m_mod.EffectLoader.Effects.Keys); } } internal static class PlayerCustomizationRpcBridge { private static readonly MethodInfo? MiRpcChangeCustomization = typeof(PlayerCustomization).GetMethod("RpcChangeCustomization", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly MethodInfo? MiRpcResetCustomization = typeof(PlayerCustomization).GetMethod("RpcResetCustomization", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly MethodInfo? MiRpcClearCategory = typeof(PlayerCustomization).GetMethod("RpcClearCategory", BindingFlags.Instance | BindingFlags.NonPublic); internal static bool IsSupported { get { if (MiRpcChangeCustomization != null && MiRpcResetCustomization != null) { return MiRpcClearCategory != null; } return false; } } internal static void RpcChangeCustomization(PlayerCustomization pc, int cosmeticId, bool shouldSave) { if (MiRpcChangeCustomization == null) { throw new InvalidOperationException("RpcChangeCustomization not found on PlayerCustomization."); } MiRpcChangeCustomization.Invoke(pc, new object[2] { cosmeticId, shouldSave }); } internal static void RpcResetCustomization(PlayerCustomization pc) { if (MiRpcResetCustomization == null) { throw new InvalidOperationException("RpcResetCustomization not found on PlayerCustomization."); } MiRpcResetCustomization.Invoke(pc, Array.Empty()); } internal static void RpcClearCategory(PlayerCustomization pc, CosmeticType category) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (MiRpcClearCategory == null) { throw new InvalidOperationException("RpcClearCategory not found on PlayerCustomization."); } MiRpcClearCategory.Invoke(pc, new object[1] { category }); } } internal static class ReflectionEx { private const BindingFlags BINDING_FLAGS = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; public static void SetField(this object obj, string prop, object val) { obj.GetType().GetField(prop, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).SetValue(obj, val); } public static T GetField(this object obj, string prop) { return (T)obj.GetType().GetField(prop, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue(obj); } public static void SetProperty(this object obj, string prop, object val) { obj.GetType().GetField(prop, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).SetValue(obj, val); } public static T GetProperty(this object obj, string prop) { return (T)obj.GetType().GetField(prop, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue(obj); } public static void CallMethod(this object obj, string methodName, params object[] vals) { obj.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Invoke(obj, vals); } public static T CallMethod(this object obj, string methodName, params object[] vals) { return (T)obj.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Invoke(obj, vals); } } public class Scheduler { private class RequestState { private IEnumerator? m_enumerator; public EffectRequest Request { get; } public Effect Effect { get; } public TimedEffectState? TimedEffectState { get; } public bool MoveNext() { if (m_enumerator != null) { if (m_enumerator.MoveNext()) { return true; } (m_enumerator as IDisposable)?.Dispose(); m_enumerator = null; } switch (TimedEffectState?.State) { case CrowdControl.Delegates.Effects.TimedEffectState.EffectState.NotStarted: if (m_enumerator == null) { m_enumerator = TimedEffectState.Start(); } m_enumerator.MoveNext(); return true; case CrowdControl.Delegates.Effects.TimedEffectState.EffectState.Running: case CrowdControl.Delegates.Effects.TimedEffectState.EffectState.Paused: if (m_enumerator == null) { m_enumerator = TimedEffectState.Tick(); } m_enumerator.MoveNext(); return true; default: return false; } } public void Pause() { (m_enumerator as IDisposable)?.Dispose(); m_enumerator = null; TimedEffectState.EffectState? effectState = TimedEffectState?.State; if (effectState.HasValue && effectState.GetValueOrDefault() == CrowdControl.Delegates.Effects.TimedEffectState.EffectState.Running) { m_enumerator = TimedEffectState.Pause(); } } public void Resume() { (m_enumerator as IDisposable)?.Dispose(); m_enumerator = null; TimedEffectState.EffectState? effectState = TimedEffectState?.State; if (effectState.HasValue && effectState.GetValueOrDefault() == CrowdControl.Delegates.Effects.TimedEffectState.EffectState.Paused) { m_enumerator = TimedEffectState.Resume(); } } public void Stop() { (m_enumerator as IDisposable)?.Dispose(); m_enumerator = null; TimedEffectState.EffectState? effectState = TimedEffectState?.State; if (effectState.HasValue) { TimedEffectState.EffectState valueOrDefault = effectState.GetValueOrDefault(); if ((uint)(valueOrDefault - 1) <= 1u) { m_enumerator = TimedEffectState.Stop(); } } } public RequestState(EffectRequest request, Effect effect) { Request = request; Effect = effect; if (Effect.IsTimed) { long num = request.duration.GetValueOrDefault(); if (num <= 0) { num = checked((long)effect.EffectAttribute.DefaultDuration.TotalMilliseconds); } TimedEffectState = new TimedEffectState(effect, request, SITimeSpan.FromMilliseconds(num)); } } } private CrowdControlMod m_mod; private NetworkClient m_networkClient; private readonly ConcurrentQueue m_requestQueue; private readonly ConcurrentDictionary m_runningEffects; private RequestState? m_blockingHostRelay; private float m_blockingHostRelayElapsed; private float m_nextFocusHoldLogUnscaled; public Scheduler(CrowdControlMod mod, NetworkClient networkClient) { m_mod = mod; m_networkClient = networkClient; m_requestQueue = new ConcurrentQueue(); m_runningEffects = new ConcurrentDictionary(); base..ctor(); } public bool IsRunning(string id) { foreach (RequestState item in m_requestQueue) { TimedEffectState timedEffectState = item.TimedEffectState; if (timedEffectState != null && timedEffectState.Effect.EffectAttribute.IDs.Contains(id)) { return true; } } bool flag; foreach (RequestState value in m_runningEffects.Values) { TimedEffectState timedEffectState2 = value.TimedEffectState; if (timedEffectState2 != null) { TimedEffectState.EffectState state = timedEffectState2.State; flag = (uint)(state - 3) <= 1u; if (!flag && value.Effect.EffectAttribute.IDs.Contains(id)) { return true; } } } TimedEffectState timedEffectState3 = m_blockingHostRelay?.TimedEffectState; flag = timedEffectState3 != null; if (flag) { TimedEffectState.EffectState state = timedEffectState3.State; bool flag2 = (uint)(state - 3) <= 1u; flag = !flag2; } if (flag && m_blockingHostRelay.Effect.EffectAttribute.IDs.Contains(id)) { return true; } return false; } private static bool IsTimedSlotActive(TimedEffectState? tes) { TimedEffectState.EffectState? effectState = tes?.State; if (effectState.HasValue) { TimedEffectState.EffectState valueOrDefault = effectState.GetValueOrDefault(); if ((uint)valueOrDefault <= 2u) { return true; } } return false; } private bool HasActiveTimedConflict(Effect effect) { IReadOnlyList conflicts = effect.EffectAttribute.Conflicts; if (conflicts.Count == 0) { return false; } foreach (RequestState value in m_runningEffects.Values) { if (!IsTimedSlotActive(value.TimedEffectState)) { continue; } foreach (string iD in value.Effect.EffectAttribute.IDs) { if (conflicts.Contains(iD, StringComparer.Ordinal)) { return true; } } } TimedEffectState timedEffectState = m_blockingHostRelay?.TimedEffectState; if (timedEffectState != null && IsTimedSlotActive(timedEffectState)) { foreach (string iD2 in m_blockingHostRelay.Effect.EffectAttribute.IDs) { if (conflicts.Contains(iD2, StringComparer.Ordinal)) { return true; } } } return false; } public void ProcessRequest(SimpleJSONRequest? request) { //IL_0010: 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_002e: 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_0043: Expected I4, but got Unknown //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Invalid comparison between Unknown and I4 //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Expected O, but got Unknown //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Expected O, but got Unknown //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Expected O, but got Unknown RequestType? val = request?.type; if (!val.HasValue) { return; } RequestType valueOrDefault = val.GetValueOrDefault(); switch ((int)valueOrDefault) { default: if ((int)valueOrDefault == 253) { m_mod.GameStateManager.UpdateGameState(force: true); } break; case 0: { EffectRequest val5 = (EffectRequest)(object)((request is EffectRequest) ? request : null); if (val5 != null) { EffectRequest val4 = val5; if (val4.code == null) { val4.code = string.Empty; } string message; if (!m_mod.EffectLoader.Effects.ContainsKey(val5.code)) { m_networkClient.Send((SimpleJSONResponse?)new EffectResponse(((SimpleJSONRequest)val5).id, (EffectStatus)2, (StandardErrors)4097)); CrowdControlMod.Instance.Logger.LogError((object)string.Format("{0} (unknown code: '{1}').", (object)(StandardErrors)4097, val5.code ?? "(null)")); } else if (m_mod.GameStateManager.ShouldRejectCasinoOnlyOutsidePlay(val5.code, out message)) { m_networkClient.Send((SimpleJSONResponse?)(object)EffectResponse.Failure(((SimpleJSONRequest)val5).id, message)); } else { m_networkClient.Send((SimpleJSONResponse?)new EffectResponse(((SimpleJSONRequest)val5).id, (EffectStatus)((!m_mod.GameStateManager.IsReady(val5.code)) ? 1 : 0))); } } break; } case 1: { EffectRequest val3 = (EffectRequest)(object)((request is EffectRequest) ? request : null); if (val3 != null) { EffectRequest val4 = val3; if (val4.code == null) { val4.code = string.Empty; } if (!m_mod.EffectLoader.Effects.TryGetValue(val3.code, out Effect value2)) { m_networkClient.Send((SimpleJSONResponse?)new EffectResponse(((SimpleJSONRequest)val3).id, (EffectStatus)2, (StandardErrors)4097)); CrowdControlMod.Instance.Logger.LogError((object)string.Format("{0} (unknown code: '{1}').", (object)(StandardErrors)4097, val3.code ?? "(null)")); } else { m_requestQueue.Enqueue(new RequestState(val3, value2)); } } break; } case 2: { EffectRequest val2 = (EffectRequest)(object)((request is EffectRequest) ? request : null); if (val2 != null) { if (!m_runningEffects.TryGetValue(((SimpleJSONRequest)val2).id, out RequestState value)) { m_networkClient.Send((SimpleJSONResponse?)new EffectResponse(((SimpleJSONRequest)val2).id, (EffectStatus)1, (StandardErrors)16899)); CrowdControlMod.Instance.Logger.LogError((object)(StandardErrors)16899); } else { value.Stop(); } } break; } } } public void Enqueue(EffectRequest request, Effect effect) { m_requestQueue.Enqueue(new RequestState(request, effect)); } public void PauseAll() { foreach (KeyValuePair runningEffect in m_runningEffects) { runningEffect.Value.Pause(); } } public void ResumeAll() { foreach (KeyValuePair runningEffect in m_runningEffects) { runningEffect.Value.Resume(); } } public void Tick() { //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Expected O, but got Unknown //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Expected O, but got Unknown ProcessBlockingHostRelay(); RequestState result; while (m_blockingHostRelay == null && m_requestQueue.TryPeek(out result)) { if (!Application.isFocused) { if (Time.unscaledTime >= m_nextFocusHoldLogUnscaled) { m_nextFocusHoldLogUnscaled = Time.unscaledTime + 2f; GameStateManager.LogCrowdControl("Effects paused (window not focused / alt-tab). Crowd Control state: NotFocused — effect queue will resume when the window regains focus."); } break; } if (!m_requestQueue.TryDequeue(out RequestState result2) || result2 != result) { break; } string code = result2.Request.code ?? string.Empty; CrowdControlHostCcEffectCode effectCode2; if (m_mod.GameStateManager.ShouldRejectCasinoOnlyOutsidePlay(code, out string message)) { m_networkClient.SendAsync((SimpleJSONResponse?)(object)EffectResponse.Failure(((SimpleJSONRequest)result2.Request).id, message)).Forget(); } else if (!m_mod.GameStateManager.IsReady(code)) { m_networkClient.SendAsync((SimpleJSONResponse?)new EffectResponse(((SimpleJSONRequest)result2.Request).id, (EffectStatus)3)).Forget(); } else if (result.TimedEffectState != null) { CrowdControlHostCcEffectCode effectCode; if (HasActiveTimedConflict(result.Effect)) { m_networkClient.SendAsync((SimpleJSONResponse?)new EffectResponse(((SimpleJSONRequest)result.Request).id, (EffectStatus)1, (StandardErrors)32768)).Forget(); } else if (!NetworkServer.active && CrowdControlHostCcRelay.NeedsRelayHost(code) && CrowdControlHostCcRelay.TryMapCode(code, out effectCode)) { float durationSeconds = (float)result.TimedEffectState.Duration.TotalSeconds; if (CrowdControlHostCcRelay.ClientSendTimedStart(effectCode, ((SimpleJSONRequest)result.Request).id, durationSeconds)) { m_blockingHostRelay = result; m_blockingHostRelayElapsed = 0f; break; } m_networkClient.SendAsync((SimpleJSONResponse?)(object)EffectResponse.Failure(((SimpleJSONRequest)result.Request).id, (StandardErrors)16384)).Forget(); } else { m_runningEffects.TryAdd(((SimpleJSONRequest)result.Request).id, result); } } else if (!NetworkServer.active && CrowdControlHostCcRelay.NeedsRelayHost(code) && CrowdControlHostCcRelay.TryMapCode(code, out effectCode2)) { if (CrowdControlHostCcRelay.ClientSendInstant(effectCode2, ((SimpleJSONRequest)result.Request).id)) { m_blockingHostRelay = result; m_blockingHostRelayElapsed = 0f; break; } m_networkClient.SendAsync((SimpleJSONResponse?)(object)EffectResponse.Failure(((SimpleJSONRequest)result.Request).id, (StandardErrors)16384)).Forget(); } else { EffectResponse response; try { response = result.Effect.Start(result.Request); } catch (Exception ex) { response = EffectResponse.Failure(((SimpleJSONRequest)result.Request).id, (StandardErrors)1); CrowdControlMod.Instance.Logger.LogError((object)ex.Message); } m_networkClient.AttachMetadata(response); CrowdControlEffectHud.NotifyInstant(result.Request.code, response); m_networkClient.SendAsync((SimpleJSONResponse?)(object)response).Forget(); } } ConsumeEnumerators(); } private void ProcessBlockingHostRelay() { if (m_blockingHostRelay != null) { m_blockingHostRelayElapsed += CrowdControlMod.DeltaTime; uint id = ((SimpleJSONRequest)m_blockingHostRelay.Request).id; if (CrowdControlHostCcRelay.TryConsumeResponse(id, out EffectResponse response)) { FinishBlockingHostRelay(response); m_blockingHostRelay = null; m_blockingHostRelayElapsed = 0f; } else if (m_blockingHostRelayElapsed > 6f) { CrowdControlHostCcRelay.ClearPending(id); FinishBlockingHostRelay(EffectResponse.Failure(id, (StandardErrors)12291)); m_blockingHostRelay = null; m_blockingHostRelayElapsed = 0f; } } } private void FinishBlockingHostRelay(EffectResponse relayResponse) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) RequestState blockingHostRelay = m_blockingHostRelay; if (blockingHostRelay.TimedEffectState == null) { m_networkClient.AttachMetadata(relayResponse); CrowdControlEffectHud.NotifyInstant(blockingHostRelay.Request.code, relayResponse); m_networkClient.SendAsync((SimpleJSONResponse?)(object)relayResponse).Forget(); } else if ((int)relayResponse.status != 0) { m_networkClient.SendAsync((SimpleJSONResponse?)(object)relayResponse).Forget(); } else { m_runningEffects.TryAdd(((SimpleJSONRequest)blockingHostRelay.Request).id, blockingHostRelay); } } private void ConsumeEnumerators() { foreach (KeyValuePair runningEffect in m_runningEffects) { if (!runningEffect.Value.MoveNext()) { m_runningEffects.TryRemove(runningEffect.Key, out RequestState _); } } } } [Serializable] [JsonConverter(typeof(Converter))] public struct SITimeSpan : IEquatable, IEquatable, IEquatable, IComparable, IComparable, IComparable, IFormattable { private class Converter : JsonConverter { public override void WriteJson(JsonWriter writer, SITimeSpan value, JsonSerializer serializer) { writer.WriteValue(value._value.TotalSeconds); } public override SITimeSpan ReadJson(JsonReader reader, Type objectType, SITimeSpan existingValue, bool hasExistingValue, JsonSerializer serializer) { if (reader.Value is TimeSpan timeSpan) { return timeSpan; } if (reader.Value is string s) { if (TimeSpan.TryParse(s, out var result)) { return result; } if (double.TryParse(s, out var result2)) { return result2; } } return Convert.ToDouble(reader.Value); } } public static readonly SITimeSpan Zero = new SITimeSpan(TimeSpan.Zero); public static readonly SITimeSpan MinValue = new SITimeSpan(TimeSpan.MinValue); public static readonly SITimeSpan MaxValue = new SITimeSpan(TimeSpan.MaxValue); private readonly TimeSpan _value; public long Ticks => _value.Ticks; public int Milliseconds => _value.Milliseconds; public int Seconds => _value.Seconds; public int Minutes => _value.Minutes; public int Hours => _value.Hours; public int Days => _value.Days; public double TotalMilliseconds => _value.TotalMilliseconds; public double TotalSeconds => _value.TotalSeconds; public double TotalMinutes => _value.TotalMinutes; public double TotalHours => _value.TotalHours; public double TotalDays => _value.TotalDays; public override string ToString() { return _value.ToString(); } public string ToString(string? format) { return _value.ToString(format); } public string ToString(string? format, IFormatProvider? formatProvider) { return _value.ToString(format, formatProvider); } public static SITimeSpan Parse(string input) { if (input.Contains('.')) { return new SITimeSpan(TimeSpan.ParseExact(input, "mm\\:ss\\.fff", null)); } return new SITimeSpan(TimeSpan.Parse(input)); } public static bool TryParse(string s, out SITimeSpan result) { TimeSpan result2; bool result3 = TimeSpan.TryParse(s, out result2); result = new SITimeSpan(result2); return result3; } public static int Compare(SITimeSpan t1, SITimeSpan t2) { return TimeSpan.Compare(t1._value, t2._value); } public static int Compare(TimeSpan t1, SITimeSpan t2) { return TimeSpan.Compare(t1, t2._value); } public static int Compare(SITimeSpan t1, TimeSpan t2) { return TimeSpan.Compare(t1._value, t2); } public static int Compare(double t1, SITimeSpan t2) { if (t1 > t2.TotalSeconds) { return 1; } if (!(t1 < t2.TotalSeconds)) { return 0; } return -1; } public static int Compare(SITimeSpan t1, double t2) { if (t1.TotalSeconds > t2) { return 1; } if (!(t1.TotalSeconds < t2)) { return 0; } return -1; } public static bool Equals(SITimeSpan t1, SITimeSpan t2) { return TimeSpan.Equals(t1._value, t2._value); } public static bool Equals(TimeSpan t1, SITimeSpan t2) { return TimeSpan.Equals(t1, t2._value); } public static bool Equals(SITimeSpan t1, TimeSpan t2) { return TimeSpan.Equals(t1._value, t2); } public static bool Equals(double t1, SITimeSpan t2) { return object.Equals(t1, (double)t2); } public static bool Equals(SITimeSpan t1, double t2) { return object.Equals((double)t1, t2); } public static SITimeSpan FromTicks(long value) { return new SITimeSpan(TimeSpan.FromTicks(value)); } public static SITimeSpan FromMilliseconds(double value) { return new SITimeSpan(TimeSpan.FromMilliseconds(value)); } public static SITimeSpan FromSeconds(double value) { return new SITimeSpan(TimeSpan.FromSeconds(value)); } public static SITimeSpan FromMinutes(double value) { return new SITimeSpan(TimeSpan.FromMinutes(value)); } public static SITimeSpan FromHours(double value) { return new SITimeSpan(TimeSpan.FromHours(value)); } public static SITimeSpan FromDays(double value) { return new SITimeSpan(TimeSpan.FromDays(value)); } public SITimeSpan Duration() { return new SITimeSpan(_value.Duration()); } public SITimeSpan Add(SITimeSpan other) { return new SITimeSpan(_value.Add(other._value)); } public SITimeSpan Subtract(SITimeSpan other) { return new SITimeSpan(_value.Subtract(other._value)); } public SITimeSpan Negate() { return new SITimeSpan(_value.Negate()); } private SITimeSpan(TimeSpan value) { _value = value; } private SITimeSpan(double value) { _value = TimeSpan.FromSeconds(value); } private SITimeSpan(long value) { _value = TimeSpan.FromSeconds(value); } public SITimeSpan? NullIfZero() { if (!(_value == TimeSpan.Zero)) { return this; } return null; } public static implicit operator SITimeSpan(double value) { return new SITimeSpan(value); } public static implicit operator SITimeSpan?(double? value) { if (!value.HasValue) { return null; } return new SITimeSpan(value.Value); } public static implicit operator SITimeSpan(TimeSpan value) { return new SITimeSpan(value); } public static implicit operator SITimeSpan?(TimeSpan? value) { if (!value.HasValue) { return null; } return new SITimeSpan(value.Value); } public static implicit operator SITimeSpan(Func value) { return new SITimeSpan(value()); } public static implicit operator SITimeSpan?(Func? value) { if (value == null) { return null; } return new SITimeSpan(value()); } public static implicit operator SITimeSpan(Func value) { return new SITimeSpan(value()._value); } public static implicit operator SITimeSpan?(Func? value) { if (value == null) { return null; } return new SITimeSpan(value()._value); } public static explicit operator double(SITimeSpan value) { return value._value.TotalSeconds; } public static explicit operator double?(SITimeSpan? value) { return value?._value.TotalSeconds; } public static explicit operator float(SITimeSpan value) { return (float)value._value.TotalSeconds; } public static explicit operator float?(SITimeSpan? value) { return (float?)value?._value.TotalSeconds; } public static explicit operator long(SITimeSpan value) { return checked((long)value._value.TotalSeconds); } public static explicit operator long?(SITimeSpan? value) { return checked((long?)value?._value.TotalSeconds); } public static explicit operator TimeSpan(SITimeSpan value) { return value._value; } public static explicit operator TimeSpan?(SITimeSpan? value) { return value?._value; } public static explicit operator Func(SITimeSpan value) { return () => value._value; } public static explicit operator Func(SITimeSpan? value) { return () => value?._value; } public static explicit operator Func(SITimeSpan value) { return () => value; } public static explicit operator Func(SITimeSpan? value) { return () => value; } public override bool Equals(object? obj) { if (obj is SITimeSpan other) { return Equals(other); } if (obj is TimeSpan other2) { return Equals(other2); } if (obj is double other3) { return Equals(other3); } return false; } public override int GetHashCode() { return _value.GetHashCode(); } public bool Equals(SITimeSpan other) { return _value.Equals(other._value); } public int CompareTo(SITimeSpan other) { return _value.CompareTo(other._value); } public static bool operator ==(SITimeSpan a, SITimeSpan b) { return a._value.Equals(b._value); } public static bool operator !=(SITimeSpan a, SITimeSpan b) { return !a._value.Equals(b._value); } public static bool operator <(SITimeSpan a, SITimeSpan b) { return a._value < b._value; } public static bool operator <=(SITimeSpan a, SITimeSpan b) { return a._value <= b._value; } public static bool operator >(SITimeSpan a, SITimeSpan b) { return a._value > b._value; } public static bool operator >=(SITimeSpan a, SITimeSpan b) { return a._value >= b._value; } public bool Equals(TimeSpan other) { return _value.Equals(other); } public int CompareTo(TimeSpan other) { return _value.CompareTo(other); } public static bool operator ==(SITimeSpan a, TimeSpan b) { return a.Equals(b); } public static bool operator ==(TimeSpan a, SITimeSpan b) { return b.Equals(a); } public static bool operator !=(SITimeSpan a, TimeSpan b) { return !a.Equals(b); } public static bool operator !=(TimeSpan a, SITimeSpan b) { return !b.Equals(a); } public static bool operator <(SITimeSpan a, TimeSpan b) { return a._value < b; } public static bool operator <(TimeSpan a, SITimeSpan b) { return a < b._value; } public static bool operator <=(SITimeSpan a, TimeSpan b) { return a._value <= b; } public static bool operator <=(TimeSpan a, SITimeSpan b) { return a <= b._value; } public static bool operator >(SITimeSpan a, TimeSpan b) { return a._value > b; } public static bool operator >(TimeSpan a, SITimeSpan b) { return a > b._value; } public static bool operator >=(SITimeSpan a, TimeSpan b) { return a._value >= b; } public static bool operator >=(TimeSpan a, SITimeSpan b) { return a >= b._value; } public static SITimeSpan operator -(SITimeSpan a) { return -a._value; } public static SITimeSpan operator +(TimeSpan a, SITimeSpan b) { return a + b._value; } public static SITimeSpan operator -(TimeSpan a, SITimeSpan b) { return a - b._value; } public static SITimeSpan operator +(SITimeSpan a, TimeSpan b) { return a._value + b; } public static SITimeSpan operator -(SITimeSpan a, TimeSpan b) { return a._value - b; } public static SITimeSpan operator +(SITimeSpan a, SITimeSpan b) { return a._value + b._value; } public static SITimeSpan operator -(SITimeSpan a, SITimeSpan b) { return a._value - b._value; } public static DateTime operator +(DateTime a, SITimeSpan b) { return a + b._value; } public static DateTime operator -(DateTime a, SITimeSpan b) { return a - b._value; } public static DateTimeOffset operator +(DateTimeOffset a, SITimeSpan b) { return a + b._value; } public static DateTimeOffset operator -(DateTimeOffset a, SITimeSpan b) { return a - b._value; } public static SITimeSpan operator +(double a, SITimeSpan b) { return a + b._value.TotalSeconds; } public static SITimeSpan operator -(double a, SITimeSpan b) { return a - b._value.TotalSeconds; } public static SITimeSpan operator *(double a, SITimeSpan b) { return a * b._value.TotalSeconds; } public static SITimeSpan operator +(SITimeSpan a, double b) { return a._value.TotalSeconds + b; } public static SITimeSpan operator -(SITimeSpan a, double b) { return a._value.TotalSeconds - b; } public static SITimeSpan operator *(SITimeSpan a, double b) { return a._value.TotalSeconds * b; } public static SITimeSpan operator /(SITimeSpan a, double b) { return a._value.TotalSeconds / b; } public static SITimeSpan operator %(SITimeSpan a, double b) { return a._value.TotalSeconds % b; } public bool Equals(double other) { return _value.TotalSeconds.Equals(other); } public int CompareTo(double other) { return _value.TotalSeconds.CompareTo(other); } public static bool operator ==(SITimeSpan a, double b) { return a.Equals(b); } public static bool operator ==(double a, SITimeSpan b) { return b.Equals(a); } public static bool operator !=(SITimeSpan a, double b) { return !a.Equals(b); } public static bool operator !=(double a, SITimeSpan b) { return !b.Equals(a); } public static bool operator <(SITimeSpan a, double b) { return a._value.TotalSeconds < b; } public static bool operator <(double a, SITimeSpan b) { return a < b._value.TotalSeconds; } public static bool operator <=(SITimeSpan a, double b) { return a._value.TotalSeconds <= b; } public static bool operator >=(SITimeSpan a, double b) { return a._value.TotalSeconds >= b; } public static bool operator >(SITimeSpan a, double b) { return a._value.TotalSeconds > b; } public static bool operator >(double a, SITimeSpan b) { return a > b._value.TotalSeconds; } public static bool operator <=(double a, SITimeSpan b) { return a <= b._value.TotalSeconds; } public static bool operator >=(double a, SITimeSpan b) { return a >= b._value.TotalSeconds; } } public static class TaskEx { public static async void Forget(this Task task) { try { await task.ConfigureAwait(continueOnCapturedContext: false); } catch (Exception ex) { CrowdControlMod.Instance.Logger.LogError((object)ex); } } public static async void Forget(this Task task, bool silent) { try { await task.ConfigureAwait(continueOnCapturedContext: false); } catch (Exception ex) { if (!silent) { CrowdControlMod.Instance.Logger.LogError((object)ex); } } } } } namespace CrowdControl.Patches { [HarmonyPatch(typeof(CustomNetworkManager), "OnStartServer")] internal static class CustomNetworkManager_OnStartServer_CrowdControlNet { private static void Postfix() { CrowdControlItemNetwork.RegisterServerHandlerIfNeeded(); CrowdControlStreamerEffectNetwork.RegisterServerHandlerIfNeeded(); CrowdControlHostCcRelay.RegisterServerHandlerIfNeeded(); CrowdControlGlobalHudMirrorNetwork.RegisterServerHandlerIfNeeded(); } } [HarmonyPatch(typeof(CustomNetworkManager), "OnStopServer")] internal static class CustomNetworkManager_OnStopServer_CrowdControlNet { private static void Postfix() { CrowdControlItemNetwork.UnregisterServerHandlerIfNeeded(); CrowdControlStreamerEffectNetwork.UnregisterServerHandlerIfNeeded(); CrowdControlHostCcRelay.UnregisterServerHandlerIfNeeded(); CrowdControlGlobalHudMirrorNetwork.UnregisterServerHandlerIfNeeded(); } } [HarmonyPatch(typeof(CustomNetworkManager), "OnClientConnect")] internal static class CustomNetworkManager_OnClientConnect_CrowdControlNet { private static void Postfix() { CrowdControlHostCcRelay.RegisterClientResponseHandlerIfNeeded(); CrowdControlGlobalTimedHud.InstallClientHandlerIfNeeded(); } } [HarmonyPatch(typeof(NetworkManager), "OnStartServer")] internal static class NetworkManager_OnStartServer_CrowdControlItemNet { private static void Postfix() { CrowdControlItemNetwork.RegisterServerHandlerIfNeeded(); CrowdControlStreamerEffectNetwork.RegisterServerHandlerIfNeeded(); CrowdControlHostCcRelay.RegisterServerHandlerIfNeeded(); CrowdControlGlobalHudMirrorNetwork.RegisterServerHandlerIfNeeded(); } } [HarmonyPatch(typeof(NetworkManager), "OnStopServer")] internal static class NetworkManager_OnStopServer_CrowdControlItemNet { private static void Postfix() { CrowdControlItemNetwork.UnregisterServerHandlerIfNeeded(); CrowdControlStreamerEffectNetwork.UnregisterServerHandlerIfNeeded(); CrowdControlHostCcRelay.UnregisterServerHandlerIfNeeded(); CrowdControlGlobalHudMirrorNetwork.UnregisterServerHandlerIfNeeded(); } } [HarmonyPatch(typeof(NetworkManager), "OnStartClient")] internal static class NetworkManager_OnStartClient_CrowdControlNet { private static void Postfix() { CrowdControlHostCcRelay.RegisterClientResponseHandlerIfNeeded(); CrowdControlGlobalTimedHud.InstallClientHandlerIfNeeded(); } } [HarmonyPatch(typeof(NetworkManager), "OnStopClient")] internal static class NetworkManager_OnStopClient_CrowdControlNet { private static void Postfix() { CrowdControlHostCcRelay.UnregisterClientResponseHandlerIfNeeded(); CrowdControlGlobalTimedHud.UninstallClientHandlerIfNeeded(); } } [HarmonyPatch(typeof(GameBase), "ServerSetBet")] internal static class GameBase_ServerSetBet_OopsMaxBetsPostfix { private static void Postfix(GameBase __instance) { CasinoOopsMaxBetsGate.AfterServerSetBet(__instance); } } [HarmonyPatch] internal static class MirrorGeneratedNetworkCode_InitReadWriters_CrowdControlWriters { private const string GameGeneratedNetworkCodeTypeName = "Mirror.GeneratedNetworkCode, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"; private static MethodBase TargetMethod() { Type type = Type.GetType("Mirror.GeneratedNetworkCode, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", throwOnError: false); if (type == null) { throw new InvalidOperationException("Crowd Control: could not resolve Mirror.GeneratedNetworkCode, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null for InitReadWriters postfix."); } MethodInfo methodInfo = AccessTools.Method(type, "InitReadWriters", (Type[])null, (Type[])null); if (methodInfo == null) { throw new InvalidOperationException("Crowd Control: InitReadWriters not found on " + type.FullName + "."); } return methodInfo; } private static void Postfix() { CrowdControlMirrorWriterBootstrap.ApplyAllCustomMessageWriters(); if ((Object)(object)CrowdControlMod.Instance != (Object)null) { CrowdControlMod.Instance.Logger.LogInfo((object)"Crowd Control: custom Mirror message writers registered (post GeneratedNetworkCode.InitReadWriters)."); } } } [HarmonyPatch(typeof(PlayerController), "OnStartClient")] internal static class PlayerController_OnStartClient_LocalMovementDup { private static void Postfix(PlayerController __instance) { GwyfLocalMovementSpeed.PreparePrivatePlayerSettings(__instance); } } } namespace CrowdControl.Delegates.Metadata { [AttributeUsage(AttributeTargets.Method)] public class MetadataAttribute : Attribute { public string[] IDs { get; } public MetadataAttribute(params string[] ids) { IDs = ids; base..ctor(); } public MetadataAttribute(string ids) : this(new string[1] { ids }) { } public MetadataAttribute([ParamCollection] IEnumerable ids) : this(ids.ToArray()) { } } public delegate DataResponse MetadataDelegate(CrowdControlMod mod); public static class MetadataDelegates { public static readonly string[] CommonMetadata = new string[3] { "balance", "tickets", "day" }; [Metadata("balance")] public static DataResponse GwyfBalance(CrowdControlMod mod) { try { MoneyManager instance = NetworkSingleton.Instance; if ((Object)(object)instance == (Object)null) { return DataResponse.Failure("balance", "MoneyManager not available."); } return DataResponse.Success("balance", (object)instance.balance); } catch (Exception ex) { CrowdControlMod.Instance.Logger.LogError((object)$"Crowd Control metadata error: {ex}"); return DataResponse.Failure("balance", (object)ex, "Internal error; see game log."); } } [Metadata("tickets")] public static DataResponse GwyfTickets(CrowdControlMod mod) { try { MoneyManager instance = NetworkSingleton.Instance; if ((Object)(object)instance == (Object)null) { return DataResponse.Failure("tickets", "MoneyManager not available."); } return DataResponse.Success("tickets", (object)instance.ticketBalance); } catch (Exception ex) { CrowdControlMod.Instance.Logger.LogError((object)$"Crowd Control metadata error: {ex}"); return DataResponse.Failure("tickets", (object)ex, "Internal error; see game log."); } } [Metadata("day")] public static DataResponse GwyfDay(CrowdControlMod mod) { try { GameManager instance = NetworkSingleton.Instance; if ((Object)(object)instance == (Object)null) { return DataResponse.Failure("day", "GameManager not available."); } return DataResponse.Success("day", (object)instance.daysPassed); } catch (Exception ex) { CrowdControlMod.Instance.Logger.LogError((object)$"Crowd Control metadata error: {ex}"); return DataResponse.Failure("day", (object)ex, "Internal error; see game log."); } } } public static class MetadataLoader { private const BindingFlags BINDING_FLAGS = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; public static readonly Dictionary Metadata; static MetadataLoader() { Metadata = new Dictionary(); Type[] types = Assembly.GetExecutingAssembly().GetTypes(); foreach (Type type in types) { try { MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { try { foreach (MetadataAttribute customAttribute in methodInfo.GetCustomAttributes()) { string[] iDs = customAttribute.IDs; foreach (string key in iDs) { try { Metadata[key] = (MetadataDelegate)Delegate.CreateDelegate(typeof(MetadataDelegate), methodInfo); } catch (Exception ex) { CrowdControlMod.Instance.Logger.LogError((object)ex); } } } } catch { } } } catch { } } } } } namespace CrowdControl.Delegates.Effects { internal static class CosmeticEffectTargeting { internal static bool CanApplyHostRpc(PlayerCustomization pc) { if ((Object)(object)pc == (Object)null) { return false; } NetworkIdentity netIdentity = ((NetworkBehaviour)pc).netIdentity; if ((Object)(object)netIdentity == (Object)null) { return false; } PlayerProfile component = ((Component)pc).GetComponent(); if ((Object)(object)component != (Object)null && component.steamId != 0L) { return true; } if (NetworkServer.active) { return netIdentity.connectionToClient != null; } return false; } } public abstract class Effect { public EffectAttribute EffectAttribute { get; } public bool IsTimed => EffectAttribute.DefaultDuration > 0.0; public CrowdControlMod Mod { get; } public NetworkClient Client { get; } protected Effect(CrowdControlMod mod, NetworkClient client) { Mod = mod; Client = client; EffectAttribute = GetType().GetCustomAttributes(inherit: false).First(); } public abstract EffectResponse Start(EffectRequest request); public virtual EffectResponse? Tick(EffectRequest request) { return null; } public virtual EffectResponse? Pause(EffectRequest request) { return EffectResponse.Paused(((SimpleJSONMessage)request).ID, (string)null); } public virtual EffectResponse? Resume(EffectRequest request) { return EffectResponse.Resumed(((SimpleJSONMessage)request).ID, (string)null); } public virtual EffectResponse? Stop(EffectRequest request) { return EffectResponse.Finished(((SimpleJSONMessage)request).ID, (string)null); } } [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] public class EffectAttribute : Attribute { public IReadOnlyList IDs { get; } public SITimeSpan DefaultDuration { get; } public IReadOnlyList Conflicts { get; } public EffectAttribute(string[] ids, SITimeSpan defaultDuration, string[] conflicts) { IDs = ids; DefaultDuration = defaultDuration; Conflicts = conflicts; base..ctor(); } public EffectAttribute([ParamCollection] IEnumerable ids) : this(ids.ToArray(), SITimeSpan.Zero, Array.Empty()) { } public EffectAttribute(params string[] ids) : this(ids.ToArray(), SITimeSpan.Zero, Array.Empty()) { } public EffectAttribute(string[] ids, float defaultDuration, string[] conflicts) : this(ids, (SITimeSpan)defaultDuration, conflicts) { } public EffectAttribute(string[] ids, float defaultDuration, string conflict) : this(ids, defaultDuration, new string[1] { conflict }) { } public EffectAttribute(string id) : this(new string[1] { id }, SITimeSpan.Zero, Array.Empty()) { } public EffectAttribute(string id, float defaultDuration) : this(new string[1] { id }, defaultDuration, (!(SITimeSpan.Zero > 0.0)) ? Array.Empty() : new string[1] { id }) { } public EffectAttribute(string id, float defaultDuration, string conflict) : this(new string[1] { id }, defaultDuration, new string[1] { conflict }) { } public EffectAttribute(string id, float defaultDuration, string[] conflicts) : this(new string[1] { id }, defaultDuration, conflicts) { } public EffectAttribute(string id, float defaultDuration, bool selfConflict) : this(new string[1] { id }, defaultDuration, (!selfConflict) ? Array.Empty() : new string[1] { id }) { } public EffectAttribute(string[] ids, float defaultDuration, bool selfConflict) : this(ids, defaultDuration, selfConflict ? ids : Array.Empty()) { } public EffectAttribute(string id, bool selfConflict) : this(new string[1] { id }, SITimeSpan.Zero, (!selfConflict) ? Array.Empty() : new string[1] { id }) { } public EffectAttribute(string[] ids, bool selfConflict) : this(ids, SITimeSpan.Zero, selfConflict ? ids : Array.Empty()) { } } public class EffectLoader { private const BindingFlags BINDING_FLAGS = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; public readonly Dictionary Effects = new Dictionary(); public EffectLoader(CrowdControlMod mod, NetworkClient client) { foreach (Type item in from type in Assembly.GetExecutingAssembly().GetTypes() where type.IsSubclassOf(typeof(Effect)) select type) { try { foreach (EffectAttribute customAttribute in item.GetCustomAttributes()) { foreach (string iD in customAttribute.IDs) { try { Effects[iD] = (Effect)Activator.CreateInstance(item, mod, client); } catch (Exception ex) { CrowdControlMod.Instance.Logger.LogError((object)ex); } } } } catch (Exception ex2) { CrowdControlMod.Instance.Logger.LogError((object)ex2); } } } } public class TimedEffectState { public enum EffectState { NotStarted, Running, Paused, Finished, Errored } [CompilerGenerated] private sealed class d__16 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public TimedEffectState <>4__this; private EffectResponse 5__2; private bool 5__3; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__16(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } 5__2 = null; <>1__state = -2; } private bool MoveNext() { bool result; try { int num = <>1__state; TimedEffectState timedEffectState = <>4__this; switch (num) { default: result = false; goto end_IL_0000; case 0: <>1__state = -1; 5__2 = null; 5__3 = false; <>1__state = -3; break; case 1: <>1__state = -3; break; } if (!(5__3 = timedEffectState.TryGetLock())) { <>2__current = null; <>1__state = 1; result = true; } else if (timedEffectState.State != EffectState.Running) { result = false; <>m__Finally1(); } else { try { 5__2 = timedEffectState.Effect.Pause(timedEffectState.Request); timedEffectState.State = EffectState.Paused; } catch (Exception ex) { 5__2 = EffectResponse.Failure(((SimpleJSONRequest)timedEffectState.Request).id, (StandardErrors)1); CrowdControlMod.Instance.Logger.LogError((object)ex.Message); timedEffectState.State = EffectState.Errored; } <>m__Finally1(); result = false; } end_IL_0000:; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; TimedEffectState timedEffectState = <>4__this; if (5__3) { timedEffectState.ReleaseLock(); timedEffectState.Client.Send((SimpleJSONResponse?)(object)5__2); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__17 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public TimedEffectState <>4__this; private EffectResponse 5__2; private bool 5__3; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__17(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } 5__2 = null; <>1__state = -2; } private bool MoveNext() { bool result; try { int num = <>1__state; TimedEffectState timedEffectState = <>4__this; switch (num) { default: result = false; goto end_IL_0000; case 0: <>1__state = -1; 5__2 = null; 5__3 = false; <>1__state = -3; break; case 1: <>1__state = -3; break; } if (!(5__3 = timedEffectState.TryGetLock())) { <>2__current = null; <>1__state = 1; result = true; } else if (timedEffectState.State != EffectState.Paused) { result = false; <>m__Finally1(); } else { try { 5__2 = timedEffectState.Effect.Resume(timedEffectState.Request); timedEffectState.State = EffectState.Running; } catch (Exception ex) { 5__2 = EffectResponse.Failure(((SimpleJSONRequest)timedEffectState.Request).id, (StandardErrors)1); CrowdControlMod.Instance.Logger.LogError((object)ex.Message); timedEffectState.State = EffectState.Errored; } <>m__Finally1(); result = false; } end_IL_0000:; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; TimedEffectState timedEffectState = <>4__this; if (5__3) { timedEffectState.ReleaseLock(); timedEffectState.Client.Send((SimpleJSONResponse?)(object)5__2); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__15 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public TimedEffectState <>4__this; private EffectResponse 5__2; private bool 5__3; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__15(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } 5__2 = null; <>1__state = -2; } private bool MoveNext() { bool result; try { int num = <>1__state; TimedEffectState timedEffectState = <>4__this; switch (num) { default: result = false; goto end_IL_0000; case 0: <>1__state = -1; 5__2 = null; 5__3 = false; <>1__state = -3; break; case 1: <>1__state = -3; break; } if (!(5__3 = timedEffectState.TryGetLock())) { <>2__current = null; <>1__state = 1; result = true; } else if (timedEffectState.State != 0) { result = false; <>m__Finally1(); } else { try { 5__2 = timedEffectState.Effect.Start(timedEffectState.Request); timedEffectState.TimeRemaining = timedEffectState.Duration; timedEffectState.State = EffectState.Running; timedEffectState.m_sawCasinoRoundReadyWhileRunning = false; } catch (Exception ex) { 5__2 = EffectResponse.Failure(((SimpleJSONRequest)timedEffectState.Request).id, (StandardErrors)1); CrowdControlMod.Instance.Logger.LogError((object)ex.Message); timedEffectState.State = EffectState.Errored; } <>m__Finally1(); result = false; } end_IL_0000:; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) <>1__state = -1; TimedEffectState timedEffectState = <>4__this; if (!5__3) { return; } timedEffectState.ReleaseLock(); if (5__2 != null) { timedEffectState.Client.Send((SimpleJSONResponse?)(object)5__2); if ((int)5__2.status == 0 && timedEffectState.State == EffectState.Running) { CrowdControlEffectHud.NotifyTimedStarted(timedEffectState, 5__2); CrowdControlGlobalHudMirror.Announce(timedEffectState.Request.code, ((SimpleJSONRequest)timedEffectState.Request).id, (float)timedEffectState.Duration.TotalSeconds); } } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__18 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public TimedEffectState <>4__this; private EffectResponse 5__2; private bool 5__3; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__18(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } 5__2 = null; <>1__state = -2; } private bool MoveNext() { bool result; try { int num = <>1__state; TimedEffectState timedEffectState = <>4__this; switch (num) { default: result = false; goto end_IL_0000; case 0: <>1__state = -1; 5__2 = null; 5__3 = false; <>1__state = -3; break; case 1: <>1__state = -3; break; } if (!(5__3 = timedEffectState.TryGetLock())) { <>2__current = null; <>1__state = 1; result = true; } else if (timedEffectState.State == EffectState.Finished) { result = false; <>m__Finally1(); } else { try { 5__2 = timedEffectState.Effect.Stop(timedEffectState.Request) ?? EffectResponse.Finished(((SimpleJSONRequest)timedEffectState.Request).id, (string)null); timedEffectState.State = EffectState.Finished; } catch (Exception ex) { 5__2 = EffectResponse.Failure(((SimpleJSONRequest)timedEffectState.Request).id, (StandardErrors)1); CrowdControlMod.Instance.Logger.LogError((object)ex.Message); timedEffectState.State = EffectState.Errored; } <>m__Finally1(); result = false; } end_IL_0000:; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { //IL_003c: 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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Invalid comparison between Unknown and I4 //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Invalid comparison between Unknown and I4 <>1__state = -1; TimedEffectState timedEffectState = <>4__this; if (!5__3) { return; } timedEffectState.ReleaseLock(); if (5__2 != null) { timedEffectState.Client.Send((SimpleJSONResponse?)(object)5__2); EffectStatus status = 5__2.status; if (((int)status == 1 || (int)status == 8) ? true : false) { CrowdControlEffectHud.NotifyTimedEnded(((SimpleJSONRequest)timedEffectState.Request).id); CrowdControlGlobalHudMirror.AnnounceEnd(((SimpleJSONRequest)timedEffectState.Request).id); } } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public readonly EffectRequest Request; public readonly SITimeSpan Duration; public readonly Effect Effect; public readonly NetworkClient Client; public SITimeSpan TimeRemaining; private bool m_sawCasinoRoundReadyWhileRunning; private int m_stateLock; private static readonly IEnumerator EMPTY_ENUMERATOR = Enumerable.Empty().GetEnumerator(); public EffectState State { get; private set; } private bool TryGetLock() { return Interlocked.CompareExchange(ref m_stateLock, 1, 0) == 0; } private void ReleaseLock() { m_stateLock = 0; } public TimedEffectState(Effect effect, EffectRequest request, SITimeSpan duration) { Effect = effect; Client = effect.Client; Request = request; Duration = duration; TimeRemaining = duration; } [IteratorStateMachine(typeof(d__15))] public IEnumerator Start() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__15(0) { <>4__this = this }; } [IteratorStateMachine(typeof(d__16))] public IEnumerator Pause() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__16(0) { <>4__this = this }; } [IteratorStateMachine(typeof(d__17))] public IEnumerator Resume() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__17(0) { <>4__this = this }; } [IteratorStateMachine(typeof(d__18))] public IEnumerator Stop() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__18(0) { <>4__this = this }; } public IEnumerator Tick() { //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Invalid comparison between Unknown and I4 //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Invalid comparison between Unknown and I4 EffectResponse val = null; bool flag = false; try { if (!(flag = TryGetLock())) { return EMPTY_ENUMERATOR; } string code = Request.code ?? string.Empty; bool flag2 = CrowdControlMod.Instance.GameStateManager.IsCasinoRoundPlayReady(); bool flag3 = GameStateManager.ShouldFreezeTimedOutsideCasinoRound(code); if (State == EffectState.Running && flag2) { m_sawCasinoRoundReadyWhileRunning = true; } if (!flag2 && !flag3) { EffectState state = State; if ((uint)(state - 1) <= 1u) { return Stop(); } } if (flag3 && !flag2 && m_sawCasinoRoundReadyWhileRunning) { if (State == EffectState.Running) { return Pause(); } if (State == EffectState.Paused) { return EMPTY_ENUMERATOR; } } if (flag3 && flag2 && State == EffectState.Paused) { return Resume(); } if (State != EffectState.Running) { return EMPTY_ENUMERATOR; } if (!flag2 && (!flag3 || m_sawCasinoRoundReadyWhileRunning)) { return EMPTY_ENUMERATOR; } try { if (TimeRemaining > 0.0) { Effect.Tick(Request); TimeRemaining -= (double)CrowdControlMod.DeltaTime; } else { val = Effect.Stop(Request) ?? EffectResponse.Finished(((SimpleJSONRequest)Request).id, (string)null); State = EffectState.Finished; TimeRemaining = SITimeSpan.Zero; } } catch (Exception ex) { val = EffectResponse.Failure(((SimpleJSONRequest)Request).id, (StandardErrors)1); CrowdControlMod.Instance.Logger.LogError((object)ex.Message); State = EffectState.Errored; } return EMPTY_ENUMERATOR; } finally { if (flag) { ReleaseLock(); if (val != null) { Client.Send((SimpleJSONResponse?)(object)val); EffectStatus status = val.status; if (((int)status == 1 || (int)status == 8) ? true : false) { CrowdControlEffectHud.NotifyTimedEnded(((SimpleJSONRequest)Request).id); CrowdControlGlobalHudMirror.AnnounceEnd(((SimpleJSONRequest)Request).id); } } } } } } } namespace CrowdControl.Delegates.Effects.Implementations { [Effect("add_cash_100")] public class AddCash100 : Effect { public AddCash100(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfMultiplayer.TryGetMoneyManager(out MoneyManager money)) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } money.CmdTryChangeBalance(100L, (PlayerProfile)null, (ChangeType)4); GameStateManager.LogCrowdControl("+$100 (CmdTryChangeBalance)"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("add_cash_1000")] public class AddCash1000 : Effect { public AddCash1000(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfMultiplayer.TryGetMoneyManager(out MoneyManager money)) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } money.CmdTryChangeBalance(1000L, (PlayerProfile)null, (ChangeType)4); GameStateManager.LogCrowdControl("+$1000 (CmdTryChangeBalance)"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("add_cash_50")] public class AddCash50 : Effect { public AddCash50(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfMultiplayer.TryGetMoneyManager(out MoneyManager money)) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } money.CmdTryChangeBalance(50L, (PlayerProfile)null, (ChangeType)4); GameStateManager.LogCrowdControl("+$50 (CmdTryChangeBalance)"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("add_cash_500")] public class AddCash500 : Effect { private const long Amount = 500L; public AddCash500(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfMultiplayer.TryGetMoneyManager(out MoneyManager money)) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } money.CmdTryChangeBalance(500L, (PlayerProfile)null, (ChangeType)4); GameStateManager.LogCrowdControl($"+${500L} (requested on server via CmdTryChangeBalance)"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("add_day_time")] public class AddDayTime : Effect { private const float DeltaSeconds = -30f; private const float AddRemainingSeconds = 30f; public AddDayTime(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!NetworkServer.active) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } GameManager instance = NetworkSingleton.Instance; if ((Object)(object)instance == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } GameSettings val = Resources.Load("GameSettings"); if ((Object)(object)val == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } if (!GwyfDayTimerRules.CanAddRemainingSeconds(val, instance, 30f)) { string text = GwyfDayTimerRules.DescribeCannotAddTime(val, instance, 30f); GameStateManager.LogCrowdControl("Add day time blocked: " + text + " (host)."); return EffectResponse.Failure(((SimpleJSONMessage)request).ID, text); } instance.ServerAdjustTimer(-30f); GameStateManager.LogCrowdControl($"ServerAdjustTimer({-30f}) — ~30s more day time (host only)"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("add_tickets_1")] public class AddTickets1 : Effect { public AddTickets1(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfMultiplayer.TryGetMoneyManager(out MoneyManager money)) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } money.CmdTryChangeTicketBalance(1L); GameStateManager.LogCrowdControl("+1 ticket (CmdTryChangeTicketBalance)"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("add_tickets_2")] public class AddTickets2 : Effect { private const long Amount = 2L; public AddTickets2(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfMultiplayer.TryGetMoneyManager(out MoneyManager money)) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } money.CmdTryChangeTicketBalance(2L); GameStateManager.LogCrowdControl($"+{2L} tickets (CmdTryChangeTicketBalance)"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("add_tickets_5")] public class AddTickets5 : Effect { public AddTickets5(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfMultiplayer.TryGetMoneyManager(out MoneyManager money)) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } money.CmdTryChangeTicketBalance(5L); GameStateManager.LogCrowdControl("+5 tickets (CmdTryChangeTicketBalance)"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("upgrade_bonus_draw_boost")] public class UpgradeBonusDrawBoost : Effect { public UpgradeBonusDrawBoost(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!CrowdControlStreamerEffectNetwork.TryRunForLocalStreamer(CrowdControlStreamerEffectOp.UpgradeBonusDraw, out string error)) { if (!string.IsNullOrEmpty(error)) { CrowdControlMod.Instance.Logger.LogWarning((object)error); } return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } GameStateManager.LogCrowdControl("Upgrades: +Bonus Draw for streamer."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("buff_drink_tipsy", 15f, true)] public class BuffDrinkTipsy15s : Effect { public BuffDrinkTipsy15s(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!CrowdControlStreamerEffectNetwork.TryRunForLocalStreamer(CrowdControlStreamerEffectOp.BuffDrinkTipsy15s, out string error)) { if (!string.IsNullOrEmpty(error)) { CrowdControlMod.Instance.Logger.LogWarning((object)error); } return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } GameStateManager.LogCrowdControl("Buff: drink-style tipsy + voice wobble (15s) for streamer."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("buff_immunity", 15f, true)] public class BuffImmunity15s : Effect { public BuffImmunity15s(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!CrowdControlStreamerEffectNetwork.TryRunForLocalStreamer(CrowdControlStreamerEffectOp.BuffImmunity15s, out string error)) { if (!string.IsNullOrEmpty(error)) { CrowdControlMod.Instance.Logger.LogWarning((object)error); } return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } GameStateManager.LogCrowdControl("Buff: Immunity (15s) for streamer."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("buff_inspiring_melody", 15f, true)] public class BuffInspiringMelody15s : Effect { public BuffInspiringMelody15s(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!CrowdControlStreamerEffectNetwork.TryRunForLocalStreamer(CrowdControlStreamerEffectOp.BuffInspiringMelody15s, out string error)) { if (!string.IsNullOrEmpty(error)) { CrowdControlMod.Instance.Logger.LogWarning((object)error); } return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } GameStateManager.LogCrowdControl("Buff: Inspiring Melody (15s) for streamer."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("upgrade_insurance_boost")] public class UpgradeInsuranceBoost : Effect { public UpgradeInsuranceBoost(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!CrowdControlStreamerEffectNetwork.TryRunForLocalStreamer(CrowdControlStreamerEffectOp.UpgradeInsurance, out string error)) { if (!string.IsNullOrEmpty(error)) { CrowdControlMod.Instance.Logger.LogWarning((object)error); } return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } GameStateManager.LogCrowdControl("Upgrades: +Insurance for streamer."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("upgrade_stakeholder_boost")] public class UpgradeStakeholderBoost : Effect { public UpgradeStakeholderBoost(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!CrowdControlStreamerEffectNetwork.TryRunForLocalStreamer(CrowdControlStreamerEffectOp.UpgradeStakeholder, out string error)) { if (!string.IsNullOrEmpty(error)) { CrowdControlMod.Instance.Logger.LogWarning((object)error); } return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } GameStateManager.LogCrowdControl("Upgrades: +Stakeholder for streamer."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("casino_hot_table", 30f, new string[] { "casino_hot_table", "casino_house_crush" })] public class CasinoHotTable30s : Effect { private const float Scale = 2.15f; private const float MaxEstimated = 3.25f; public CasinoHotTable30s(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!NetworkServer.active) { return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } CasinoTimedOdds.BeginEstimatedScaleSession(((SimpleJSONMessage)request).ID, 2.15f, 3.25f); GameStateManager.LogCrowdControl($"Casino: hot table x{2.15f} (cap {3.25f}) 30s (host)."); uint iD = ((SimpleJSONMessage)request).ID; long? duration = request.duration; CrowdControlTimedCasinoHud.AfterHostLocalTimedStart("casino_hot_table", iD, (duration.HasValue && duration.GetValueOrDefault() > 0) ? ((float)request.duration.Value / 1000f) : 30f); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } public override EffectResponse? Stop(EffectRequest request) { if (NetworkServer.active) { CasinoTimedOdds.RestoreEstimatedSession(((SimpleJSONMessage)request).ID); } else { CrowdControlHostCcRelay.ClientSendTimedStop(((SimpleJSONMessage)request).ID); } GameStateManager.LogCrowdControl("Casino: hot table ended — restored table estimates."); return EffectResponse.Finished(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("casino_house_crush", 30f, new string[] { "casino_house_crush", "casino_hot_table" })] public class CasinoHouseCrush30s : Effect { private const float CrushEstimated = 0.04f; public CasinoHouseCrush30s(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!NetworkServer.active) { return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } CasinoTimedOdds.BeginEstimatedUniformSession(((SimpleJSONMessage)request).ID, 0.04f); GameStateManager.LogCrowdControl($"Casino: house crush (~{0.04f} est) 30s (host)."); uint iD = ((SimpleJSONMessage)request).ID; long? duration = request.duration; CrowdControlTimedCasinoHud.AfterHostLocalTimedStart("casino_house_crush", iD, (duration.HasValue && duration.GetValueOrDefault() > 0) ? ((float)request.duration.Value / 1000f) : 30f); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } public override EffectResponse? Stop(EffectRequest request) { if (NetworkServer.active) { CasinoTimedOdds.RestoreEstimatedSession(((SimpleJSONMessage)request).ID); } else { CrowdControlHostCcRelay.ClientSendTimedStop(((SimpleJSONMessage)request).ID); } GameStateManager.LogCrowdControl("Casino: house crush ended — restored table estimates."); return EffectResponse.Finished(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("casino_maxbet_surge", 30f, new string[] { "casino_maxbet_surge", "casino_oops_max_bets" })] public class CasinoMaxBetSurge30s : Effect { private const double Factor = 2.0; private const double MaxMult = 4.0; public CasinoMaxBetSurge30s(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!NetworkServer.active) { return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } CasinoTimedOdds.BeginMaxBetScaleSession(((SimpleJSONMessage)request).ID, 2.0, 4.0); GameStateManager.LogCrowdControl($"Casino: max-bet surge x{2.0} (cap {4.0}) 30s (host)."); uint iD = ((SimpleJSONMessage)request).ID; long? duration = request.duration; CrowdControlTimedCasinoHud.AfterHostLocalTimedStart("casino_maxbet_surge", iD, (duration.HasValue && duration.GetValueOrDefault() > 0) ? ((float)request.duration.Value / 1000f) : 30f); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } public override EffectResponse? Stop(EffectRequest request) { if (NetworkServer.active) { CasinoTimedOdds.RestoreMaxBetSession(((SimpleJSONMessage)request).ID); } else { CrowdControlHostCcRelay.ClientSendTimedStop(((SimpleJSONMessage)request).ID); } GameStateManager.LogCrowdControl("Casino: max-bet surge ended — restored multipliers."); return EffectResponse.Finished(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("casino_oops_max_bets", 30f, new string[] { "casino_oops_max_bets", "casino_maxbet_surge" })] public class CasinoOopsMaxBets30s : Effect { private const float RetriggerSeconds = 0.4f; private float _accum; public CasinoOopsMaxBets30s(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!NetworkServer.active) { return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } CasinoOopsMaxBetsGate.BeginSession(); _accum = 0.4f; int num = CasinoBetMaxPusher.PushAllTablesToAffordableMax(); GameStateManager.LogCrowdControl($"Casino: oops max bets 30s — pushed {num} table(s) on start (host)."); uint iD = ((SimpleJSONMessage)request).ID; long? duration = request.duration; CrowdControlTimedCasinoHud.AfterHostLocalTimedStart("casino_oops_max_bets", iD, (duration.HasValue && duration.GetValueOrDefault() > 0) ? ((float)request.duration.Value / 1000f) : 30f); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } public override EffectResponse? Tick(EffectRequest request) { if (!NetworkServer.active) { return null; } _accum += CrowdControlMod.DeltaTime; if (_accum < 0.4f) { return null; } _accum = 0f; CasinoBetMaxPusher.PushAllTablesToAffordableMax(); return null; } public override EffectResponse? Stop(EffectRequest request) { if (NetworkServer.active) { CasinoOopsMaxBetsGate.EndSession(); } else { CrowdControlHostCcRelay.ClientSendTimedStop(((SimpleJSONMessage)request).ID); } GameStateManager.LogCrowdControl("Casino: oops max bets window ended (no bet restore — tables keep last keypad state)."); return EffectResponse.Finished(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("cosmetic_clear_hats")] public class CosmeticClearHatsMe : Effect { public CosmeticClearHatsMe(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!NetworkClient.active || (Object)(object)NetworkClient.localPlayer == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } PlayerCustomization component = ((Component)NetworkClient.localPlayer).GetComponent(); if ((Object)(object)component == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } component.ClearCategory((CosmeticType)0); GameStateManager.LogCrowdControl("Cosmetics: cleared hats for local player."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("cosmetic_random_piece")] public class CosmeticRandomCosmeticMe : Effect { public CosmeticRandomCosmeticMe(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!NetworkClient.active || (Object)(object)NetworkClient.localPlayer == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } PlayerCustomization component = ((Component)NetworkClient.localPlayer).GetComponent(); if ((Object)(object)component == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } int[] validCosmeticIdsSorted = CosmeticDataManager.GetValidCosmeticIdsSorted(); if (validCosmeticIdsSorted.Length == 0) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } int num = validCosmeticIdsSorted[Random.Range(0, validCosmeticIdsSorted.Length)]; component.CmdChangeCustomization(num, false); GameStateManager.LogCrowdControl($"Cosmetics: random piece for local player (id {num})."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("cosmetic_reset_outfit")] public class CosmeticResetOutfitMe : Effect { public CosmeticResetOutfitMe(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!NetworkClient.active || (Object)(object)NetworkClient.localPlayer == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } PlayerCustomization component = ((Component)NetworkClient.localPlayer).GetComponent(); if ((Object)(object)component == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } component.ResetCustomization(); GameStateManager.LogCrowdControl("Cosmetics: reset outfit for local player."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("grant_auxiliary_money")] public class GrantAuxiliaryMoney : Effect { public GrantAuxiliaryMoney(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!NetworkServer.active) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } GameManager instance = NetworkSingleton.Instance; if ((Object)(object)instance == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } instance.ServerGetAuxiliaryMoney(); GameStateManager.LogCrowdControl("ServerGetAuxiliaryMoney (host only)"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("upgrade_gamblers_confidence_boost")] public class UpgradeGamblersConfidenceBoost : Effect { public UpgradeGamblersConfidenceBoost(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!CrowdControlStreamerEffectNetwork.TryRunForLocalStreamer(CrowdControlStreamerEffectOp.UpgradeBuffGamblersConfidence, out string error)) { if (!string.IsNullOrEmpty(error)) { CrowdControlMod.Instance.Logger.LogWarning((object)error); } return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } GameStateManager.LogCrowdControl("Upgrades: +Gamblers Confidence for streamer."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("upgrade_reset_run")] public class UpgradeResetRun : Effect { public UpgradeResetRun(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!CrowdControlStreamerEffectNetwork.TryRunForLocalStreamer(CrowdControlStreamerEffectOp.UpgradeResetRun, out string error)) { if (!string.IsNullOrEmpty(error)) { CrowdControlMod.Instance.Logger.LogWarning((object)error); } if (!string.IsNullOrEmpty(error)) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, error); } return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("spawn_bat", true)] public class ItemGiveBatMe : Effect { public ItemGiveBatMe(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { SpawnableSO val = GwyfItemSpawnHelper.ResolveSpawnable(CrowdControlSpawnItemKind.Bat); if ((Object)(object)val == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } if (!GwyfItemSpawnHelper.TrySpawnItemNearLocalStreamer(val, CrowdControlSpawnItemKind.Bat, out Item _, out string errorMessage)) { if (!string.IsNullOrEmpty(errorMessage)) { CrowdControlMod.Instance.Logger.LogWarning((object)errorMessage); } return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } GameStateManager.LogCrowdControl("Item: bat spawned nearby (" + (NetworkServer.active ? "host" : "request sent to host") + ")."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("spawn_drink", true)] public class ItemGiveDrinkMe : Effect { public ItemGiveDrinkMe(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { SpawnableSO val = GwyfItemSpawnHelper.ResolveSpawnable(CrowdControlSpawnItemKind.Drink); if ((Object)(object)val == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } if (!GwyfItemSpawnHelper.TrySpawnItemNearLocalStreamer(val, CrowdControlSpawnItemKind.Drink, out Item _, out string errorMessage)) { if (!string.IsNullOrEmpty(errorMessage)) { CrowdControlMod.Instance.Logger.LogWarning((object)errorMessage); } return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } GameStateManager.LogCrowdControl("Item: drink spawned nearby (" + (NetworkServer.active ? "host" : "request sent to host") + ")."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("spawn_immunity_cross", true)] public class ItemGiveImmunityCrossMe : Effect { public ItemGiveImmunityCrossMe(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { SpawnableSO val = GwyfItemSpawnHelper.ResolveSpawnable(CrowdControlSpawnItemKind.ImmunityCross); if ((Object)(object)val == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } if (!GwyfItemSpawnHelper.TrySpawnItemNearLocalStreamer(val, CrowdControlSpawnItemKind.ImmunityCross, out Item _, out string errorMessage)) { if (!string.IsNullOrEmpty(errorMessage)) { CrowdControlMod.Instance.Logger.LogWarning((object)errorMessage); } return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } GameStateManager.LogCrowdControl("Item: immunity cross spawned nearby (" + (NetworkServer.active ? "host" : "request sent to host") + ")."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("spawn_microphone", true)] public class ItemGiveMicrophoneMe : Effect { public ItemGiveMicrophoneMe(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { SpawnableSO val = GwyfItemSpawnHelper.ResolveSpawnable(CrowdControlSpawnItemKind.Microphone); if ((Object)(object)val == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } if (!GwyfItemSpawnHelper.TrySpawnItemNearLocalStreamer(val, CrowdControlSpawnItemKind.Microphone, out Item _, out string errorMessage)) { if (!string.IsNullOrEmpty(errorMessage)) { CrowdControlMod.Instance.Logger.LogWarning((object)errorMessage); } return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } GameStateManager.LogCrowdControl("Item: microphone spawned nearby (" + (NetworkServer.active ? "host" : "request sent to host") + ")."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("spawn_coordinator", true)] [Effect("spawn_golden_chip", true)] [Effect("spawn_devils_reel", true)] [Effect("spawn_angels_reel", true)] [Effect("spawn_time_machine", true)] [Effect("spawn_taser", true)] [Effect("spawn_quota_gun", true)] [Effect("spawn_mystery_box", true)] [Effect("spawn_upgrade_stakeholder", true)] [Effect("spawn_upgrade_insurance", true)] [Effect("spawn_upgrade_bonus_draw", true)] [Effect("spawn_upgrade_gamblers_confidence", true)] [Effect("spawn_holy_statue", true)] [Effect("spawn_voice_wand", true)] [Effect("spawn_gacha_sphere", true)] [Effect("spawn_basketball", true)] [Effect("spawn_sledding_frog", true)] [Effect("spawn_bongo", true)] [Effect("spawn_dice", true)] [Effect("spawn_chess_piece", true)] [Effect("spawn_bingbong", true)] [Effect("spawn_debt_bag", true)] public class ItemSpawnNearCatalogExtraMe : Effect { private static readonly Dictionary s_codeToKind = new Dictionary(StringComparer.Ordinal) { ["spawn_coordinator"] = CrowdControlSpawnItemKind.CoordinatorCamera, ["spawn_golden_chip"] = CrowdControlSpawnItemKind.GoldenChip, ["spawn_devils_reel"] = CrowdControlSpawnItemKind.DevilsReel, ["spawn_angels_reel"] = CrowdControlSpawnItemKind.AngelsReel, ["spawn_time_machine"] = CrowdControlSpawnItemKind.TimeMachine, ["spawn_taser"] = CrowdControlSpawnItemKind.Taser, ["spawn_quota_gun"] = CrowdControlSpawnItemKind.QuotaGun, ["spawn_mystery_box"] = CrowdControlSpawnItemKind.MysteryBox, ["spawn_upgrade_stakeholder"] = CrowdControlSpawnItemKind.UpgradeStakeholder, ["spawn_upgrade_insurance"] = CrowdControlSpawnItemKind.UpgradeInsurance, ["spawn_upgrade_bonus_draw"] = CrowdControlSpawnItemKind.UpgradeBonusDraw, ["spawn_upgrade_gamblers_confidence"] = CrowdControlSpawnItemKind.UpgradeGamblersConfidence, ["spawn_holy_statue"] = CrowdControlSpawnItemKind.HolyStatue, ["spawn_voice_wand"] = CrowdControlSpawnItemKind.VoiceWand, ["spawn_gacha_sphere"] = CrowdControlSpawnItemKind.GachaSphere, ["spawn_basketball"] = CrowdControlSpawnItemKind.Basketball, ["spawn_sledding_frog"] = CrowdControlSpawnItemKind.SleddingFrog, ["spawn_bongo"] = CrowdControlSpawnItemKind.Bongo, ["spawn_dice"] = CrowdControlSpawnItemKind.Dice, ["spawn_chess_piece"] = CrowdControlSpawnItemKind.ChessPiece, ["spawn_bingbong"] = CrowdControlSpawnItemKind.BingBong, ["spawn_debt_bag"] = CrowdControlSpawnItemKind.DebtBag }; public ItemSpawnNearCatalogExtraMe(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { string text = request.code ?? string.Empty; if (!s_codeToKind.TryGetValue(text, out var value)) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } if (!GwyfItemSpawnHelper.TrySpawnByKindNearLocalStreamer(value, out Item _, out string errorMessage)) { if (!string.IsNullOrEmpty(errorMessage)) { CrowdControlMod.Instance.Logger.LogWarning((object)errorMessage); } return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } SpawnableSO val = GwyfItemSpawnHelper.ResolveSpawnable(value); string text2 = (((Object)(object)val != (Object)null) ? val.spawnableName : $"off-catalog {value}"); GameStateManager.LogCrowdControl("Item: spawned '" + text2 + "' nearby (" + text + ")."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("luck_tipsy_hangover", 30f, new string[] { "luck_tipsy_hangover", "luck_tipsy_surge" })] public class LuckTipsyHangover30s : Effect { public LuckTipsyHangover30s(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!CrowdControlStreamerEffectNetwork.TryRunForLocalStreamer(CrowdControlStreamerEffectOp.LuckTipsyHangover30s, out string error)) { if (!string.IsNullOrEmpty(error)) { CrowdControlMod.Instance.Logger.LogWarning((object)error); } return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } GameStateManager.LogCrowdControl("Luck: TipsyFortune hangover -0.45 (30s) for streamer."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("luck_tipsy_surge", 30f, new string[] { "luck_tipsy_surge", "luck_tipsy_hangover" })] public class LuckTipsySurge30s : Effect { public LuckTipsySurge30s(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!CrowdControlStreamerEffectNetwork.TryRunForLocalStreamer(CrowdControlStreamerEffectOp.LuckTipsySurge30s, out string error)) { if (!string.IsNullOrEmpty(error)) { CrowdControlMod.Instance.Logger.LogWarning((object)error); } return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } GameStateManager.LogCrowdControl("Luck: TipsyFortune +0.65 (30s) for streamer."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect(new string[] { "player_movement_fast" }, 15f, new string[] { "player_movement_slow", "player_movement_very_slow" })] public class MovementSpeedFastMe : Effect { private const float SpeedMultiplier = 1.5f; public MovementSpeedFastMe(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfLocalMovementSpeed.TryApplySpeedMultiplier(1.5f, out string error)) { if (!string.IsNullOrEmpty(error)) { CrowdControlMod.Instance.Logger.LogWarning((object)error); } return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } GameStateManager.LogCrowdControl($"Movement: fast ({1.5f:0.##}×) for local player."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } public override EffectResponse? Pause(EffectRequest request) { GwyfLocalMovementSpeed.PauseHeldMultiplier(); return base.Pause(request); } public override EffectResponse? Resume(EffectRequest request) { GwyfLocalMovementSpeed.ResumeHeldMultiplier(); return base.Resume(request); } public override EffectResponse? Stop(EffectRequest request) { GwyfLocalMovementSpeed.RestoreBaseline(); GameStateManager.LogCrowdControl("Movement: restored default speeds (fast ended)."); return EffectResponse.Finished(((SimpleJSONMessage)request).ID, (string)null); } } [Effect(new string[] { "player_movement_slow" }, 15f, new string[] { "player_movement_fast", "player_movement_very_slow" })] public class MovementSpeedSlowMe : Effect { private const float SpeedMultiplier = 0.55f; public MovementSpeedSlowMe(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfLocalMovementSpeed.TryApplySpeedMultiplier(0.55f, out string error)) { if (!string.IsNullOrEmpty(error)) { CrowdControlMod.Instance.Logger.LogWarning((object)error); } return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } GameStateManager.LogCrowdControl($"Movement: slow ({0.55f:0.##}×) for local player."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } public override EffectResponse? Pause(EffectRequest request) { GwyfLocalMovementSpeed.PauseHeldMultiplier(); return base.Pause(request); } public override EffectResponse? Resume(EffectRequest request) { GwyfLocalMovementSpeed.ResumeHeldMultiplier(); return base.Resume(request); } public override EffectResponse? Stop(EffectRequest request) { GwyfLocalMovementSpeed.RestoreBaseline(); GameStateManager.LogCrowdControl("Movement: restored default speeds (slow ended)."); return EffectResponse.Finished(((SimpleJSONMessage)request).ID, (string)null); } } [Effect(new string[] { "player_movement_very_slow" }, 15f, new string[] { "player_movement_fast", "player_movement_slow" })] public class MovementSpeedVerySlowMe : Effect { private const float SpeedMultiplier = 0.22f; public MovementSpeedVerySlowMe(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfLocalMovementSpeed.TryApplySpeedMultiplier(0.22f, out string error)) { if (!string.IsNullOrEmpty(error)) { CrowdControlMod.Instance.Logger.LogWarning((object)error); } return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } GameStateManager.LogCrowdControl($"Movement: very slow ({0.22f:0.##}×) for local player."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } public override EffectResponse? Pause(EffectRequest request) { GwyfLocalMovementSpeed.PauseHeldMultiplier(); return base.Pause(request); } public override EffectResponse? Resume(EffectRequest request) { GwyfLocalMovementSpeed.ResumeHeldMultiplier(); return base.Resume(request); } public override EffectResponse? Stop(EffectRequest request) { GwyfLocalMovementSpeed.RestoreBaseline(); GameStateManager.LogCrowdControl("Movement: restored default speeds (very slow ended)."); return EffectResponse.Finished(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("upgrade_gamblers_confidence_nerf")] public class UpgradeGamblersConfidenceNerf : Effect { public UpgradeGamblersConfidenceNerf(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!CrowdControlStreamerEffectNetwork.TryRunForLocalStreamer(CrowdControlStreamerEffectOp.UpgradeNerfGamblersConfidence, out string error)) { if (!string.IsNullOrEmpty(error)) { CrowdControlMod.Instance.Logger.LogWarning((object)error); } return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } GameStateManager.LogCrowdControl("Upgrades: Gamblers Confidence nerf for streamer."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("remove_cash_100")] public class RemoveCash100 : Effect { public RemoveCash100(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfMultiplayer.TryGetMoneyManager(out MoneyManager money)) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } if (money.balance < 100) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)17153); } money.CmdTryChangeBalance(-100L, (PlayerProfile)null, (ChangeType)4); GameStateManager.LogCrowdControl("-$100 (CmdTryChangeBalance)"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("remove_cash_1000")] public class RemoveCash1000 : Effect { public RemoveCash1000(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfMultiplayer.TryGetMoneyManager(out MoneyManager money)) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } if (money.balance < 1000) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)17153); } money.CmdTryChangeBalance(-1000L, (PlayerProfile)null, (ChangeType)4); GameStateManager.LogCrowdControl("-$1000 (CmdTryChangeBalance)"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("remove_cash_50")] public class RemoveCash50 : Effect { public RemoveCash50(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfMultiplayer.TryGetMoneyManager(out MoneyManager money)) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } if (money.balance < 50) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)17153); } money.CmdTryChangeBalance(-50L, (PlayerProfile)null, (ChangeType)4); GameStateManager.LogCrowdControl("-$50 (CmdTryChangeBalance)"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("remove_cash_500")] public class RemoveCash500 : Effect { private const long Amount = 500L; public RemoveCash500(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfMultiplayer.TryGetMoneyManager(out MoneyManager money)) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } if (money.balance < 500) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)17153); } money.CmdTryChangeBalance(-500L, (PlayerProfile)null, (ChangeType)4); GameStateManager.LogCrowdControl($"-${500L} (requested on server via CmdTryChangeBalance)"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("remove_day_time")] public class RemoveDayTime : Effect { private const float DeltaSeconds = 30f; private const float RemoveRemainingSeconds = 30f; public RemoveDayTime(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!NetworkServer.active) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16384); } GameManager instance = NetworkSingleton.Instance; if ((Object)(object)instance == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } GameSettings val = Resources.Load("GameSettings"); if ((Object)(object)val == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } if (!GwyfDayTimerRules.CanRemoveRemainingSeconds(val, instance, 30f)) { string text = GwyfDayTimerRules.DescribeCannotRemoveTime(val, instance, 30f); GameStateManager.LogCrowdControl("Remove day time blocked: " + text + " (host)."); return EffectResponse.Failure(((SimpleJSONMessage)request).ID, text); } instance.ServerAdjustTimer(30f); GameStateManager.LogCrowdControl($"ServerAdjustTimer(+{30f}) — day ends sooner (host only)"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("remove_tickets_1")] public class RemoveTickets1 : Effect { public RemoveTickets1(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfMultiplayer.TryGetMoneyManager(out MoneyManager money)) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } if (money.ticketBalance < 1) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)17153); } money.CmdTryChangeTicketBalance(-1L); GameStateManager.LogCrowdControl("-1 ticket (CmdTryChangeTicketBalance)"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("remove_tickets_2")] public class RemoveTickets2 : Effect { private const long Amount = 2L; public RemoveTickets2(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfMultiplayer.TryGetMoneyManager(out MoneyManager money)) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } if (money.ticketBalance < 2) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)17153); } money.CmdTryChangeTicketBalance(-2L); GameStateManager.LogCrowdControl($"-{2L} tickets (CmdTryChangeTicketBalance)"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("remove_tickets_5")] public class RemoveTickets5 : Effect { public RemoveTickets5(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfMultiplayer.TryGetMoneyManager(out MoneyManager money)) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } if (money.ticketBalance < 5) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)17153); } money.CmdTryChangeTicketBalance(-5L); GameStateManager.LogCrowdControl("-5 tickets (CmdTryChangeTicketBalance)"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("reset_balances")] public class ResetRunBalances : Effect { public ResetRunBalances(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfMultiplayer.TryGetMoneyManager(out MoneyManager money)) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } money.CmdResetBalancesToDefault(); GameStateManager.LogCrowdControl("Reset shared balances to defaults (CmdResetBalancesToDefault)."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } internal static class VoiceFxDurationHelper { internal static float ResolveSeconds(EffectRequest request, SITimeSpan defaultDuration) { long valueOrDefault = request.duration.GetValueOrDefault(); if (valueOrDefault > 0) { return (float)valueOrDefault / 1000f; } return (float)defaultDuration.TotalSeconds; } } [Effect("voice_low", 15f, new string[] { "voice_low", "voice_wobble", "voice_radio" })] public class VoiceFxLow : Effect { public VoiceFxLow(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfSceneHelpers.TryGetLocalPlayerVoiceFx(out PlayerVoiceFX pv) || (Object)(object)pv == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } float num = VoiceFxDurationHelper.ResolveSeconds(request, base.EffectAttribute.DefaultDuration); pv.CmdStartTimedVoiceFX((VoipFX)2, num, true); GameStateManager.LogCrowdControl("Voice: Low pitch started (local)."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } public override EffectResponse? Stop(EffectRequest request) { if (GwyfSceneHelpers.TryGetLocalPlayerVoiceFx(out PlayerVoiceFX pv) && (Object)(object)pv != (Object)null) { pv.CmdResetVoiceFX(); } GameStateManager.LogCrowdControl("Voice: Low pitch ended (local)."); return EffectResponse.Finished(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("voice_radio", 20f, new string[] { "voice_low", "voice_wobble", "voice_radio" })] public class VoiceFxRadio : Effect { public VoiceFxRadio(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfSceneHelpers.TryGetLocalPlayerVoiceFx(out PlayerVoiceFX pv) || (Object)(object)pv == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } float num = VoiceFxDurationHelper.ResolveSeconds(request, base.EffectAttribute.DefaultDuration); pv.CmdStartTimedVoiceFX((VoipFX)4, num, true); GameStateManager.LogCrowdControl("Voice: Radio started (local)."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } public override EffectResponse? Stop(EffectRequest request) { if (GwyfSceneHelpers.TryGetLocalPlayerVoiceFx(out PlayerVoiceFX pv) && (Object)(object)pv != (Object)null) { pv.CmdResetVoiceFX(); } GameStateManager.LogCrowdControl("Voice: Radio ended (local)."); return EffectResponse.Finished(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("voice_reset")] public class VoiceFxResetAll : Effect { public VoiceFxResetAll(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfSceneHelpers.TryGetLocalPlayerVoiceFx(out PlayerVoiceFX pv) || (Object)(object)pv == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } pv.CmdResetVoiceFX(); GameStateManager.LogCrowdControl("Voice: reset FX for local player."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("voice_wobble", 15f, new string[] { "voice_low", "voice_wobble", "voice_radio" })] public class VoiceFxWobble : Effect { public VoiceFxWobble(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfSceneHelpers.TryGetLocalPlayerVoiceFx(out PlayerVoiceFX pv) || (Object)(object)pv == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } float num = VoiceFxDurationHelper.ResolveSeconds(request, base.EffectAttribute.DefaultDuration); pv.CmdStartTimedVoiceFX((VoipFX)1, num, true); GameStateManager.LogCrowdControl("Voice: Wobble started (local)."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } public override EffectResponse? Stop(EffectRequest request) { if (GwyfSceneHelpers.TryGetLocalPlayerVoiceFx(out PlayerVoiceFX pv) && (Object)(object)pv != (Object)null) { pv.CmdResetVoiceFX(); } GameStateManager.LogCrowdControl("Voice: Wobble ended (local)."); return EffectResponse.Finished(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("voice_no_mouth_off")] public class VoiceNoMouthOff : Effect { public VoiceNoMouthOff(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfSceneHelpers.TryGetLocalPlayerVoiceFx(out PlayerVoiceFX pv) || (Object)(object)pv == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } pv.CmdSetNoMouthFX(false); GameStateManager.LogCrowdControl("Voice: no-mouth filter OFF (local)."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("voice_no_mouth_on")] public class VoiceNoMouthOn : Effect { public VoiceNoMouthOn(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { if (!GwyfSceneHelpers.TryGetLocalPlayerVoiceFx(out PlayerVoiceFX pv) || (Object)(object)pv == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)16640); } pv.CmdSetNoMouthFX(true); GameStateManager.LogCrowdControl("Voice: no-mouth filter ON (local)."); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } }