Decompiled source of PunishInfo v1.1.0

plugins/com.github.daioutzu.punishinfo.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using Abilities;
using BepInEx;
using BepInEx.Logging;
using GameplayEntities;
using HarmonyLib;
using LLScreen;
using Microsoft.CodeAnalysis;
using Multiplayer;
using PunishInfo.FrameSync;
using PunishInfo.MatchInfo;
using PunishInfo.PluginSync;
using PunishInfo.Setup;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("com.github.daioutzu.punishinfo")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0+3f1be305d6728173debe2b893b99672a62e003ef")]
[assembly: AssemblyProduct("PunishInfo")]
[assembly: AssemblyTitle("com.github.daioutzu.punishinfo")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PunishInfo
{
	[BepInPlugin("com.github.daioutzu.punishinfo", "PunishInfo", "1.1.0")]
	[BepInProcess("LLBlaze.exe")]
	public class PunishInfo_Plugin : BaseUnityPlugin
	{
		public static ManualLogSource Logger;

		internal MatchInfoData pluginData;

		internal MatchInfoData pluginDataSave;

		internal CustomStateHistory stateHistory;

		public static PunishInfo_Plugin Instance { get; private set; }

		internal static Harmony Harmony { get; private set; } = new Harmony("com.github.daioutzu.punishinfo");


		private void Awake()
		{
			Instance = this;
			Logger = ((BaseUnityPlugin)this).Logger;
			if (!PluginBundle.Load((BaseUnityPlugin)(object)this, "ui_prefabs", "ui_sprites"))
			{
				Logger.LogFatal((object)"Plugin com.github.daioutzu.punishinfo has failed to load Bundle!");
				return;
			}
			Harmony.PatchAll();
			Logger.LogInfo((object)"Plugin com.github.daioutzu.punishinfo is loaded!");
		}
	}
	internal enum PunishType
	{
		NONE,
		COUNTER,
		PUNISH,
		PARRY_PUNISH
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "com.github.daioutzu.punishinfo";

		public const string PLUGIN_NAME = "PunishInfo";

		public const string PLUGIN_VERSION = "1.1.0";
	}
}
namespace PunishInfo.Setup
{
	internal static class PluginBundle
	{
		public static Dictionary<string, GameObject> prefabs { get; private set; } = new Dictionary<string, GameObject>();


		public static Dictionary<string, Sprite> sprites { get; private set; } = new Dictionary<string, Sprite>();


		public static bool Load(BaseUnityPlugin plugin, string bundleName)
		{
			AssetBundle val = AssetBundle.LoadFromFile(Path.Combine(new DirectoryInfo(Path.Combine(Path.GetDirectoryName(plugin.Info.Location), "Bundles")).FullName, bundleName));
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			LoadPrefabs(val);
			LoadSprites(val);
			val.Unload(false);
			return true;
		}

		public static bool Load(BaseUnityPlugin plugin, string prefabBundle, string uibunble)
		{
			DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(Path.GetDirectoryName(plugin.Info.Location), "Bundles"));
			AssetBundle val = AssetBundle.LoadFromFile(Path.Combine(directoryInfo.FullName, uibunble));
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			LoadSprites(val);
			val = AssetBundle.LoadFromFile(Path.Combine(directoryInfo.FullName, prefabBundle));
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			LoadPrefabs(val);
			val.Unload(false);
			return true;
		}

		private static void LoadPrefabs(AssetBundle bundle)
		{
			GameObject[] array = bundle.LoadAllAssets<GameObject>();
			foreach (GameObject val in array)
			{
				prefabs.Add(((Object)val).name, val);
			}
		}

		private static void LoadSprites(AssetBundle bundle)
		{
			Sprite[] array = bundle.LoadAllAssets<Sprite>();
			foreach (Sprite val in array)
			{
				sprites.Add(((Object)val).name, val);
			}
		}
	}
}
namespace PunishInfo.MatchInfo
{
	internal class AttackInfo
	{
		private const int HIT_TYPE_DURATION = 90;

		private int playerIndex = -1;

		private int prevHideTime = int.MaxValue;

