using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; 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.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using ConnectorLib.JSON; using CrowdControl.BigWalk; using CrowdControl.Delegates.Effects; using CrowdControl.Delegates.Metadata; using Enviro; using HarmonyLib; using HouseHouse.Dream; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Mirror; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] namespace System.Runtime.CompilerServices { [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 value) { NullableFlags = new byte[1] { value }; } public NullableAttribute(byte[] value) { NullableFlags = value; } } [AttributeUsage(AttributeTargets.Module | 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 value) { Flag = value; } } } namespace CrowdControl { public class CrowdControlBehaviour : MonoBehaviour { public CrowdControlBehaviour(IntPtr ptr) : base(ptr) { } private void FixedUpdate() { CrowdControlMod.Instance?.OnFixedUpdate(); } private void Update() { CrowdControlMod.Instance?.OnUpdate(); } private void OnGUI() { CrowdControlMod.Instance?.OnGUI(); } private void OnApplicationQuit() { CrowdControlMod.Instance?.Shutdown(); } private void OnDestroy() { CrowdControlMod.Instance?.Shutdown(); } private void OnApplicationFocus(bool hasFocus) { try { CrowdControlMod.Instance?.GameStateManager?.InvalidateStateCache(); CrowdControlMod.Instance?.GameStateManager?.UpdateGameState(); } catch { } } private void OnApplicationPause(bool isPaused) { try { CrowdControlMod.Instance?.GameStateManager?.InvalidateStateCache(); CrowdControlMod.Instance?.GameStateManager?.UpdateGameState(); } catch { } } } [BepInPlugin("WarpWorld.CrowdControl", "Crowd Control for Big Walk", "1.0.0")] public class CrowdControlMod : BasePlugin { public const string MOD_GUID = "WarpWorld.CrowdControl"; public const string MOD_NAME = "Crowd Control for Big Walk"; public const string MOD_VERSION = "1.0.0"; private readonly Harmony harmony = new Harmony("WarpWorld.CrowdControl"); private const double MANUAL_RECONNECT_COOLDOWN_SECONDS = 5.0; private DateTime m_nextManualReconnectAllowedUtc = DateTime.MinValue; private bool m_hadFocus = true; private static readonly string[] HostOnlyEffects = new string[1] { "ghostMode" }; private bool? m_hostOnlyShown; private bool m_clientPresent; private float m_nextClientCheck; private const float CLIENT_CHECK_INTERVAL = 2f; private SessionRole m_lastRole = SessionRole.None; private string? _modVersion = null; public static float DeltaTime => (Time.timeScale > 0f) ? (Time.fixedDeltaTime / Time.timeScale) : 0f; public ModLogger Logger { get; private set; } = null; internal static CrowdControlMod Instance { get; private set; } = null; public GameStateManager GameStateManager { get; private set; } = null; public EffectLoader EffectLoader { get; private set; } = null; public bool ClientConnected => Client.Connected; public NetworkClient Client { get; private set; } = null; public Scheduler Scheduler { get; private set; } = null; public string Version { get { try { if (!string.IsNullOrEmpty(_modVersion)) { return _modVersion; } string text = File.ReadAllText(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "ccver")); if (string.IsNullOrEmpty(text)) { _modVersion = "1.0.0"; } else { _modVersion = text; } return _modVersion; } catch (Exception value) { Logger.Warning($"Error retrieving mod version: {value}"); return "0"; } } } public override void Load() { Instance = this; Logger = new ModLogger(((BasePlugin)this).Log); ModSettings.Initialize(); Logger.Msg("Loaded WarpWorld.CrowdControl. Patching."); harmony.PatchAll(); if (EffectRelay.VerboseLogging) { try { foreach (MethodBase patchedMethod in harmony.GetPatchedMethods()) { Logger.Msg("[patch] " + patchedMethod.DeclaringType?.Name + "." + patchedMethod.Name); } } catch (Exception ex) { Logger.Warning("Could not enumerate patches: " + ex.Message); } } Logger.Msg("Initializing Crowd Control"); try { GameStateManager = new GameStateManager(this); Client = new NetworkClient(this); EffectLoader = new EffectLoader(this, Client); Scheduler = new Scheduler(this, Client); } catch (Exception value) { Logger.Error($"Crowd Control Init Error: {value}"); } ((BasePlugin)this).AddComponent(); Logger.Msg("Crowd Control Initialized"); } public override bool Unload() { Shutdown(); return ((BasePlugin)this).Unload(); } internal void Shutdown() { try { Client?.Stop(); Client?.Dispose(); } catch { } } internal void OnFixedUpdate() { if (GameStateManager != null) { GameStateManager.InvalidateStateCache(); GameStateManager.UpdateGameState(); Scheduler?.Tick(); } } private void HandleOverlayToggleHotkey() { if (Input.GetKeyDown((KeyCode)289)) { bool flag = Overlay.Toggle(); Logger.Msg("F8 pressed - overlay " + (flag ? "shown" : "hidden") + "."); if (flag) { Overlay.Show("Crowd Control display on (F8)", force: true); } } } private void HandleManualReconnectHotkey() { if (!Input.GetKeyDown((KeyCode)290)) { return; } DateTime utcNow = DateTime.UtcNow; if (!(utcNow < m_nextManualReconnectAllowedUtc)) { m_nextManualReconnectAllowedUtc = utcNow.AddSeconds(5.0); Logger.Msg("F9 pressed - manual Crowd Control reconnect requested."); NetworkClient client = Client; if (client != null && client.RequestReconnect()) { Overlay.Show("Reconnecting to Crowd Control...", force: true); Logger.Msg("Manual Crowd Control reconnect queued."); } else { Overlay.Show("Crowd Control client not found.", force: true); Logger.Msg("Manual Crowd Control reconnect skipped because the Crowd Control client was not found."); } } } public void ShowGameUiMessage(string message) { Overlay.Show(message); } private void UpdateHostOnlyEffectVisibility() { if (!ClientConnected) { m_hostOnlyShown = null; return; } bool isHost = NetRole.IsHost; if (m_hostOnlyShown != isHost) { m_hostOnlyShown = isHost; if (isHost) { Client.ShowEffects(HostOnlyEffects); } else { Client.HideEffects(HostOnlyEffects); } Logger.Msg($"Host-only effects {(isHost ? "shown" : "hidden")} ({string.Join(", ", HostOnlyEffects)})."); } } internal void OnGUI() { try { Overlay.Draw(ClientConnected, m_clientPresent); } catch { } } private void UpdateSessionRole() { SessionRole current = NetRole.Current; if (current != m_lastRole) { m_lastRole = current; EffectRelay.ResetProbe(); Overlay.Clear(); RemoteTimers.Clear(); Logger.Msg($"Session role is now {current}."); } } private void UpdateClientPresence() { float realtimeSinceStartup = Time.realtimeSinceStartup; if (realtimeSinceStartup < m_nextClientCheck) { return; } m_nextClientCheck = realtimeSinceStartup + 2f; try { m_clientPresent = Client?.CrowdControlClientFound ?? false; } catch { m_clientPresent = false; } } internal void OnUpdate() { try { HandleOverlayToggleHotkey(); HandleManualReconnectHotkey(); UpdateClientPresence(); UpdateSessionRole(); EffectRelay.PollHostStatus(); UpdateHostOnlyEffectVisibility(); bool isFocused = Application.isFocused; if (isFocused != m_hadFocus) { m_hadFocus = isFocused; GameStateManager?.InvalidateStateCache(); GameStateManager?.UpdateGameState(); } } catch { } } } public sealed class ModLogger { private readonly ManualLogSource _log; public ModLogger(ManualLogSource log) { _log = log; } public void Msg(object message) { _log.LogInfo(message); } public void Warning(object message) { _log.LogWarning(message); } public void Error(object message) { _log.LogError(message); } } public class DelimitedStreamReader : IDisposable { private readonly MemoryStream _memory_stream = new MemoryStream(); private readonly NetworkStream m_stream; private const int MAX_MESSAGE_SIZE = 1048576; public DelimitedStreamReader(NetworkStream stream) { m_stream = stream; } ~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 = m_stream.ReadByte()) != -1 && num != 0) { if (_memory_stream.Length >= 1048576) { _memory_stream.SetLength(0L); throw new InvalidDataException("Message exceeded the maximum allowed size without a null terminator. Dropping the connection."); } _memory_stream.WriteByte(checked((byte)num)); } if (num == -1) { throw new EndOfStreamException("Reached end of stream without finding a null terminator."); } string result = Encoding.UTF8.GetString(_memory_stream.ToArray()); _memory_stream.SetLength(0L); return result; } } public static class EffectRequestEx { public const string DEFAULT_VIEWER_NAME = "the crowd"; public const int MAX_VIEWER_NAME_LENGTH = 32; public static string GetViewerDisplayName(this EffectRequest request, string fallback = "the crowd") { //IL_0060: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Invalid comparison between Unknown and I4 string text = request.viewer; if (string.IsNullOrWhiteSpace(text) && request.viewers != null) { foreach (JToken viewer in request.viewers) { JToken obj = ((viewer is JObject) ? viewer : null); string text2 = ((obj != null) ? obj.Value((object)"name") : null); string text3 = text2; if (text3 == null) { JTokenType type = viewer.Type; if (1 == 0) { } string text4 = (((int)type != 8) ? null : Extensions.Value((IEnumerable)viewer)); if (1 == 0) { } text3 = text4; } text = text3; if (!string.IsNullOrWhiteSpace(text)) { break; } } } string text5 = SanitizeDisplayName(text); return (text5.Length > 0) ? text5 : fallback; } public static string SanitizeDisplayName(string name) { if (string.IsNullOrWhiteSpace(name)) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(Math.Min(name.Length, 32)); bool flag = true; foreach (char c in name) { if (char.IsControl(c) || char.IsSurrogate(c) || ((c == '<' || c == '>') ? true : false)) { continue; } if (char.IsWhiteSpace(c)) { if (flag) { continue; } stringBuilder.Append(' '); flag = true; } else { stringBuilder.Append(c); flag = false; } if (stringBuilder.Length < 32) { continue; } break; } return stringBuilder.ToString().TrimEnd(); } } public static class EffectRequestExtensions { public static string Describe(this EffectRequest request) { try { if (!string.IsNullOrWhiteSpace(request.message)) { return request.message; } return request.GetViewerDisplayName() + " used " + request.code; } catch { return "Crowd Control effect"; } } } public class GameStateManager { public const bool CARE_ABOUT_FOCUS = true; private GameState? m_cachedState; private volatile bool m_stateResendRequested; private GameState? _last_game_state; private readonly CrowdControlMod m_mod; public GameState CurrentState { get { //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_002f: 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_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) GameState valueOrDefault = m_cachedState.GetValueOrDefault(); GameState result; if (!m_cachedState.HasValue) { valueOrDefault = GetGameState(); m_cachedState = valueOrDefault; result = valueOrDefault; } else { result = valueOrDefault; } return result; } } public bool IsReady(string code = "") { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Invalid comparison between Unknown and I4 if (GhostGuard.ShouldHold(code)) { return false; } return (int)CurrentState == 1; } public GameState GetGameState() { //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) try { bool flag = !GameRefs.OthersInWorld; if (!Application.isFocused && flag) { return (GameState)(-5); } if (!flag && !Application.runInBackground) { Application.runInBackground = true; } if (Time.timeScale == 0f) { return (GameState)(-7); } if (NetRole.Current == SessionRole.None) { return (GameState)(-13); } if (NetRole.HostMissingMod) { return (GameState)(-2); } if (NetRole.HostVersionMismatch) { return (GameState)(-4); } if (NetRole.HostModUnknown) { return (GameState)(-6); } PlayerCharacter localPlayer = GameRefs.LocalPlayer; if ((Object)(object)localPlayer == (Object)null) { return (GameState)(-6); } WorldManager world = GameRefs.World; if ((Object)(object)world != (Object)null && world.inUI && flag) { return (GameState)(-13); } if (localPlayer.dreamer != null && localPlayer.dreamer.isDreaming) { return (GameState)(-11); } if (localPlayer.faller != null && localPlayer.faller.isDazed) { return (GameState)(-12); } return (GameState)1; } catch (Exception value) { CrowdControlMod.Instance.Logger.Error($"GameStateManager Error: {value}"); return (GameState)(-1); } } public void InvalidateStateCache() { m_cachedState = null; } public void RequestStateResend() { m_stateResendRequested = true; } [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(CurrentState, 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 GameStateManager(CrowdControlMod mod) { m_mod = mod; } public bool UpdateGameState(GameState newState, string message = null, bool force = false) { //IL_0025: 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_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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown if (m_stateResendRequested) { m_stateResendRequested = false; force = true; } if (force || _last_game_state != (GameState?)newState) { _last_game_state = newState; return m_mod.Client.Send((SimpleJSONResponse)new GameUpdate(newState, message)); } return true; } } 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 readonly object m_sendLock = new object(); private readonly AutoResetEvent m_reconnectRequested = new AutoResetEvent(initialState: false); private volatile bool m_disposed; private readonly Thread m_readLoop; private readonly Thread m_maintenanceLoop; private bool m_loggedNoProcess; private bool m_loggedConnectFailure; private static readonly EmptyResponse KEEPALIVE = new EmptyResponse { type = (ResponseType)255 }; public bool Connected => m_client?.Connected ?? false; public bool CrowdControlClientFound => IsCrowdControlSemaphorePresent() || IsCrowdControlProcessRunning(); ~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_quitting.Cancel(); } catch { } CloseConnection(); } private bool WaitForReconnectOrQuit(TimeSpan timeout) { return WaitHandle.WaitAny(new WaitHandle[2] { m_quitting.Token.WaitHandle, m_reconnectRequested }, timeout) != 258; } private void CloseConnection() { lock (m_sendLock) { try { m_streamReader?.Dispose(); } catch { } finally { m_streamReader = null; } try { TcpClient client = m_client; if (client != null && client.Connected) { m_client.Client.Shutdown(SocketShutdown.Both); } m_client?.Close(); m_client?.Dispose(); } catch { } finally { m_client = null; } } } private static bool IsBenignShutdownException(Exception e, bool quitting) { return quitting || e is ThreadAbortException || e is ObjectDisposedException || e is OperationCanceledException || (e is IOException { InnerException: SocketException innerException } && IsBenignSocketError(innerException.SocketErrorCode)) || (e is SocketException ex2 && IsBenignSocketError(ex2.SocketErrorCode)); } 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 bool RequestReconnect() { if (m_disposed || m_quitting.IsCancellationRequested) { return false; } if (!CrowdControlClientFound) { return false; } CloseConnection(); m_loggedConnectFailure = false; m_reconnectRequested.Set(); return true; } 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()) { if (!m_loggedNoProcess) { CrowdControlMod.Instance.Logger.Msg("No Crowd Control client found. Waiting for it to start before attempting to connect..."); m_loggedNoProcess = true; } m_loggedConnectFailure = false; WaitForReconnectOrQuit((TimeSpan)TIMEOUT_NO_PROCESS); continue; } if (m_loggedNoProcess) { CrowdControlMod.Instance.Logger.Msg("Crowd Control client found."); m_loggedNoProcess = false; } if (!m_loggedConnectFailure) { CrowdControlMod.Instance.Logger.Msg("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) { m_loggedConnectFailure = false; ClientLoop(); } else if (!m_loggedConnectFailure) { CrowdControlMod.Instance.Logger.Msg("Failed to connect to Crowd Control. Retrying quietly..."); m_loggedConnectFailure = true; } } catch (Exception ex) { if (!IsBenignShutdownException(ex, m_quitting.IsCancellationRequested) && !m_loggedConnectFailure) { CrowdControlMod.Instance.Logger.Error(ex); CrowdControlMod.Instance.Logger.Error("Failed to connect to Crowd Control. Retrying quietly..."); m_loggedConnectFailure = true; } } finally { CloseConnection(); } if (m_quitting.IsCancellationRequested) { break; } WaitForReconnectOrQuit((TimeSpan)TIMEOUT_NO_CONNECTION); } } 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(1000); } } private void ClientLoop() { Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; try { m_streamReader = new DelimitedStreamReader(m_client.GetStream()); CrowdControlMod.Instance.Logger.Msg("Connected to Crowd Control"); m_mod.GameStateManager?.RequestStateResend(); try { while (!m_quitting.IsCancellationRequested) { string text = m_streamReader.ReadUntilNullTerminator(); OnMessage(text.Trim()); } } catch (EndOfStreamException) { if (!m_quitting.IsCancellationRequested) { CrowdControlMod.Instance.Logger.Msg("Disconnected from Crowd Control"); } } catch (Exception ex2) { if (!IsBenignShutdownException(ex2, m_quitting.IsCancellationRequested)) { CrowdControlMod.Instance.Logger.Error(ex2); CrowdControlMod.Instance.Logger.Error("Disconnected from Crowd Control"); } } } finally { CloseConnection(); } } 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 message2) { CrowdControlMod.Instance.Logger.Error(message2); } } private static bool IsCrowdControlSemaphorePresent() { try { Semaphore result; return Semaphore.TryOpenExisting("CrowdControl", out result); } catch { return false; } } private static bool IsCrowdControlProcessRunning() { Process[] array = null; try { array = Process.GetProcesses(); bool result = false; Process[] array2 = array; foreach (Process process in array2) { try { if (process.ProcessName.IndexOf("crowdcontrol", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } catch (InvalidOperationException) { } catch (Exception) { result = true; } } return result; } catch (Exception) { return true; } finally { if (array != null) { Process[] array3 = array; foreach (Process process2 in array3) { process2.Dispose(); } } } } public bool Send(SimpleJSONResponse response) { try { if (response == null || m_disposed || m_quitting.IsCancellationRequested) { return false; } byte[] bytes = Encoding.UTF8.GetBytes(((SimpleJSONMessage)response).Serialize()); byte[] array = new byte[checked(bytes.Length + 1)]; Array.Copy(bytes, array, bytes.Length); lock (m_sendLock) { TcpClient client = m_client; if (client == null || !client.Connected) { return false; } m_client.GetStream().Write(array, 0, array.Length); return true; } } catch (Exception ex) { if (!IsBenignShutdownException(ex, m_quitting.IsCancellationRequested)) { CrowdControlMod.Instance.Logger.Error($"Error sending a message to the Crowd Control client: {ex}"); } return false; } } public Task SendAsync(SimpleJSONResponse response) { return Task.Run(() => Send(response)); } public void Stop(string message = null) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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_0035: Expected O, but got Unknown if (!m_disposed) { if (message != null) { Send((SimpleJSONResponse)new MessageResponse { type = (ResponseType)254, message = message }); } try { m_quitting.Cancel(); } catch { } CloseConnection(); } } public Task StopAsync(string message = null) { return Task.Run(delegate { Stop(message); }); } 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 var value)) { response.metadata.Add(text, value(m_mod)); } else { CrowdControlMod.Instance.Logger.Error("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(IEnumerable codes, string message = null) { //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, message)); } 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(IEnumerable codes, string message = null) { //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, message)); } public bool ShowAllEffects() { return ShowEffects(m_mod.EffectLoader.EffectIDs); } public Task ShowAllEffectsAsync() { return ShowEffectsAsync(m_mod.EffectLoader.EffectIDs); } 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(IEnumerable codes, string message = null) { //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, message)); } 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(IEnumerable codes, string message = null) { //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, message)); } public bool HideAllEffects() { return HideEffects(m_mod.EffectLoader.EffectIDs); } public Task HideAllEffectsAsync() { return HideEffectsAsync(m_mod.EffectLoader.EffectIDs); } 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(IEnumerable codes, string message = null) { //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, message)); } 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(IEnumerable codes, string message = null) { //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, message)); } public bool EnableAllEffects() { return EnableEffects(m_mod.EffectLoader.EffectIDs); } public Task EnableAllEffectsAsync() { return EnableEffectsAsync(m_mod.EffectLoader.EffectIDs); } 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(IEnumerable codes, string message = null) { //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, message)); } 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(IEnumerable codes, string message = null) { //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, message)); } public bool DisableAllEffects() { return DisableEffects(m_mod.EffectLoader.EffectIDs); } public Task DisableAllEffectsAsync() { return DisableEffectsAsync(m_mod.EffectLoader.EffectIDs); } } 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) { FieldInfo field = obj.GetType().GetField(prop, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); field.SetValue(obj, val); } public static T GetField(this object obj, string prop) { FieldInfo field = obj.GetType().GetField(prop, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); return (T)field.GetValue(obj); } public static void SetProperty(this object obj, string prop, object val) { FieldInfo field = obj.GetType().GetField(prop, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); field.SetValue(obj, val); } public static T GetProperty(this object obj, string prop) { FieldInfo field = obj.GetType().GetField(prop, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); return (T)field.GetValue(obj); } public static void CallMethod(this object obj, string methodName, params object[] vals) { MethodInfo method = obj.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); method.Invoke(obj, vals); } public static T CallMethod(this object obj, string methodName, params object[] vals) { MethodInfo method = obj.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); return (T)method.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 TimedEffectState.EffectState.NotStarted: if (m_enumerator == null) { m_enumerator = TimedEffectState.Start(); } m_enumerator.MoveNext(); return true; case TimedEffectState.EffectState.Running: case 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; TimedEffectState.EffectState? effectState2 = effectState; if (effectState2.HasValue) { TimedEffectState.EffectState valueOrDefault = effectState2.GetValueOrDefault(); if (valueOrDefault == TimedEffectState.EffectState.Running) { m_enumerator = TimedEffectState.Pause(); } } } public void Resume() { (m_enumerator as IDisposable)?.Dispose(); m_enumerator = null; TimedEffectState.EffectState? effectState = TimedEffectState?.State; TimedEffectState.EffectState? effectState2 = effectState; if (effectState2.HasValue) { TimedEffectState.EffectState valueOrDefault = effectState2.GetValueOrDefault(); if (valueOrDefault == TimedEffectState.EffectState.Paused) { m_enumerator = TimedEffectState.Resume(); } } } public void Stop() { (m_enumerator as IDisposable)?.Dispose(); m_enumerator = null; TimedEffectState.EffectState? effectState = TimedEffectState?.State; TimedEffectState.EffectState? effectState2 = effectState; if (effectState2.HasValue) { TimedEffectState.EffectState valueOrDefault = effectState2.GetValueOrDefault(); if ((uint)valueOrDefault <= 2u) { m_enumerator = TimedEffectState.Stop(); } } } public RequestState(EffectRequest request, Effect effect) { Request = request; Effect = effect; if (Effect.IsTimed) { TimedEffectState = new TimedEffectState(effect, request, SITimeSpan.FromMilliseconds(request.duration.GetValueOrDefault())); } } } private readonly CrowdControlMod m_mod; private readonly NetworkClient m_networkClient; private readonly ConcurrentQueue m_messageQueue = new ConcurrentQueue(); private readonly ConcurrentQueue m_requestQueue = new ConcurrentQueue(); private readonly ConcurrentDictionary m_runningEffects = new ConcurrentDictionary(); public Scheduler(CrowdControlMod mod, NetworkClient networkClient) { m_mod = mod; m_networkClient = networkClient; } public bool IsRunning(string id) { return m_runningEffects.Values.Any((RequestState r) => r.Effect.EffectAttribute.IDs.Contains(id)) || m_requestQueue.Any((RequestState r) => r.Effect.EffectAttribute.IDs.Contains(id)); } private bool HasConflict(Effect effect) { EffectAttribute effectAttribute = effect.EffectAttribute; foreach (RequestState value in m_runningEffects.Values) { EffectAttribute effectAttribute2 = value.Effect.EffectAttribute; if (effectAttribute.Conflicts.Intersect(effectAttribute2.IDs).Any()) { return true; } if (effectAttribute2.Conflicts.Intersect(effectAttribute.IDs).Any()) { return true; } } return false; } public void ProcessRequest(SimpleJSONRequest request) { if (request != null) { m_messageQueue.Enqueue(request); } } private void HandleMessage(SimpleJSONRequest request) { //IL_0002: 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_0009: 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_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Invalid comparison between Unknown and I4 //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected I4, but got Unknown //IL_036b: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Expected O, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Invalid comparison between Unknown and I4 //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Invalid comparison between Unknown and I4 //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Expected O, but got Unknown //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Expected O, but got Unknown //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Expected O, but got Unknown RequestType type = request.type; RequestType val = type; if ((int)val <= 32) { switch ((int)val) { 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; } if (!m_mod.EffectLoader.TryGetEffect(val5.code, out var _)) { m_networkClient.Send((SimpleJSONResponse)new EffectResponse(((SimpleJSONRequest)val5).id, (EffectStatus)2, (StandardErrors)4097, (string)null)); CrowdControlMod.Instance.Logger.Error("Effect test requested for unknown effect \"" + val5.code + "\"."); } else { m_networkClient.Send((SimpleJSONResponse)new EffectResponse(((SimpleJSONRequest)val5).id, (EffectStatus)((!m_mod.GameStateManager.IsReady(val5.code)) ? 3 : 0))); } } return; } 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.TryGetEffect(val3.code, out var effect)) { m_networkClient.Send((SimpleJSONResponse)new EffectResponse(((SimpleJSONRequest)val3).id, (EffectStatus)2, (StandardErrors)4097, (string)null)); CrowdControlMod.Instance.Logger.Error("Effect start requested for unknown effect \"" + val3.code + "\"."); } else { m_requestQueue.Enqueue(new RequestState(val3, effect)); } } return; } case 2: { EffectRequest val2 = (EffectRequest)(object)((request is EffectRequest) ? request : null); if (val2 == null) { return; } bool flag = false; foreach (RequestState value2 in m_runningEffects.Values) { if (((SimpleJSONRequest)value2.Request).id == ((SimpleJSONRequest)val2).id || (val2.code != null && value2.Effect.EffectAttribute.IDs.Contains(val2.code))) { value2.Stop(); flag = true; } } if (!flag) { m_networkClient.Send((SimpleJSONResponse)new EffectResponse(((SimpleJSONRequest)val2).id, (EffectStatus)1, (StandardErrors)16899, (string)null)); } return; } } if ((int)val != 32) { return; } DataRequest val6 = (DataRequest)(object)((request is DataRequest) ? request : null); if (val6 == null) { return; } DataResponse val7; if (val6.key != null && MetadataLoader.Metadata.TryGetValue(val6.key, out var value)) { try { val7 = value(m_mod); } catch (Exception message) { CrowdControlMod.Instance.Logger.Error(message); val7 = DataResponse.Failure(val6.key, ((object)(StandardErrors)1/*cast due to .constrained prefix*/).ToString()); } } else { val7 = DataResponse.Failure(val6.key ?? string.Empty, "Unknown metadata key."); } ((SimpleJSONResponse)val7).id = ((SimpleJSONRequest)val6).id; m_networkClient.Send((SimpleJSONResponse)(object)val7); } else if ((int)val != 252) { if ((int)val == 253) { m_mod.GameStateManager.UpdateGameState(force: true); } } else { m_networkClient.Send((SimpleJSONResponse)new VersionResponse(request.id, VersionNumber.op_Implicit(m_mod.Version))); } } public void Enqueue(EffectRequest request, Effect effect) { m_requestQueue.Enqueue(new RequestState(request, effect)); } public static Overlay.ActiveEffect[] ActiveTimedEffects() { Scheduler scheduler = CrowdControlMod.Instance?.Scheduler; if (scheduler == null) { return Array.Empty(); } try { List list = new List(); foreach (RequestState value in scheduler.m_runningEffects.Values) { TimedEffectState timedEffectState = value.TimedEffectState; if (timedEffectState != null) { TimedEffectState.EffectState state = timedEffectState.State; if ((uint)(state - 1) <= 1u) { list.Add(new Overlay.ActiveEffect(EffectNames.Pretty(value.Request.code), (float)timedEffectState.TimeRemaining, (float)timedEffectState.Duration, timedEffectState.State == TimedEffectState.EffectState.Paused)); } } } return list.ToArray(); } catch { return Array.Empty(); } } 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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Invalid comparison between Unknown and I4 //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Invalid comparison between Unknown and I4 //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Expected O, but got Unknown //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Expected O, but got Unknown SimpleJSONRequest result; while (m_messageQueue.TryDequeue(out result)) { try { HandleMessage(result); } catch (Exception message) { CrowdControlMod.Instance.Logger.Error(message); } } RequestState result2; while (m_requestQueue.TryDequeue(out result2)) { GameState currentState = m_mod.GameStateManager.CurrentState; if ((int)currentState == -2) { m_networkClient.SendAsync((SimpleJSONResponse)(object)EffectResponse.Failure(((SimpleJSONRequest)result2.Request).id, "The host is not running the Crowd Control mod.")).Forget(); continue; } if ((int)currentState == -4) { m_networkClient.SendAsync((SimpleJSONResponse)(object)EffectResponse.Failure(((SimpleJSONRequest)result2.Request).id, "The host's Crowd Control mod is a different version.")).Forget(); continue; } if (!m_mod.GameStateManager.IsReady(result2.Request.code)) { m_networkClient.SendAsync((SimpleJSONResponse)new EffectResponse(((SimpleJSONRequest)result2.Request).id, (EffectStatus)3)).Forget(); continue; } if (HasConflict(result2.Effect)) { m_networkClient.SendAsync((SimpleJSONResponse)new EffectResponse(((SimpleJSONRequest)result2.Request).id, (EffectStatus)3, (StandardErrors)32768, (string)null)).Forget(); continue; } if (result2.TimedEffectState != null) { m_runningEffects.TryAdd(((SimpleJSONRequest)result2.Request).id, result2); continue; } EffectResponse response; try { response = result2.Effect.Start(result2.Request); } catch (Exception message2) { response = EffectResponse.Failure(((SimpleJSONRequest)result2.Request).id, (StandardErrors)1, (string)null); CrowdControlMod.Instance.Logger.Error(message2); } m_networkClient.AttachMetadata(response); m_networkClient.SendAsync((SimpleJSONResponse)(object)response).Forget(); } ConsumeEnumerators(); } private void ConsumeEnumerators() { foreach (KeyValuePair runningEffect in m_runningEffects) { if (!runningEffect.Value.MoveNext()) { m_runningEffects.TryRemove(runningEffect.Key, out var _); } } } } [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 result3; bool result2 = TimeSpan.TryParse(s, out result3); result = new SITimeSpan(result3); return result2; } 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; } return (t1 < t2.TotalSeconds) ? (-1) : 0; } public static int Compare(SITimeSpan t1, double t2) { if (t1.TotalSeconds > t2) { return 1; } return (t1.TotalSeconds < t2) ? (-1) : 0; } 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() { return (_value == TimeSpan.Zero) ? ((SITimeSpan?)null) : new SITimeSpan?(this); } 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) { Exception ex2 = ex; CrowdControlMod.Instance.Logger.Error(ex2); } } public static async void Forget(this Task task, bool silent) { try { await task.ConfigureAwait(continueOnCapturedContext: false); } catch (Exception ex) { Exception ex2 = ex; if (!silent) { CrowdControlMod.Instance.Logger.Error(ex2); } } } } } namespace CrowdControl.Delegates.Metadata { [AttributeUsage(AttributeTargets.Method)] public class MetadataAttribute : Attribute { public string[] IDs { get; } public MetadataAttribute(string ids) : this(new string[1] { ids }) { } public MetadataAttribute(IEnumerable ids) : this(ids.Select((string id) => id).ToArray()) { } public MetadataAttribute(params string[] ids) { IDs = ids; } } public delegate DataResponse MetadataDelegate(CrowdControlMod mod); public static class MetadataDelegates { public static readonly string[] CommonMetadata = Array.Empty(); } 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 message) { CrowdControlMod.Instance.Logger.Error(message); } } } } catch { } } } catch { } } } } } namespace CrowdControl.Delegates.Effects { 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)] public class EffectAttribute : Attribute { public IReadOnlyList IDs { get; } public SITimeSpan DefaultDuration { get; } public IReadOnlyList Conflicts { get; } public EffectAttribute(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, (!(defaultDuration > 0f)) ? 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 EffectAttribute(string[] ids, SITimeSpan defaultDuration, string[] conflicts) { IDs = ids; DefaultDuration = defaultDuration; Conflicts = conflicts; } } public class EffectLoader { private const BindingFlags BINDING_FLAGS = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private readonly ConcurrentDictionary m_effects = new ConcurrentDictionary(); private readonly ConcurrentDictionary m_regexes = new ConcurrentDictionary(); public IEnumerable EffectIDs => m_effects.Keys; public bool TryGetEffect(string id, out Effect effect) { if (m_effects.TryGetValue(id, out effect)) { return true; } foreach (KeyValuePair effect2 in m_effects) { if (!m_regexes.GetOrAdd(effect2.Key, (string key) => new Regex(key, RegexOptions.Compiled)).IsMatch(id)) { continue; } effect = effect2.Value; return true; } return false; } public EffectLoader(CrowdControlMod mod, NetworkClient client) { foreach (Type item in from type in Assembly.GetExecutingAssembly().GetTypes() where type.IsSubclassOf(typeof(Effect)) && !type.IsAbstract select type) { try { foreach (EffectAttribute customAttribute in item.GetCustomAttributes()) { foreach (string iD in customAttribute.IDs) { try { m_effects[iD] = (Effect)Activator.CreateInstance(item, mod, client); } catch (Exception message) { CrowdControlMod.Instance.Logger.Error(message); } } } } catch (Exception message2) { CrowdControlMod.Instance.Logger.Error(message2); } } } } public class TimedEffectState { public enum EffectState { NotStarted, Running, Paused, Finished, Errored } public readonly EffectRequest Request; public readonly SITimeSpan Duration; public readonly Effect Effect; public readonly NetworkClient Client; public SITimeSpan TimeRemaining; private int m_stateLock; private static readonly IEnumerator EMPTY_ENUMERATOR = Enumerable.Empty().GetEnumerator(); public EffectState State { get; private set; } = EffectState.NotStarted; 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; } private void FinalizeResponse(EffectResponse response) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 if (response != null) { bool flag = response.timeRemaining == 0; bool flag2 = flag; if (flag2) { EffectStatus status = response.status; bool flag3 = (((int)status == 0 || status - 6 <= 1) ? true : false); flag2 = flag3; } if (flag2) { response.timeRemaining = checked((long)TimeRemaining.TotalMilliseconds); } Client.AttachMetadata(response); } } public IEnumerator Start() { EffectResponse response = null; bool locked = false; try { while (true) { bool flag; locked = (flag = TryGetLock()); if (flag) { break; } yield return null; } if (State == EffectState.NotStarted) { try { response = Effect.Start(Request); TimeRemaining = Duration; State = EffectState.Running; yield break; } catch (Exception ex) { Exception e = ex; response = EffectResponse.Failure(((SimpleJSONRequest)Request).id, (StandardErrors)1, (string)null); CrowdControlMod.Instance.Logger.Error(e.Message); State = EffectState.Errored; yield break; } } } finally { if (locked) { ReleaseLock(); FinalizeResponse(response); Client.Send((SimpleJSONResponse)(object)response); } } } public IEnumerator Pause() { EffectResponse response = null; bool locked = false; try { while (true) { bool flag; locked = (flag = TryGetLock()); if (flag) { break; } yield return null; } if (State == EffectState.Running) { try { response = Effect.Pause(Request); State = EffectState.Paused; yield break; } catch (Exception ex) { Exception e = ex; response = EffectResponse.Failure(((SimpleJSONRequest)Request).id, (StandardErrors)1, (string)null); CrowdControlMod.Instance.Logger.Error(e.Message); State = EffectState.Errored; yield break; } } } finally { if (locked) { ReleaseLock(); FinalizeResponse(response); Client.Send((SimpleJSONResponse)(object)response); } } } public IEnumerator Resume() { EffectResponse response = null; bool locked = false; try { while (true) { bool flag; locked = (flag = TryGetLock()); if (flag) { break; } yield return null; } if (State == EffectState.Paused) { try { response = Effect.Resume(Request); State = EffectState.Running; yield break; } catch (Exception ex) { Exception e = ex; response = EffectResponse.Failure(((SimpleJSONRequest)Request).id, (StandardErrors)1, (string)null); CrowdControlMod.Instance.Logger.Error(e.Message); State = EffectState.Errored; yield break; } } } finally { if (locked) { ReleaseLock(); FinalizeResponse(response); Client.Send((SimpleJSONResponse)(object)response); } } } public IEnumerator Stop() { EffectResponse response = null; bool locked = false; try { while (true) { bool flag; locked = (flag = TryGetLock()); if (flag) { break; } yield return null; } if (State != EffectState.Finished) { try { response = Effect.Stop(Request) ?? EffectResponse.Finished(((SimpleJSONRequest)Request).id, (string)null); State = EffectState.Finished; yield break; } catch (Exception ex) { Exception e = ex; response = EffectResponse.Failure(((SimpleJSONRequest)Request).id, (StandardErrors)1, (string)null); CrowdControlMod.Instance.Logger.Error(e.Message); State = EffectState.Errored; yield break; } } } finally { if (locked) { ReleaseLock(); FinalizeResponse(response); Client.Send((SimpleJSONResponse)(object)response); } } } public IEnumerator Tick() { EffectResponse val = null; bool flag = false; try { if (!(flag = TryGetLock())) { return EMPTY_ENUMERATOR; } switch (State) { case EffectState.Running: if (!CrowdControlMod.Instance.GameStateManager.IsReady(Request.code)) { return Pause(); } 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, (string)null); CrowdControlMod.Instance.Logger.Error(ex.Message); State = EffectState.Errored; } break; case EffectState.Paused: if (!CrowdControlMod.Instance.GameStateManager.IsReady(Request.code)) { break; } return Resume(); } return EMPTY_ENUMERATOR; } finally { if (flag) { ReleaseLock(); if (val != null) { FinalizeResponse(val); Client.Send((SimpleJSONResponse)(object)val); } } } } } } namespace CrowdControl.Delegates.Effects.Implementations { [Effect(new string[] { "forceSit", "sleepNow", "forceWave", "dropEverything", "revokeWalking" }, 20f, new string[] { "forceSit", "sleepNow" })] public class BodyEffects : Effect { private float _prevForward; private float _prevSprint; private float _prevCrouch; private float _prevCrouchSprint; private float _prevSwim; private float _prevSwimSprint; private const float RESEND_INTERVAL = 0.5f; private float _sinceResend; private bool _applied; public BodyEffects(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { try { PlayerCharacter localPlayer = GameRefs.LocalPlayer; PlayerNetworking val = ((localPlayer != null) ? localPlayer.playerNetworking : null); if ((Object)(object)localPlayer == (Object)null || (Object)(object)val == (Object)null) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } switch (request.code) { case "forceSit": { val.CmdSetSitting(true); PlayerSitter sitter = localPlayer.sitter; if (sitter != null) { sitter.SetSittingLocal(true); } break; } case "sleepNow": val.CmdSetSleeping(true); if (localPlayer.sleeper != null) { localPlayer.sleeper.forceSleeping = true; } break; case "forceWave": val.CmdSetGestureLeftWave(true); val.CmdSetGestureRightWave(true); break; case "dropEverything": { PlayerMisc misc = localPlayer.misc; if (misc != null) { misc.EmptyAllPockets(); } break; } case "revokeWalking": { PlayerTunings tunings = localPlayer.tunings; if (tunings == null) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } _prevForward = tunings.forwardSpeed; _prevSprint = tunings.forwardSprintSpeed; _prevCrouch = tunings.crouchForwardSpeed; _prevCrouchSprint = tunings.crouchForwardSprintSpeed; _prevSwim = tunings.swimForwardSpeed; _prevSwimSprint = tunings.swimForwardSprintSpeed; tunings.forwardSpeed = 0f; tunings.forwardSprintSpeed = 0f; tunings.crouchForwardSpeed = 0f; tunings.crouchForwardSprintSpeed = 0f; tunings.swimForwardSpeed = 0f; tunings.swimForwardSprintSpeed = 0f; break; } default: return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)4097, (string)null); } _applied = true; base.Mod.Logger.Msg(request.GetViewerDisplayName() + " started " + request.code); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } catch (Exception value) { base.Mod.Logger.Error($"{request.code} start error: {value}"); return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } } public override EffectResponse Tick(EffectRequest request) { if (!_applied) { return null; } try { PlayerCharacter localPlayer = GameRefs.LocalPlayer; if ((Object)(object)localPlayer == (Object)null) { return null; } string code = request.code; string text = code; if (!(text == "sleepNow")) { if (text == "revokeWalking") { PlayerTunings tunings = localPlayer.tunings; if (tunings != null) { tunings.forwardSpeed = 0f; tunings.forwardSprintSpeed = 0f; tunings.crouchForwardSpeed = 0f; tunings.crouchForwardSprintSpeed = 0f; tunings.swimForwardSpeed = 0f; tunings.swimForwardSprintSpeed = 0f; } } } else if (localPlayer.sleeper != null) { localPlayer.sleeper.forceSleeping = true; } _sinceResend += CrowdControlMod.DeltaTime; if (_sinceResend < 0.5f) { return null; } _sinceResend = 0f; PlayerNetworking playerNetworking = localPlayer.playerNetworking; if ((Object)(object)playerNetworking == (Object)null) { return null; } switch (request.code) { case "forceSit": { playerNetworking.CmdSetSitting(true); PlayerSitter sitter = localPlayer.sitter; if (sitter != null) { sitter.SetSittingLocal(true); } break; } case "sleepNow": playerNetworking.CmdSetSleeping(true); break; case "forceWave": playerNetworking.CmdSetGestureLeftWave(true); playerNetworking.CmdSetGestureRightWave(true); break; } } catch { } return null; } public override EffectResponse Stop(EffectRequest request) { try { PlayerCharacter localPlayer = GameRefs.LocalPlayer; PlayerNetworking val = ((localPlayer != null) ? localPlayer.playerNetworking : null); if ((Object)(object)localPlayer != (Object)null && (Object)(object)val != (Object)null && _applied) { switch (request.code) { case "forceSit": { val.CmdSetSitting(false); PlayerSitter sitter = localPlayer.sitter; if (sitter != null) { sitter.SetSittingLocal(false); } break; } case "sleepNow": if (localPlayer.sleeper != null) { localPlayer.sleeper.forceSleeping = false; } val.CmdSetSleeping(false); break; case "forceWave": val.CmdSetGestureLeftWave(false); val.CmdSetGestureRightWave(false); break; case "revokeWalking": { PlayerTunings tunings = localPlayer.tunings; if (tunings != null) { tunings.forwardSpeed = _prevForward; tunings.forwardSprintSpeed = _prevSprint; tunings.crouchForwardSpeed = _prevCrouch; tunings.crouchForwardSprintSpeed = _prevCrouchSprint; tunings.swimForwardSpeed = _prevSwim; tunings.swimForwardSprintSpeed = _prevSwimSprint; } break; } } } } catch (Exception value) { base.Mod.Logger.Error($"{request.code} stop error: {value}"); } _applied = false; return EffectResponse.Finished(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("dream", 20f)] public class DreamEffect : Effect { private DreamController _controller; public DreamEffect(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { try { if (!NetRole.IsHost) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, "Only the session host can start a dream."); } PlayerCharacter localPlayer = GameRefs.LocalPlayer; if ((Object)(object)localPlayer == (Object)null || localPlayer.dreamer == null) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } _controller = FindController(); if ((Object)(object)_controller == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, "No dream is available in this area."); } localPlayer.dreamer.ServerStartDream(_controller); base.Mod.Logger.Msg(request.GetViewerDisplayName() + " started dream"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } catch (Exception value) { base.Mod.Logger.Error($"dream start error: {value}"); return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } } public override EffectResponse Stop(EffectRequest request) { try { PlayerCharacter localPlayer = GameRefs.LocalPlayer; if (((localPlayer != null) ? localPlayer.dreamer : null) != null && (Object)(object)_controller != (Object)null) { localPlayer.dreamer.ServerStopDream(_controller); } } catch (Exception value) { base.Mod.Logger.Error($"dream stop error: {value}"); } _controller = null; return EffectResponse.Finished(((SimpleJSONMessage)request).ID, (string)null); } private static DreamController FindController() { try { Il2CppReferenceArray val = Resources.FindObjectsOfTypeAll(Il2CppType.Of()); if (val == null || ((Il2CppArrayBase)(object)val).Length == 0) { return null; } return ((Il2CppObjectBase)((Il2CppArrayBase)(object)val)[0]).TryCast(); } catch { return null; } } } [Effect(new string[] { "xray", "eyeMood", "iceFloor" }, 30f, new string[] { "xray", "eyeMood", "iceFloor" })] public class EyeAndFrictionEffects : Effect { private static readonly PlayerEyeMood[] Moods; private static readonly Random Rng; private bool _previousXray; private PlayerEyeMood _previousLeft; private PlayerEyeMood _previousRight; private PlayerEyeMood _forcedMood; private bool _applied; public EyeAndFrictionEffects(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } private static PeckEffectPropXRay FindXRay() { try { if ((Object)(object)PeckEffectPropXRay.activeEffect != (Object)null) { return PeckEffectPropXRay.activeEffect; } Il2CppReferenceArray val = Resources.FindObjectsOfTypeAll(Il2CppType.Of()); return (val != null && ((Il2CppArrayBase)(object)val).Length > 0) ? ((Il2CppObjectBase)((Il2CppArrayBase)(object)val)[0]).TryCast() : null; } catch { return null; } } public override EffectResponse Start(EffectRequest request) { //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) try { PlayerCharacter localPlayer = GameRefs.LocalPlayer; if ((Object)(object)localPlayer == (Object)null) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } switch (request.code) { case "xray": { PeckEffectPropXRay val = FindXRay(); if ((Object)(object)val == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, "X-ray isn't available in this world."); } val.SetEffectActive(true); PlayerEyes playerEyes2 = localPlayer.playerEyes; if (playerEyes2 != null) { _previousXray = playerEyes2.xrayActive; playerEyes2.xrayActive = true; } break; } case "eyeMood": { PlayerEyes playerEyes = localPlayer.playerEyes; if (playerEyes == null) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } _previousLeft = playerEyes.moodLeft; _previousRight = playerEyes.moodRight; _forcedMood = Moods[Rng.Next(Moods.Length)]; playerEyes.SetEyeMood(_forcedMood); EyeMoodOverride.Set(_forcedMood); break; } case "iceFloor": IceFloorOverride.Active = true; break; default: return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)4097, (string)null); } _applied = true; base.Mod.Logger.Msg(request.GetViewerDisplayName() + " started " + request.code); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } catch (Exception value) { base.Mod.Logger.Error($"{request.code} start error: {value}"); return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } } public override EffectResponse Tick(EffectRequest request) { if (!_applied) { return null; } try { PlayerCharacter localPlayer = GameRefs.LocalPlayer; if ((Object)(object)localPlayer == (Object)null) { return null; } string code = request.code; string text = code; if (text == "xray" && localPlayer.playerEyes != null) { localPlayer.playerEyes.xrayActive = true; } } catch { } return null; } public override EffectResponse Stop(EffectRequest request) { //IL_00a5: 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) try { PlayerCharacter localPlayer = GameRefs.LocalPlayer; if ((Object)(object)localPlayer != (Object)null && _applied) { switch (request.code) { case "xray": { PeckEffectPropXRay obj = FindXRay(); if (obj != null) { obj.SetEffectActive(false); } if (localPlayer.playerEyes != null) { localPlayer.playerEyes.xrayActive = _previousXray; } break; } case "eyeMood": EyeMoodOverride.Clear(); if (localPlayer.playerEyes != null) { localPlayer.playerEyes.SetEyeMood(_previousLeft, _previousRight); } break; case "iceFloor": IceFloorOverride.Active = false; break; } } } catch (Exception value) { base.Mod.Logger.Error($"{request.code} stop error: {value}"); } _applied = false; return EffectResponse.Finished(((SimpleJSONMessage)request).ID, (string)null); } static EyeAndFrictionEffects() { PlayerEyeMood[] array = new PlayerEyeMood[6]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); Moods = (PlayerEyeMood[])(object)array; Rng = new Random(); } } [Effect(new string[] { "dropHeld", "kickHeld", "emptyBackpack", "emptyHolster", "spawnItems" })] public class ItemEffects : Effect { private const float FULL_WIND_UP = 1f; private const float PUNT_LIFT = 0.35f; private const int BODY_COUNT = 3; private static readonly Random Rng = new Random(); public ItemEffects(CrowdControlMod mod, NetworkClient client) : base(mod, client) { RelayHandlers.Register("spawnItems", DropBodies); } public override EffectResponse Start(EffectRequest request) { try { PlayerCharacter localPlayer = GameRefs.LocalPlayer; if ((Object)(object)localPlayer == (Object)null) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } switch (request.code) { case "dropHeld": return DoDrop(request, localPlayer); case "kickHeld": return DoPunt(request, localPlayer); case "emptyBackpack": { PlayerRegistry registry2 = localPlayer.registry; return DoEmptyPocket(request, localPlayer, (registry2 != null) ? registry2.backpackPocket : null, "backpack"); } case "emptyHolster": { PlayerRegistry registry = localPlayer.registry; return DoEmptyPocket(request, localPlayer, (registry != null) ? registry.holsterPocket : null, "holster"); } case "spawnItems": return DoSpawn(request, localPlayer); default: return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)4097, (string)null); } } catch (Exception value) { base.Mod.Logger.Error($"{request.code} start error: {value}"); return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } } private EffectResponse DoDrop(EffectRequest request, PlayerCharacter p) { //IL_0064: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) PlayerHands hands = p.hands; if (hands == null || !hands.isHoldingSomething) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, "You aren't holding anything."); } Prop heldProp = hands.heldProp; Vector3 val = (((Object)(object)((heldProp != null) ? heldProp.kernal : null) != (Object)null) ? hands.heldProp.kernal.position : p.kernal.position); PlayerHeldInformation val2 = PlayerHeldInformation.ThrowInfo(0f, val, Quaternion.identity); hands.Drop(val2); try { PlayerNetworking playerNetworking = p.playerNetworking; if (playerNetworking != null) { playerNetworking.CmdPickUp(val2); } } catch (Exception ex) { base.Mod.Logger.Warning("drop replication failed: " + ex.Message); } base.Mod.Logger.Msg(request.GetViewerDisplayName() + " made the player drop their item"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } private EffectResponse DoPunt(EffectRequest request, PlayerCharacter p) { //IL_0088: 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_008d: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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) PlayerHands hands = p.hands; if (hands == null || !hands.isHoldingSomething) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, "You aren't holding anything to kick."); } Prop heldProp = hands.heldProp; Rigidbody val = ((heldProp != null) ? heldProp.rb : null); if ((Object)(object)val == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, "That item can't be kicked."); } Vector3 val2 = (((Object)(object)heldProp.kernal != (Object)null) ? heldProp.kernal.position : val.position); Quaternion val3 = Quaternion.LookRotation(AimDirection(p)); PlayerHeldInformation val4 = PlayerHeldInformation.ThrowInfo(1f, val2, val3); hands.Drop(val4); try { PlayerNetworking playerNetworking = p.playerNetworking; if (playerNetworking != null) { playerNetworking.CmdPickUp(val4); } } catch (Exception ex) { base.Mod.Logger.Warning("punt replication failed: " + ex.Message); } base.Mod.Logger.Msg(request.GetViewerDisplayName() + " punted the player's item"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } private EffectResponse DoEmptyPocket(EffectRequest request, PlayerCharacter p, PropHome pocket, string label) { if (p.misc == null) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } if ((Object)(object)pocket == (Object)null || (Object)(object)pocket.pinnedProp == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, "Your " + label + " is already empty."); } p.misc.EmptyPocket(pocket); base.Mod.Logger.Msg(request.GetViewerDisplayName() + " emptied the player's " + label); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } private EffectResponse DoSpawn(EffectRequest request, PlayerCharacter p) { if (!NetRole.IsHost) { if (!EffectRelay.SendToHost(request)) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } base.Mod.Logger.Msg(request.GetViewerDisplayName() + " asked the host for bodies"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } int num = DropBodiesCounted(p); if (num == 0) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, "Couldn't spawn any bodies."); } base.Mod.Logger.Msg($"{request.GetViewerDisplayName()} dropped {num} bodies"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } private static void DropBodies(PlayerCharacter target) { int num = DropBodiesCounted(target); CrowdControlMod.Instance.Logger.Msg($"[body diag] relayed Body Double for {(((Object)(object)target != (Object)null) ? ((Object)target).name : "unknown")} -> {num} spawned"); if (num == 0) { throw new InvalidOperationException("no bodies spawned"); } } private static int DropBodiesCounted(PlayerCharacter target) { //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) PlayerCharacter localPlayer = GameRefs.LocalPlayer; object obj; if (localPlayer == null) { obj = null; } else { PlayerRegistry registry = localPlayer.registry; obj = ((registry != null) ? registry.corpsePrefab : null); } GameObject val = (GameObject)obj; CrowdControlMod.Instance.Logger.Msg($"[body diag] target={(((Object)(object)target != (Object)null) ? ((Object)target).name : "null")} prefab={(((Object)(object)val != (Object)null) ? "ok" : "NULL")}"); if ((Object)(object)localPlayer == (Object)null || (Object)(object)val == (Object)null) { return 0; } PlayerCharacter val2 = target ?? localPlayer; Vector3 val3 = (((Object)(object)val2.kernal != (Object)null) ? val2.kernal.position : localPlayer.kernal.position); int num = 0; checked { for (int i = 0; i < 3; i++) { try { Corpse val4 = Corpse.CreateAndSpawn(localPlayer, val); if ((Object)(object)val4 == (Object)null) { CrowdControlMod.Instance.Logger.Warning("[body diag] CreateAndSpawn returned null"); continue; } ApplyLook(val4, val2); Transform transform = ((Component)val4).transform; if ((Object)(object)transform != (Object)null) { transform.position = val3 + new Vector3(((float)Rng.NextDouble() - 0.5f) * 3f, 1.5f + (float)i * 0.5f, ((float)Rng.NextDouble() - 0.5f) * 3f); } num++; } catch (Exception value) { CrowdControlMod.Instance.Logger.Warning($"[body diag] spawn failed: {value}"); } } return num; } } private static void ApplyLook(Corpse corpse, PlayerCharacter wearer) { try { PlayerNetworking val = ((wearer != null) ? wearer.playerNetworking : null); if (!((Object)(object)val == (Object)null)) { corpse.NetworkheadColorIndex = val.lookIdHead; corpse.NetworktorsoColorIndex = val.lookIdTorso; corpse.NetworklegsColorIndex = val.lookIdLegs; } } catch (Exception ex) { CrowdControlMod.Instance.Logger.Warning("[body diag] look copy failed: " + ex.Message); } } private static Vector3 AimDirection(PlayerCharacter p) { //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_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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_0043: 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_0052: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_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_0064: Unknown result type (might be due to invalid IL or missing references) Vector3 forward = Vector3.forward; Camera main = Camera.main; if ((Object)(object)main != (Object)null) { forward = ((Component)main).transform.forward; } else if ((Object)(object)p.kernal != (Object)null) { forward = p.kernal.forward; } Vector3 val = forward + Vector3.up * 0.35f; return ((Vector3)(ref val)).normalized; } } [Effect(new string[] { "sensUp", "sensDown", "invertLook", "lookLock" }, 30f, new string[] { "sensUp", "sensDown", "invertLook" })] public class LookTunings : Effect { private const float SENS_UP = 3f; private const float SENS_DOWN = 0.25f; private const float LOOK_CENTRE = 0f; private const float LOOK_RANGE = 8f; private float _mouse; private float _stick; private bool _applied; public LookTunings(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { try { PlayerTunings tunings = GameRefs.Tunings; if (tunings == null) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } switch (request.code) { case "sensUp": ScaleSensitivity(tunings, 3f); break; case "sensDown": ScaleSensitivity(tunings, 0.25f); break; case "invertLook": ScaleSensitivity(tunings, -1f); break; case "lookLock": { PlayerCharacter localPlayer = GameRefs.LocalPlayer; PlayerCameraMinder val = ((localPlayer != null) ? localPlayer.cameraMinder : null); if (val == null) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } val.SetHeadFixed(0f, 8f); break; } default: return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)4097, (string)null); } _applied = true; base.Mod.Logger.Msg(request.GetViewerDisplayName() + " started " + request.code); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } catch (Exception value) { base.Mod.Logger.Error($"{request.code} start error: {value}"); return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } } public override EffectResponse Stop(EffectRequest request) { try { PlayerTunings tunings = GameRefs.Tunings; if (tunings != null && _applied) { switch (request.code) { case "sensUp": case "sensDown": case "invertLook": tunings.mouseLookSpeed = _mouse; tunings.stickLookSpeed = _stick; break; case "lookLock": { PlayerCharacter localPlayer = GameRefs.LocalPlayer; PlayerCameraMinder val = ((localPlayer != null) ? localPlayer.cameraMinder : null); if (val != null) { val.ClearHeadFixed(); } break; } } } } catch (Exception value) { base.Mod.Logger.Error($"{request.code} stop error: {value}"); } _applied = false; return EffectResponse.Finished(((SimpleJSONMessage)request).ID, (string)null); } private void ScaleSensitivity(PlayerTunings t, float factor) { _mouse = t.mouseLookSpeed; _stick = t.stickLookSpeed; t.mouseLookSpeed = _mouse * factor; t.stickLookSpeed = _stick * factor; } } [Effect(new string[] { "teleportRandom", "launchPlayer", "pickUpPlayer" })] public class MotionEffects : Effect { private const float LAUNCH_UP = 18f; private const float LAUNCH_SIDE = 6f; private const float ARRIVAL_LIFT = 1.5f; private static readonly Random Rng = new Random(); private static bool _pointsLogged; public MotionEffects(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { try { PlayerCharacter localPlayer = GameRefs.LocalPlayer; if ((Object)(object)localPlayer == (Object)null) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } return (EffectResponse)(request.code switch { "teleportRandom" => DoTeleport(request, localPlayer), "launchPlayer" => DoLaunch(request, localPlayer), "pickUpPlayer" => DoPickUp(request, localPlayer), _ => EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)4097, (string)null), }); } catch (Exception value) { base.Mod.Logger.Error($"{request.code} start error: {value}"); return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } } private EffectResponse DoTeleport(EffectRequest request, PlayerCharacter p) { //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: 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) List allPoints = TeleportPoint.allPoints; if (allPoints == null || allPoints.Count == 0) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } LogTeleportPoints(allPoints); List list = new List(); for (int i = 0; i < allPoints.Count; i = checked(i + 1)) { TeleportPoint val = allPoints[i]; if ((Object)(object)val != (Object)null && !string.IsNullOrWhiteSpace(val.customName)) { list.Add(val); } } TeleportPoint val2 = ((list.Count > 0) ? list[Rng.Next(list.Count)] : allPoints[Rng.Next(allPoints.Count)]); Vector3 position = ((Component)val2).transform.position + Vector3.up * 1.5f; if (!GameRefs.Teleport(position)) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } string text = (string.IsNullOrWhiteSpace(val2.customName) ? ((Object)val2).name : val2.customName); base.Mod.Logger.Msg(request.GetViewerDisplayName() + " teleported the player to '" + text + "'"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } private void LogTeleportPoints(List points) { if (_pointsLogged) { return; } _pointsLogged = true; try { List list = new List(); for (int i = 0; i < points.Count; i = checked(i + 1)) { TeleportPoint val = points[i]; if (!((Object)(object)val == (Object)null)) { list.Add(string.IsNullOrWhiteSpace(val.customName) ? ("[" + ((Object)val).name + "]") : val.customName); } } base.Mod.Logger.Msg($"[teleport diag] {points.Count} points: {string.Join(", ", list)}"); } catch (Exception ex) { base.Mod.Logger.Warning("[teleport diag] failed: " + ex.Message); } } private EffectResponse DoLaunch(EffectRequest request, PlayerCharacter p) { //IL_00bb: Unknown result type (might be due to invalid IL or missing references) PlayerCharacter val = GameRefs.HeldBy(p); if ((Object)(object)val != (Object)null) { base.Mod.Logger.Msg("launchPlayer held back - player is being carried by " + ((Object)val).name + "; retrying."); return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } Rigidbody rb = p.rb; if ((Object)(object)rb == (Object)null) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(((float)Rng.NextDouble() * 2f - 1f) * 6f, 18f, ((float)Rng.NextDouble() * 2f - 1f) * 6f); rb.AddForce(val2, (ForceMode)2); base.Mod.Logger.Msg(request.GetViewerDisplayName() + " yeeted the player"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } private EffectResponse DoPickUp(EffectRequest request, PlayerCharacter p) { List allPlayerCharacters = PlayerCharacter.allPlayerCharacters; if (allPlayerCharacters == null) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } List list = new List(); for (int i = 0; i < allPlayerCharacters.Count; i = checked(i + 1)) { PlayerCharacter val = allPlayerCharacters[i]; if ((Object)(object)val != (Object)null && !((Object)val).Equals((Object)(object)p)) { list.Add(val); } } if (list.Count == 0) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, "There is nobody else here to pick you up."); } PlayerCharacter val2 = list[Rng.Next(list.Count)]; val2.playerNetworking.CmdPickUpPlayer(p); base.Mod.Logger.Msg(request.GetViewerDisplayName() + " had the player picked up"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } } [Effect(new string[] { "speedUp", "speedDown", "moonJump" }, 30f, new string[] { "speedUp", "speedDown", "moonJump" })] public class MovementTunings : Effect { private const float SPEED_UP = 2f; private const float SPEED_DOWN = 0.4f; private const float JUMP_UP = 2.5f; private float _forward; private float _forwardSprint; private float _crouch; private float _crouchSprint; private float _swim; private float _swimSprint; private float _jumpForce; private float _maxUpwards; private bool _applied; public MovementTunings(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { try { PlayerTunings tunings = GameRefs.Tunings; if (tunings == null) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } switch (request.code) { case "speedUp": ScaleSpeeds(tunings, 2f); break; case "speedDown": ScaleSpeeds(tunings, 0.4f); break; case "moonJump": _jumpForce = tunings.jumpForce; _maxUpwards = tunings.maxUpwardsVelocity; tunings.jumpForce = _jumpForce * 2.5f; tunings.maxUpwardsVelocity = _maxUpwards * 2.5f; break; default: return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)4097, (string)null); } _applied = true; base.Mod.Logger.Msg(request.GetViewerDisplayName() + " started " + request.code); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } catch (Exception value) { base.Mod.Logger.Error($"{request.code} start error: {value}"); return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } } public override EffectResponse Stop(EffectRequest request) { try { PlayerTunings tunings = GameRefs.Tunings; if (tunings != null && _applied) { switch (request.code) { case "speedUp": case "speedDown": RestoreSpeeds(tunings); break; case "moonJump": tunings.jumpForce = _jumpForce; tunings.maxUpwardsVelocity = _maxUpwards; break; } } } catch (Exception value) { base.Mod.Logger.Error($"{request.code} stop error: {value}"); } _applied = false; return EffectResponse.Finished(((SimpleJSONMessage)request).ID, (string)null); } private void ScaleSpeeds(PlayerTunings t, float factor) { _forward = t.forwardSpeed; _forwardSprint = t.forwardSprintSpeed; _crouch = t.crouchForwardSpeed; _crouchSprint = t.crouchForwardSprintSpeed; _swim = t.swimForwardSpeed; _swimSprint = t.swimForwardSprintSpeed; t.forwardSpeed = _forward * factor; t.forwardSprintSpeed = _forwardSprint * factor; t.crouchForwardSpeed = _crouch * factor; t.crouchForwardSprintSpeed = _crouchSprint * factor; t.swimForwardSpeed = _swim * factor; t.swimForwardSprintSpeed = _swimSprint * factor; } private void RestoreSpeeds(PlayerTunings t) { t.forwardSpeed = _forward; t.forwardSprintSpeed = _forwardSprint; t.crouchForwardSpeed = _crouch; t.crouchForwardSprintSpeed = _crouchSprint; t.swimForwardSpeed = _swim; t.swimForwardSprintSpeed = _swimSprint; } } [Effect("blindfold", 15f, new string[] { "blindfold", "xray" })] public class PostFxEffects : Effect { private bool _applied; public PostFxEffects(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { try { PostProcessingManager instance = PostProcessingManager.instance; if (instance == null) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } string code = request.code; string text = code; if (text == "blindfold") { PostProcessingManager.SetBlindfold(true); _applied = true; base.Mod.Logger.Msg(request.GetViewerDisplayName() + " started " + request.code); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)4097, (string)null); } catch (Exception value) { base.Mod.Logger.Error($"{request.code} start error: {value}"); return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } } public override EffectResponse Stop(EffectRequest request) { try { PostProcessingManager instance = PostProcessingManager.instance; if (instance != null && _applied) { string code = request.code; string text = code; if (text == "blindfold") { PostProcessingManager.SetBlindfold(false); } } } catch (Exception value) { base.Mod.Logger.Error($"{request.code} stop error: {value}"); } _applied = false; return EffectResponse.Finished(((SimpleJSONMessage)request).ID, (string)null); } } [Effect("lightning")] public class SmiteEffect : Effect { private const float FLASH_DURATION = 0.18f; private const float FLASH_INTENSITY = 8000f; private const float FLASH_RANGE = 60f; private const float FLASH_HEIGHT = 6f; private const float STRIKE_UP = 9f; private const float STRIKE_OUT = 4f; private static readonly Random Rng = new Random(); public SmiteEffect(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { //IL_003d: 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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) try { PlayerCharacter localPlayer = GameRefs.LocalPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)localPlayer.kernal == (Object)null) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } Vector3 position = localPlayer.kernal.position; Flash(position + Vector3.up * 6f); Rigidbody rb = localPlayer.rb; if ((Object)(object)rb != (Object)null) { Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(((float)Rng.NextDouble() - 0.5f) * 4f, 9f, ((float)Rng.NextDouble() - 0.5f) * 4f); rb.AddForce(val, (ForceMode)2); } try { PlayerFaller faller = localPlayer.faller; if (faller != null) { faller.TriggerFall(); } } catch { } base.Mod.Logger.Msg(request.GetViewerDisplayName() + " smote the player"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } catch (Exception value) { base.Mod.Logger.Error($"lightning start error: {value}"); return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } } private static void Flash(Vector3 position) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown //IL_0013: 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) try { GameObject val = new GameObject("CC_SmiteFlash"); val.transform.position = position; Light val2 = val.AddComponent(); val2.type = (LightType)2; val2.color = new Color(0.85f, 0.9f, 1f); val2.intensity = 8000f; val2.range = 60f; Object.Destroy((Object)(object)val, 0.18f); } catch (Exception ex) { CrowdControlMod.Instance.Logger.Warning("smite flash failed: " + ex.Message); } } } [Effect(new string[] { "night", "day" })] public class TimeOfDayEffects : Effect { private const float NIGHT_HOUR = 1.5f; private const float NOON_HOUR = 12f; private const float TOLERANCE_HOURS = 2f; public TimeOfDayEffects(CrowdControlMod mod, NetworkClient client) : base(mod, client) { RelayHandlers.Register("night", delegate { ApplyTime(1.5f); }); RelayHandlers.Register("day", delegate { ApplyTime(12f); }); } public override EffectResponse Start(EffectRequest request) { try { if (!SkyManager.initalized) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } float num = ((request.code == "night") ? 1.5f : 12f); float currentTime = SkyManager.GetCurrentTime(); if (HoursApart(currentTime, num) <= 2f) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (request.code == "night") ? "It's already night." : "It's already midday."); } EffectRelay.RequestEverywhere(request.code); base.Mod.Logger.Msg($"{request.GetViewerDisplayName()} set the time to {num:0.#}h (was {currentTime:0.#}h)"); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } catch (Exception value) { base.Mod.Logger.Error($"{request.code} start error: {value}"); return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } } private static float HoursApart(float a, float b) { float num = Math.Abs(a - b) % 24f; return (num > 12f) ? (24f - num) : num; } private static void ApplyTime(float hour) { if (SkyManager.initalized) { SkyManager.SetFixedTime(hour); } } } [Effect(new string[] { "muteVoice", "echoVoice", "ghostMode" }, 30f, new string[] { "muteVoice", "echoVoice", "ghostMode" })] public class VoiceEffects : Effect { private const float ECHO_AMOUNT = 1f; private float _previousEcho; private Vector3 _ghostOrigin; private bool _hasGhostOrigin; private bool _applied; public VoiceEffects(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) try { if (!NetRole.InSession) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } PlayerCharacter localPlayer = GameRefs.LocalPlayer; PlayerNetworking val = ((localPlayer != null) ? localPlayer.playerNetworking : null); if ((Object)(object)val == (Object)null) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } switch (request.code) { case "muteVoice": val.CmdSetMute(true); break; case "echoVoice": _previousEcho = val.echoAmount; val.CmdSetEchoAmount(1f); break; case "ghostMode": { if (!NetRole.IsHost) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, "Ghost only works for the session host."); } PlayerCharacter localPlayer2 = GameRefs.LocalPlayer; if ((Object)(object)((localPlayer2 != null) ? localPlayer2.kernal : null) != (Object)null) { _ghostOrigin = localPlayer2.kernal.position; _hasGhostOrigin = true; } val.CmdSetGhost(true); val.CmdSetAudioGhost(true); GhostGuard.Active = true; break; } default: return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)4097, (string)null); } _applied = true; base.Mod.Logger.Msg(request.GetViewerDisplayName() + " started " + request.code); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } catch (Exception value) { base.Mod.Logger.Error($"{request.code} start error: {value}"); return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } } public override EffectResponse Stop(EffectRequest request) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) try { PlayerCharacter localPlayer = GameRefs.LocalPlayer; PlayerNetworking val = ((localPlayer != null) ? localPlayer.playerNetworking : null); if ((Object)(object)val != (Object)null && _applied) { switch (request.code) { case "muteVoice": val.CmdSetMute(false); break; case "echoVoice": val.CmdSetEchoAmount(_previousEcho); break; case "ghostMode": GhostGuard.Active = false; val.CmdSetGhost(false); val.CmdSetAudioGhost(false); if (_hasGhostOrigin && GameRefs.Teleport(_ghostOrigin)) { base.Mod.Logger.Msg("Ghost ended - returned the player to their starting point."); } _hasGhostOrigin = false; break; } } } catch (Exception value) { base.Mod.Logger.Error($"{request.code} stop error: {value}"); } _applied = false; return EffectResponse.Finished(((SimpleJSONMessage)request).ID, (string)null); } } [Effect(new string[] { "weatherStorm", "weatherFog" }, 60f, new string[] { "weatherStorm", "weatherFog" })] public class WeatherEffects : Effect { private static float _sharedPreviousFog; private static bool _fogCaptured; private const float FOG_DENSITY = 50f; private static readonly string[] StormNames = new string[4] { "thunder", "storm", "rain", "heavy" }; private static readonly string[] FogNames = new string[4] { "fog", "mist", "haze", "overcast" }; private EnviroWeatherType _previousWeather; private float _previousFogDensity; private bool _applied; private static bool _diagLogged; private static bool _nullLogged; private static EnviroManager Enviro { get { try { return EnviroManager.instance; } catch { return null; } } } public WeatherEffects(CrowdControlMod mod, NetworkClient client) : base(mod, client) { RelayHandlers.Register("weatherFog", delegate { ApplyFog(on: true); RelayState.MarkActive("weatherFog"); }); RelayHandlers.Register("weatherFogOff", delegate { ApplyFog(on: false); RelayState.MarkInactive("weatherFog"); }); } private static void ApplyFog(bool on) { EnviroManager enviro = Enviro; if ((Object)(object)((enviro != null) ? ((EnviroManagerBase)enviro).Fog : null) == (Object)null) { return; } if (on) { if (!_fogCaptured) { _sharedPreviousFog = ((EnviroManagerBase)enviro).Fog.customFogDensityModifer; _fogCaptured = true; } ((EnviroManagerBase)enviro).Fog.customFogDensityModifer = 50f; } else if (_fogCaptured) { ((EnviroManagerBase)enviro).Fog.customFogDensityModifer = _sharedPreviousFog; _fogCaptured = false; } } public override EffectResponse Start(EffectRequest request) { try { if (RelayState.IsActive(request.code)) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } EnviroManager enviro = Enviro; if ((Object)(object)enviro == (Object)null) { if (!_nullLogged) { _nullLogged = true; base.Mod.Logger.Warning("[weather diag] EnviroManager.instance is NULL - no world effect can function"); } return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } LogWeatherDiagnostics(enviro); string code = request.code; string text = code; if (!(text == "weatherFog")) { if (!(text == "weatherStorm")) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)4097, (string)null); } if ((Object)(object)((EnviroManagerBase)enviro).Weather == (Object)null) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } EnviroWeatherType val = FindWeather(enviro, StormNames); if ((Object)(object)val == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, "No storm weather preset in this world."); } _previousWeather = ((EnviroManagerBase)enviro).Weather.targetWeatherType; if ((Object)(object)enviro.currentZone != (Object)null) { enviro.currentZone.ChangeZoneWeatherInstant(val); } else { ((EnviroManagerBase)enviro).Weather.ChangeWeatherInstant(val); } } else { if ((Object)(object)((EnviroManagerBase)enviro).Fog == (Object)null) { return EffectResponse.Failure(((SimpleJSONMessage)request).ID, "There is no fog system in this world."); } EffectRelay.RequestEverywhere("weatherFog", (float)((double)(request.duration ?? 60000) / 1000.0)); } _applied = true; base.Mod.Logger.Msg(request.GetViewerDisplayName() + " started " + request.code); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } catch (Exception value) { base.Mod.Logger.Error($"{request.code} start error: {value}"); return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } } public override EffectResponse Stop(EffectRequest request) { try { EnviroManager enviro = Enviro; if ((Object)(object)enviro != (Object)null && _applied) { string code = request.code; string text = code; if (!(text == "weatherFog")) { if (text == "weatherStorm" && (Object)(object)((EnviroManagerBase)enviro).Weather != (Object)null && (Object)(object)_previousWeather != (Object)null) { if ((Object)(object)enviro.currentZone != (Object)null) { enviro.currentZone.ChangeZoneWeatherInstant(_previousWeather); } else { ((EnviroManagerBase)enviro).Weather.ChangeWeatherInstant(_previousWeather); } } } else { EffectRelay.RequestEverywhere("weatherFogOff"); } } } catch (Exception value) { base.Mod.Logger.Error($"{request.code} stop error: {value}"); } _applied = false; return EffectResponse.Finished(((SimpleJSONMessage)request).ID, (string)null); } private static void LogWeatherDiagnostics(EnviroManager env) { if (_diagLogged) { return; } _diagLogged = true; try { List list = new List(); EnviroWeatherModule weather = ((EnviroManagerBase)env).Weather; object obj; if (weather == null) { obj = null; } else { EnviroWeather settings = weather.Settings; obj = ((settings != null) ? settings.weatherTypes : null); } List val = (List)obj; if (val != null) { for (int i = 0; i < val.Count; i = checked(i + 1)) { EnviroWeatherType obj2 = val[i]; list.Add(((obj2 != null) ? ((Object)obj2).name : null) ?? ""); } } CrowdControlMod.Instance.Logger.Msg($"[weather diag] zone={(((Object)(object)env.currentZone != (Object)null) ? ((Object)env.currentZone).name : "none")} lightning={(((Object)(object)((EnviroManagerBase)env).Lightning != (Object)null) ? "yes" : "no")} fog={(((Object)(object)((EnviroManagerBase)env).Fog != (Object)null) ? "yes" : "no")} time={(((Object)(object)((EnviroManagerBase)env).Time != (Object)null) ? "yes" : "no")} skyMgrInit={SkyManager.initalized} types=[{string.Join(", ", list)}]"); } catch (Exception ex) { CrowdControlMod.Instance.Logger.Warning("[weather diag] failed: " + ex.Message); } } private static EnviroWeatherType FindWeather(EnviroManager env, string[] wanted) { EnviroWeather settings = ((EnviroManagerBase)env).Weather.Settings; List val = ((settings != null) ? settings.weatherTypes : null); if (val == null) { return null; } foreach (string value in wanted) { for (int j = 0; j < val.Count; j = checked(j + 1)) { EnviroWeatherType val2 = val[j]; if (val2 != null && ((Object)val2).name != null && ((Object)val2).name.ToLowerInvariant().Contains(value)) { return val2; } } } return null; } } [Effect(new string[] { "lowGravity", "highGravity", "desaturate" }, 45f, new string[] { "lowGravity", "highGravity" })] public class WorldPhysicsEffects : Effect { private const float LOW_GRAVITY = 0.25f; private const float HIGH_GRAVITY = 2.5f; private const float DESATURATED = 0.05f; private Vector3 _previousGravity; private float _previousSaturation; private bool _applied; public WorldPhysicsEffects(CrowdControlMod mod, NetworkClient client) : base(mod, client) { } public override EffectResponse Start(EffectRequest request) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) try { switch (request.code) { case "lowGravity": case "highGravity": { if (!GameRefs.InGame) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } _previousGravity = Physics.gravity; float num = ((request.code == "lowGravity") ? 0.25f : 2.5f); Physics.gravity = _previousGravity * num; break; } case "desaturate": { PlayerCharacter localPlayer = GameRefs.LocalPlayer; PlayerCameraMinder val = ((localPlayer != null) ? localPlayer.cameraMinder : null); if (val == null) { return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } _previousSaturation = val.saturationScalar; val.saturationScalar = 0.05f; break; } default: return EffectResponse.Failure(((SimpleJSONMessage)request).ID, (StandardErrors)4097, (string)null); } _applied = true; base.Mod.Logger.Msg(request.GetViewerDisplayName() + " started " + request.code); return EffectResponse.Success(((SimpleJSONMessage)request).ID, (string)null); } catch (Exception value) { base.Mod.Logger.Error($"{request.code} start error: {value}"); return EffectResponse.Retry(((SimpleJSONMessage)request).ID, (string)null); } } public override EffectResponse Tick(EffectRequest request) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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_008b: Unknown result type (might be due to invalid IL or missing references) if (!_applied) { return null; } try { switch (request.code) { case "lowGravity": case "highGravity": { float num = ((request.code == "lowGravity") ? 0.25f : 2.5f); Vector3 val2 = _previousGravity * num; if (Physics.gravity != val2) { Physics.gravity = val2; } break; } case "desaturate": { PlayerCharacter localPlayer = GameRefs.LocalPlayer; PlayerCameraMinder val = ((localPlayer != null) ? localPlayer.cameraMinder : null); if (val != null) { val.saturationScalar = 0.05f; } break; } } } catch { } return null; } public override EffectResponse Stop(EffectRequest request) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) try { if (_applied) { switch (request.code) { case "lowGravity": case "highGravity": Physics.gravity = _previousGravity; break; case "desaturate": { PlayerCharacter localPlayer = GameRefs.LocalPlayer; PlayerCameraMinder val = ((localPlayer != null) ? localPlayer.cameraMinder : null); if (val != null) { val.saturationScalar = _previousSaturation; } break; } } } } catch (Exception value) { base.Mod.Logger.Error($"{request.code} stop error: {value}"); } _applied = false; return EffectResponse.Finished(((SimpleJSONMessage)request).ID, (string)null); } } } namespace CrowdControl.BigWalk { public static class CcTheme { public static readonly Color Slate800 = Hex(1709866); public static readonly Color Slate700 = Hex(2171190); public static readonly Color Slate600 = Hex(2632003); public static readonly Color Slate500 = Hex(2961485); public static readonly Color Slate400 = Hex(3289939); public static readonly Color Royal50 = Hex(7764980); public static readonly Color Royal100 = Hex(5984960); public static readonly Color Royal200 = Hex(3352434); public static readonly Color White100 = Hex(16448250); public static readonly Color White200 = Hex(13487593); public static readonly Color White300 = Hex(11184845); public static readonly Color Teal200 = Hex(2024093); public static readonly Color Red200 = Hex(15351146); public static readonly Color Yellow300 = Hex(16754437); public static readonly Color Blurple200 = Hex(4239863); private static Color Hex(int rgb, float a = 1f) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) return new Color((float)((rgb >> 16) & 0xFF) / 255f, (float)((rgb >> 8) & 0xFF) / 255f, (float)(rgb & 0xFF) / 255f, a); } public static Color Fade(this Color c, float alpha) { //IL_0000: 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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) return new Color(c.r, c.g, c.b, c.a * alpha); } } public enum Authority { Local, OwnedCommand, Host, Unverified } public enum Confidence { High, Medium, Low } public sealed record EffectDef(string Code, string Name, string Description, float Duration, string[] Conflicts, Authority Authority, string Hook, Confidence Confidence, bool Shipped); public static class EffectCatalog { private static readonly HashSet DeferredCodes = new HashSet(StringComparer.OrdinalIgnoreCase) { "noJump", "forceCrouch", "dropPose", "forceFall", "spin", "insomnia", "fovIn", "fovOut", "binoculars", "voice2D", "forcePoint", "weatherClear", "day", "blindfold", "cursedEyes", "scrambleRadio" }; public static readonly EffectDef[] Movement = new EffectDef[17] { E("speedUp", "Caffeinated", "Crank the walk and sprint speed way up.", 30f, Authority.Local, "PlayerTunings.forwardSpeed / forwardSprintSpeed", Confidence.High, "speedUp", "speedDown"), E("speedDown", "Molasses", "Drop the walk and sprint speed to a crawl.", 30f, Authority.Local, "PlayerTunings.forwardSpeed / forwardSprintSpeed", Confidence.High, "speedUp", "speedDown"), E("moonJump", "Moon Boots", "Jump absurdly high.", 45f, Authority.Local, "PlayerTunings.jumpForce / maxUpwardsVelocity", Confidence.High, "moonJump", "noJump"), E("noJump", "Heavy Legs", "Take away jumping entirely.", 30f, Authority.Local, "PlayerTunings.jumpForce", Confidence.High, "moonJump", "noJump"), E("lowGravity", "Low Gravity", "Float like the moon just showed up.", 45f, Authority.Host, "CmdChangeGravityScale", Confidence.High, "lowGravity", "highGravity"), E("highGravity", "Heavy World", "Gravity cranked up - every step is a chore.", 30f, Authority.Host, "CmdChangeGravityScale", Confidence.High, "lowGravity", "highGravity"), E("iceFloor", "Banana Peel", "The ground loses all friction.", 30f, Authority.Unverified, "PlayerCollision._zeroFrictionMaterial", Confidence.Medium, "iceFloor"), E("forceCrouch", "Stay Down", "Force the player into a crouch.", 20f, Authority.OwnedCommand, "CmdSetCrouchness", Confidence.High, "forceCrouch", "forceSit"), E("forceSit", "Take A Seat", "Sit the player down whether they like it or not.", 15f, Authority.OwnedCommand, "CmdSetSitting", Confidence.High, "forceCrouch", "forceSit"), E("sleepNow", "Nap Time", "Force the player to fall asleep.", 15f, Authority.OwnedCommand, "PlayerSleeper.forceSleeping / CmdSetSleeping", Confidence.High, "sleepNow", "insomnia"), E("insomnia", "Insomnia", "The player cannot fall asleep at all.", 60f, Authority.Host, "PlayerSleeper.preventSleeping", Confidence.Medium, "sleepNow", "insomnia"), E("revokeWalking", "Walking License Revoked", "Undo the game's own proof that you can walk.", 30f, Authority.Host, "PlayerTeacher.canWalk / LearnState", Confidence.Medium, "revokeWalking"), E("spin", "Spin Cycle", "Spin the player in place.", 15f, Authority.Unverified, "PlayerMover.applySittingSpin / sittingSpinSpeed", Confidence.Medium, "spin"), E("teleportRandom", "Scenic Detour", "Teleport the player to a random known point.", 0f, Authority.Host, "CmdTeleport + TeleportPoint.allPoints", Confidence.High), E("launchPlayer", "Yeet", "Fire the player into the air.", 0f, Authority.Host, "CmdSendVelocity / LaunchSettings", Confidence.High), E("forceFall", "Trip", "Trigger a fall and the dazed state that follows.", 0f, Authority.Host, "PlayerFaller.TriggerFall / isDazed", Confidence.High), E("dropPose", "Posture Check", "Kick the player out of any pose or seat.", 0f, Authority.Host, "CmdExitPose / PeckEffectLeavePose", Confidence.High) }; public static readonly EffectDef[] Vision = new EffectDef[12] { E("fovIn", "Tunnel Vision", "Squeeze the field of view down.", 30f, Authority.Local, "PlayerCameraMinder.fovFromSettings", Confidence.Medium, "fovIn", "fovOut"), E("fovOut", "Fisheye", "Blow the field of view wide open.", 30f, Authority.Local, "PlayerCameraMinder.fovFromSettings", Confidence.Medium, "fovIn", "fovOut"), E("invertLook", "Inverted Look", "Flip the look axes.", 45f, Authority.Local, "PlayerLooks / PlayerTunings.mouseLookSpeed", Confidence.High, "invertLook"), E("sensUp", "Twitchy", "Look sensitivity through the roof.", 30f, Authority.Local, "PlayerTunings.mouseLookSpeed / stickLookSpeed", Confidence.High, "sensUp", "sensDown"), E("sensDown", "Stiff Neck", "Look sensitivity down to nearly nothing.", 30f, Authority.Local, "PlayerTunings.mouseLookSpeed / stickLookSpeed", Confidence.High, "sensUp", "sensDown"), E("lookLock", "Eyes Forward", "Clamp how far the player can turn their head.", 30f, Authority.Local, "PlayerTunings.upperLookLimit / lowerLookLimit / sideLookLimit", Confidence.High, "lookLock"), E("desaturate", "Grayscale", "Drain the colour out of the world.", 45f, Authority.Local, "PlayerCameraMinder.saturationScalar", Confidence.Medium, "desaturate"), E("blindfold", "Blindfold", "Mask the player's view.", 15f, Authority.Unverified, "PeckEffectMask", Confidence.Low, "blindfold"), E("xray", "X-Ray Eyes", "Turn on the see-through vision mode.", 30f, Authority.Unverified, "PlayerEyes.xrayActive / PeckEffectPropXRay", Confidence.Medium, "xray"), E("binoculars", "Binoculars", "Force the zoomed binocular view on.", 20f, Authority.Unverified, "PlayerEyes.binocularsActive / PeckEffectTelescope", Confidence.Medium, "binoculars"), E("cursedEyes", "Cursed Eyes", "Apply the game's own eye curse effect.", 30f, Authority.Unverified, "PeckEffectCurseEyes", Confidence.Low, "cursedEyes"), E("dream", "Daydream", "Drop the player into a dream sequence.", 20f, Authority.Host, "PlayerDreamer.ServerStartDream", Confidence.Medium, "dream") }; public static readonly EffectDef[] Social = new EffectDef[11] { E("muteVoice", "Laryngitis", "Mute the player's voice chat.", 30f, Authority.OwnedCommand, "CmdSetMute / PlayerLips.isMuted", Confidence.High, "muteVoice"), E("echoVoice", "Cave Voice", "Drench the player's voice in echo.", 45f, Authority.OwnedCommand, "CmdSetEchoAmount", Confidence.High, "echoVoice"), E("voice2D", "Voice In Your Head", "Strip the positional audio from the player's voice.", 45f, Authority.OwnedCommand, "CmdSet2DVoice", Confidence.Medium, "voice2D"), E("ghostMode", "Ghost", "Turn the player into a ghost.", 30f, Authority.OwnedCommand, "CmdSetGhost / CmdSetAudioGhost", Confidence.High, "ghostMode"), E("renamePlayer", "Name Change", "Rename the player after the viewer who bought it.", 60f, Authority.OwnedCommand, "CmdSetPlayerName", Confidence.High, "renamePlayer"), E("forceWave", "Friendly", "Force the player to wave nonstop.", 20f, Authority.OwnedCommand, "CmdSetGestureLeftWave / CmdSetGestureRightWave", Confidence.High, "forceWave", "forcePoint"), E("forcePoint", "Accusatory", "Force the player to point nonstop.", 20f, Authority.OwnedCommand, "CmdSetGestureLeftPoint / CmdSetGestureRightPoint", Confidence.High, "forceWave", "forcePoint"), E("pickUpPlayer", "Abduction", "Make another player pick this one up.", 0f, Authority.Host, "CmdPickUpPlayer", Confidence.Medium), E("dropEverything", "Butterfingers", "Empty every pocket the player has.", 0f, Authority.Host, "PlayerMisc.EmptyAllPockets", Confidence.High), E("scrambleRadio", "Bad Reception", "Scramble the FM radio.", 45f, Authority.Unverified, "PeckLogicScrambler / FmRadioDial", Confidence.Low, "scrambleRadio"), E("eyeMood", "Mood Swing", "Force a random eye mood on the player.", 30f, Authority.OwnedCommand, "CmdSetMenuEyes / PlayerEyes.SetEyeMood", Confidence.Medium, "eyeMood") }; public static readonly EffectDef[] Items = new EffectDef[4] { E("dropHeld", "Butterfingers", "Make the player drop whatever they're holding.", 0f, Authority.Local, "PlayerHands.ProcessDrop", Confidence.High), E("kickHeld", "Punt", "Boot the held item across the map at full force.", 0f, Authority.Local, "PlayerHands.heldProp + PlayerTunings.kickSettings", Confidence.High), E("emptyBackpack", "Backpack Raid", "Empty the player's backpack onto the ground.", 0f, Authority.Local, "PlayerRegistry.backpackPocket + PlayerMisc.EmptyPocket", Confidence.High), E("emptyHolster", "Holster Raid", "Empty the player's holster onto the ground.", 0f, Authority.Local, "PlayerRegistry.holsterPocket + PlayerMisc.EmptyPocket", Confidence.High) }; public static readonly EffectDef[] World = new EffectDef[6] { E("weatherStorm", "Storm", "Roll in a thunderstorm instantly.", 60f, Authority.Host, "Enviro.ChangeWeatherInstant", Confidence.Medium, "weatherStorm", "weatherFog", "weatherClear"), E("weatherFog", "Pea Soup", "Drown the world in fog.", 60f, Authority.Host, "Enviro.ChangeWeatherInstant + fog override", Confidence.Medium, "weatherStorm", "weatherFog", "weatherClear"), E("weatherClear", "Blue Skies", "Force perfectly clear weather.", 60f, Authority.Host, "Enviro.ChangeWeatherInstant", Confidence.Medium, "weatherStorm", "weatherFog", "weatherClear"), E("lightning", "Smite", "Call a lightning bolt down near the player.", 0f, Authority.Host, "Enviro.CastLightningBoltRandom", Confidence.Medium), E("night", "Sudden Night", "Slam the clock to the middle of the night.", 60f, Authority.Host, "Enviro time-of-day", Confidence.Medium, "night", "day"), E("day", "Sudden Noon", "Slam the clock to midday.", 60f, Authority.Host, "Enviro time-of-day", Confidence.Medium, "night", "day") }; public static readonly EffectDef[] All = Movement.Concat(Vision).Concat(Social).Concat(Items) .Concat(World) .ToArray(); public static readonly EffectDef[] Shipped = All.Where((EffectDef e) => e.Shipped).ToArray(); private static EffectDef E(string code, string name, string desc, float duration, Authority authority, string hook, Confidence confidence, params string[] conflicts) { return new EffectDef(code, name, desc, duration, conflicts, authority, hook, confidence, !DeferredCodes.Contains(code)); } } public static class EffectNames { private static readonly Dictionary Names = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "speedUp", "Speed Up" }, { "speedDown", "Speed Down" }, { "moonJump", "Moon Jump" }, { "lowGravity", "Low Gravity" }, { "highGravity", "High Gravity" }, { "iceFloor", "Ice Physics" }, { "forceSit", "Force Sit" }, { "sleepNow", "Force Sleep" }, { "revokeWalking", "No Walking" }, { "teleportRandom", "Random Teleport" }, { "launchPlayer", "Launch Player" }, { "invertLook", "Invert Look" }, { "sensUp", "High Sensitivity" }, { "sensDown", "Low Sensitivity" }, { "lookLock", "Lock View" }, { "desaturate", "Grayscale" }, { "xray", "X-Ray Vision" }, { "blindfold", "Blindfold" }, { "dream", "Dream" }, { "muteVoice", "Mute Voice" }, { "echoVoice", "Echo Voice" }, { "ghostMode", "Ghost Mode" }, { "renamePlayer", "Name Change" }, { "forceWave", "Force Wave" }, { "pickUpPlayer", "Pick Up Player" }, { "dropEverything", "Empty Pockets" }, { "eyeMood", "Random Eye Mood" }, { "dropHeld", "Drop Item" }, { "kickHeld", "Kick Item" }, { "emptyBackpack", "Empty Backpack" }, { "emptyHolster", "Empty Holster" }, { "spawnItems", "Body Double" }, { "weatherStorm", "Storm" }, { "weatherFog", "Fog" }, { "lightning", "Lightning Strike" }, { "night", "Sudden Night" }, { "day", "Sudden Noon" } }; public static string Pretty(string code) { if (string.IsNullOrWhiteSpace(code)) { return "Effect"; } if (Names.TryGetValue(code, out var value)) { return value; } checked { StringBuilder stringBuilder = new StringBuilder(code.Length + 4); for (int i = 0; i < code.Length; i++) { char c = code[i]; if (i > 0 && char.IsUpper(c) && !char.IsUpper(code[i - 1])) { stringBuilder.Append(' '); } stringBuilder.Append((i == 0) ? char.ToUpperInvariant(c) : c); } return stringBuilder.ToString(); } } } public static class EffectRelay { private readonly struct Payload { public readonly string Code; public readonly string Nonce; public readonly bool ForwardOnward; public readonly string Data; public Payload(string code, string nonce, bool forwardOnward, string data) { Code = code; Nonce = nonce; ForwardOnward = forwardOnward; Data = data; } } [HarmonyPatch(typeof(PlayerNetworking), "UserCode_CmdSendTextChatMessage__String")] private static class PlayerNetworking_CmdTextChat { private static bool Prefix(PlayerNetworking __instance, string message) { Trace("Cmd body", message, IsRelayPayload(message)); if (IsPassthrough(message)) { return true; } return !HandleMessage(__instance, message); } } [HarmonyPatch(typeof(PlayerNetworking), "InvokeUserCode_CmdSendTextChatMessage__String")] private static class PlayerNetworking_InvokeCmdTextChat { private static bool Prefix(NetworkBehaviour __0, NetworkReader __1) { try { int position; string text = PeekString(__1, out position); if (text == null) { Trace("Cmd stub", null, payload: false); return true; } Trace("Cmd stub", text, IsRelayPayload(text)); if (IsPassthrough(text)) { __1.Position = position; return true; } if (!HandleMessage((__0 != null) ? ((Il2CppObjectBase)__0).TryCast() : null, text)) { __1.Position = position; return true; } return false; } catch (Exception value) { CrowdControlMod.Instance.Logger.Error($"Relay Cmd stub patch failed: {value}"); return true; } } } [HarmonyPatch(typeof(PlayerNetworking), "UserCode_RpcTextChatMessage__String")] private static class PlayerNetworking_RpcTextChat { private static bool Prefix(string message) { Trace("Rpc body", message, IsRelayPayload(message)); if (IsPassthrough(message)) { return true; } return !HandleMessage(null, message); } } [HarmonyPatch(typeof(PlayerNetworking), "InvokeUserCode_RpcTextChatMessage__String")] private static class PlayerNetworking_InvokeRpcTextChat { private static bool Prefix(NetworkBehaviour __0, NetworkReader __1) { try { int position; string text = PeekString(__1, out position); if (text == null) { Trace("Rpc stub", null, payload: false); return true; } Trace("Rpc stub", text, IsRelayPayload(text)); if (IsPassthrough(text)) { __1.Position = position; return true; } if (!HandleMessage((__0 != null) ? ((Il2CppObjectBase)__0).TryCast() : null, text)) { __1.Position = position; return true; } return false; } catch (Exception value) { CrowdControlMod.Instance.Logger.Error($"Relay Rpc stub patch failed: {value}"); return true; } } } public const string MAGIC = " SeenNonces = new HashSet(StringComparer.Ordinal); private static readonly Queue NonceOrder = new Queue(); private const int NONCE_MEMORY = 256; private static int _nonceCounter; private const string PING = "__ping"; private const string PONG = "__pong"; private const float PROBE_DELAY = 3f; private const float PROBE_GAP = 5f; private const float PROBE_TIMEOUT = 5f; private const int PROBE_ATTEMPTS = 2; private static float _nextProbe = float.NaN; private static int _probesSent; private static readonly HashSet WarnedGuestVersions = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly HashSet PassthroughNonces = new HashSet(StringComparer.Ordinal); private static readonly Queue PassthroughOrder = new Queue(); public static bool VerboseLogging = false; private static int _traceBudget = 40; public static void ResetProbe() { _nextProbe = float.NaN; _probesSent = 0; _traceBudget = 40; WarnedGuestVersions.Clear(); NetRole.ResetHostProbe(); } public static void PollHostStatus() { checked { try { if (!NetRole.IsClient || NetRole.HostModState != NetRole.HostMod.Unknown) { return; } PlayerCharacter localPlayer = GameRefs.LocalPlayer; if ((Object)(object)((localPlayer != null) ? localPlayer.playerNetworking : null) == (Object)null) { _nextProbe = float.NaN; return; } float realtimeSinceStartup = Time.realtimeSinceStartup; if (float.IsNaN(_nextProbe)) { _nextProbe = realtimeSinceStartup + 3f; } else { if (realtimeSinceStartup < _nextProbe) { return; } if (_probesSent >= 2) { NetRole.NoteHostSilent(); } else if (SendToHost("__ping", NewNonce(), forwardOnward: false, "1.0.0")) { _probesSent++; if (VerboseLogging) { CrowdControlMod.Instance.Logger.Msg($"[relay] probe {_probesSent}/{2} sent to host (v{"1.0.0"})"); } _nextProbe = realtimeSinceStartup + ((_probesSent < 2) ? 5f : 5f); } } } catch { } } } private static void NoteGuestVersion(string guestVersion) { try { string text = (string.IsNullOrWhiteSpace(guestVersion) ? "unknown" : guestVersion.Trim()); if (!string.Equals(text, "1.0.0", StringComparison.OrdinalIgnoreCase) && WarnedGuestVersions.Add(text)) { CrowdControlMod.Instance.Logger.Warning($"A player has mod v{text}; this host has v{"1.0.0"}. Versions should match."); Overlay.Show("Player mod v" + text + " ≠ yours", force: true); } } catch { } } private static bool ClaimNonce(string nonce) { if (string.IsNullOrEmpty(nonce)) { return true; } if (!SeenNonces.Add(nonce)) { return false; } NonceOrder.Enqueue(nonce); if (NonceOrder.Count > 256) { SeenNonces.Remove(NonceOrder.Dequeue()); } return true; } private static string NewNonce() { uint value = 0u; try { PlayerCharacter localPlayer = GameRefs.LocalPlayer; uint? obj; if (localPlayer == null) { obj = null; } else { PlayerNetworking playerNetworking = localPlayer.playerNetworking; obj = ((playerNetworking != null) ? new uint?(((NetworkBehaviour)playerNetworking).netId) : ((uint?)null)); } uint? num = obj; value = num.GetValueOrDefault(); } catch { } return $"{value}-{checked(++_nonceCounter)}"; } public static bool RequestEverywhere(string code, float durationSeconds = 0f) { string nonce = NewNonce(); ClaimNonce(nonce); bool result = RelayHandlers.Dispatch(code, GameRefs.LocalPlayer); string data = ((durationSeconds > 0f) ? durationSeconds.ToString("0.##", CultureInfo.InvariantCulture) : ""); if (NetRole.IsHost) { BroadcastToClients(code, nonce, data); } else { SendToHost(code, nonce, forwardOnward: true, data); } return result; } private static void UpdateRemoteTimer(string code, string data) { try { float result; if (code.EndsWith("Off", StringComparison.OrdinalIgnoreCase)) { RemoteTimers.Stop(code.Substring(0, checked(code.Length - 3))); } else if (float.TryParse(data, NumberStyles.Float, CultureInfo.InvariantCulture, out result)) { RemoteTimers.Start(code, result); } } catch { } } public static bool SendToHost(EffectRequest request) { return SendToHost(request.code, NewNonce(), forwardOnward: false); } private static bool SendToHost(string code, string nonce, bool forwardOnward, string data = "") { try { PlayerCharacter localPlayer = GameRefs.LocalPlayer; PlayerNetworking val = ((localPlayer != null) ? localPlayer.playerNetworking : null); if ((Object)(object)val == (Object)null) { return false; } val.CmdSendTextChatMessage(Wrap(string.Join('|'.ToString(), code, nonce, forwardOnward ? "1" : "0", data ?? ""))); return true; } catch (Exception value) { CrowdControlMod.Instance.Logger.Error($"Relay send failed: {value}"); return false; } } private static void MarkPassthrough(string nonce) { if (PassthroughNonces.Add(nonce)) { PassthroughOrder.Enqueue(nonce); if (PassthroughOrder.Count > 256) { PassthroughNonces.Remove(PassthroughOrder.Dequeue()); } } } private static bool IsPassthrough(string message) { Payload payload; return IsRelayPayload(message) && TryDecode(message, out payload) && PassthroughNonces.Contains(payload.Nonce); } private static bool BroadcastToClients(string code, string nonce, string data = "") { try { if (!NetRole.IsHost) { return false; } PlayerCharacter localPlayer = GameRefs.LocalPlayer; PlayerNetworking val = ((localPlayer != null) ? localPlayer.playerNetworking : null); if ((Object)(object)val == (Object)null) { return false; } MarkPassthrough(nonce); val.CmdSendTextChatMessage(Wrap(string.Join('|'.ToString(), code, nonce, "0", data ?? ""))); return true; } catch (Exception ex) { CrowdControlMod.Instance.Logger.Warning("Broadcast failed: " + ex.Message); return false; } } private static string Wrap(string fields) { string text = Convert.ToBase64String(Encoding.UTF8.GetBytes(fields)).Replace('+', '-').Replace('/', '_') .TrimEnd('='); return ""; } private static string Unwrap(string message) { int num = message.IndexOf("", num, StringComparison.Ordinal); if (num2 <= num) { return null; } text = message.Substring(num, num2 - num).Replace('-', '+').Replace('_', '/'); } switch (text.Length % 4) { case 2: text += "=="; break; case 3: text += "="; break; } try { return Encoding.UTF8.GetString(Convert.FromBase64String(text)); } catch { return null; } } public static bool IsRelayPayload(string message) { return message != null && message.IndexOf("= 0; } private static bool TryDecode(string message, out Payload payload) { payload = default(Payload); string text = Unwrap(message); if (text == null) { return false; } string[] array = text.Split('|'); if (array.Length < 3) { return false; } payload = new Payload(array[0], array[1], array[2] == "1", (array.Length > 3) ? array[3] : ""); return true; } private static bool HandleMessage(PlayerNetworking sender, string message) { if (!IsRelayPayload(message)) { return false; } try { if (!TryDecode(message, out var payload)) { CrowdControlMod.Instance.Logger.Warning("[relay] payload arrived but did not decode - was it mangled in transit?"); return true; } if (!ClaimNonce(payload.Nonce)) { return true; } bool isHost = NetRole.IsHost; if (payload.Code == "__ping") { if (!isHost) { return true; } NoteGuestVersion(payload.Data); bool flag = BroadcastToClients("__pong", NewNonce(), "1.0.0"); CrowdControlMod.Instance.Logger.Msg("[relay] ping from guest (v" + payload.Data + ") -> pong " + (flag ? "sent" : "FAILED")); return true; } if (payload.Code == "__pong") { if (isHost) { return true; } CrowdControlMod.Instance.Logger.Msg("[relay] pong from host (v" + payload.Data + ")"); NetRole.NoteHostReplied(payload.Data); return true; } if (isHost) { PlayerCharacter requester = ((sender != null) ? sender.playerCharacter : null) ?? GameRefs.LocalPlayer; bool flag2 = RelayHandlers.Dispatch(payload.Code, requester); CrowdControlMod.Instance.Logger.Msg("[relay] '" + payload.Code + "' from guest -> " + (flag2 ? "applied" : "FAILED")); if (flag2) { UpdateRemoteTimer(payload.Code, payload.Data); } if (flag2 && payload.ForwardOnward) { BroadcastToClients(payload.Code, payload.Nonce, payload.Data); } } else { if (NetRole.HostModState != NetRole.HostMod.Present) { NetRole.NoteHostReplied(""); } if (RelayHandlers.Dispatch(payload.Code, GameRefs.LocalPlayer)) { UpdateRemoteTimer(payload.Code, payload.Data); } } } catch (Exception value) { CrowdControlMod.Instance.Logger.Error($"Relay handling failed: {value}"); } return true; } private static void Trace(string layer, string message, bool payload) { checked { if (VerboseLogging && _traceBudget > 0) { _traceBudget--; CrowdControlMod.Instance.Logger.Msg($"[relay] {layer} intercepted {(payload ? "a CC payload" : "ordinary chat")} ({message?.Length ?? 0} chars)"); } } } private static string PeekString(NetworkReader reader, out int position) { position = reader.Position; try { return NetworkReaderExtensions.ReadString(reader); } catch { reader.Position = position; return null; } } } public static class EyeMoodOverride { [HarmonyPatch(typeof(PlayerEyes), "SetEyeMood", new Type[] { typeof(PlayerEyeMood) })] private static class PlayerEyes_SetEyeMood_Single { private static void Prefix(PlayerEyes __instance, ref PlayerEyeMood bothEyesMood) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected I4, but got Unknown if (_forced.HasValue && IsLocalEyes(__instance)) { bothEyesMood = (PlayerEyeMood)(int)_forced.Value; } } } [HarmonyPatch(typeof(PlayerEyes), "SetEyeMood", new Type[] { typeof(PlayerEyeMood), typeof(PlayerEyeMood) })] private static class PlayerEyes_SetEyeMood_Pair { private static void Prefix(PlayerEyes __instance, ref PlayerEyeMood moodLeft, ref PlayerEyeMood moodRight) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected I4, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected I4, but got Unknown if (_forced.HasValue && IsLocalEyes(__instance)) { moodLeft = (PlayerEyeMood)(int)_forced.Value; moodRight = (PlayerEyeMood)(int)_forced.Value; } } } private static PlayerEyeMood? _forced; public static bool IsActive => _forced.HasValue; public static void Set(PlayerEyeMood mood) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) _forced = mood; } public static void Clear() { _forced = null; } private static bool IsLocalEyes(PlayerEyes eyes) { try { PlayerCharacter localPlayer = GameRefs.LocalPlayer; return (Object)(object)localPlayer != (Object)null && localPlayer.playerEyes != null && ((Object)localPlayer.playerEyes).Equals((Object)(object)eyes); } catch { return false; } } } public static class GameRefs { public static WorldManager World { get { try { return WorldManager.instance; } catch { return null; } } } public static PlayerCharacter LocalPlayer { get { try { return WorldManager.localPlayerCharacter; } catch { return null; } } } public static PlayerTunings Tunings { get { try { PlayerCharacter localPlayer = LocalPlayer; return (localPlayer != null) ? localPlayer.tunings : null; } catch { return null; } } } public static bool OthersInWorld { get { try { List allPlayerCharacters = PlayerCharacter.allPlayerCharacters; return allPlayerCharacters != null && allPlayerCharacters.Count > 1; } catch { return false; } } } public static bool InGame { get { try { WorldManager world = World; return (Object)(object)world != (Object)null && !world.inUI && (Object)(object)LocalPlayer != (Object)null; } catch { return false; } } } public static bool Teleport(Vector3 position, bool preserveRotation = true) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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_004d: Unknown result type (might be due to invalid IL or missing references) try { PlayerCharacter localPlayer = LocalPlayer; if ((Object)(object)localPlayer == (Object)null || localPlayer.grease == null) { return false; } Quaternion val = (((Object)(object)localPlayer.kernal != (Object)null) ? localPlayer.kernal.rotation : Quaternion.identity); localPlayer.grease.Teleport(position, val, preserveRotation); try { PlayerMover mover = localPlayer.mover; if (mover != null) { mover.ResetPosition(); } } catch { } return true; } catch (Exception ex) { CrowdControlMod.Instance?.Logger.Warning("Teleport failed: " + ex.Message); return false; } } public static PlayerCharacter HeldBy(PlayerCharacter p) { try { if ((Object)(object)p == (Object)null) { return null; } List allPlayerCharacters = PlayerCharacter.allPlayerCharacters; if (allPlayerCharacters == null) { return null; } for (int i = 0; i < allPlayerCharacters.Count; i = checked(i + 1)) { PlayerCharacter val = allPlayerCharacters[i]; if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)p)) { PlayerHands hands = val.hands; if ((Object)(object)((hands != null) ? hands.heldCharacter : null) == (Object)(object)p) { return val; } } } } catch { } return null; } } public static class GhostGuard { private static readonly HashSet AllowedWhileGhost = new HashSet(StringComparer.OrdinalIgnoreCase) { "invertLook", "sensUp", "sensDown", "lookLock", "desaturate", "xray", "blindfold", "eyeMood", "weatherFog", "night", "day", "ghostMode" }; public static bool Active { get; set; } public static bool ShouldHold(string code) { return Active && !string.IsNullOrEmpty(code) && !AllowedWhileGhost.Contains(code); } } public static class IceFloorOverride { [HarmonyPatch(typeof(PlayerMover), "FixedUpdate")] private static class PlayerMover_FixedUpdate { private static void Postfix(PlayerMover __instance) { //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_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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007a: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) if (!Active) { _slideVelocity = Vector3.zero; return; } try { PlayerCharacter localPlayer = GameRefs.LocalPlayer; if (!((Object)(object)localPlayer == (Object)null) && localPlayer.mover != null && ((Object)localPlayer.mover).Equals((Object)(object)__instance)) { Rigidbody rb = localPlayer.rb; if (!((Object)(object)rb == (Object)null)) { Vector3 linearVelocity = rb.linearVelocity; Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(linearVelocity.x, 0f, linearVelocity.z); Vector3 val2 = Vector3.Lerp(val, _slideVelocity, 0.93f); rb.linearVelocity = new Vector3(val2.x, linearVelocity.y, val2.z); _slideVelocity = val2; } } } catch { } } } [HarmonyPatch(typeof(PlayerCollision), "ModificationEventForPair")] private static class PlayerCollision_ModificationEventForPair { private static void Postfix(ModifiableContactPair pair) { if (!Active) { return; } try { for (int i = 0; i < ((ModifiableContactPair)(ref pair)).contactCount; i = checked(i + 1)) { ((ModifiableContactPair)(ref pair)).SetDynamicFriction(i, 0f); ((ModifiableContactPair)(ref pair)).SetStaticFriction(i, 0f); } } catch { } } } private const float MOMENTUM = 0.93f; private static Vector3 _slideVelocity; public static bool Active { get; set; } } public static class ModSettings { private const string SECTION = "CrowdControl"; private static ConfigEntry _showMessages; private static ConfigEntry _showIndicator; private static ConfigEntry _messageSeconds; public static bool ShowMessages => _showMessages?.Value ?? true; public static bool ShowIndicator => _showIndicator?.Value ?? true; public static float MessageSeconds => _messageSeconds?.Value ?? 4f; public static void Initialize() { try { ConfigFile config = ((BasePlugin)CrowdControlMod.Instance).Config; _showMessages = config.Bind("CrowdControl", "ShowMessages", true, "Displays a short line when an effect fires. Turn off for a clean capture."); _showIndicator = config.Bind("CrowdControl", "ShowConnectionIndicator", true, "Small dot showing whether the mod is connected to the Crowd Control app. Green connected, red not."); _messageSeconds = config.Bind("CrowdControl", "MessageSeconds", 4f, "How long an on-screen effect message stays visible."); } catch (Exception ex) { CrowdControlMod.Instance?.Logger.Warning("Could not create settings: " + ex.Message); } } } public enum SessionRole { None, Host, Client } public static class NetRole { public enum HostMod { Unknown, Present, Missing } public enum VersionMatch { Unknown, Same, HostNewer, HostOlder } public static HostMod HostModState { get; private set; } public static bool HostHasMod => IsHost || HostModState == HostMod.Present; public static bool HostMissingMod => IsClient && HostModState == HostMod.Missing; public static bool HostModUnknown => IsClient && HostModState == HostMod.Unknown; public static VersionMatch HostVersionMatch { get; private set; } public static string HostVersion { get; private set; } public static bool HostVersionMismatch { get { bool isClient = IsClient; bool flag = isClient; if (flag) { VersionMatch hostVersionMatch = HostVersionMatch; bool flag2 = (uint)(hostVersionMatch - 2) <= 1u; flag = flag2; } return flag; } } public static string VersionWarning { get { VersionMatch hostVersionMatch = HostVersionMatch; if (1 == 0) { } string result = hostVersionMatch switch { VersionMatch.HostNewer => "Update your mod (host has " + HostVersion + ")", VersionMatch.HostOlder => "Host needs to update (has " + HostVersion + ")", _ => null, }; if (1 == 0) { } return result; } } public static SessionRole Current { get { try { if (NetworkServer.activeHost) { return SessionRole.Host; } if (NetworkClient.active) { return SessionRole.Client; } return SessionRole.None; } catch (Exception ex) { CrowdControlMod.Instance?.Logger.Warning("NetRole probe failed: " + ex.Message); return SessionRole.None; } } } public static bool IsHost => Current == SessionRole.Host; public static bool IsClient => Current == SessionRole.Client; public static bool InSession => Current != SessionRole.None; public static void NoteHostReplied(string hostVersion) { if (string.IsNullOrWhiteSpace(hostVersion)) { if (HostModState != HostMod.Present) { HostModState = HostMod.Present; CrowdControlMod.Instance?.Logger.Msg("Host relay traffic seen - host is running the mod. Effects enabled."); } return; } HostVersion = hostVersion.Trim(); HostVersionMatch = Compare("1.0.0", HostVersion); if (HostModState != HostMod.Present) { HostModState = HostMod.Present; switch (HostVersionMatch) { case VersionMatch.Same: CrowdControlMod.Instance?.Logger.Msg("Host is running the mod (v" + HostVersion + ") - effects enabled."); break; case VersionMatch.HostNewer: CrowdControlMod.Instance?.Logger.Warning($"Host has a NEWER mod (v{HostVersion}, we have v{"1.0.0"}). Update this mod."); break; case VersionMatch.HostOlder: CrowdControlMod.Instance?.Logger.Warning($"Host has an OLDER mod (v{HostVersion}, we have v{"1.0.0"}). The host should update."); break; default: CrowdControlMod.Instance?.Logger.Warning("Host reported an unreadable mod version '" + HostVersion + "'."); break; } } } private static VersionMatch Compare(string ours, string theirs) { try { if (!Version.TryParse(ours, out Version result)) { return VersionMatch.Unknown; } if (!Version.TryParse(theirs, out Version result2)) { return VersionMatch.Unknown; } int num = result.CompareTo(result2); if (num == 0) { return VersionMatch.Same; } return (num < 0) ? VersionMatch.HostNewer : VersionMatch.HostOlder; } catch { return VersionMatch.Unknown; } } public static void NoteHostSilent() { if (HostModState != HostMod.Missing) { HostModState = HostMod.Missing; CrowdControlMod.Instance?.Logger.Warning("Host is not running the mod - effects disabled for this session."); } } public static void ResetHostProbe() { HostModState = HostMod.Unknown; HostVersionMatch = VersionMatch.Unknown; HostVersion = null; } } public static class Overlay { private readonly struct Line { public readonly string Text; public readonly float Expires; public readonly float Born; public Line(string text, float born, float expires) { Text = text; Born = born; Expires = expires; } } public readonly struct ActiveEffect { public readonly string Label; public readonly float Remaining; public readonly float Duration; public readonly bool Paused; public ActiveEffect(string label, float remaining, float duration, bool paused) { Label = label; Remaining = remaining; Duration = duration; Paused = paused; } } private const float MARGIN = 14f; private const float WIDTH = 232f; private const float PAD = 7f; private const float ACCENT = 2f; private const float RADIUS = 5f; private const float HEADER = 16f; private const float ROW = 15f; private const float BAR = 3f; private const float GAP = 3f; private const int MAX_TEXT = 30; private const int MAX_LINES = 2; private static readonly List Lines = new List(); private static bool _hidden; private static Texture2D _pixel; private static Texture2D _panel; private static int _panelW; private static int _panelH; private static GUIStyle _name; private static GUIStyle _meta; private static GUIStyle _metaRight; private static GUIStyle _msg; public static bool Toggle() { _hidden = !_hidden; return !_hidden; } public static void Show(string text, bool force = false) { if (string.IsNullOrWhiteSpace(text) || (!force && (!ModSettings.ShowMessages || _hidden))) { return; } if (force) { _hidden = false; } float num = Now(); lock (Lines) { Lines.Add(new Line(Trim(text), num, num + ModSettings.MessageSeconds)); while (Lines.Count > 2) { Lines.RemoveAt(0); } } } public static void Clear() { lock (Lines) { Lines.Clear(); } } public static void Draw(bool connected, bool clientPresent) { //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) try { if (_hidden) { return; } EnsureStyles(); ActiveEffect[] array = MergeWithRemote(Scheduler.ActiveTimedEffects()); Line[] array2 = TakeLines(); bool flag = clientPresent || connected; bool flag2 = ModSettings.ShowIndicator && flag; string text = null; if (flag) { if (NetRole.HostVersionMismatch) { text = NetRole.VersionWarning; } else if (NetRole.HostMissingMod) { text = "Host requires the mod"; } } bool flag3 = text != null; if (!flag2 && !flag3 && array.Length == 0 && array2.Length == 0) { return; } float num = 7f; if (flag2) { num += 19f; } if (flag3) { num += 18f; } if (array.Length != 0) { num += (float)array.Length * 21f - 3f; } if (array2.Length != 0) { if (array.Length != 0) { num += 7f; } num += (float)array2.Length * 15f; } num += 7f; Rect card = default(Rect); ((Rect)(ref card))..ctor(14f, 14f, 232f, num); DrawCard(card); float num2 = ((Rect)(ref card)).x + 2f + 7f; float num3 = 216f; float num4 = ((Rect)(ref card)).y + 7f; if (flag2) { DrawHeader(num2, num4, num3, connected); num4 += 19f; } if (flag3) { DrawWarning(num2, num4, num3, text); num4 += 18f; } for (int i = 0; i < array.Length; i = checked(i + 1)) { DrawEffect(num2, num4, num3, array[i]); num4 += 21f; } if (array2.Length != 0) { if (array.Length != 0) { Fill(new Rect(num2, num4, num3, 1f), CcTheme.Slate500); num4 += 4f; } float num5 = Now(); Line[] array3 = array2; for (int j = 0; j < array3.Length; j++) { Line line = array3[j]; float num6 = Mathf.Clamp01((num5 - line.Born) / 0.15f); float num7 = Mathf.Clamp01(line.Expires - num5); float alpha = Mathf.Min(num6, num7); DrawText(_msg, new Rect(num2, num4, num3, 15f), line.Text, CcTheme.White200.Fade(alpha)); num4 += 15f; } } } catch { } } private static void DrawCard(Rect card) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) Texture2D panel = checked(GetPanel((int)((Rect)(ref card)).width, (int)((Rect)(ref card)).height)); Color color = GUI.color; GUI.color = CcTheme.Slate500; GUI.DrawTexture(card, (Texture)(object)panel); GUI.color = CcTheme.Slate800.Fade(0.96f); GUI.DrawTexture(new Rect(((Rect)(ref card)).x + 1f, ((Rect)(ref card)).y + 1f, ((Rect)(ref card)).width - 2f, ((Rect)(ref card)).height - 2f), (Texture)(object)panel); GUI.color = CcTheme.Royal50; GUI.DrawTexture(new Rect(((Rect)(ref card)).x + 1f, ((Rect)(ref card)).y + 3f, 2f, ((Rect)(ref card)).height - 6f), (Texture)(object)_pixel); GUI.color = color; } private static void DrawHeader(float x, float y, float w, bool connected) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0004: 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_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_003a: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) Color val = (connected ? CcTheme.Teal200 : CcTheme.Red200); Fill(new Rect(x - 2f, y + 4f - 2f, 12f, 12f), val.Fade(0.18f)); Fill(new Rect(x, y + 4f, 8f, 8f), val); DrawText(_meta, new Rect(x + 8f + 6f, y, w - 8f - 6f, 16f), "CROWD CONTROL", connected ? CcTheme.White300 : CcTheme.Red200); if (!connected) { DrawText(_metaRight, new Rect(x, y, w, 16f), "F9", CcTheme.Red200); } } private static void DrawWarning(float x, float y, float w, string text) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) Fill(new Rect(x, y, w, 15f), CcTheme.Yellow300.Fade(0.14f)); Fill(new Rect(x, y, 2f, 15f), CcTheme.Yellow300); DrawText(_msg, new Rect(x + 7f, y, w - 9f, 15f), text, CcTheme.Yellow300); } private static void DrawEffect(float x, float y, float w, ActiveEffect e) { //IL_0010: 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_0015: 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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) Color c = (e.Paused ? CcTheme.Yellow300 : CcTheme.Royal50); DrawText(_name, new Rect(x, y, w - 44f, 15f), e.Label, e.Paused ? CcTheme.White300 : CcTheme.White100); DrawText(_metaRight, new Rect(x, y, w, 15f), e.Paused ? "paused" : FormatTime(e.Remaining), e.Paused ? CcTheme.Yellow300 : CcTheme.White100); float num = y + 15f; Fill(new Rect(x, num, w, 3f), CcTheme.Slate600); float num2 = ((e.Duration > 0f) ? Mathf.Clamp01(e.Remaining / e.Duration) : 0f); if (num2 > 0f) { Rect rect = default(Rect); ((Rect)(ref rect))..ctor(x, num, w * num2, 3f); Fill(rect, c.Fade(e.Paused ? 0.5f : 1f)); if (!e.Paused && ((Rect)(ref rect)).width > 2f) { Fill(new Rect(((Rect)(ref rect)).xMax - 2f, num, 2f, 3f), CcTheme.Blurple200); } } } private static ActiveEffect[] MergeWithRemote(ActiveEffect[] local) { ActiveEffect[] array = RemoteTimers.Snapshot(); if (array.Length == 0) { return local; } List list = new List(checked(local.Length + array.Length)); list.AddRange(local); ActiveEffect[] array2 = array; for (int i = 0; i < array2.Length; i++) { ActiveEffect item = array2[i]; bool flag = false; for (int j = 0; j < local.Length; j++) { ActiveEffect activeEffect = local[j]; if (string.Equals(activeEffect.Label, item.Label, StringComparison.OrdinalIgnoreCase)) { flag = true; break; } } if (!flag) { list.Add(item); } } return list.ToArray(); } private static Line[] TakeLines() { if (!ModSettings.ShowMessages) { return Array.Empty(); } float num = Now(); checked { lock (Lines) { for (int num2 = Lines.Count - 1; num2 >= 0; num2--) { if (Lines[num2].Expires <= num) { Lines.RemoveAt(num2); } } return Lines.ToArray(); } } } private static string FormatTime(float seconds) { if (seconds < 0f) { seconds = 0f; } int num = Mathf.CeilToInt(seconds); return (num >= 60) ? $"{num / 60}:{num % 60:00}" : $"{num}s"; } private static string Trim(string text) { return (text.Length <= 30) ? text : (text.Substring(0, 29).TrimEnd() + "…"); } private static void DrawText(GUIStyle style, Rect rect, string text, Color color) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: 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_0023: Unknown result type (might be due to invalid IL or missing references) if (!string.IsNullOrEmpty(text)) { Color color2 = GUI.color; GUI.color = color; GUI.Label(rect, text, style); GUI.color = color2; } } private static void Fill(Rect rect, Color color) { //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_000e: 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) Color color2 = GUI.color; GUI.color = color; GUI.DrawTexture(rect, (Texture)(object)_pixel); GUI.color = color2; } private static Texture2D GetPanel(int w, int h) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_panel != (Object)null && _panelW == w && _panelH == h) { return _panel; } if ((Object)(object)_panel != (Object)null) { Object.Destroy((Object)(object)_panel); } _panel = new Texture2D(w, h, (TextureFormat)5, false) { hideFlags = (HideFlags)61 }; _panelW = w; _panelH = h; checked { Color[] array = (Color[])(object)new Color[w * h]; float num = 5f; for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { float num2 = (((float)j < num) ? (num - (float)j) : (((float)j >= (float)w - num) ? ((float)j - ((float)w - num - 1f)) : 0f)); float num3 = (((float)i < num) ? (num - (float)i) : (((float)i >= (float)h - num) ? ((float)i - ((float)h - num - 1f)) : 0f)); float num4 = 1f; if (num2 > 0f && num3 > 0f) { float num5 = Mathf.Sqrt(num2 * num2 + num3 * num3); num4 = Mathf.Clamp01(num - num5 + 0.5f); } array[i * w + j] = new Color(1f, 1f, 1f, num4); } } _panel.SetPixels(Il2CppStructArray.op_Implicit(array)); _panel.Apply(); return _panel; } } private static void EnsureStyles() { //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_0026: Expected O, but got Unknown //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Expected O, but got Unknown //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Expected O, but got Unknown //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Expected O, but got Unknown //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Expected O, but got Unknown if ((Object)(object)_pixel == (Object)null) { _pixel = new Texture2D(1, 1) { hideFlags = (HideFlags)61 }; _pixel.SetPixel(0, 0, Color.white); _pixel.Apply(); } if (_name == null) { _name = new GUIStyle(GUI.skin.label) { fontSize = 12, fontStyle = (FontStyle)1, alignment = (TextAnchor)3, padding = new RectOffset(0, 0, 0, 0), wordWrap = false }; } if (_meta == null) { _meta = new GUIStyle(GUI.skin.label) { fontSize = 10, alignment = (TextAnchor)3, padding = new RectOffset(0, 0, 0, 0), wordWrap = false }; } if (_metaRight == null) { _metaRight = new GUIStyle(GUI.skin.label) { fontSize = 10, fontStyle = (FontStyle)1, alignment = (TextAnchor)5, padding = new RectOffset(0, 0, 0, 0), wordWrap = false }; } if (_msg == null) { _msg = new GUIStyle(GUI.skin.label) { fontSize = 11, alignment = (TextAnchor)3, padding = new RectOffset(0, 0, 0, 0), wordWrap = false }; } } private static float Now() { try { return Time.realtimeSinceStartup; } catch { return 0f; } } } public static class RelayHandlers { private static readonly Dictionary> Handlers = new Dictionary>(StringComparer.OrdinalIgnoreCase); public static void Register(string code, Action handler) { Handlers[code] = handler; } public static bool CanHandle(string code) { return Handlers.ContainsKey(code); } public static bool Dispatch(string code, PlayerCharacter requester) { if (!Handlers.TryGetValue(code, out var value)) { CrowdControlMod.Instance.Logger.Warning("Relayed effect '" + code + "' has no host-side handler."); return false; } if ((Object)(object)requester == (Object)null) { CrowdControlMod.Instance.Logger.Warning("Relayed effect '" + code + "' arrived without a requesting player."); return false; } try { value(requester); return true; } catch (Exception value2) { CrowdControlMod.Instance.Logger.Error($"Relayed effect '{code}' failed on the host: {value2}"); return false; } } } public static class RelayState { private const float ENTRY_LIFETIME = 180f; private static readonly Dictionary Active = new Dictionary(StringComparer.OrdinalIgnoreCase); public static void MarkActive(string code) { Active[code] = Time(); } public static void MarkInactive(string code) { Active.Remove(code); } public static bool IsActive(string code) { if (!Active.TryGetValue(code, out var value)) { return false; } if (Time() - value > 180f) { Active.Remove(code); return false; } return true; } public static void Clear() { Active.Clear(); } private static float Time() { try { return Time.realtimeSinceStartup; } catch { return 0f; } } } public static class RemoteTimers { private readonly struct Entry { public readonly string Label; public readonly float Ends; public readonly float Duration; public Entry(string label, float ends, float duration) { Label = label; Ends = ends; Duration = duration; } } private static readonly Dictionary Rows = new Dictionary(StringComparer.OrdinalIgnoreCase); public static void Start(string code, float durationSeconds) { if (string.IsNullOrWhiteSpace(code) || durationSeconds <= 0f) { return; } lock (Rows) { Rows[code] = new Entry(EffectNames.Pretty(code), Now() + durationSeconds, durationSeconds); } } public static void Stop(string code) { lock (Rows) { Rows.Remove(code); } } public static void Clear() { lock (Rows) { Rows.Clear(); } } public static Overlay.ActiveEffect[] Snapshot() { float num = Now(); lock (Rows) { if (Rows.Count == 0) { return Array.Empty(); } List list = new List(Rows.Count); List list2 = null; foreach (KeyValuePair row in Rows) { float num2 = row.Value.Ends - num; if (num2 <= 0f) { (list2 ?? (list2 = new List())).Add(row.Key); } else { list.Add(new Overlay.ActiveEffect(row.Value.Label, num2, row.Value.Duration, paused: false)); } } if (list2 != null) { foreach (string item in list2) { Rows.Remove(item); } } return list.ToArray(); } } private static float Now() { try { return Time.realtimeSinceStartup; } catch { return 0f; } } } }