The BepInEx console will not appear when launching like it does for other games on Thunderstore (you can turn it back on in your BepInEx.cfg file). If your PEAK crashes on startup, add -dx12 to your launch parameters.
Decompiled source of PeakTeamRace v1.0.2
_PeakTeamRace.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using DG.Tweening; using DG.Tweening.Core; using DG.Tweening.Plugins.Options; using HarmonyLib; using Photon.Pun; using Photon.Realtime; using TMPro; using UnityEngine; using UnityEngine.UI; using Zorro.Core; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("\u200b\u200bPeakTeamRace")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("\u200b\u200bPeakTeamRace")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("bffd4bcb-a83c-4d1f-a0f8-44899c7289b0")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace _PeakTeamRace; [BepInPlugin("com.xiaohai.peakteamrace", "\u200b\u200bPeakTeamRace", "1.0.2")] public class Plugin : BaseUnityPlugin { public const string PluginGUID = "com.xiaohai.peakteamrace"; public const string PluginName = "\u200b\u200bPeakTeamRace"; public const string PluginVersion = "1.0.2"; public ConfigEntry<float> rewardMultiplier; public ConfigEntry<float> penaltyMax; public ConfigEntry<bool> useTeamColor; public ConfigEntry<bool> useChain; public static Plugin Instance { get; private set; } public static ManualLogSource Log { get; private set; } public void Awake() { //IL_002a: 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) //IL_00cc: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin \u200b\u200bPeakTeamRace v 1.0.2is loaded!"); new Harmony("com.xiaohai.peakteamrace").PatchAll(); rewardMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Settings", "RewardMultiplier", 1f, "Multiplier for the extra stamina reward after winning(0-1).获胜方获得额外体力奖励的倍率(0 到 1)"); penaltyMax = ((BaseUnityPlugin)this).Config.Bind<float>("Settings", "PenaltyFloor", 0.65f, "Maximum penalty for losing (0 - 0.9),失败惩罚异常状态最大值(0 - 0.9)"); useTeamColor = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "useTeamColor/是否使用队伍颜色", false, "true =Sets the team's color for all players. 如果填写true,则将所有玩家的颜色设置成队伍颜色.."); useChain = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "useChain/是否使用链条", true, "true =Players on the same team are connected by chains. 如果填写true,则同队玩家之间会被链条连接."); GameObject val = new GameObject("TeamChainSystem"); TeamChainSystem teamChainSystem = val.AddComponent<TeamChainSystem>(); Object.DontDestroyOnLoad((Object)(object)val); } } public class TeamRaceManager : Singleton<TeamRaceManager> { [CompilerGenerated] private sealed class <>c__DisplayClass32_0 { public Random rng; internal int <RandomlyAssignTeamsCoroutine>b__1(int x) { return rng.Next(); } } [CompilerGenerated] private sealed class <RandomlyAssignTeamsCoroutine>d__32 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public TeamRaceManager <>4__this; private List<Character> <allPlayers>5__1; private TeamChainSystem <system>5__2; private object[] <serializedData>5__3; private List<Character>.Enumerator <>s__4; private Character <player>5__5; private <>c__DisplayClass32_0 <>8__6; private List<int> <indices>5__7; private int <teamSplitIndex>5__8; private int <i>5__9; private int <playerId>5__10; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RandomlyAssignTeamsCoroutine>d__32(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <allPlayers>5__1 = null; <system>5__2 = null; <serializedData>5__3 = null; <>s__4 = default(List<Character>.Enumerator); <player>5__5 = null; <>8__6 = null; <indices>5__7 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (!PhotonNetwork.IsMasterClient) { return false; } <>2__current = <>4__this.WaitForResultProcessing(); <>1__state = 1; return true; case 1: <>1__state = -1; <>4__this.PlayerTeams.Clear(); <allPlayers>5__1 = Character.AllCharacters.Where((Character p) => (Object)(object)p != (Object)null && (Object)(object)((MonoBehaviourPun)p).photonView != (Object)null).ToList(); if (<allPlayers>5__1.Count < 2) { <>s__4 = <allPlayers>5__1.GetEnumerator(); try { while (<>s__4.MoveNext()) { <player>5__5 = <>s__4.Current; <>4__this.PlayerTeams[((MonoBehaviourPun)<player>5__5).photonView.ViewID] = 0; <player>5__5 = null; } } finally { ((IDisposable)<>s__4).Dispose(); } <>s__4 = default(List<Character>.Enumerator); } else { <>8__6 = new <>c__DisplayClass32_0(); <indices>5__7 = Enumerable.Range(0, <allPlayers>5__1.Count).ToList(); <>8__6.rng = new Random(); <indices>5__7 = <indices>5__7.OrderBy((int x) => <>8__6.rng.Next()).ToList(); <teamSplitIndex>5__8 = <allPlayers>5__1.Count / 2; <i>5__9 = 0; while (<i>5__9 < <indices>5__7.Count) { <playerId>5__10 = ((MonoBehaviourPun)<allPlayers>5__1[<indices>5__7[<i>5__9]]).photonView.ViewID; <>4__this.PlayerTeams[<playerId>5__10] = ((<i>5__9 >= <teamSplitIndex>5__8) ? 1 : 0); <i>5__9++; } <>8__6 = null; <indices>5__7 = null; } <system>5__2 = TeamChainSystem.Instance; if ((Object)(object)<system>5__2 != (Object)null) { <system>5__2.ClearAllChains(); } if (Plugin.Instance.useChain.Value) { <>4__this.CreateTeamChains(); } <serializedData>5__3 = <>4__this.SerializeTeamsForRPC(); <>4__this._photonView.RPC("RPC_AssignTeams", (RpcTarget)0, <serializedData>5__3); <>4__this.DebugLogTeamAssignments(<allPlayers>5__1); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <WaitForResultProcessing>d__33 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public TeamRaceManager <>4__this; private float <timeout>5__1; private float <startTime>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <WaitForResultProcessing>d__33(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <timeout>5__1 = 10f; <startTime>5__2 = Time.time; break; case 1: <>1__state = -1; break; } if (<>4__this.IsProcessingResults) { if (Time.time - <startTime>5__2 > <timeout>5__1) { return false; } <>2__current = (object)new WaitForSeconds(0.5f); <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public readonly Dictionary<int, float> PlayerFinishTimes = new Dictionary<int, float>(); public readonly Dictionary<int, int> PlayerScores = new Dictionary<int, int>(); public readonly int[] TeamScores = new int[2]; private PhotonView _photonView; private HashSet<int> _activePlayersAtStart; public readonly Color[] TeamColors = (Color[])(object)new Color[2] { new Color(1f, 0.3f, 0.3f), new Color(0.3f, 0.3f, 1f) }; private bool reachedCampfire = false; public STATUSTYPE shouldStatus; public float shouldStatusValue = -1f; public Dictionary<int, int> PlayerTeams { get; private set; } = new Dictionary<int, int>(); public float FirstPlaceTime { get; private set; } = float.MaxValue; public int LocalPlayerTeamId { get; private set; } = -1; public bool IsProcessingResults { get; private set; } private TeamRaceTimer timer => TeamRaceTimer.Instance; public bool isChinese => (int)LocalizedText.CURRENT_LANGUAGE == 9; protected override void Awake() { base.Awake(); _photonView = ((Component)this).GetComponentInChildren<PhotonView>(); if ((Object)(object)_photonView == (Object)null) { _photonView = ((Component)this).gameObject.AddComponent<PhotonView>(); PhotonNetwork.AllocateViewID(_photonView); } PlayerTeams = new Dictionary<int, int>(); } private void Update() { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_0090: 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) if ((Object)(object)Character.localCharacter == (Object)null || (Object)(object)((MonoBehaviourPun)Character.localCharacter).photonView == (Object)null) { return; } if ((Object)(object)Patch.nextCampfire != (Object)null) { float num = Vector3.Distance(Character.localCharacter.Center, ((Component)Patch.nextCampfire).transform.position); if (num < 3f && !reachedCampfire) { PlayerReachedCampfire(); } return; } _ = Patch.nextPoint; if (true) { float num2 = Vector3.Distance(Character.localCharacter.Center, Patch.nextPoint); if (num2 <= 1f && !reachedCampfire) { PlayerReachedCampfire(); } } } public void StartTeamAssignment() { ((MonoBehaviour)this).StartCoroutine(RandomlyAssignTeamsCoroutine()); } [IteratorStateMachine(typeof(<RandomlyAssignTeamsCoroutine>d__32))] private IEnumerator RandomlyAssignTeamsCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <RandomlyAssignTeamsCoroutine>d__32(0) { <>4__this = this }; } [IteratorStateMachine(typeof(<WaitForResultProcessing>d__33))] private IEnumerator WaitForResultProcessing() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <WaitForResultProcessing>d__33(0) { <>4__this = this }; } private object[] SerializeTeamsForRPC() { return new object[3] { PlayerTeams.Count, PlayerTeams.Keys.ToArray(), PlayerTeams.Values.ToArray() }; } [PunRPC] private void RPC_AssignTeams(object[] data) { PlayerTeams.Clear(); PlayerFinishTimes.Clear(); PlayerScores.Clear(); Array.Clear(TeamScores, 0, TeamScores.Length); FirstPlaceTime = float.MaxValue; reachedCampfire = false; _activePlayersAtStart = new HashSet<int>(PlayerTeams.Keys); int num = (int)data[0]; int[] array = (int[])data[1]; int[] array2 = (int[])data[2]; for (int i = 0; i < num; i++) { PlayerTeams[array[i]] = array2[i]; } UpdateLocalPlayerTeam(); } public void UpdateLocalPlayerTeam() { if (!((Object)(object)Character.localCharacter != (Object)null) || !((Object)(object)((MonoBehaviourPun)Character.localCharacter).photonView != (Object)null)) { return; } int viewID = ((MonoBehaviourPun)Character.localCharacter).photonView.ViewID; if (PlayerTeams.TryGetValue(viewID, out var value)) { LocalPlayerTeamId = value; Plugin.Log.LogInfo((object)$"你的队伍ID是: Team{LocalPlayerTeamId} (红队0/蓝队1)"); string text = (isChinese ? ("你的队伍是: " + ((value == 0) ? "<color=red>红队</color>" : "<color=blue>蓝队</color>")) : ("Your team is: " + ((value == 0) ? "<color=red>Red Team</color>" : "<color=blue>Blue Team</color>"))); TeamRaceTimer.SetMessage("<size=40>" + text + "</size>", 15f); ResultUI.ShowResultUI("<size=45>" + text + "</size>", 15f); if (!timer.isRunning) { timer.StartTimer(); } if (Plugin.Instance.useTeamColor.Value) { SetTeamColor(value); } } else { Plugin.Log.LogWarning((object)"本地玩家未分配到队伍!"); } } private void SetTeamColor(int teamID) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) Singleton<Customization>.Instance.skins[1].color = TeamColors[teamID]; CharacterCustomization.SetCharacterSkinColor(1); } public int GetPlayerTeam(int playerViewId) { int value; return PlayerTeams.TryGetValue(playerViewId, out value) ? value : (-1); } public List<int> GetTeammates(int playerViewId) { if (!PlayerTeams.TryGetValue(playerViewId, out var myTeamId)) { return new List<int>(); } return (from pair in PlayerTeams where pair.Value == myTeamId select pair.Key).ToList(); } private void PlayerReachedCampfire() { reachedCampfire = true; float num = timer.StopTimer(); _photonView.RPC("RPC_SyncPlayerReachedCampfire", (RpcTarget)2, new object[2] { ((MonoBehaviourPun)Character.localCharacter).photonView.ViewID, num }); string msg = (isChinese ? ("<size=30><color=green>你到达了篝火! 完成时间: " + timer.FormatTime(num) + "</size></color>") : ("<size=30><color=green>You reached the campfire! Finish time: " + timer.FormatTime(num) + "</size></color>")); TeamRaceTimer.SetMessage(msg, 5f); } [PunRPC] private void RPC_SyncPlayerReachedCampfire(int playerViewId, float finishTime) { if (PhotonNetwork.IsMasterClient) { IsProcessingResults = true; HandleResult(GetCharacterByViewId(playerViewId), finishTime); } } [PunRPC] private void RPC_SyncResult(object[] data) { //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_02fc: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_0336: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Unknown result type (might be due to invalid IL or missing references) IsProcessingResults = true; FirstPlaceTime = (float)data[0]; TeamScores[0] = (int)data[1]; TeamScores[1] = (int)data[2]; int num = (int)data[3]; int[] array = (int[])data[4]; float[] array2 = (float[])data[5]; PlayerFinishTimes.Clear(); for (int i = 0; i < num; i++) { PlayerFinishTimes[array[i]] = array2[i]; } int num2 = (int)data[6]; int[] array3 = (int[])data[7]; int[] array4 = (int[])data[8]; PlayerScores.Clear(); for (int j = 0; j < num2; j++) { PlayerScores[array3[j]] = array4[j]; } bool flag = false; string text = ""; if ((TeamScores[0] > TeamScores[1] && LocalPlayerTeamId == 0) || (TeamScores[0] < TeamScores[1] && LocalPlayerTeamId == 1)) { flag = true; } else if (TeamScores[0] == TeamScores[1]) { flag = true; } int value; int num3 = (PlayerScores.TryGetValue(((MonoBehaviourPun)Character.localCharacter).photonView.ViewID, out value) ? value : 0); if (flag) { float num4 = num3 / 100; if (Character.localCharacter.data.dead) { shouldStatusValue = num4; shouldStatus = (STATUSTYPE)7; } else { Character.localCharacter.AddExtraStamina(num4 * Plugin.Instance.rewardMultiplier.Value); } text = (isChinese ? $"<size=35><color=green>你赢了! 获得额外耐力: {num4 * 100f:F2}%</color></size>" : $"<size=35><color=green>You win! Add extra stamina: {num4 * 100f:F2}%</color></size>"); } else { List<STATUSTYPE> list = new List<STATUSTYPE> { (STATUSTYPE)8, (STATUSTYPE)2, (STATUSTYPE)6, (STATUSTYPE)3 }; int index = Random.Range(0, list.Count); float num5 = 1f - (float)(num3 / 100); num5 = Mathf.Clamp(num5, 0f, Plugin.Instance.penaltyMax.Value); if (Character.localCharacter.refs.afflictions.statusSum + num5 >= 1f) { num5 = 0.9f - Character.localCharacter.refs.afflictions.statusSum; } if (Character.localCharacter.data.dead) { shouldStatus = list[index]; shouldStatusValue = num5; } else { Character.localCharacter.refs.afflictions.AddStatus(list[index], num5, false); } text = (isChinese ? $"<size=35><color=red>你输了! 获得负面状态: {list[index]}</color></size>" : $"<size=35><color=red>You lose! Add Affliction: {list[index]}</color></size>"); } Plugin.Log.LogInfo((object)$"已同步比赛结果: 第一名时间={FirstPlaceTime:F2}s, 红队={TeamScores[0]}, 蓝队={TeamScores[1]}"); string result = GenerateResultText(text); ResultUI.ShowResultUI(result, 15f, useEffects: false); IsProcessingResults = false; } public void HandleResult(Character player, float finishTime) { if (PhotonNetwork.IsMasterClient && !((Object)(object)player == (Object)null)) { int viewID = ((MonoBehaviourPun)player).photonView.ViewID; PlayerFinishTimes[viewID] = finishTime; if (finishTime < FirstPlaceTime) { FirstPlaceTime = finishTime; } int num = CalculatePlayerScore(viewID, finishTime); PlayerScores[viewID] = num; if (PlayerTeams.TryGetValue(viewID, out var value)) { TeamScores[value] += num; } Plugin.Log.LogInfo((object)$"玩家{player.characterName}完成! 时间: {timer.FormatTime(finishTime)}, 积分: {num}"); if (CheckAllPlayersFinished()) { object[] array = SerializeResultsForRPC(); _photonView.RPC("RPC_SyncResult", (RpcTarget)0, array); } } } private bool CheckAllPlayersFinished() { HashSet<int> second = PhotonNetwork.CurrentRoom.Players.Values.Select((Player p) => p.ActorNumber).ToHashSet(); IEnumerable<int> source = _activePlayersAtStart.Intersect(second); return source.All((int playerId) => PlayerFinishTimes.ContainsKey(playerId)); } private int CalculatePlayerScore(int playerViewId, float finishTime) { List<float> list = PlayerFinishTimes.Values.ToList(); if (list.Count == 1) { return 100; } int num = 1; foreach (float item in list) { if (item < finishTime) { num++; } } int count = list.Count; int num2 = 0; int num3 = 100; int num4 = num3 - (num - 1) * (num3 - num2) / (count - 1); return Mathf.Clamp(num4, num2, num3); } private object[] SerializeResultsForRPC() { int[] array = PlayerFinishTimes.Keys.ToArray(); float[] array2 = PlayerFinishTimes.Values.ToArray(); int[] array3 = PlayerScores.Keys.ToArray(); int[] array4 = PlayerScores.Values.ToArray(); return new object[9] { FirstPlaceTime, TeamScores[0], TeamScores[1], array.Length, array, array2, array3.Length, array3, array4 }; } private Character GetCharacterByViewId(int viewId) { foreach (Character allCharacter in Character.AllCharacters) { if ((Object)(object)allCharacter != (Object)null && (Object)(object)((MonoBehaviourPun)allCharacter).photonView != (Object)null && ((MonoBehaviourPun)allCharacter).photonView.ViewID == viewId) { return allCharacter; } } return null; } private string GenerateResultText(string extraText) { StringBuilder stringBuilder = new StringBuilder(); string text = ((TeamScores[1] > TeamScores[0]) ? "<size=30>win</size>" : ""); string text2 = ((TeamScores[1] < TeamScores[0]) ? "<size=30>win</size>" : ""); string value = ((!isChinese) ? $"<size=60><color=blue>Team Blue</color>: {TeamScores[1]}</size>{text} <size=60><color=red>Team Red</color>: {TeamScores[0]}</size>{text2}" : $"<size=60><color=blue>蓝队</color>: {TeamScores[1]}分</size>{text} <size=60><color=red>红队</color>: {TeamScores[0]}分</size>{text2}"); stringBuilder.AppendLine(value); stringBuilder.AppendLine(); stringBuilder.AppendLine("<size=40>Player Time Score</size>"); stringBuilder.AppendLine(); int value3; var list = (from p in PlayerFinishTimes orderby p.Value select new { ViewID = p.Key, Time = p.Value, Score = (PlayerScores.TryGetValue(p.Key, out value3) ? value3 : 0) }).ToList(); for (int i = 0; i < list.Count; i++) { var anon = list[i]; Character characterByViewId = GetCharacterByViewId(anon.ViewID); string text3 = (((Object)(object)characterByViewId != (Object)null) ? characterByViewId.characterName : "Unknown"); int value2; string text4 = ((!PlayerTeams.TryGetValue(anon.ViewID, out value2)) ? "white" : ((value2 == 0) ? "red" : "blue")); string text5 = TeamRaceTimer.Instance.FormatTime(anon.Time); stringBuilder.Append($"<size=32>{i + 1}."); stringBuilder.Append("<color=" + text4 + ">" + text3 + "</color></size>"); int num = 15 - text3.Length; if (num > 0) { stringBuilder.Append(new string(' ', num)); } int num2 = 15 - text5.Length; if (num2 > 0) { stringBuilder.Append(new string(' ', num2)); } stringBuilder.Append(text5); int num3 = 17 - anon.Score.ToString().Length; if (num3 > 0) { stringBuilder.Append(new string(' ', num3)); } stringBuilder.Append($"<size=32>{anon.Score}</size>"); stringBuilder.AppendLine(); } stringBuilder.AppendLine(extraText); return stringBuilder.ToString(); } private void CreateTeamChains() { if ((Object)(object)TeamChainSystem.Instance == (Object)null) { return; } TeamChainSystem instance = TeamChainSystem.Instance; Dictionary<int, List<Character>> dictionary = new Dictionary<int, List<Character>>(); foreach (Character allCharacter in Character.AllCharacters) { if ((Object)(object)((MonoBehaviourPun)allCharacter).photonView == (Object)null) { continue; } int viewID = ((MonoBehaviourPun)allCharacter).photonView.ViewID; if (PlayerTeams.TryGetValue(viewID, out var value)) { if (!dictionary.ContainsKey(value)) { dictionary[value] = new List<Character>(); } dictionary[value].Add(allCharacter); } } foreach (KeyValuePair<int, List<Character>> item in dictionary) { instance.CreateChainsForTeam(item.Key, item.Value); } } private void DebugLogTeamAssignments(List<Character> players) { string text = "红队(0): "; string text2 = "蓝队(1): "; foreach (Character player in players) { if ((Object)(object)((MonoBehaviourPun)player).photonView == (Object)null) { continue; } int viewID = ((MonoBehaviourPun)player).photonView.ViewID; if (PlayerTeams.TryGetValue(viewID, out var value)) { string text3 = player.characterName; if (string.IsNullOrEmpty(text3)) { text3 = "未命名玩家"; } if (value == 0) { text += $"{text3}({viewID}), "; } else { text2 += $"{text3}({viewID}), "; } } } Plugin.Log.LogInfo((object)text.TrimEnd(',', ' ')); Plugin.Log.LogInfo((object)text2.TrimEnd(',', ' ')); Plugin.Log.LogInfo((object)$"队伍分配完成! 总计: {players.Count}名玩家"); } } public class TeamRaceTimer : MonoBehaviour { private float messageTimer; private TMP_Text timerText; private float startTime; private float pausedTime; public bool isRunning; private bool isPaused; public string message = ""; public float CurrentTime => isRunning ? (Time.time - startTime) : pausedTime; public static TeamRaceTimer Instance { get; private set; } private void Start() { timerText = ((Component)this).GetComponentInChildren<TMP_Text>(); if ((Object)(object)timerText == (Object)null) { Debug.LogError((object)"无法找到计时器文本组件!"); ((Behaviour)this).enabled = false; return; } timerText.text = "00:00.00"; timerText.alignment = (TextAlignmentOptions)514; timerText.richText = true; SetVisible(visible: false); Instance = this; } public void StartTimer() { SetVisible(visible: true); if (isPaused) { startTime = Time.time - pausedTime; isPaused = false; } else { startTime = Time.time; pausedTime = 0f; } isRunning = true; } public void PauseTimer() { if (isRunning) { pausedTime = CurrentTime; isRunning = false; isPaused = true; } } public float StopTimer() { float currentTime = CurrentTime; isRunning = false; isPaused = false; return currentTime; } public void ResetTimer() { startTime = Time.time; pausedTime = 0f; isRunning = false; isPaused = false; timerText.text = message + "\n\n " + FormatTime(0f); } public string FormatTime(float time) { int num = Mathf.FloorToInt(time / 60f); int num2 = Mathf.FloorToInt(time % 60f); int num3 = Mathf.FloorToInt(time * 100f % 100f); string text = ((Singleton<TeamRaceManager>.Instance.LocalPlayerTeamId == 0) ? "red" : "blue"); return $"<size=32><color={text}>{num:00}:{num2:00}.{num3:00}</size></color>"; } public void SetVisible(bool visible) { CanvasGroup component = ((Component)this).GetComponent<CanvasGroup>(); if ((Object)(object)component != (Object)null) { component.alpha = (visible ? 1f : 0f); } else { ((Component)this).gameObject.SetActive(visible); } } private void Update() { messageTimer -= Time.deltaTime; if (messageTimer <= 0f) { message = ""; } timerText.text = message + "\n\n" + FormatTime(CurrentTime); } public static void SetMessage(string msg, float time) { if ((Object)(object)Instance != (Object)null) { Instance.message = msg; Instance.messageTimer = time; } } } public class ResultUI : MonoBehaviour { private static ResultUI _instance; private TMP_Text _resultText; private CanvasGroup _canvasGroup; private float _showTime = 5f; private float _timer; private bool _isShowing; public static ResultUI Instance => _instance; 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; _resultText = ((Component)this).GetComponentInChildren<TMP_Text>(); _resultText.richText = true; _resultText.text = ""; _canvasGroup = ((Component)this).gameObject.GetComponentInChildren<CanvasGroup>(); if ((Object)(object)_canvasGroup == (Object)null) { _canvasGroup = ((Component)this).gameObject.AddComponent<CanvasGroup>(); } _canvasGroup.alpha = 0f; _canvasGroup.blocksRaycasts = false; _canvasGroup.interactable = false; } public static void ShowResultUI(string result, float time, bool useEffects = true) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Instance == (Object)null)) { Instance._resultText.text = result; Instance._showTime = time; Instance._isShowing = true; Instance._resultText.transform.localScale = Vector3.one; Instance._canvasGroup.alpha = 0f; if (useEffects) { Instance.PlayAnimatedSequence(time); return; } Instance._canvasGroup.alpha = 1f; Instance._timer = time; ((Behaviour)Instance).enabled = true; } } private void PlayAnimatedSequence(float displayTime) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Expected O, but got Unknown DOTween.Kill((object)_resultText.transform, false); DOTween.Kill((object)_canvasGroup, false); Sequence val = DOTween.Sequence(); _resultText.transform.localScale = Vector3.zero; _canvasGroup.alpha = 0f; TweenSettingsExtensions.Append(val, (Tween)(object)TweenSettingsExtensions.SetEase<TweenerCore<Vector3, Vector3, VectorOptions>>(ShortcutExtensions.DOScale(_resultText.transform, 1.2f, 0.5f), (Ease)27)); TweenSettingsExtensions.Append(val, (Tween)(object)TweenSettingsExtensions.SetEase<TweenerCore<Vector3, Vector3, VectorOptions>>(ShortcutExtensions.DOScale(_resultText.transform, 1f, 0.3f), (Ease)3)); TweenSettingsExtensions.Join(val, (Tween)(object)DOTween.To((DOGetter<float>)(() => _canvasGroup.alpha), (DOSetter<float>)delegate(float x) { _canvasGroup.alpha = x; }, 1f, 0.5f)); TweenSettingsExtensions.AppendInterval(val, displayTime - 1f); TweenSettingsExtensions.Append(val, (Tween)(object)TweenSettingsExtensions.OnComplete<TweenerCore<float, float, FloatOptions>>(DOTween.To((DOGetter<float>)(() => _canvasGroup.alpha), (DOSetter<float>)delegate(float x) { _canvasGroup.alpha = x; }, 0f, 1f), (TweenCallback)delegate { _resultText.text = ""; _isShowing = false; ((Behaviour)this).enabled = false; })); TweenExtensions.Play<Sequence>(val); } private void Update() { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown if (!_isShowing) { return; } _timer -= Time.deltaTime; if (_timer <= 0f) { TweenSettingsExtensions.OnComplete<TweenerCore<float, float, FloatOptions>>(DOTween.To((DOGetter<float>)(() => _canvasGroup.alpha), (DOSetter<float>)delegate(float x) { _canvasGroup.alpha = x; }, 0f, 0.5f), (TweenCallback)delegate { _resultText.text = ""; _isShowing = false; }); } } } [HarmonyPatch] public static class Patch { [HarmonyPatch(typeof(GUIManager), "Start")] private static class PatchGUIManager { public static void Postfix(GUIManager __instance) { InitTimerUI(__instance); InitResultUI(__instance); } private static void InitTimerUI(GUIManager __instance) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0065: 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_0091: 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_00bd: Unknown result type (might be due to invalid IL or missing references) AscentUI componentInChildren = ((Component)__instance).GetComponentInChildren<AscentUI>(); Transform val = ((componentInChildren != null) ? ((Component)componentInChildren).transform : null); if (!((Object)(object)val == (Object)null)) { RectTransform val2 = (RectTransform)Object.Instantiate<Transform>(val, val.parent); ((Object)val2).name = "TeamRaceTimer"; Object.Destroy((Object)(object)((Component)val2).GetComponent<AscentUI>()); ((Component)val2).gameObject.AddComponent<TeamRaceTimer>(); val2.anchorMin = new Vector2(1f, 0.5f); val2.anchorMax = new Vector2(1f, 0.5f); val2.pivot = new Vector2(1f, 0.5f); val2.anchoredPosition = new Vector2(-50f, 0f); val2.sizeDelta = new Vector2(200f, 50f); } } private static void InitResultUI(GUIManager __instance) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_007f: 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_00a1: 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_00f0: Unknown result type (might be due to invalid IL or missing references) AscentUI componentInChildren = ((Component)__instance).GetComponentInChildren<AscentUI>(); Transform val = ((componentInChildren != null) ? ((Component)componentInChildren).transform : null); if (!((Object)(object)val == (Object)null)) { Transform val2 = Object.Instantiate<Transform>(val, val.parent); ((Object)val2).name = "ResultUI"; Object.Destroy((Object)(object)((Component)val2).GetComponent<AscentUI>()); ((Component)val2).gameObject.AddComponent<ResultUI>(); RectTransform component = ((Component)val2).GetComponent<RectTransform>(); component.anchorMin = new Vector2(0.5f, 0.5f); component.anchorMax = new Vector2(0.5f, 0.5f); component.pivot = new Vector2(0.5f, 0.5f); component.anchoredPosition = Vector2.zero; component.sizeDelta = new Vector2(800f, 600f); TMP_Text componentInChildren2 = ((Component)val2).GetComponentInChildren<TMP_Text>(); if ((Object)(object)componentInChildren2 != (Object)null) { componentInChildren2.alignment = (TextAlignmentOptions)257; componentInChildren2.fontSize = 24f; ((Graphic)componentInChildren2).color = Color.white; } } } } [HarmonyPatch(typeof(MapHandler))] private static class PatchMapHandler { [HarmonyPatch("GoToSegment")] public static void Postfix(MapHandler __instance, ref Segment s) { //IL_00de: 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) //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_0097: 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_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_0064: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance.segments[(int)s]._segmentCampfire == (Object)null) { nextCampfire = null; Plugin.Log.LogInfo((object)"无篝火位置,直奔顶点吧!"); GameObject val = GameObject.Find("Flag_planted_seagull"); if ((Object)(object)val != (Object)null) { nextPoint = val.transform.position; Plugin.Log.LogInfo((object)$"已设置下一个点为: {nextPoint}"); } else { nextPoint = (nextPoint = Singleton<MountainProgressHandler>.Instance.progressPoints.Last().transform.position); } } else { nextCampfire = __instance.segments[(int)s]._segmentCampfire.gameObject.GetComponentInChildren<Campfire>(true); if (!((Object)(object)nextCampfire != (Object)null)) { return; } float num = Vector3.Distance(((Component)nextCampfire).transform.position, ((Component)Character.localCharacter).transform.position); Plugin.Log.LogInfo((object)$"下一个篝火位置: {nextCampfire},距离玩家{num:F2}M"); } Singleton<TeamRaceManager>.Instance.StartTeamAssignment(); } } [HarmonyPatch(typeof(RunManager))] private static class PatchRunManager { [HarmonyPatch("Awake")] public static void Postfix(RunManager __instance) { if ((Object)(object)((Component)__instance).gameObject.GetComponent<TeamRaceManager>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<TeamRaceManager>(); Plugin.Log.LogInfo((object)"已添加TeamRaceManager组件到RunManager对象上"); } } } [HarmonyPatch(typeof(MountainProgressHandler))] private static class PatchMountainProgressHandler { [HarmonyPatch("CheckAreaAchievement")] public static void Prefix(MountainProgressHandler __instance, ref ProgressPoint pointReached) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Invalid comparison between Unknown and I4 //IL_0093: 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) if (pointReached.title.ToLower() != "shore") { return; } List<Campfire> list = Object.FindObjectsByType<Campfire>((FindObjectsSortMode)0).ToList(); Plugin.Log.LogInfo((object)$"已经到达海岸!,共找到{list.Count}个篝火!"); foreach (Campfire item in list) { if ((Object)(object)nextCampfire == (Object)null && (int)item.state != 1 && (Object)(object)Character.localCharacter != (Object)null) { float num = Vector3.Distance(((Component)item).transform.position, Character.localCharacter.Center); if (num > 50f) { nextCampfire = item; Plugin.Log.LogInfo((object)("已设置nextCampfire为当前Campfire: " + ((Object)item).name)); Singleton<TeamRaceManager>.Instance.StartTeamAssignment(); break; } } } } } [HarmonyPatch(typeof(Character))] private static class PatchCharacter { [HarmonyPatch("RPCA_Revive")] [HarmonyPostfix] private static void RevivePatch(Character __instance) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Invalid comparison between Unknown and I4 //IL_004f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)(object)Character.localCharacter && Singleton<TeamRaceManager>.Instance.shouldStatusValue != -1f) { if ((int)Singleton<TeamRaceManager>.Instance.shouldStatus != 7) { __instance.refs.afflictions.AddStatus(Singleton<TeamRaceManager>.Instance.shouldStatus, Singleton<TeamRaceManager>.Instance.shouldStatusValue, false); Singleton<TeamRaceManager>.Instance.shouldStatusValue = -1f; } else { __instance.AddExtraStamina(Singleton<TeamRaceManager>.Instance.shouldStatusValue); Singleton<TeamRaceManager>.Instance.shouldStatusValue = -1f; } } } } public static Campfire nextCampfire; public static Vector3 nextPoint; } public class TeamChainSystem : MonoBehaviour { public class ChainLink { public Character playerA; public Character playerB; public LineRenderer lineRenderer; public SpringJoint springJoint; private int teamId; public ChainLink(Character a, Character b, int team) { playerA = a; playerB = b; teamId = team; CreateVisualChain(); CreatePhysicsConnection(); } private void CreateVisualChain() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject($"Team{teamId}_Chain_{((MonoBehaviourPun)playerA).photonView.ViewID}-{((MonoBehaviourPun)playerB).photonView.ViewID}"); lineRenderer = val.AddComponent<LineRenderer>(); lineRenderer.positionCount = 2; ((Renderer)lineRenderer).material = new Material(Shader.Find("Sprites/Default")); lineRenderer.startColor = Instance.ChainColor; lineRenderer.endColor = Instance.ChainColor; lineRenderer.startWidth = Instance.ChainWidth; lineRenderer.endWidth = Instance.ChainWidth; } private void CreatePhysicsConnection() { Rigidbody hipRigidbody = GetHipRigidbody(playerA); Rigidbody hipRigidbody2 = GetHipRigidbody(playerB); if ((Object)(object)hipRigidbody != (Object)null && (Object)(object)hipRigidbody2 != (Object)null) { springJoint = ((Component)hipRigidbody).gameObject.AddComponent<SpringJoint>(); ((Joint)springJoint).connectedBody = hipRigidbody2; springJoint.spring = 15f; springJoint.damper = 0.5f; springJoint.minDistance = 2f; springJoint.maxDistance = Instance.ChainLength; ((Joint)springJoint).enableCollision = true; } } private Rigidbody GetHipRigidbody(Character character) { Transform val = ((Component)character).transform.FindRecursive("Hip"); return (val != null) ? ((Component)val).GetComponent<Rigidbody>() : null; } public void Update() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: 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_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: 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_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)playerA == (Object)null || (Object)(object)playerB == (Object)null) { Destroy(); return; } Vector3 hipPosition = GetHipPosition(playerA); Vector3 hipPosition2 = GetHipPosition(playerB); lineRenderer.SetPosition(0, hipPosition); lineRenderer.SetPosition(1, hipPosition2); float num = Vector3.Distance(hipPosition, hipPosition2); if (num > Instance.ChainLength && (Object)(object)springJoint != (Object)null) { Rigidbody hipRigidbody = GetHipRigidbody(playerA); if ((Object)(object)hipRigidbody != (Object)null) { Vector3 val = hipPosition2 - hipPosition; Vector3 normalized = ((Vector3)(ref val)).normalized; float num2 = (num - Instance.ChainLength) * 10f; hipRigidbody.AddForce(normalized * num2, (ForceMode)2); } } } private Vector3 GetHipPosition(Character character) { //IL_0037: 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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) Transform val = ((Component)character).transform.FindRecursive("Hip"); return (val != null) ? val.position : (((Component)character).transform.position + Vector3.up * 0.5f); } public void Destroy() { if ((Object)(object)lineRenderer != (Object)null) { Object.Destroy((Object)(object)((Component)lineRenderer).gameObject); } if ((Object)(object)springJoint != (Object)null) { Object.Destroy((Object)(object)springJoint); } } } public float ChainLength = 5f; public Color ChainColor = new Color(0.36f, 0.22f, 0.09f); public float ChainWidth = 0.1f; private Dictionary<int, List<ChainLink>> teamChains = new Dictionary<int, List<ChainLink>>(); public static TeamChainSystem Instance { get; private set; } private void Awake() { if ((Object)(object)Instance == (Object)null) { Instance = this; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); } else { Object.Destroy((Object)(object)((Component)this).gameObject); } } public void CreateChainsForTeam(int teamId, List<Character> members) { RemoveTeamChains(teamId); members.Sort((Character a, Character b) => ((MonoBehaviourPun)a).photonView.ViewID.CompareTo(((MonoBehaviourPun)b).photonView.ViewID)); List<ChainLink> list = new List<ChainLink>(); for (int i = 0; i < members.Count - 1; i++) { ChainLink item = new ChainLink(members[i], members[i + 1], teamId); list.Add(item); } if (members.Count > 2) { list.Add(new ChainLink(members[0], members[members.Count - 1], teamId)); } teamChains[teamId] = list; } public void RemoveTeamChains(int teamId) { if (!teamChains.TryGetValue(teamId, out var value)) { return; } foreach (ChainLink item in value) { item.Destroy(); } teamChains.Remove(teamId); } private void LateUpdate() { foreach (KeyValuePair<int, List<ChainLink>> teamChain in teamChains) { foreach (ChainLink item in teamChain.Value) { item.Update(); } } } public void ClearAllChains() { List<int> list = teamChains.Keys.ToList(); foreach (int item in list) { RemoveTeamChains(item); } teamChains.Clear(); } } public static class TransformExtensions { public static Transform FindRecursive(this Transform parent, string name) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown if (((Object)parent).name == name) { return parent; } foreach (Transform item in parent) { Transform parent2 = item; Transform val = parent2.FindRecursive(name); if ((Object)(object)val != (Object)null) { return val; } } return null; } }