		private int prevOnHitFrame;

		private PlayerStatistics playerStatistics;

		private int prevHitCount;

		private PunishType prevPunishType;

		internal static AttackInfo[] attackInfos = new AttackInfo[4];

		private GameObject attackInfoObjects;

		private GameObject counterObj;

		private GameObject punishObj;

		private GameObject hitCountObj;

		private Image imhitCount;

		internal GameHudPlayerInfo GameHudPlayerInfo { get; private set; }

		internal AttackInfo(GameHudPlayerInfo hudPlayerInfo)
		{
			GameHudPlayerInfo = hudPlayerInfo;
			playerIndex = GameHudPlayerInfo.shownPlayer.CJFLMDNNMIE;
			attackInfos[playerIndex] = this;
		}

		internal void Init()
		{
			attackInfoObjects = Object.Instantiate<GameObject>(PluginBundle.prefabs["AttackInfo"], ((Component)GameHudPlayerInfo).transform);
			((Object)attackInfoObjects).name = $"AttackInfo_{playerIndex}";
			GameObject gameObject = ((Component)attackInfoObjects.transform.GetChild(0)).gameObject;
			counterObj = gameObject;
			counterObj.SetActive(false);
			GameObject gameObject2 = ((Component)attackInfoObjects.transform.GetChild(1)).gameObject;
			punishObj = gameObject2;
			punishObj.SetActive(false);
			hitCountObj = ((Component)attackInfoObjects.transform.GetChild(2)).gameObject;
			imhitCount = hitCountObj.GetComponent<Image>();
			hitCountObj.SetActive(false);
			playerStatistics = PunishInfo_Plugin.Instance.pluginData.playerStatistics[playerIndex];
		}

		private static bool GetSideHit(PlayerEntity playerEntity, Side side)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			Side val = ((EntityData)((MovableEntity)playerEntity).moveableData).heading;
			if (((MovableData)((AbilityEntity)playerEntity).abilityData).abilityState.StartsWith("CROC_CLIMB"))
			{
				val = (Side)(val ^ 1);
			}
			return val != side;
		}

		internal void HitOtherPlayer(PlayerEntity victim, Side side)
		{
			//IL_0031: 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)
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendFormat("\n[{4}] P{0} Hit P{1} | {2} | {3}", playerIndex, ((AbilityEntity)victim).playerIndex, GetSideHit(victim, side) ? "Behind" : "Front", ((MovableData)victim.playerData).playerState, Math.SecondsToString(World.GetTimeLeftSecs() + 1));
			if (((MovableData)((AbilityEntity)victim).abilityData).abilityState != "")
			{
				stringBuilder.AppendFormat(" | {0}", ((MovableData)((AbilityEntity)victim).abilityData).abilityState);
			}
			if (IsCounter(victim, ((MovableEntity)victim).GetCurrentAbilityState()))
			{
				playerStatistics.punishType = PunishType.COUNTER;
				prevHideTime = Sync.curFrame + 90;
			}
			else
			{
				if (!IsPunish(victim, ((MovableEntity)victim).GetCurrentAbilityState()))
				{
					playerStatistics.punishType = PunishType.NONE;
					return;
				}
				playerStatistics.punishType = PunishType.PUNISH;
				prevHideTime = Sync.curFrame + 90;
			}
			stringBuilder.AppendFormat(" | {0}", playerStatistics.punishType.ToString());
			if (playerStatistics.victimIndex == ((AbilityEntity)victim).playerIndex)
			{
				prevHitCount = playerStatistics.additionalHitCount++;
				stringBuilder.AppendFormat(" | Combo: {0}", playerStatistics.additionalHitCount);
			}
			else
			{
				prevHitCount = (playerStatistics.additionalHitCount = 0);
			}
			SetVictim(victim);
			prevOnHitFrame = Sync.curFrame;
			PunishInfo_Plugin.Logger.LogWarning((object)stringBuilder.ToString());
		}

