Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of UpgradeVote v0.2.0
LerrdyhoReposession-UpgradeVotes.dll
Decompiled 5 months agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using MenuLib; using MenuLib.MonoBehaviors; using Microsoft.CodeAnalysis; using Photon.Pun; using Steamworks; using Steamworks.Data; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("Lerdi")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+175556a80540d5c304895b0f89ca9e4432ef33f0")] [assembly: AssemblyProduct("LerrdyhoReposession-UpgradeVotes")] [assembly: AssemblyTitle("LerrdyhoReposession-UpgradeVotes")] [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 UpgradeVote { [BepInPlugin("com.lerrdy.repo.upgradevote", "Upgrade Vote", "0.4.0")] public class UpgradeVotePlugin : BaseUnityPlugin { public const string PluginGuid = "com.lerrdy.repo.upgradevote"; public const string PluginName = "Upgrade Vote"; public const string PluginVersion = "0.4.0"; internal static ManualLogSource Log; private Harmony _harmony; internal static ConfigEntry<bool> EnablePlugin; internal static ConfigEntry<float> VoteDurationSeconds; internal static ConfigEntry<bool> VerboseLogging; internal static void LogDebug(string msg) { if (VerboseLogging != null && VerboseLogging.Value) { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)msg); } } } private void Awake() { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; EnablePlugin = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnablePlugin", true, "Enable / disable the Upgrade Vote plugin."); VoteDurationSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Voting", "VoteDurationSeconds", 15f, "Duration (seconds) of each upgrade vote."); VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "VerboseLogging", false, "If true, prints extra debug logs for troubleshooting."); if (!EnablePlugin.Value) { Log.LogInfo((object)"[UpgradeVote] Plugin disabled via config."); return; } try { _harmony = new Harmony("com.lerrdy.repo.upgradevote"); _harmony.PatchAll(); Log.LogInfo((object)"[UpgradeVote] Harmony patches applied."); } catch (Exception ex) { Log.LogError((object)"[UpgradeVote] Harmony.PatchAll() threw:"); Log.LogError((object)ex.ToString()); } Log.LogInfo((object)"[UpgradeVote] Loaded Upgrade Vote v0.4.0"); } private void OnDestroy() { try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch { } } } public class UpgradeVoteNetwork : MonoBehaviourPun { public static UpgradeVoteNetwork Instance { get; private set; } private void Awake() { if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)this); } else { Instance = this; } } private void OnDestroy() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } public void HostStartRound(int roundId, string upgradeKey, string[] playerNames, string[] playerSteamIds, float duration) { if ((Object)(object)((MonoBehaviourPun)this).photonView == (Object)null) { ManualLogSource log = UpgradeVotePlugin.Log; if (log != null) { log.LogWarning((object)"[UpgradeVote] HostStartRound: photonView null."); } return; } ManualLogSource log2 = UpgradeVotePlugin.Log; if (log2 != null) { log2.LogInfo((object)$"[UpgradeVote] RPC UpgradeVote_StartRound round={roundId} key={upgradeKey}"); } ((MonoBehaviourPun)this).photonView.RPC("UpgradeVote_StartRound", (RpcTarget)0, new object[5] { roundId, upgradeKey, playerNames, playerSteamIds, duration }); } public void SendVote(int roundId, int voterActorNumber, int choiceIndex) { if (!PhotonNetwork.IsConnected || PhotonNetwork.CurrentRoom == null) { return; } PhotonView photonView = ((MonoBehaviourPun)this).photonView; if ((Object)(object)photonView == (Object)null) { ManualLogSource log = UpgradeVotePlugin.Log; if (log != null) { log.LogWarning((object)"[UpgradeVote] SendVote: photonView is null, aborting."); } return; } ManualLogSource log2 = UpgradeVotePlugin.Log; if (log2 != null) { log2.LogInfo((object)$"[UpgradeVote] RPC UpgradeVote_SubmitVote round={roundId} actor={voterActorNumber} choice={choiceIndex}"); } photonView.RPC("UpgradeVote_SubmitVote", (RpcTarget)2, new object[3] { roundId, voterActorNumber, choiceIndex }); } public void HostBroadcastVoteUpdate(int roundId, int[] voteCounts) { if (!((Object)(object)((MonoBehaviourPun)this).photonView == (Object)null)) { ((MonoBehaviourPun)this).photonView.RPC("UpgradeVote_VoteUpdate", (RpcTarget)0, new object[2] { roundId, voteCounts }); } } public void HostEndRound(int roundId, int winnerIndex, string winnerName, string upgradeKey) { if (!((Object)(object)((MonoBehaviourPun)this).photonView == (Object)null)) { ManualLogSource log = UpgradeVotePlugin.Log; if (log != null) { log.LogInfo((object)$"[UpgradeVote] RPC UpgradeVote_EndRound round={roundId} winnerIndex={winnerIndex} winner={winnerName}"); } ((MonoBehaviourPun)this).photonView.RPC("UpgradeVote_EndRound", (RpcTarget)0, new object[4] { roundId, winnerIndex, winnerName, upgradeKey }); } } [PunRPC] private void UpgradeVote_StartRound(int roundId, string upgradeKey, string[] playerNames, string[] playerSteamIds, float duration) { UpgradeVoteManager.Instance.OnNetworkStartRound(roundId, upgradeKey, playerNames, playerSteamIds, duration); } [PunRPC] private void UpgradeVote_SubmitVote(int roundId, int voterActorNumber, int choiceIndex) { UpgradeVoteManager.Instance.OnNetworkVote(roundId, voterActorNumber, choiceIndex); } [PunRPC] private void UpgradeVote_VoteUpdate(int roundId, int[] voteCounts) { UpgradeVoteManager.Instance.OnNetworkVoteUpdate(roundId, voteCounts); } [PunRPC] private void UpgradeVote_EndRound(int roundId, int winnerIndex, string winnerName, string upgradeKey) { UpgradeVoteManager.Instance.OnNetworkEndRound(roundId, winnerIndex, winnerName, upgradeKey); } } public class UpgradeVoteManager : MonoBehaviour { private sealed class PlayerRow { public string Name; public REPOButton Button; public TextMeshProUGUI VotesLabel; } private static UpgradeVoteManager _instance; private string[] _localPlayerSteamIDs = Array.Empty<string>(); private const string NameIndentTag = "<indent=32px>"; private const bool DebugFillTestPlayers = true; private readonly Queue<string> _upgradeQueue = new Queue<string>(); private bool _networkAttached = false; private int _currentRoundId = 0; private string _currentUpgradeKey = null; private List<PlayerAvatar> _currentPlayers = new List<PlayerAvatar>(); private Dictionary<int, int> _votesByActor = new Dictionary<int, int>(); private float _hostTimer = 0f; private bool _hostVoteActive = false; private bool _localVoteActive = false; private int _localRoundId = -1; private string[] _localPlayerNames = Array.Empty<string>(); private int[] _localVoteCounts = Array.Empty<int>(); private int? _localMyChoiceIndex = null; private float _localTimer = 0f; private REPOPopupPage _votePopup; private REPOLabel _timerLabel; private REPOPopupPage _popup; private readonly List<REPOButton> _playerButtons = new List<REPOButton>(); private REPOLabel _questionLabel; private GameObject _toastCanvas; private float _toastTimer = 0f; private readonly List<Image> _playerAvatarImages = new List<Image>(); private readonly List<PlayerRow> _playerRows = new List<PlayerRow>(); private readonly HashSet<int> _avatarLoggedOnce = new HashSet<int>(); public static UpgradeVoteManager Instance { get { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown if ((Object)(object)_instance == (Object)null) { _instance = Object.FindObjectOfType<UpgradeVoteManager>(); if ((Object)(object)_instance == (Object)null) { GameObject val = new GameObject("UpgradeVoteManager"); _instance = val.AddComponent<UpgradeVoteManager>(); Object.DontDestroyOnLoad((Object)(object)val); ManualLogSource log = UpgradeVotePlugin.Log; if (log != null) { log.LogInfo((object)"[UpgradeVote] UpgradeVoteManager created lazily."); } } } return _instance; } } private bool _isHost => SemiFunc.IsMasterClientOrSingleplayer(); private void Awake() { if ((Object)(object)_instance != (Object)null && (Object)(object)_instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } _instance = this; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); ManualLogSource log = UpgradeVotePlugin.Log; if (log != null) { log.LogInfo((object)"[UpgradeVote] UpgradeVoteManager Awake (singleton set)."); } } public void HostRegisterLocalVote(int choiceIndex) { if (_isHost && _hostVoteActive && choiceIndex >= 0 && choiceIndex < _currentPlayers.Count) { _votesByActor[-1] = choiceIndex; } } private void RefreshPlayerAvatars() { int num = Mathf.Min(_playerAvatarImages.Count, _localPlayerSteamIDs.Length); for (int i = 0; i < num; i++) { Image val = _playerAvatarImages[i]; if (!((Object)(object)val == (Object)null)) { string text = _localPlayerSteamIDs[i]; if (UpgradeVotePlugin.VerboseLogging.Value && !_avatarLoggedOnce.Contains(i)) { _avatarLoggedOnce.Add(i); UpgradeVotePlugin.LogDebug(string.Format("[Avatar] Refresh index {0}, steamId={1}", i, text ?? "NULL")); } Sprite avatarSprite = SteamAvatarCache.GetAvatarSprite(text); bool enabled = (Object)(object)avatarSprite != (Object)null; val.sprite = avatarSprite; ((Behaviour)val).enabled = enabled; } } } private void Update() { if (!UpgradeVotePlugin.EnablePlugin.Value) { return; } AttachNetworkIfPossible(); if (_isHost && _hostVoteActive) { _hostTimer -= Time.deltaTime; if (_hostTimer < 0f) { _hostTimer = 0f; } int count = _currentPlayers.Count; if (count > 0 && _votesByActor.Count >= count) { HostResolveCurrentVote(); } else if (_hostTimer <= 0f) { HostResolveCurrentVote(); } } if (_localVoteActive) { if ((Object)(object)_timerLabel != (Object)null) { _localTimer -= Time.deltaTime; if (_localTimer < 0f) { _localTimer = 0f; } ((TMP_Text)_timerLabel.labelTMP).text = $"Time left: {_localTimer:0.0}s"; } RefreshPlayerAvatars(); } if ((Object)(object)_toastCanvas != (Object)null) { _toastTimer -= Time.deltaTime; if (_toastTimer <= 0f) { Object.Destroy((Object)(object)_toastCanvas); _toastCanvas = null; } } UpgradeVoteNotification.Update(); } private static string ColorString(string text, Color color) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) return "<color=#" + ColorUtility.ToHtmlStringRGB(color) + ">" + text + "</color>"; } private static string GetPrettyUpgradeName(string fullKey) { if (string.IsNullOrEmpty(fullKey)) { return "upgrade"; } if (fullKey.StartsWith("playerUpgrade", StringComparison.OrdinalIgnoreCase)) { fullKey = fullKey.Substring("playerUpgrade".Length).TrimStart('_', '.', '/'); } int num = fullKey.LastIndexOf('/'); if (num >= 0 && num < fullKey.Length - 1) { fullKey = fullKey.Substring(num + 1); } int num2 = fullKey.LastIndexOf('.'); if (num2 > 0) { fullKey = fullKey.Substring(0, num2); } fullKey = fullKey.Replace('_', ' '); if (string.IsNullOrWhiteSpace(fullKey)) { return "upgrade"; } return char.ToUpper(fullKey[0]) + fullKey.Substring(1); } private string BuildPlayerRowLabel(string playerName, int votesForThisPlayer, int totalPlayers, bool isMyVote, bool highlightWinner) { //IL_0021: 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_001a: 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_004f: 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) int num = Mathf.Clamp(totalPlayers, 4, 12); Color color = (highlightWinner ? Color.green : (isMyVote ? Color.yellow : Color.white)); StringBuilder stringBuilder = new StringBuilder(); bool flag = isMyVote || highlightWinner; stringBuilder.Append("<mspace=0.25em>["); stringBuilder.Append(ColorString(flag ? "X" : " ", color)); stringBuilder.Append("]</mspace> "); stringBuilder.Append(ColorString(playerName, color)); stringBuilder.Append($" <size=18>({votesForThisPlayer}/{num} votes)</size>"); return stringBuilder.ToString(); } private void AttachNetworkIfPossible() { if (_networkAttached || (Object)(object)PunManager.instance == (Object)null) { return; } GameObject gameObject = ((Component)PunManager.instance).gameObject; if ((Object)(object)gameObject.GetComponent<UpgradeVoteNetwork>() == (Object)null) { gameObject.AddComponent<UpgradeVoteNetwork>(); } _networkAttached = true; ManualLogSource log = UpgradeVotePlugin.Log; if (log != null) { log.LogInfo((object)"[UpgradeVote] Attached UpgradeVoteNetwork to PunManager."); } if (_isHost && !_hostVoteActive && _upgradeQueue.Count > 0) { ManualLogSource log2 = UpgradeVotePlugin.Log; if (log2 != null) { log2.LogInfo((object)"[UpgradeVote] Network attached with pending upgrades; starting first vote."); } HostStartNextVoteIfAny(); } } public void EnqueueUpgrade(string fullKey, int count) { if (_isHost && !string.IsNullOrEmpty(fullKey) && count > 0) { for (int i = 0; i < count; i++) { _upgradeQueue.Enqueue(fullKey); } ManualLogSource log = UpgradeVotePlugin.Log; if (log != null) { log.LogInfo((object)$"[UpgradeVote] Enqueued {count}x {fullKey} (queue size now {_upgradeQueue.Count})."); } if (!_hostVoteActive) { HostStartNextVoteIfAny(); } } } private void HostStartNextVoteIfAny() { if (!_isHost || _hostVoteActive || _upgradeQueue.Count == 0) { return; } _currentUpgradeKey = _upgradeQueue.Dequeue(); _currentRoundId++; _currentPlayers = SemiFunc.PlayerGetAll() ?? new List<PlayerAvatar>(); _currentPlayers = _currentPlayers.Where((PlayerAvatar p) => (Object)(object)p != (Object)null && (Object)(object)p.photonView != (Object)null).ToList(); string[] array = _currentPlayers.Select(GetPlayerNameSafe).ToArray(); string[] playerSteamIds = _currentPlayers.Select(GetPlayerSteamIDSafe).ToArray(); _votesByActor.Clear(); _hostTimer = Mathf.Max(1f, UpgradeVotePlugin.VoteDurationSeconds.Value); _hostVoteActive = true; if ((Object)(object)UpgradeVoteNetwork.Instance != (Object)null && PhotonNetwork.IsConnected && PhotonNetwork.CurrentRoom != null) { ManualLogSource log = UpgradeVotePlugin.Log; if (log != null) { log.LogInfo((object)$"[UpgradeVote] Starting vote round #{_currentRoundId} for {_currentUpgradeKey} (players={array.Length}) via NETWORK."); } UpgradeVoteNetwork.Instance.HostStartRound(_currentRoundId, _currentUpgradeKey, array, playerSteamIds, _hostTimer); } else { ManualLogSource log2 = UpgradeVotePlugin.Log; if (log2 != null) { log2.LogWarning((object)("[UpgradeVote] HostStartNextVoteIfAny: no UpgradeVoteNetwork/room; starting LOCAL-only vote for " + _currentUpgradeKey + ".")); } OnNetworkStartRound(_currentRoundId, _currentUpgradeKey, array, playerSteamIds, _hostTimer); } } private void HostResolveCurrentVote() { if (!_isHost || !_hostVoteActive) { return; } _hostVoteActive = false; int count = _currentPlayers.Count; int[] array = new int[count]; Array.Clear(array, 0, array.Length); foreach (KeyValuePair<int, int> item in _votesByActor) { int value = item.Value; if (value >= 0 && value < count) { array[value]++; } } int num = -1; string text = "(none)"; if (count > 0) { if (array.All((int c) => c <= 0)) { num = Random.Range(0, count); } else { int num2 = array.Max(); List<int> list = new List<int>(); for (int i = 0; i < array.Length; i++) { if (array[i] == num2) { list.Add(i); } } int index = Random.Range(0, list.Count); num = list[index]; } if (num >= 0 && num < count) { PlayerAvatar avatar = _currentPlayers[num]; text = GetPlayerNameSafe(avatar); try { ApplyUpgradeToPlayer(_currentUpgradeKey, avatar); } catch (Exception arg) { ManualLogSource log = UpgradeVotePlugin.Log; if (log != null) { log.LogWarning((object)$"[UpgradeVote] Failed to apply {_currentUpgradeKey} to {text}: {arg}"); } } } } ManualLogSource log2 = UpgradeVotePlugin.Log; if (log2 != null) { log2.LogInfo((object)$"[UpgradeVote] Round #{_currentRoundId} result: {_currentUpgradeKey} -> {text}"); } if ((Object)(object)UpgradeVoteNetwork.Instance != (Object)null && PhotonNetwork.IsConnected && PhotonNetwork.CurrentRoom != null) { UpgradeVoteNetwork.Instance.HostEndRound(_currentRoundId, num, text, _currentUpgradeKey); } else { OnNetworkEndRound(_currentRoundId, num, text, _currentUpgradeKey); } HostStartNextVoteIfAny(); } private void ApplyUpgradeToPlayer(string fullKey, PlayerAvatar avatar) { if ((Object)(object)StatsManager.instance == (Object)null) { ManualLogSource log = UpgradeVotePlugin.Log; if (log != null) { log.LogWarning((object)"[UpgradeVote] StatsManager.instance null, cannot apply upgrade."); } return; } if ((Object)(object)PunManager.instance == (Object)null) { ManualLogSource log2 = UpgradeVotePlugin.Log; if (log2 != null) { log2.LogWarning((object)"[UpgradeVote] PunManager.instance null, cannot apply upgrade."); } return; } string text = SemiFunc.PlayerGetSteamID(avatar); if (string.IsNullOrEmpty(text)) { ManualLogSource log3 = UpgradeVotePlugin.Log; if (log3 != null) { log3.LogWarning((object)"[UpgradeVote] steamID null/empty, cannot apply upgrade."); } return; } if (!StatsManager.instance.dictionaryOfDictionaries.TryGetValue(fullKey, out var value)) { ManualLogSource log4 = UpgradeVotePlugin.Log; if (log4 != null) { log4.LogWarning((object)("[UpgradeVote] dictionaryOfDictionaries missing key '" + fullKey + "'.")); } return; } int value2 = 0; value.TryGetValue(text, out value2); int num2 = (value[text] = value2 + 1); PhotonView component = ((Component)PunManager.instance).GetComponent<PhotonView>(); if ((Object)(object)component == (Object)null) { ManualLogSource log5 = UpgradeVotePlugin.Log; if (log5 != null) { log5.LogWarning((object)"[UpgradeVote] PunManager PhotonView null, cannot send UpdateStatRPC."); } return; } ManualLogSource log6 = UpgradeVotePlugin.Log; if (log6 != null) { log6.LogInfo((object)$"[UpgradeVote] Applying {fullKey} to {text} (new value {num2}) via UpdateStatRPC."); } component.RPC("UpdateStatRPC", (RpcTarget)0, new object[3] { fullKey, text, num2 }); } private string GetPlayerNameSafe(PlayerAvatar avatar) { if ((Object)(object)avatar == (Object)null) { return "Unknown"; } try { FieldInfo fieldInfo = AccessTools.Field(typeof(PlayerAvatar), "playerName"); if (fieldInfo != null) { string text = fieldInfo.GetValue(avatar) as string; if (!string.IsNullOrEmpty(text)) { return text; } } } catch { } PhotonView photonView = avatar.photonView; return $"Player {((photonView != null) ? photonView.ViewID : (-1))}"; } private string GetPlayerSteamIDSafe(PlayerAvatar avatar) { if ((Object)(object)avatar == (Object)null) { return null; } try { FieldInfo fieldInfo = AccessTools.Field(typeof(PlayerAvatar), "steamID"); if (fieldInfo != null) { string text = fieldInfo.GetValue(avatar) as string; if (!string.IsNullOrEmpty(text)) { return text; } } } catch { } return null; } public void OnNetworkStartRound(int roundId, string upgradeKey, string[] playerNames, string[] playerSteamIds, float duration) { UpgradeVotePlugin.LogDebug($"[UpgradeVote] OnNetworkStartRound round={roundId} key={upgradeKey}"); _localRoundId = roundId; _currentUpgradeKey = upgradeKey; _localPlayerNames = playerNames ?? Array.Empty<string>(); _localPlayerSteamIDs = playerSteamIds ?? new string[_localPlayerNames.Length]; if (UpgradeVotePlugin.VerboseLogging.Value) { List<string> list = new List<string>(_localPlayerNames); List<string> list2 = new List<string>(_localPlayerSteamIDs); while (list.Count < 12) { int num = list.Count + 1; list.Add($"TestPlayer {num}"); list2.Add(null); } _localPlayerNames = list.ToArray(); _localPlayerSteamIDs = list2.ToArray(); } _localVoteCounts = new int[_localPlayerNames.Length]; _localMyChoiceIndex = null; _localTimer = duration; _localVoteActive = true; BuildVoteUI(); } public void OnNetworkVote(int roundId, int voterActorNumber, int choiceIndex) { if (!_isHost || !_hostVoteActive || roundId != _currentRoundId) { return; } int count = _currentPlayers.Count; if (choiceIndex < 0 || choiceIndex >= count) { return; } _votesByActor[voterActorNumber] = choiceIndex; int[] array = new int[count]; foreach (KeyValuePair<int, int> item in _votesByActor) { int value = item.Value; if (value >= 0 && value < count) { array[value]++; } } UpgradeVoteNetwork.Instance?.HostBroadcastVoteUpdate(roundId, array); } public void OnNetworkVoteUpdate(int roundId, int[] voteCounts) { if (_localVoteActive && roundId == _localRoundId) { _localVoteCounts = voteCounts ?? Array.Empty<int>(); RefreshPlayerLines(); } } public void OnNetworkEndRound(int roundId, int winnerIndex, string winnerName, string upgradeKey) { if (roundId == _localRoundId) { ManualLogSource log = UpgradeVotePlugin.Log; if (log != null) { log.LogInfo((object)$"[UpgradeVote] OnNetworkEndRound round={roundId} winner={winnerName}"); } _localVoteActive = false; DestroyVoteUI(); string prettyUpgradeName = GetPrettyUpgradeName(upgradeKey); UpgradeVoteNotification.ShowUpgradeAward(winnerName, prettyUpgradeName); } } private void BuildVoteUI() { //IL_0068: 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) //IL_00c2: Expected O, but got Unknown //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Expected O, but got Unknown UpgradeVotePlugin.LogDebug($"[Avatar] BuildVoteUI: names={_localPlayerNames.Length}, steamIds={_localPlayerSteamIDs.Length}"); DestroyVoteUI(); MenuAPI.CloseAllPagesAddedOnTop(); string prettyUpgradeName = GetPrettyUpgradeName(_currentUpgradeKey); string text = "Kdo dostane\n\"" + prettyUpgradeName + "\"?\n"; _popup = MenuAPI.CreateREPOPopupPage(text, true, true, 0f, (Vector2?)new Vector2(-100f, 0f)); _playerButtons.Clear(); for (int i = 0; i < _localPlayerNames.Length; i++) { int idx = i; _popup.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform parent) { //IL_0026: 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_003c: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Expected O, but got Unknown //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) REPOButton val = MenuAPI.CreateREPOButton((string)null, (Action)delegate { OnLocalPlayerButtonClicked(idx); }, parent, default(Vector2)); RectTransform rectTransform = ((REPOElement)val).rectTransform; float num = rectTransform.sizeDelta.y; if (num <= 0f) { num = 56f; } rectTransform.anchorMin = new Vector2(0f, rectTransform.anchorMin.y); rectTransform.anchorMax = new Vector2(0.3f, rectTransform.anchorMax.y); rectTransform.offsetMin = new Vector2(0f, rectTransform.offsetMin.y); rectTransform.offsetMax = new Vector2(-40f, rectTransform.offsetMax.y); LayoutElement val2 = ((Component)val).gameObject.GetComponent<LayoutElement>() ?? ((Component)val).gameObject.AddComponent<LayoutElement>(); val2.minWidth = 0f; val2.preferredWidth = -1f; val2.flexibleWidth = 1f; val2.minHeight = num; val2.preferredHeight = num; val2.flexibleHeight = 0f; TextMeshProUGUI labelTMP = val.labelTMP; RectTransform rectTransform2 = ((TMP_Text)labelTMP).rectTransform; ((TMP_Text)labelTMP).alignment = (TextAlignmentOptions)513; ((TMP_Text)labelTMP).enableWordWrapping = false; ((TMP_Text)labelTMP).overflowMode = (TextOverflowModes)0; float x = rectTransform2.offsetMin.x; GameObject val3 = new GameObject("Avatar"); val3.transform.SetParent(((Component)val).transform, false); Image val4 = val3.AddComponent<Image>(); RectTransform rectTransform3 = ((Graphic)val4).rectTransform; rectTransform3.anchorMin = new Vector2(0f, 0.5f); rectTransform3.anchorMax = new Vector2(0f, 0.5f); rectTransform3.pivot = new Vector2(0f, 0.5f); rectTransform3.sizeDelta = new Vector2(32f, 32f); rectTransform3.anchoredPosition = new Vector2(x, 0f); _playerAvatarImages.Add(val4); _playerButtons.Add(val); return ((REPOElement)val).rectTransform; }, 0f, 0f); } _popup.AddElement((BuilderDelegate)delegate(Transform parent) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) _timerLabel = MenuAPI.CreateREPOLabel((string)null, parent, new Vector2(254f, 30f)); ((TMP_Text)_timerLabel.labelTMP).alignment = (TextAlignmentOptions)514; ((TMP_Text)_timerLabel.labelTMP).text = $"Time left: {_localTimer:0.0}s"; }); _popup.OpenPage(true); ((Component)_popup).GetComponent<MenuPage>().PageStateSet((PageState)1); RefreshPlayerLines(); RefreshPlayerAvatars(); } private void DestroyVoteUI() { if ((Object)(object)_popup != (Object)null) { _popup.ClosePage(true); _popup = null; } _playerAvatarImages.Clear(); _timerLabel = null; _questionLabel = null; _playerButtons.Clear(); } private TextMeshProUGUI CreateTMP(GameObject parent, string text, int size, TextAlignmentOptions alignment = 514) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0038: 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_006e: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("TMP"); val.transform.SetParent(parent.transform, false); TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>(); ((TMP_Text)val2).text = text; ((TMP_Text)val2).fontSize = size; ((TMP_Text)val2).alignment = alignment; ((Graphic)val2).color = Color.white; ((TMP_Text)val2).enableWordWrapping = false; ((TMP_Text)val2).overflowMode = (TextOverflowModes)0; RectTransform component = val.GetComponent<RectTransform>(); component.sizeDelta = new Vector2(0f, 40f); return val2; } private void OnLocalPlayerButtonClicked(int index) { if (_localVoteActive && index >= 0 && index < _localPlayerNames.Length) { _localMyChoiceIndex = index; RefreshPlayerLines(); if (PhotonNetwork.IsConnected && PhotonNetwork.CurrentRoom != null && (Object)(object)UpgradeVoteNetwork.Instance != (Object)null) { int voterActorNumber = ((PhotonNetwork.LocalPlayer != null) ? PhotonNetwork.LocalPlayer.ActorNumber : (-1)); UpgradeVoteNetwork.Instance.SendVote(_localRoundId, voterActorNumber, index); } else { HostRegisterLocalVote(index); } } } private void RefreshPlayerLines() { //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) if (_playerButtons.Count == 0) { return; } int num = Mathf.Clamp(_localPlayerNames.Length, 1, 12); for (int i = 0; i < _playerButtons.Count; i++) { REPOButton val = _playerButtons[i]; if (!((Object)(object)val == (Object)null)) { string arg = ((i < _localPlayerNames.Length) ? _localPlayerNames[i] : $"Player {i + 1}"); int num2 = ((i < _localVoteCounts.Length) ? _localVoteCounts[i] : 0); Color color = ((_localMyChoiceIndex.HasValue && _localMyChoiceIndex.Value == i) ? Color.yellow : Color.white); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("<indent=32px>"); stringBuilder.Append(ColorString($"{i + 1}. {arg}", color)); if (num2 > 0) { string arg2 = ((num2 == 1) ? "" : "s"); stringBuilder.Append($" <size=18>({num2} vote{arg2})</size>"); } ((TMP_Text)val.labelTMP).enableWordWrapping = false; ((TMP_Text)val.labelTMP).overflowMode = (TextOverflowModes)0; ((TMP_Text)val.labelTMP).alignment = (TextAlignmentOptions)513; ((TMP_Text)val.labelTMP).text = stringBuilder.ToString(); } } } private void ShowResultToast(string upgradeKey, string winnerName) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: 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_0106: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(winnerName)) { winnerName = "(no one)"; } if ((Object)(object)_toastCanvas != (Object)null) { Object.Destroy((Object)(object)_toastCanvas); } _toastCanvas = new GameObject("UpgradeVoteToast"); Canvas val = _toastCanvas.AddComponent<Canvas>(); val.renderMode = (RenderMode)0; val.sortingOrder = 10000; _toastCanvas.AddComponent<CanvasScaler>(); _toastCanvas.AddComponent<GraphicRaycaster>(); GameObject val2 = new GameObject("Panel"); val2.transform.SetParent(_toastCanvas.transform, false); Image val3 = val2.AddComponent<Image>(); ((Graphic)val3).color = new Color(0f, 0f, 0f, 0.8f); RectTransform component = val2.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0.3f, 0.8f); component.anchorMax = new Vector2(0.7f, 0.95f); component.offsetMin = Vector2.zero; component.offsetMax = Vector2.zero; TextMeshProUGUI val4 = CreateTMP(val2, "Upgrade '" + upgradeKey + "' awarded to " + winnerName + ".", 24, (TextAlignmentOptions)514); ((TMP_Text)val4).alignment = (TextAlignmentOptions)514; _toastTimer = 3f; } private void TrySendChatMessage(string msg) { try { Type type = AccessTools.TypeByName("ChatManager"); if (type == null) { ManualLogSource log = UpgradeVotePlugin.Log; if (log != null) { log.LogInfo((object)("[UpgradeVote] (Chat fallback) " + msg)); } return; } object obj = AccessTools.Field(type, "instance")?.GetValue(null); if (obj == null) { ManualLogSource log2 = UpgradeVotePlugin.Log; if (log2 != null) { log2.LogInfo((object)("[UpgradeVote] (Chat fallback2) " + msg)); } return; } MethodInfo methodInfo = AccessTools.Method(type, "AddMessage", new Type[1] { typeof(string) }, (Type[])null); if (methodInfo != null) { methodInfo.Invoke(obj, new object[1] { msg }); return; } ManualLogSource log3 = UpgradeVotePlugin.Log; if (log3 != null) { log3.LogInfo((object)("[UpgradeVote] (Chat fallback3) " + msg)); } } catch { ManualLogSource log4 = UpgradeVotePlugin.Log; if (log4 != null) { log4.LogInfo((object)("[UpgradeVote] (Chat failed) " + msg)); } } } } [HarmonyPatch] public static class ItemUpgrade_PlayerUpgrade_Patch { private static readonly Dictionary<string, int> _preUpgradeStats = new Dictionary<string, int>(); private static string _targetSteamID; private static PlayerAvatar _targetAvatar; private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("ItemUpgrade"); if (type == null) { ManualLogSource log = UpgradeVotePlugin.Log; if (log != null) { log.LogError((object)"[UpgradeVote] ItemUpgrade type not found."); } return null; } MethodInfo methodInfo = AccessTools.Method(type, "PlayerUpgrade", (Type[])null, (Type[])null); if (methodInfo == null) { ManualLogSource log2 = UpgradeVotePlugin.Log; if (log2 != null) { log2.LogError((object)"[UpgradeVote] ItemUpgrade.PlayerUpgrade method not found."); } } else { ManualLogSource log3 = UpgradeVotePlugin.Log; if (log3 != null) { log3.LogInfo((object)("[UpgradeVote] Patching ItemUpgrade.PlayerUpgrade: " + methodInfo)); } } return methodInfo; } [HarmonyPrefix] public static void Prefix(object __instance) { if (!UpgradeVotePlugin.EnablePlugin.Value || !SemiFunc.IsMasterClientOrSingleplayer()) { return; } _targetSteamID = null; _targetAvatar = null; _preUpgradeStats.Clear(); try { Type type = __instance.GetType(); object? obj = AccessTools.Field(type, "itemToggle")?.GetValue(__instance); ItemToggle val = (ItemToggle)((obj is ItemToggle) ? obj : null); if ((Object)(object)val == (Object)null) { return; } FieldInfo fieldInfo = AccessTools.Field(typeof(ItemToggle), "playerTogglePhotonID"); if (fieldInfo == null) { return; } int num = (int)fieldInfo.GetValue(val); PlayerAvatar val2 = SemiFunc.PlayerAvatarGetFromPhotonID(num); if ((Object)(object)val2 == (Object)null) { return; } _targetAvatar = val2; FieldInfo fieldInfo2 = AccessTools.Field(typeof(PlayerAvatar), "steamID"); if (fieldInfo2 == null) { return; } string text = fieldInfo2.GetValue(val2) as string; if (string.IsNullOrEmpty(text)) { return; } _targetSteamID = text; if ((Object)(object)StatsManager.instance == (Object)null) { return; } Dictionary<string, Dictionary<string, int>> dictionaryOfDictionaries = StatsManager.instance.dictionaryOfDictionaries; if (dictionaryOfDictionaries == null) { return; } foreach (KeyValuePair<string, Dictionary<string, int>> item in dictionaryOfDictionaries) { if (item.Key.StartsWith("playerUpgrade")) { if (item.Value.TryGetValue(_targetSteamID, out var value)) { _preUpgradeStats[item.Key] = value; } else { _preUpgradeStats[item.Key] = 0; } } } } catch (Exception ex) { ManualLogSource log = UpgradeVotePlugin.Log; if (log != null) { log.LogWarning((object)"[UpgradeVote] PREFIX exception:"); } ManualLogSource log2 = UpgradeVotePlugin.Log; if (log2 != null) { log2.LogWarning((object)ex.ToString()); } } } [HarmonyPostfix] public static void Postfix(object __instance) { if (!UpgradeVotePlugin.EnablePlugin.Value || !SemiFunc.IsMasterClientOrSingleplayer() || (Object)(object)StatsManager.instance == (Object)null) { return; } try { if (string.IsNullOrEmpty(_targetSteamID) || (Object)(object)_targetAvatar == (Object)null) { return; } Dictionary<string, Dictionary<string, int>> dictionaryOfDictionaries = StatsManager.instance.dictionaryOfDictionaries; if (dictionaryOfDictionaries == null) { return; } UpgradeVoteManager instance = UpgradeVoteManager.Instance; if ((Object)(object)instance == (Object)null) { return; } foreach (KeyValuePair<string, Dictionary<string, int>> item in dictionaryOfDictionaries) { string key = item.Key; if (key.StartsWith("playerUpgrade")) { Dictionary<string, int> value = item.Value; int num = (_preUpgradeStats.ContainsKey(key) ? _preUpgradeStats[key] : 0); int num2 = (value.ContainsKey(_targetSteamID) ? value[_targetSteamID] : 0); if (num2 > num) { int count = num2 - num; value[_targetSteamID] = num; instance.EnqueueUpgrade(key, count); } } } MonoBehaviour val = (MonoBehaviour)((__instance is MonoBehaviour) ? __instance : null); if ((Object)(object)val != (Object)null && (Object)(object)((Component)val).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)val).gameObject); } } catch (Exception ex) { ManualLogSource log = UpgradeVotePlugin.Log; if (log != null) { log.LogWarning((object)"[UpgradeVote] POSTFIX exception:"); } ManualLogSource log2 = UpgradeVotePlugin.Log; if (log2 != null) { log2.LogWarning((object)ex.ToString()); } } finally { _targetSteamID = null; _targetAvatar = null; _preUpgradeStats.Clear(); } } } public static class SteamAvatarCache { private static readonly Dictionary<ulong, Sprite> _cache = new Dictionary<ulong, Sprite>(); private static readonly Dictionary<ulong, Task<Image?>> _pending = new Dictionary<ulong, Task<Image?>>(); public static Sprite GetAvatarSprite(string steamIdString) { //IL_006b: 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_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: 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_0103: Unknown result type (might be due to invalid IL or missing references) //IL_010c: 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) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Expected O, but got Unknown //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(steamIdString)) { return null; } if (!ulong.TryParse(steamIdString, out var result)) { return null; } if (_cache.TryGetValue(result, out Sprite value) && (Object)(object)value != (Object)null) { return value; } try { if (!_pending.TryGetValue(result, out Task<Image?> value2)) { SteamId val = default(SteamId); val.Value = result; value2 = SteamFriends.GetLargeAvatarAsync(val); _pending[result] = value2; return null; } if (!value2.IsCompleted) { return null; } _pending.Remove(result); if (!value2.IsCompletedSuccessfully) { return null; } Image? result2 = value2.Result; if (!result2.HasValue) { return null; } Image value3 = result2.Value; if (value3.Width == 0 || value3.Height == 0 || value3.Data == null || value3.Data.Length == 0) { return null; } Texture2D val2 = new Texture2D((int)value3.Width, (int)value3.Height, (TextureFormat)4, false); ((Texture)val2).filterMode = (FilterMode)1; val2.LoadRawTextureData(value3.Data); val2.Apply(); FlipTextureVertically(val2); Sprite val3 = Sprite.Create(val2, new Rect(0f, 0f, (float)((Texture)val2).width, (float)((Texture)val2).height), new Vector2(0.5f, 0.5f)); _cache[result] = val3; return val3; } catch (Exception arg) { ManualLogSource log = UpgradeVotePlugin.Log; if (log != null) { log.LogWarning((object)$"[Avatar] Exception while loading avatar for {steamIdString}: {arg}"); } return null; } } private static void FlipTextureVertically(Texture2D tex) { int width = ((Texture)tex).width; int height = ((Texture)tex).height; Color[] pixels = tex.GetPixels(); Color[] array = (Color[])(object)new Color[pixels.Length]; for (int i = 0; i < height; i++) { int sourceIndex = i * width; int destinationIndex = (height - 1 - i) * width; Array.Copy(pixels, sourceIndex, array, destinationIndex, width); } tex.SetPixels(array); tex.Apply(); } } internal static class UpgradeVoteNotification { private static float _timer = 0f; private static string _text = ""; private const string EmojiMoney = "{$$}"; private static readonly Color TextColor = new Color(0f, 1f, 0.2f); public static void ShowUpgradeAward(string winnerName, string prettyUpgradeName, float duration = 3f) { if (string.IsNullOrEmpty(winnerName)) { winnerName = "(no one)"; } if (string.IsNullOrEmpty(prettyUpgradeName)) { prettyUpgradeName = "upgrade"; } _timer = duration; _text = "<size=26>" + winnerName + "</size> <size=18>Dostal</size>\n<size=26>" + prettyUpgradeName + "</size>"; } public static void Update() { //IL_003f: 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) if (!(_timer <= 0f)) { _timer = Mathf.Max(0f, _timer - Time.deltaTime); SemiFunc.UIBigMessage(_text, "{$$}", 28f, TextColor, Color.white); } } } }