using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using LethalCompanyInputUtils.Api;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ChatPoll")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("A mod for Lethal Company that allows the host to start polls in chat that players can vote on")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ChatPoll")]
[assembly: AssemblyTitle("ChatPoll")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace ChatPoll
{
internal class InputActions : LcInputActions
{
[InputAction(/*Could not decode attribute arguments.*/)]
internal InputAction OpenPollCreator { get; private set; }
[InputAction(/*Could not decode attribute arguments.*/)]
internal InputAction EndPoll { get; private set; }
internal static bool ShouldInputBeIgnored()
{
if ((Object)(object)StartOfRound.Instance == (Object)null)
{
return true;
}
if (StartOfRound.Instance.localPlayerController.isTypingChat)
{
return true;
}
if (StartOfRound.Instance.localPlayerController.inTerminalMenu)
{
return true;
}
if (StartOfRound.Instance.localPlayerController.quickMenuManager.isMenuOpen)
{
return true;
}
return false;
}
}
[BepInPlugin("BGN.ChatPoll", "Chat Poll", "1.0.0")]
[BepInProcess("Lethal Company.exe")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
public const string GUID = "BGN.ChatPoll";
public const string NAME = "Chat Poll";
public const string VERSION = "1.0.0";
internal static ManualLogSource Logger;
internal static readonly InputActions inputActions = new InputActions();
private static readonly MethodInfo hudManagerAddChatMessageMethod = typeof(HUDManager).GetMethod("AddChatMessage", BindingFlags.Instance | BindingFlags.NonPublic);
private static readonly MethodInfo hudManagerAddTextMessageServerRpcMethod = typeof(HUDManager).GetMethod("AddTextMessageServerRpc", BindingFlags.Instance | BindingFlags.NonPublic);
private void Awake()
{
Logger = ((BaseUnityPlugin)this).Logger;
Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
Logger.LogInfo((object)"Plugin BGN.ChatPoll is loaded!");
}
internal static void PrintToChatLocally(string message)
{
hudManagerAddChatMessageMethod.Invoke(HUDManager.Instance, new object[2] { message, "" });
}
internal static void PrintToChat(string message)
{
hudManagerAddTextMessageServerRpcMethod.Invoke(HUDManager.Instance, new object[1] { message });
}
}
internal class PollCreatorUI : MonoBehaviour
{
private const string WindowTitle = "Poll Creator";
private const int WindowWidth = 600;
private const int WindowHeight = 350;
private static readonly GUILayoutOption[] WindowOptions = (GUILayoutOption[])(object)new GUILayoutOption[2]
{
GUILayout.Width(600f),
GUILayout.Height(350f)
};
private bool isWindowOpen;
private Vector2 windowPollOptionsScrollPosition;
private string pollTitle = string.Empty;
private bool hasDuration;
private float duration = 40f;
private const float MinDuration = 10f;
private const float MaxDuration = 90f;
private readonly List<string> pollOptions = new List<string>();
private const int MinimumPollOptions = 2;
private const int MaximumPollOptions = 10;
private void Start()
{
for (int i = 0; i < 2; i++)
{
pollOptions.Add(string.Empty);
}
Plugin.inputActions.OpenPollCreator.performed += OpenPollCreator_performed;
}
private void OnDestroy()
{
Plugin.inputActions.OpenPollCreator.performed -= OpenPollCreator_performed;
}
private void OpenPollCreator_performed(CallbackContext context)
{
if (!isWindowOpen && !InputActions.ShouldInputBeIgnored())
{
isWindowOpen = true;
StartOfRound.Instance.localPlayerController.quickMenuManager.isMenuOpen = true;
Cursor.lockState = (CursorLockMode)0;
Cursor.visible = true;
}
}
private void Update()
{
if (!StartOfRound.Instance.localPlayerController.quickMenuManager.isMenuOpen)
{
isWindowOpen = false;
}
}
private void OnGUI()
{
//IL_0039: 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_0059: Expected O, but got Unknown
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
if (isWindowOpen)
{
int num = (Screen.width - 600) / 2;
int num2 = (Screen.height - 350) / 2;
GUILayout.Window(GUIUtility.GetControlID((FocusType)2), new Rect((float)num, (float)num2, 600f, 350f), new WindowFunction(DrawUI), "Poll Creator", WindowOptions);
}
}
private void DrawUI(int id)
{
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
GUILayoutOption val = GUILayout.MaxWidth(300f);
GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { val });
DrawSettingsUI();
GUILayout.EndVertical();
GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { val });
DrawOptionsUI();
GUILayout.EndVertical();
GUILayout.EndHorizontal();
}
private void DrawSettingsUI()
{
//IL_00ba: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
GUILayout.Label("Title:", Array.Empty<GUILayoutOption>());
pollTitle = GUILayout.TextArea(pollTitle, 80, Array.Empty<GUILayoutOption>());
hasDuration = GUILayout.Toggle(hasDuration, " Duration: (" + (hasDuration ? $"{duration} seconds" : "disabled") + ")", Array.Empty<GUILayoutOption>());
GUI.enabled = hasDuration;
duration = Mathf.Round(GUILayout.HorizontalSlider(duration, 10f, 90f, Array.Empty<GUILayoutOption>()));
GUI.enabled = true;
GUILayout.FlexibleSpace();
GUILayout.EndVertical();
Color color = GUI.color;
if (PollManager.Instance.IsPollActive)
{
GUI.color = Color.red;
if (GUILayout.Button("End poll", Array.Empty<GUILayoutOption>()))
{
PollManager.Instance.EndPoll();
}
}
else
{
GUI.color = Color.green;
if (GUILayout.Button("Start poll", Array.Empty<GUILayoutOption>()))
{
PollManager.Instance.StartPoll(pollTitle, hasDuration ? duration : float.PositiveInfinity, pollOptions.ToArray());
}
}
GUI.color = color;
}
private void DrawOptionsUI()
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: 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_006a: 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_0092: Unknown result type (might be due to invalid IL or missing references)
windowPollOptionsScrollPosition = GUILayout.BeginScrollView(windowPollOptionsScrollPosition, GUI.skin.box);
int num = -1;
for (int i = 0; i < pollOptions.Count; i++)
{
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
pollOptions[i] = GUILayout.TextArea(pollOptions[i], 80, Array.Empty<GUILayoutOption>());
GUI.enabled = pollOptions.Count > 2;
Color color = GUI.color;
GUI.color = Color.red;
if (GUILayout.Button("X", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }))
{
num = i;
}
GUI.color = color;
GUI.enabled = true;
GUILayout.EndHorizontal();
}
if (num >= 0)
{
pollOptions.RemoveAt(num);
}
GUILayout.EndScrollView();
GUI.enabled = pollOptions.Count < 10;
if (GUILayout.Button("Add option", Array.Empty<GUILayoutOption>()))
{
pollOptions.Add(string.Empty);
}
GUI.enabled = true;
}
}
internal class PollManager : MonoBehaviour
{
private const string PrimaryTextColorCode = "green";
private const string SecondaryTextColorCode = "yellow";
private const string TertiaryTextColorCode = "white";
private float timer;
private string[] options;
private readonly Dictionary<ulong, int> votersOptions = new Dictionary<ulong, int>();
internal static PollManager Instance { get; private set; }
internal bool IsPollActive { get; private set; }
private void Awake()
{
Instance = this;
}
private void Start()
{
Plugin.inputActions.EndPoll.performed += EndPoll_performed;
}
private void OnDestroy()
{
Plugin.inputActions.EndPoll.performed -= EndPoll_performed;
}
private void EndPoll_performed(CallbackContext context)
{
if (!InputActions.ShouldInputBeIgnored())
{
EndPoll();
}
}
private void Update()
{
if (IsPollActive)
{
timer -= Time.deltaTime;
if (timer <= 0f)
{
EndPoll();
}
}
}
internal void StartPoll(string title, float duration, string[] options)
{
if (IsPollActive)
{
return;
}
IsPollActive = true;
timer = duration;
this.options = options;
votersOptions.Clear();
StringBuilder stringBuilder = new StringBuilder("<color=green>");
stringBuilder.AppendLine("<align=flush>╔ POLL ╗</align>");
if (!string.IsNullOrEmpty(title))
{
stringBuilder.AppendLine("<align=justified><color=yellow>\"" + title + "\"</color></align>");
}
stringBuilder.Append("<color=white>");
for (int i = 0; i < options.Length; i++)
{
stringBuilder.Append($"{i + 1}. {options[i]}");
if (i < options.Length - 1)
{
stringBuilder.AppendLine();
}
}
stringBuilder.AppendLine("</color>");
stringBuilder.AppendLine("<align=justified><color=yellow>^ Vote by sending the number!</color></align>");
stringBuilder.Append("<align=flush>╚╝</align>");
stringBuilder.Append("</color>");
Plugin.PrintToChat(stringBuilder.ToString());
}
internal void EndPoll()
{
if (!IsPollActive)
{
return;
}
IsPollActive = false;
Dictionary<int, int> dictionary = new Dictionary<int, int>(options.Length);
for (int i = 0; i < options.Length; i++)
{
dictionary[i] = 0;
}
foreach (int value in votersOptions.Values)
{
dictionary[value]++;
}
StringBuilder stringBuilder = new StringBuilder("<color=green>");
stringBuilder.AppendLine("<align=flush>╔ RESULTS ╗</align>");
if (votersOptions.Count > 0)
{
stringBuilder.Append("<color=white>");
for (int j = 0; j < options.Length; j++)
{
float num = (float)dictionary[j] / (float)votersOptions.Count * 100f;
stringBuilder.Append($"({num:n0}%) {options[j]}");
if (j < options.Length - 1)
{
stringBuilder.AppendLine();
}
}
stringBuilder.AppendLine("</color>");
}
else
{
stringBuilder.AppendLine("<color=yellow>No one voted...</color>");
}
stringBuilder.Append("<align=flush>╚╝</align>");
stringBuilder.Append("</color>");
Plugin.PrintToChat(stringBuilder.ToString());
}
internal void AddVote(ulong clientId, int optionIndex)
{
if (optionIndex >= 0 && optionIndex < options.Length)
{
votersOptions[clientId] = optionIndex;
}
}
}
}
namespace ChatPoll.Patches
{
[HarmonyPatch]
internal static class PollPatch
{
private static PollManager pollManager;
[HarmonyPrefix]
[HarmonyPatch(typeof(StartOfRound), "Awake")]
private static void InitializePollManagerPatch(StartOfRound __instance)
{
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
if (GameNetworkManager.Instance.isHostingGame)
{
if ((Object)(object)pollManager != (Object)null)
{
Plugin.Logger.LogError((object)"Tried to create a poll manager but one already exists");
return;
}
pollManager = new GameObject("PollManager").AddComponent<PollManager>();
((Component)pollManager).gameObject.AddComponent<PollCreatorUI>();
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(HUDManager), "__rpc_handler_2930587515")]
private static bool ProcessIncomingChatMessagePatch(ref NetworkBehaviour target, ref FastBufferReader reader, ref __RpcParams rpcParams)
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
if (!pollManager.IsPollActive)
{
return true;
}
bool flag = default(bool);
((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref flag, default(ForPrimitives));
if (!flag)
{
return true;
}
string s = default(string);
((FastBufferReader)(ref reader)).ReadValueSafe(ref s, false);
((FastBufferReader)(ref reader)).Seek(0);
if (!int.TryParse(s, out var result))
{
return true;
}
pollManager.AddVote(rpcParams.Server.Receive.SenderClientId, result - 1);
return false;
}
}
}