		internal void UpdateUI()
		{
			if (playerStatistics.punishType != prevPunishType)
			{
				ShowPunishText(playerStatistics.punishType);
				prevPunishType = playerStatistics.punishType;
			}
			if (playerStatistics.additionalHitCount != prevHitCount)
			{
				ShowHitCount(playerStatistics.additionalHitCount);
				prevHitCount = playerStatistics.additionalHitCount;
				if (prevHitCount != 0)
				{
					ShowPunishText(playerStatistics.punishType);
				}
			}
			HideUI();
		}

		private void ShowHitCount(int count)
		{
			if (!((Object)(object)hitCountObj == (Object)null))
			{
				if (count != 0)
				{
					imhitCount.sprite = PluginBundle.sprites[$"HitCount_{count - 1}"];
					hitCountObj.SetActive(true);
				}
				else
				{
					hitCountObj.SetActive(false);
				}
			}
		}

		private void HideUI()
		{
			if (Sync.curFrame > prevHideTime)
			{
				HideUINow();
			}
		}

		private void HideUINow()
		{
			punishObj.SetActive(false);
			counterObj.SetActive(false);
			hitCountObj.SetActive(false);
			prevHideTime = int.MaxValue;
		}

		private void ShowPunishText(PunishType punishType)
		{
			switch (punishType)
			{
			case PunishType.COUNTER:
				counterObj.SetActive(true);
				punishObj.SetActive(false);
				break;
			case PunishType.PUNISH:
			case PunishType.PARRY_PUNISH:
				counterObj.SetActive(false);
				punishObj.SetActive(true);
				break;
			default:
				counterObj.SetActive(false);
				punishObj.SetActive(false);
				prevHideTime = int.MaxValue;
				break;
			}
		}

		internal void SetVictim(PlayerEntity playerEntity)
		{
			playerStatistics.victimIndex = ((AbilityEntity)playerEntity).playerIndex;
		}

		internal void ResetVictim(int playerIndex)
		{
			if (playerStatistics.victimIndex == playerIndex)
			{
				playerStatistics.additionalHitCount = 0;
				playerStatistics.victimIndex = -1;
				playerStatistics.punishType = PunishType.NONE;
			}
		}

		private static bool IsCounter(PlayerEntity player, AbilityState currentAbilityState)
		{
			if (currentAbilityState == null)
			{
				return false;
			}
			int num = currentAbilityState.hitboxes?.Count ?? 0;
			for (int i = 0; i < num; i++)
			{
				string key = currentAbilityState.hitboxes[i];
				if (((Box)((AttackingEntity)player).hitboxes[key]).active)
				{
					return true;
				}
			}
			if (!string.IsNullOrEmpty(currentAbilityState.nextAbilityState))
			{
				return ((AbilityEntity)player).abilityStates[currentAbilityState.nextAbilityState].hitboxes.Count > 0;
			}
			string bufferAbility = ((AbilityEntity)player).abilityData.bufferAbility;
			if (currentAbilityState.name == "POST_CROUCH" && bufferAbility != "jump" && bufferAbility != string.Empty)
			{
				return true;
			}
			return false;
		}

		private static bool IsPunish(PlayerEntity player, AbilityState abilityState)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Invalid comparison between Unknown and I4
			//IL_0061: 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)
			//IL_0074: Invalid comparison between Unknown and I4
			string text = ((AbilityEntity)player).GetCurrentAbility()?.name;
			bool flag = !string.IsNullOrEmpty(text) && (text == "crouch" || text == "knockedOut");
			if ((int)((MovableData)player.playerData).playerState == 2 || flag)
			{
				return false;
			}
			if (!((AbilityData)player.playerData).checkedActionsThisFrame && ((int)((MovableData)player.playerData).playerState == 0 || ((int)((MovableData)player.playerData).playerState == 1 && abilityState.canBeCancelledByAnyAction)))
			{
				return false;
			}
			return true;
		}

		internal void Destroy()
		{
			Object.Destroy((Object)(object)attackInfoObjects);
			Object.Destroy((Object)(object)counterObj);
			Object.Destroy((Object)(object)punishObj);
			Object.Destroy((Object)(object)hitCountObj);
			attackInfos[playerIndex] = null;
		}
	}
	internal class PlayerStatistics
	{
		internal int additionalHitCount;

		internal PunishType punishType;

		internal int victimIndex = -1;

		internal void Load(PlayerStatistics load)
		{
			additionalHitCount = load.additionalHitCount;
			punishType = load.punishType;
			victimIndex = load.victimIndex;
		}
	}
}
namespace PunishInfo.MatchInfo.Patches
{
	[HarmonyPatch]
	internal static class AttackInfo_Patches
	{
		[HarmonyPatch(typeof(GameHudPlayerInfo), "UpdateInfo")]
		[HarmonyPostfix]
		private static void UpdateAttackInfo(GameHudPlayerInfo __instance)
		{
			for (int i = 0; i < 4; i++)
			{
				if (AttackInfo.attackInfos[i] != null)
				{
					AttackInfo.attackInfos[i].UpdateUI();
				}
			}
		}

		[HarmonyPatch(typeof(ScreenGameHud), "DestroyPlayerInfos")]
		[HarmonyPostfix]
		private static void DestroyAttackInfos(ScreenGameHud __instance)
		{
			for (int i = 0; i < 4; i++)
			{
				if (AttackInfo.attackInfos[i] != null)
				{
					AttackInfo.attackInfos[i].Destroy();
					AttackInfo.attackInfos[i] = null;
				}
			}
		}

		[HarmonyPatch(typeof(AbilityEntity), "EndAbilityStateToNormal")]
		[HarmonyPrefix]
		private static void ResetHitCount(AbilityEntity __instance)
		{
			PlayerEntity val = (PlayerEntity)(object)((__instance is PlayerEntity) ? __instance : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			for (int i = 0; i < 4; i++)
			{
				if (AttackInfo.attackInfos[i] != null && (!(((AbilityEntity)val).abilityData.bufferAbility == "bunt") || !(((MovableData)((AbilityEntity)val).abilityData).abilityState == "GET_UP")))
				{
					AttackInfo.attackInfos[i].ResetVictim(((AbilityEntity)val).playerIndex);
				}
			}
		}

		[HarmonyPatch(typeof(AbilityEntity), "Spawn")]
		[HarmonyPostfix]
		private static void ResetVictimOnSpawn(AbilityEntity __instance)
		{
			PlayerEntity val = (PlayerEntity)(object)((__instance is PlayerEntity) ? __instance : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			for (int i = 0; i < 4; i++)
			{
				if (AttackInfo.attackInfos[i] != null)
				{
					AttackInfo.attackInfos[i].ResetVictim(((AbilityEntity)val).playerIndex);
				}
			}
		}

		[HarmonyPatch(typeof(GetHitBallEntity), "HitPlayer")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> GetHitBallEntity_HitPlayer(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Expected O, but got Unknown
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Expected O, but got Unknown
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Expected O, but got Unknown
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Expected O, but got Unknown
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Expected O, but got Unknown
			CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null);
			val.SearchForward((Func<CodeInstruction, bool>)((CodeInstruction iL) => iL.opcode == OpCodes.Callvirt && (iL.operand as MethodBase).Name == "GetHitByBall")).Advance(-1);
			MethodInfo methodInfo = SymbolExtensions.GetMethodInfo((Expression<Action>)(() => Invoke_HitOtherPlayer(null, 0, (Side)0)));
			val.Insert((CodeInstruction[])(object)new CodeInstruction[6]
			{
				new CodeInstruction(OpCodes.Ldarg_1, (object)null),
				new CodeInstruction(OpCodes.Ldarg_0, (object)null),
				new CodeInstruction(OpCodes.Ldfld, (object)typeof(GetHitBallEntity).GetField("ballData")),
				new CodeInstruction(OpCodes.Ldfld, (object)typeof(BallData).GetField("lastHitterIndex")),
				new CodeInstruction(OpCodes.Ldloc_0, (object)null),
				new CodeInstruction(OpCodes.Call, (object)methodInfo)
			});
			return val.InstructionEnumeration();
		}

		private static void Invoke_HitOtherPlayer(PlayerEntity victim, int hitterIndex, Side side)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if (AttackInfo.attackInfos[hitterIndex] != null)
			{
				AttackInfo.attackInfos[hitterIndex].HitOtherPlayer(victim, side);
			}
		}
	}
	[HarmonyPatch]
	internal class SpawnPlayerInfos_Patch
	{
		[HarmonyTargetMethod]
		private static MethodInfo TargetMethod()
		{
			return typeof(ScreenGameHud).GetNestedType("<SpawnPlayerInfos>c__AnonStoreyC", BindingFlags.NonPublic).GetMethod("<>m__0", BindingFlags.Instance | BindingFlags.NonPublic);
		}

		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null);
			val.SearchForward((Func<CodeInstruction, bool>)((CodeInstruction iL) => iL.opcode == OpCodes.Callvirt && (iL.operand as MethodBase).Name == "SetPlayer")).ThrowIfNotMatch("'SetPlayer' was not found", (CodeMatch[])(object)new CodeMatch[0]).Advance(1);
			val.Insert((CodeInstruction[])(object)new CodeInstruction[2]
			{
				new CodeInstruction(OpCodes.Ldloc_2, (object)null),
				Transpilers.EmitDelegate<Action<GameHudPlayerInfo>>((Action<GameHudPlayerInfo>)delegate(GameHudPlayerInfo playerInfo)
				{
					new AttackInfo(playerInfo).Init();
				})
			});
			return val.InstructionEnumeration();
		}
	}
}
namespace PunishInfo.PluginSync
{
	internal class MatchInfoData
	{
		internal PlayerStatistics[] playerStatistics;

		public MatchInfoData()
		{
			playerStatistics = new PlayerStatistics[4];
			for (int i = 0; i < 4; i++)
			{
				playerStatistics[i] = new PlayerStatistics();
			}
		}

		public void Load(MatchInfoData load, bool saving)
		{
			for (int i = 0; i < 4; i++)
			{
				playerStatistics[i].Load(load.playerStatistics[i]);
			}
		}
	}
	internal class PluginState : FrameObject
	{
		internal MatchInfoData PluginData { get; private set; }

		public PluginState(MatchInfoData pluginData, int frame)
		{
			PluginData = pluginData;
			base.frame = frame;
		}
	}
}
namespace PunishInfo.FrameSync
{
	internal class CustomStateHistory
	{
		private List<PluginState> history;

		public CustomStateHistory()
		{
			history = new List<PluginState>(50);
		}

		public void LoadFrame(int frame)
		{
			PluginState item = FrameObject.GetItem<PluginState>(history, frame);
			if (item == null)
			{
				PunishInfo_Plugin.Logger.LogError((object)("Couldn't get savedgame for frame " + frame + " (history: " + GetHistoryString() + ")"));
			}
			else
			{
				PunishInfo_Plugin.Instance.pluginData.Load(item.PluginData, saving: false);
				if (history.Count > FrameObject.lastIndex + 1)
				{
					history.RemoveRange(FrameObject.lastIndex + 1, history.Count - (FrameObject.lastIndex + 1));
				}
			}
		}

		public void SaveFrame(int frame)
		{
			MatchInfoData matchInfoData = MatchDataPool.Get();
			matchInfoData.Load(PunishInfo_Plugin.Instance.pluginData, saving: true);
			FrameObject.AddToList<PluginState>(history, new PluginState(matchInfoData, frame));
		}

		public void DeleteFramesBefore(int frame)
		{
			while (history.Count > 0 && ((FrameObject)history[0]).frame < frame)
			{
				MatchDataPool.Return(history[0].PluginData);
				history.RemoveAt(0);
			}
		}

		public void DeleteFramesAfter(int frame)
		{
			while (history.Count > 0 && ((FrameObject)history[history.Count - 1]).frame > frame)
			{
				MatchDataPool.Return(history[history.Count - 1].PluginData);
				history.RemoveAt(history.Count - 1);
			}
		}

		public string GetHistoryString()
		{
			List<string> list = new List<string>(50);
			foreach (PluginState item in history)
			{
				list.Add(((FrameObject)item).frame.ToString());
			}
			return string.Join(",", list.ToArray());
		}

		public override string ToString()
		{
			if (history.Count == 0)
			{
				return "[empty]";
			}
			int frame = ((FrameObject)history[0]).frame;
			int frame2 = ((FrameObject)history[history.Count - 1]).frame;
			string text = "[" + frame + " - " + frame2;
			if (history.Count - 1 != frame2 - frame)
			{
				string text2 = text;
				text = text2 + " (length " + history.Count + "??)";
			}
			return text + "]";
		}
	}
	internal class MatchDataPool
	{
		private static Stack<MatchInfoData> unused;

		private static bool inited;

		private static void Init()
		{
			unused = new Stack<MatchInfoData>();
			AddSome();
			inited = true;
		}

		private static void AddSome()
		{
			for (int i = 0; i < 10; i++)
			{
				unused.Push(new MatchInfoData());
			}
		}

		public static MatchInfoData Get()
		{
			if (!inited)
			{
				Init();
			}
			if (unused.Count == 0)
			{
				AddSome();
			}
			return unused.Pop();
		}

		public static void Return(MatchInfoData pluginData)
		{
			unused.Push(pluginData);
		}
	}
}
namespace PunishInfo.FrameSync.Patches
{
	[HarmonyPatch(typeof(StateHistory))]
	internal class StateHistory_Patch
	{
		[HarmonyPatch("LoadFrame")]
		[HarmonyPostfix]
		private static void LoadFrame(StateHistory __instance, int frame)
		{
			PunishInfo_Plugin.Instance.stateHistory.LoadFrame(frame);
		}

		[HarmonyPatch("SaveFrame")]
		[HarmonyPostfix]
		private static void SaveFrame(StateHistory __instance, int frame)
		{
			PunishInfo_Plugin.Instance.stateHistory.SaveFrame(frame);
		}

		[HarmonyPatch("DeleteFramesBefore")]
		[HarmonyPostfix]
		private static void DeleteFramesBefore(StateHistory __instance, int frame)
		{
			PunishInfo_Plugin.Instance.stateHistory.DeleteFramesBefore(frame);
		}

		[HarmonyPatch("DeleteFramesAfter")]
		[HarmonyPostfix]
		private static void DeleteFramesAfter(StateHistory __instance, int frame)
		{
			PunishInfo_Plugin.Instance.stateHistory.DeleteFramesAfter(frame);
		}
	}
	[HarmonyPatch]
	internal class Sync_Patches
	{
		[HarmonyPatch(typeof(Sync), "Init")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> CreateNewStateHistory(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null);
			val.SearchForward((Func<CodeInstruction, bool>)((CodeInstruction iL) => iL.opcode == OpCodes.Stsfld && (iL.operand as FieldInfo).Name == "stateHistory")).Advance(1);
			val.Insert((CodeInstruction[])(object)new CodeInstruction[1] { Transpilers.EmitDelegate<Action>((Action)delegate
			{
				PunishInfo_Plugin.Instance.stateHistory = new CustomStateHistory();
			}) });
			return val.InstructionEnumeration();
		}
	}
	[HarmonyPatch(typeof(World))]
	internal class World_Patches
	{
		[HarmonyPatch("Init1")]
		[HarmonyPostfix]
		private static void Init1_Patch(World __instance)
		{
			PunishInfo_Plugin.Instance.pluginData = new MatchInfoData();
		}

		[HarmonyPatch("SaveState")]
		[HarmonyPostfix]
		private static void SaveState(World __instance)
		{
			PunishInfo_Plugin instance = PunishInfo_Plugin.Instance;
			if (instance.pluginDataSave == null)
			{
				instance.pluginDataSave = new MatchInfoData();
			}
			instance.pluginDataSave.Load(instance.pluginData, saving: true);
		}

		[HarmonyPatch("LoadState")]
		[HarmonyPostfix]
		private static void LoadState(World __instance)
		{
			PunishInfo_Plugin instance = PunishInfo_Plugin.Instance;
			if (instance.pluginDataSave != null)
			{
				instance.pluginData.Load(instance.pluginDataSave, saving: false);
			}
		}
	}
}