Decompiled source of TeammateRevival v4.2.1

plugins/KosmosisDire-TeammateRevival/TeammateRevive.dll

Decompiled a week ago
#define DEBUG
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
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.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using InLobbyConfig;
using InLobbyConfig.Fields;
using Microsoft.CodeAnalysis;
using Mono.Cecil.Cil;
using MonoMod.Cil;
using MonoMod.Utils;
using On.RoR2;
using On.RoR2.UI;
using On.RoR2.UI.LogBook;
using R2API;
using R2API.Networking;
using R2API.Networking.Interfaces;
using RiskOfOptions;
using RiskOfOptions.OptionConfigs;
using RiskOfOptions.Options;
using RoR2;
using RoR2.ExpansionManagement;
using RoR2.UI;
using RoR2.UI.LogBook;
using SimpleJSON;
using TMPro;
using TeammateRevive.Artifact;
using TeammateRevive.Common;
using TeammateRevive.Configuration;
using TeammateRevive.Content;
using TeammateRevive.DeathTotem;
using TeammateRevive.Debugging;
using TeammateRevive.Integrations;
using TeammateRevive.Localization;
using TeammateRevive.Logging;
using TeammateRevive.Players;
using TeammateRevive.ProgressBar;
using TeammateRevive.Resources;
using TeammateRevive.Revive;
using TeammateRevive.Revive.Rules;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Networking;
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.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("TeammateRevive")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+efed43a66155c54449bd8feeac64240a9df01807")]
[assembly: AssemblyProduct("TeammateRevive")]
[assembly: AssemblyTitle("TeammateRevive")]
[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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace TeammateRevive
{
	public class ContentManager
	{
		private readonly ReviveRules rules;

		private readonly RunTracker run;

		private readonly DeathCurseArtifact deathCurseArtifact;

		private List<ContentBase> addedContent = new List<ContentBase>();

		public static bool ContentInited;

		public ContentManager(ReviveRules rules, RunTracker run, DeathCurseArtifact deathCurseArtifact)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			this.rules = rules;
			this.run = run;
			this.deathCurseArtifact = deathCurseArtifact;
			Language.SetStringByToken += new hook_SetStringByToken(LanguageOnSetStringByToken);
			ItemCatalog.Init += new hook_Init(ItemsOnInit);
			BuffCatalog.Init += new hook_Init(BuffsOnInit);
		}

		private void LanguageOnSetStringByToken(orig_SetStringByToken orig, Language self, string token, string localizedstring)
		{
			if (Object.op_Implicit((Object)(object)Items.ShieldOnly) && token == Items.ShieldOnly.descriptionToken)
			{
				localizedstring += Language.GetString(LanguageConsts.TEAMMATE_REVIVAL_SHIELD_ONLY_POSTFIX);
			}
			orig.Invoke(self, token, localizedstring);
			if (Object.op_Implicit((Object)(object)Items.ShieldOnly) && token == Items.ShieldOnly.descriptionToken)
			{
				Log.Info("Transcendence description (" + token + ") patched!");
			}
		}

		private void BuffsOnInit(orig_Init orig)
		{
			orig.Invoke();
			if (!ContentInited)
			{
				Log.Error("BuffsOnInit called before content was inited!");
			}
			foreach (ContentBase item in addedContent)
			{
				try
				{
					item.OnBuffsAvailable();
				}
				catch (Exception arg)
				{
					Log.Error($"Error on OnBuffsAvailable for {item}: {arg}");
				}
			}
		}

		private void ItemsOnInit(orig_Init orig)
		{
			orig.Invoke();
			if (!ContentInited)
			{
				Log.Error("ItemsOnInit called before content was inited!");
			}
			foreach (ContentBase item in addedContent)
			{
				try
				{
					item.OnItemsAvailable();
				}
				catch (Exception arg)
				{
					Log.Error($"Error on OnBuffsAvailable for {item}: {arg}");
				}
			}
		}

		public void Init()
		{
			LoadAddedContent();
			deathCurseArtifact.Init();
		}

		public void LoadAddedContent()
		{
			addedContent = new List<ContentBase>
			{
				new DeathCurse(rules, run),
				new CharonsObol(),
				new DeadMansHandItem(),
				new ReviveLink(),
				new ReviveRegen(rules),
				new RevivalToken()
			};
			foreach (ContentBase item in addedContent)
			{
				item.Init();
				item.GetType().GetField("instance")?.SetValue(null, item);
			}
			ContentInited = true;
		}
	}
	public static class HideDeathCurseContent
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static hook_BuildPickupEntries <0>__OnBuildPickupEntries;

			public static hook_UpdateChoiceDisplay <1>__OnRuleChoiceUpdate;
		}

		private static readonly string[] ItemsToHide = new string[2]
		{
			CharonsObol.NameToken,
			DeadMansHandItem.NameToken
		};

		public static void Init(PluginConfig config)
		{
			//IL_0037: 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_0042: Expected O, but got Unknown
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			Log.Info($"Init: {config.HideDeathCurseItemsInLogBook}");
			if (config.HideDeathCurseItemsInLogBook)
			{
				object obj = <>O.<0>__OnBuildPickupEntries;
				if (obj == null)
				{
					hook_BuildPickupEntries val = OnBuildPickupEntries;
					<>O.<0>__OnBuildPickupEntries = val;
					obj = (object)val;
				}
				LogBookController.BuildPickupEntries += (hook_BuildPickupEntries)obj;
			}
			if (config.HideDeathCurseArtifact)
			{
				object obj2 = <>O.<1>__OnRuleChoiceUpdate;
				if (obj2 == null)
				{
					hook_UpdateChoiceDisplay val2 = OnRuleChoiceUpdate;
					<>O.<1>__OnRuleChoiceUpdate = val2;
					obj2 = (object)val2;
				}
				RuleChoiceController.UpdateChoiceDisplay += (hook_UpdateChoiceDisplay)obj2;
			}
		}

		private static void OnRuleChoiceUpdate(orig_UpdateChoiceDisplay orig, RuleChoiceController self, RuleChoiceDef def)
		{
			orig.Invoke(self, def);
			if (def.globalName.StartsWith("Artifacts.ARTIFACT_DEATH_CURSE.Off"))
			{
				((Component)self).gameObject.SetActive(false);
			}
		}

		private static Entry[] OnBuildPickupEntries(orig_BuildPickupEntries orig, Dictionary<ExpansionDef, bool> expansionAvailability)
		{
			Entry[] array = orig.Invoke(expansionAvailability);
			Entry[] array2 = array.Where((Entry r) => !ItemsToHide.Contains(r.nameToken)).ToArray();
			Log.Info($"Hiding Death Curse items ({array2.Length}/{array.Length})");
			return array2;
		}
	}
	public class ItemDropManager
	{
		private readonly RunTracker run;

		private readonly ReviveRules rules;

		public ItemDropManager(RunTracker run, ReviveRules rules)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			this.run = run;
			this.rules = rules;
			Run.BuildDropTable += new hook_BuildDropTable(OnBuildDropTable);
			AllItemsEnumerator.MoveNext += new hook_MoveNext(OnNextItemIterator);
		}

		private bool OnNextItemIterator(orig_MoveNext orig, ref AllItemsEnumerator self)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			while (run.IsDeathCurseEnabled && (self.position == (ItemIndex)(CharonsObol.Index - 1) || self.position == (ItemIndex)(DeadMansHandItem.Index - 1)))
			{
				ref ItemIndex position = ref self.position;
				position = (ItemIndex)((int)position + 1);
			}
			return orig.Invoke(ref self);
		}

		private void OnBuildDropTable(orig_BuildDropTable orig, Run self)
		{
			//IL_0058: 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_0086: Unknown result type (might be due to invalid IL or missing references)
			orig.Invoke(self);
			if (!ContentManager.ContentInited)
			{
				Log.Error("Content wasn't inited on OnBuildDropTable!");
			}
			else if (!run.IsDeathCurseEnabled && (!NetworkHelper.IsServer || !rules.Values.ForceDeathCurseRule))
			{
				RemoveItem(CharonsObol.Index, self.availableTier2DropList, CharonsObol.Name);
				RemoveItem(DeadMansHandItem.Index, self.availableLunarItemDropList, DeadMansHandItem.Name);
				RemoveItem(DeadMansHandItem.Index, self.availableLunarCombinedDropList, DeadMansHandItem.Name);
			}
		}

		private void RemoveItem(ItemIndex itemIndex, List<PickupIndex> dropList, string name)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			int num = dropList.FindIndex((PickupIndex pi) => ((PickupIndex)(ref pi)).pickupDef.itemIndex == itemIndex);
			if (num >= 0)
			{
				Log.Info("Removing '" + name + "' from drop list");
				dropList.RemoveAt(num);
			}
			else
			{
				Log.Info("Item '" + name + "' isn't found in drop list!");
			}
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("KosmosisDire.TeammateRevival", "TeammateRevival", "4.2.1")]
	public class MainTeammateRevival : BaseUnityPlugin
	{
		public const string PluginGUID = "KosmosisDire.TeammateRevival";

		public const string PluginAuthor = "KosmosisDire";

		public const string PluginName = "TeammateRevival";

		public const string PluginVersion = "4.2.1";

		public static MainTeammateRevival instance;

		private DeathCurseArtifact deathCurseArtifact;

		public PluginConfig pluginConfig;

		private PlayersTracker players;

		private RunTracker run;

		private RevivalTracker revivalTracker;

		private InLobbyConfigIntegration inLobbyConfigIntegration;

		private RiskOfOptionsIntegration riskOfOptionsIntegration;

		private ConsoleCommands consoleCommands;

		private ReviveRules rules;

		private ReviveLinkBuffIconManager linkBuffIconManager;

		private ReviveLongRangeActivationManager reviveLongRangeActivationManager;

		private DeathTotemTracker deathTotemTracker;

		private ProgressBarController progressBarController;

		private ReviveProgressBarTracker progressBarTracker;

		private ItemDropManager itemDropManager;

		private ContentManager contentManager;

		public Func<IEnumerator, Coroutine> DoCoroutine => ((MonoBehaviour)this).StartCoroutine;

		public void Awake()
		{
			instance = this;
			pluginConfig = PluginConfig.Load(((BaseUnityPlugin)this).Config);
			LanguageManager.RegisterLanguages();
			NetworkingAPI.RegisterMessageType<SyncDeathTotemMessage>();
			NetworkingAPI.RegisterMessageType<SetRulesMessage>();
			deathCurseArtifact = new DeathCurseArtifact();
			run = new RunTracker(deathCurseArtifact);
			players = new PlayersTracker(run, pluginConfig);
			rules = new ReviveRules(run, pluginConfig);
			deathTotemTracker = new DeathTotemTracker(players, run, rules);
			progressBarController = new ProgressBarController();
			progressBarTracker = new ReviveProgressBarTracker(progressBarController, players, deathTotemTracker, rules);
			revivalTracker = new RevivalTracker(players, run, rules, deathTotemTracker, progressBarTracker);
			consoleCommands = new ConsoleCommands(rules, pluginConfig);
			linkBuffIconManager = new ReviveLinkBuffIconManager();
			inLobbyConfigIntegration = new InLobbyConfigIntegration(pluginConfig);
			riskOfOptionsIntegration = new RiskOfOptionsIntegration(pluginConfig);
			reviveLongRangeActivationManager = new ReviveLongRangeActivationManager(run, deathTotemTracker);
			itemDropManager = new ItemDropManager(run, rules);
			contentManager = new ContentManager(rules, run, deathCurseArtifact);
			Log.Init(pluginConfig, ((BaseUnityPlugin)this).Logger);
			ReviveHelper.Init();
			CustomResources.LoadCustomResources();
			HideDeathCurseContent.Init(pluginConfig);
			contentManager.Init();
			rules.ApplyConfigValues();
			DebugHelper.Init(pluginConfig);
			run.RunStarted += OnRunStarted;
			run.RunEnded += OnRunEnded;
			SetupHooks();
			Log.Debug("Setup Teammate Revival");
		}

		private void SetupHooks()
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			Run.BeginGameOver += new hook_BeginGameOver(Hook_BeginGameOver);
			Run.AdvanceStage += new hook_AdvanceStage(Hook_AdvanceStage);
			NetworkUser.OnStartLocalPlayer += new hook_OnStartLocalPlayer(Hook_OnStartLocalPlayer);
		}

		private void Hook_OnStartLocalPlayer(orig_OnStartLocalPlayer orig, NetworkUser self)
		{
			orig.Invoke(self);
			if (NetworkHelper.IsClient())
			{
				ClientScene.RegisterPrefab(((Component)CustomResources.DeathTotem).gameObject);
				Object.FindObjectOfType<NetworkManager>().spawnPrefabs.Add(((Component)CustomResources.DeathTotem).gameObject);
				Log.Info("Client registered prefabs");
			}
			else
			{
				NetworkManager.singleton.connectionConfig.DisconnectTimeout = 5u;
				NetworkManager.singleton.connectionConfig.MaxSentMessageQueueSize = 1024;
			}
		}

		private void Hook_BeginGameOver(orig_BeginGameOver orig, Run self, GameEndingDef gameEndingDef)
		{
			orig.Invoke(self, gameEndingDef);
			if (!NetworkHelper.IsClient())
			{
				Log.Info("Game Over - reseting data");
				players.Reset();
				run.IsStarted = false;
			}
		}

		private void Hook_AdvanceStage(orig_AdvanceStage orig, Run self, SceneDef nextScene)
		{
			orig.Invoke(self, nextScene);
			if (!NetworkHelper.IsClient())
			{
				Log.Info("Advanced a stage - now resetting");
				players.Reset();
			}
		}

		public void Update()
		{
			DebugHelper.Update();
			players.Update();
			revivalTracker.Update();
		}

		private void OnRunStarted(RunTracker obj)
		{
			deathCurseArtifact.EnsureEnabled(rules);
		}

		private void OnRunEnded(RunTracker obj)
		{
			players.Reset();
		}
	}
	public class RunTracker
	{
		private readonly DeathCurseArtifact deathCurseArtifact;

		public static RunTracker instance;

		private bool isStarted;

		public bool IsStarted
		{
			get
			{
				return isStarted;
			}
			set
			{
				if (IsStarted != value)
				{
					isStarted = value;
					if (value)
					{
						Log.Info("Run started");
						this.RunStarted?.Invoke(this);
					}
					else
					{
						Log.Info("Run ended");
						this.RunEnded?.Invoke(this);
					}
				}
			}
		}

		public bool IsDeathCurseEnabled
		{
			get
			{
				ReviveRules reviveRules = ReviveRules.instance;
				int result;
				if (reviveRules == null || !reviveRules.Values.ForceEnableDeathCurseForSinglePlayer)
				{
					if (!deathCurseArtifact.ArtifactEnabled)
					{
						ReviveRules reviveRules2 = ReviveRules.instance;
						if (reviveRules2 == null || !reviveRules2.Values.ForceDeathCurseRule)
						{
							result = 0;
							goto IL_005a;
						}
					}
					Run obj = Run.instance;
					result = ((obj == null || obj.participatingPlayerCount != 1) ? 1 : 0);
				}
				else
				{
					result = 1;
				}
				goto IL_005a;
				IL_005a:
				return (byte)result != 0;
			}
		}

		public event Action<RunTracker> RunStarted;

		public event Action<RunTracker> RunEnded;

		public RunTracker(DeathCurseArtifact deathCurseArtifact)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			this.deathCurseArtifact = deathCurseArtifact;
			Run.onRunStartGlobal += GlobalOnRunStarted;
			Run.onRunDestroyGlobal += GlobalOnRunDestroy;
			Run.BeginStage += new hook_BeginStage(Hook_BeginStage);
			instance = this;
		}

		private void Hook_BeginStage(orig_BeginStage orig, Run self)
		{
			orig.Invoke(self);
			IsStarted = true;
		}

		private void GlobalOnRunStarted(Run obj)
		{
			IsStarted = true;
		}

		private void GlobalOnRunDestroy(Run obj)
		{
			IsStarted = false;
		}
	}
}
namespace TeammateRevive.Revive
{
	public class RevivalTracker
	{
		public static RevivalTracker instance;

		public static readonly string[] IgnoredStages = new string[1] { "bazaar" };

		private readonly PlayersTracker players;

		private readonly RunTracker run;

		private readonly ReviveRules rules;

		private readonly DeathTotemTracker deathTotemTracker;

		private readonly ReviveProgressBarTracker reviveProgressBarTracker;

		public RevivalTracker(PlayersTracker players, RunTracker run, ReviveRules rules, DeathTotemTracker deathTotemTracker, ReviveProgressBarTracker reviveProgressBarTracker)
		{
			instance = this;
			this.players = players;
			this.run = run;
			this.rules = rules;
			this.deathTotemTracker = deathTotemTracker;
			this.reviveProgressBarTracker = reviveProgressBarTracker;
			this.players.OnPlayerDead += OnPlayerDead;
			this.players.OnPlayerAlive += OnPlayerAlive;
			Stage.onStageStartGlobal += OnStageStart;
		}

		private void OnPlayerDead(Player player)
		{
			player.ClearReviveLinks();
		}

		private void OnPlayerAlive(Player player)
		{
			foreach (Player item in players.All)
			{
				item.RemoveReviveLink(player);
			}
		}

		private void OnStageStart(Stage self)
		{
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			string cachedName = self.sceneDef.cachedName;
			Log.Debug("Stage start: " + self.sceneDef.cachedName);
			deathTotemTracker.Clear();
			foreach (Player item in players.All)
			{
				item.ClearReviveLinks();
			}
			if (NetworkHelper.IsClient() || IgnoredStages.Contains(cachedName) || !run.IsDeathCurseEnabled)
			{
				return;
			}
			foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList)
			{
				RemoveReduceHpItem(readOnlyInstances);
				Inventory inventory = readOnlyInstances.master.inventory;
				if (inventory != null)
				{
					inventory.RemoveItem(RevivalToken.Index, 1);
				}
			}
		}

		public void Update()
		{
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			if (!run.IsStarted)
			{
				return;
			}
			if (NetworkHelper.IsClient())
			{
				reviveProgressBarTracker.Update();
			}
			else
			{
				if (!players.Setup)
				{
					return;
				}
				UpdatePlayersGroundPosition();
				for (int i = 0; i < players.Dead.Count; i++)
				{
					Player player = players.Dead[i];
					DeathTotemBehavior deathTotem = player.deathTotem;
					if ((Object)(object)deathTotem == (Object)null)
					{
						Log.Warn($"Death Totem is missing {i}");
						continue;
					}
					if (player.CheckAlive() && !rules.Values.DebugKeepTotem)
					{
						Log.Info("Removing totem revived by other means");
						players.PlayerAlive(player);
						continue;
					}
					float num = 0f;
					int num2 = 0;
					int insidePlayersHash = deathTotem.GetInsidePlayersHash();
					float num3 = rules.CalculateDeathTotemRadius(player);
					for (int j = 0; j < players.Alive.Count; j++)
					{
						Player player2 = players.Alive[j];
						if (player2.CheckDead())
						{
							continue;
						}
						CharacterBody body = player2.GetBody();
						bool flag = body.inventory.GetItemCount(DeadMansHandItem.Index) > 0 || (double)Vector3.Distance(body.transform.position, ((Component)deathTotem).transform.position) < (double)num3 * 0.5;
						bool flag2 = !rules.Values.RequireHitboxesActive || !body.disablingHurtBoxes;
						if (flag && flag2)
						{
							num2++;
							if (!deathTotem.insidePlayerIDs.Contains(((NetworkBehaviour)body).netId))
							{
								deathTotem.insidePlayerIDs.Add(((NetworkBehaviour)body).netId);
							}
							float reviveSpeed = rules.GetReviveSpeed(player2, deathTotem.insidePlayerIDs.Count);
							num += reviveSpeed;
							player.reviveProgress += reviveSpeed * Time.deltaTime;
							player.reviveProgress = Mathf.Clamp01(player.reviveProgress);
							player2.IncreaseReviveLinkDuration(player, Time.deltaTime + Time.deltaTime / rules.Values.ReduceReviveProgressFactor * rules.Values.ReviveLinkBuffTimeFactor);
							DamageReviver(body, player);
						}
						else if (deathTotem.insidePlayerIDs.Contains(((NetworkBehaviour)body).netId))
						{
							deathTotem.insidePlayerIDs.Remove(((NetworkBehaviour)body).netId);
						}
					}
					if (player.reviveProgress >= 1f)
					{
						Revive(player);
					}
					else
					{
						deathTotemTracker.UpdateTotem(player, insidePlayersHash, num2, num);
					}
				}
				if (run.IsDeathCurseEnabled)
				{
					UpdateReviveLinkBuffs();
				}
				reviveProgressBarTracker.Update();
			}
		}

		private void Revive(Player dead)
		{
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			Player[] array = players.Alive.Where((Player p) => p.IsLinkedTo(dead)).ToArray();
			ScheduleCutReviveeHp(dead);
			players.Respawn(dead);
			if (run.IsDeathCurseEnabled)
			{
				ApplyDeathCurses(dead, array);
			}
			foreach (Player item in players.All)
			{
				item.RemoveReviveLink(dead);
			}
			if (rules.Values.PostReviveRegenDurationSec != 0f)
			{
				Player[] array2 = array;
				foreach (Player player in array2)
				{
					player.GetBody().AddTimedBuff(ReviveRegen.Index, rules.Values.PostReviveRegenDurationSec);
				}
			}
		}

		private void ApplyDeathCurses(Player dead, Player[] linkedPlayers)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			float chance2 = Mathf.Clamp(100f - rules.Values.DeathCurseChance, 0f, 100f);
			float chance3 = Mathf.Clamp(100f - rules.Values.ReviverDeathCurseChance, 0f, 100f);
			RollCurse(dead, chance2, dead.ItemCount(RevivalToken.Index));
			Player[] array = SortByLinkDuration(linkedPlayers, dead).ToArray();
			for (int i = 0; i < array.Length; i++)
			{
				Player player2 = array[i];
				if (RollCurse(player2, chance3, i))
				{
					break;
				}
			}
			if (rules.Values.EnableRevivalToken)
			{
				dead.GiveItem(RevivalToken.Index);
			}
			static bool RollCurse(Player player, float chance, float extraLuck)
			{
				//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fe: Expected O, but got Unknown
				//IL_00a2: 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_00b4: Expected O, but got Unknown
				float num = extraLuck + player.master.master.luck;
				bool flag = Util.CheckRoll(chance, num, (player.master.master.luck > 0f) ? player.master.master : null);
				Log.Info($"Rolled curse for {player.networkUser.userName}: {chance:F1}% (luck: {player.master.master.luck:F0}+{extraLuck:F0}). Success: {flag}");
				SimpleChatMessage val;
				if (!flag)
				{
					player.GiveItem(DeathCurse.ItemIndex);
					val = new SimpleChatMessage();
					val.baseToken = LanguageConsts.TEAMMATE_REVIVAL_UI_CURSED;
					val.paramTokens = new string[2]
					{
						player.networkUser.userName,
						$"{num:F0}"
					};
					Chat.SendBroadcastChat((ChatMessageBase)(object)val);
					return true;
				}
				val = new SimpleChatMessage();
				val.baseToken = LanguageConsts.TEAMMATE_REVIVAL_UI_AVOIDED_CURSE;
				val.paramTokens = new string[2]
				{
					player.networkUser.userName,
					$"{num:F0}"
				};
				Chat.SendBroadcastChat((ChatMessageBase)(object)val);
				return false;
			}
		}

		private IEnumerable<Player> SortByLinkDuration(Player[] linkedPlayers, Player dead)
		{
			float totalTime = linkedPlayers.Sum((Player p) => p.GetReviveLinkDuration(dead));
			float p2 = 0f;
			return from player in linkedPlayers
				select new
				{
					player = player,
					fraction = (p2 += player.GetReviveLinkDuration(dead) / totalTime)
				} into t
				orderby t.fraction
				select t.player;
		}

		private void DamageReviver(CharacterBody playerBody, Player dead)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if (playerBody.inventory.GetItemCount(Items.ShieldOnly) > 0)
			{
				playerBody.healthComponent.Networkshield = CalcDamageResult(playerBody.maxShield, playerBody.healthComponent.shield, 0.1f, dead, playerBody.inventory.GetItemCount(DeadMansHandItem.Index));
			}
			else
			{
				playerBody.healthComponent.Networkhealth = CalcDamageResult(playerBody.maxHealth, playerBody.healthComponent.health, 0.05f, dead, playerBody.inventory.GetItemCount(DeadMansHandItem.Index));
			}
			if (playerBody.outOfDangerStopwatch > 3f)
			{
				playerBody.outOfDangerStopwatch = 3f;
			}
		}

		private float CalcDamageResult(float max, float current, float dmgThreshold, Player dead, int reviverReviveEverywhereCount)
		{
			float damageSpeed = rules.GetDamageSpeed(max, dead, reviverReviveEverywhereCount);
			float num = damageSpeed * Time.deltaTime;
			float num2 = max * dmgThreshold;
			if (current < num2)
			{
				return current;
			}
			return Mathf.Clamp(current - num, num2, max);
		}

		private void UpdatePlayersGroundPosition()
		{
			foreach (Player item in players.Alive)
			{
				if (!((Object)(object)item.GetBody() == (Object)null))
				{
					item.UpdateGroundPosition();
				}
			}
		}

		private void RemoveReduceHpItem(NetworkUser networkUser)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkHelper.IsClient())
			{
				Log.DebugMethod(null, "RemoveReduceHpItem", 336);
				string userName = networkUser.userName;
				CharacterMaster master = networkUser.master;
				Inventory val = ((master != null) ? master.inventory : null);
				if ((Object)(object)val == (Object)null)
				{
					Log.Warn("Player has no inventory! " + userName);
					return;
				}
				int itemCount = val.GetItemCount(DeathCurse.ItemIndex);
				val.RemoveItem(DeathCurse.ItemIndex, val.GetItemCount(CharonsObol.Index) + 1);
				Log.Info($"Removed reduce HP item for ({userName}). Was {itemCount}. Now: {val.GetItemCount(DeathCurse.ItemIndex)}");
			}
		}

		private void UpdateReviveLinkBuffs()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			foreach (Player item in players.Alive)
			{
				CharacterBody body = item.GetBody();
				if (!((Object)(object)body == (Object)null))
				{
					body.SetBuffCount(ReviveLink.Index, item.GetPlayersReviveLinks());
				}
			}
		}

		private void ScheduleCutReviveeHp(Player player)
		{
			CharacterBody.onBodyStartGlobal += Callback;
			void Callback(CharacterBody body)
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: 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)
				NetworkInstanceId? bodyId = player.BodyId;
				NetworkInstanceId netId = ((NetworkBehaviour)body).netId;
				if (bodyId.HasValue && !(bodyId.GetValueOrDefault() != netId))
				{
					CutReviveeHp(body);
					CharacterBody.onBodyStartGlobal -= Callback;
				}
			}
		}

		private void CutReviveeHp(CharacterBody body)
		{
			float networkhealth = body.healthComponent.Networkhealth;
			float num = (body.maxHealth + body.maxShield) * 0.4f;
			body.healthComponent.Networkhealth = Mathf.Clamp(num, 1f, body.maxHealth);
			body.healthComponent.Networkshield = Mathf.Clamp(body.maxHealth - num, 0f, body.maxShield);
			Log.DebugMethod($"Prev hp: {networkhealth}; Now: {body.healthComponent.health}", "CutReviveeHp", 380);
		}
	}
	public class ReviveInteraction : MonoBehaviour, IInteractable, IDisplayNameProvider
	{
		public string GetContextString(Interactor activator)
		{
			return Language.GetString(LanguageConsts.TEAMMATE_REVIVAL_UI_USE_OBOL);
		}

		public Interactability GetInteractability(Interactor activator)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			NetworkUser val = Util.LookUpBodyNetworkUser(((Component)activator).gameObject);
			if (Object.op_Implicit((Object)(object)val) && val.master.inventory.GetItemCount(CharonsObol.Index) > 0)
			{
				return (Interactability)2;
			}
			return (Interactability)1;
		}

		public void OnInteractionBegin(Interactor interactor)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			Log.DebugMethod("Interaction! " + ((Object)interactor).name, "OnInteractionBegin", 31);
			NetworkInstanceId netId = ((Component)this).gameObject.GetComponent<NetworkBehaviour>().netId;
			NetworkInstanceId val = netId;
			Log.DebugMethod("Totem Id " + ((object)(NetworkInstanceId)(ref val)).ToString(), "OnInteractionBegin", 33);
			HandleInteraction(((NetworkBehaviour)interactor).netId, netId);
		}

		public static void HandleInteraction(NetworkInstanceId playerNetId, NetworkInstanceId totemId)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			Log.DebugMethod("Server respawn!", "HandleInteraction", 39);
			Player player = PlayersTracker.instance.FindByBodyId(playerNetId);
			Log.DebugMethod("Player " + player, "HandleInteraction", 41);
			DeathTotemBehavior totemComponent = Util.FindNetworkObject(totemId).GetComponent<DeathTotemBehavior>();
			NetworkInstanceId val = totemId;
			Log.DebugMethod("Totem component " + ((object)(NetworkInstanceId)(ref val)).ToString(), "HandleInteraction", 44);
			Player player2 = PlayersTracker.instance.All.FirstOrDefault((Player dp) => (Object)(object)dp.deathTotem == (Object)(object)totemComponent);
			Log.DebugMethod("Dead " + player2, "HandleInteraction", 46);
			if (player2 == null || player == null)
			{
				Log.Error($"Cannot find player(s): {player} -> {player2}");
			}
			else if (player.GetBody().inventory.GetItemCount(CharonsObol.Index) > 0)
			{
				PlayersTracker.instance.Respawn(player2);
				player.master.master.inventory.RemoveItem(CharonsObol.Index, 1);
			}
		}

		public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator)
		{
			return false;
		}

		public bool ShouldShowOnScanner()
		{
			return false;
		}

		public string GetDisplayName()
		{
			return Language.GetString(LanguageConsts.TEAMMATE_REVIVAL_UI_USE_OBOL);
		}

		public void OnEnable()
		{
			InstanceTracker.Add<ReviveInteraction>(this);
		}

		public void OnDisable()
		{
			InstanceTracker.Remove<ReviveInteraction>(this);
		}

		public bool ShouldProximityHighlight()
		{
			return false;
		}
	}
	public class ReviveLinkBuffIconManager
	{
		private const float MIN_OPACITY = 0f;

		private const float OPACITY_CHANGE_TIME = 1f;

		private bool decreasing = false;

		private float elapsedTime = 0f;

		public ReviveLinkBuffIconManager()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			BuffIcon.UpdateIcon += new hook_UpdateIcon(Hook_Update);
		}

		private void Hook_Update(orig_UpdateIcon orig, BuffIcon buffIcon)
		{
			//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_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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: 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_0090: 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_009c: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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)
			//IL_0073: 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_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			orig.Invoke(buffIcon);
			if (!Object.op_Implicit((Object)(object)buffIcon.buffDef))
			{
				return;
			}
			Image iconImage = buffIcon.iconImage;
			Color color = ((Graphic)iconImage).color;
			if (buffIcon.buffDef.buffIndex != ReviveLink.Index)
			{
				if (color.a != 1f)
				{
					Color color2 = color;
					color2.a = 1f;
					((Graphic)iconImage).color = color2;
				}
				return;
			}
			Color val = default(Color);
			Color val2 = default(Color);
			if (decreasing)
			{
				((Color)(ref val))..ctor(color.r, color.g, color.b, 1f);
				((Color)(ref val2))..ctor(color.r, color.g, color.b, 0f);
			}
			else
			{
				((Color)(ref val))..ctor(color.r, color.g, color.b, 0f);
				((Color)(ref val2))..ctor(color.r, color.g, color.b, 1f);
			}
			((Graphic)iconImage).color = Color.Lerp(val, val2, EaseInCubic(elapsedTime / 1f));
			elapsedTime += Time.deltaTime;
			while (elapsedTime > 1f)
			{
				elapsedTime -= 1f;
				decreasing = !decreasing;
			}
		}

		private static float EaseInCubic(float val)
		{
			if (val > 1f)
			{
				return 1f;
			}
			return val * val * val;
		}
	}
}
namespace TeammateRevive.Revive.Rules
{
	public class ReviveRules
	{
		public static ReviveRules instance;

		private readonly RunTracker run;

		private readonly PluginConfig pluginConfig;

		public ReviveRuleValues Values { get; private set; }

		public float ReduceReviveProgressSpeed { get; private set; }

		public float ReviveLinkBuffTime { get; private set; }

		public event Action<ReviveRuleValues, ReviveRuleValues> ValuesChanged;

		public ReviveRules(RunTracker run, PluginConfig pluginConfig)
		{
			instance = this;
			this.run = run;
			this.pluginConfig = pluginConfig;
			run.RunStarted += OnRunStarted;
			pluginConfig.RuleValuesBindCollection.OnChanged += ApplyConfigValues;
		}

		private void OnRunStarted(RunTracker sender)
		{
			if (NetworkHelper.IsServer)
			{
				SendValues();
			}
		}

		public void ApplyConfigValues()
		{
			ApplyValues(pluginConfig.RuleValues.Clone());
		}

		public void ApplyValues(ReviveRuleValues newValues)
		{
			ReviveRuleValues values = Values;
			Values = newValues;
			ReduceReviveProgressSpeed = 0f - 1f / newValues.ReviveTimeSeconds * newValues.ReduceReviveProgressFactor;
			ReviveLinkBuffTime = newValues.ReviveTimeSeconds / newValues.ReduceReviveProgressFactor * newValues.ReviveLinkBuffTimeFactor;
			this.ValuesChanged?.Invoke(values, newValues);
		}

		public void SendValues()
		{
			NetMessageExtensions.Send((INetMessage)(object)new SetRulesMessage(Values), (NetworkDestination)1);
		}

		public float CalculateDeathTotemRadius(Player dead)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			int itemCount = dead.master.master.inventory.GetItemCount(CharonsObol.Index);
			int count = dead.deathTotem.insidePlayerIDs.Count;
			return CalculateDeathTotemRadius(itemCount, count);
		}

		public float CalculateDeathTotemRadius(int itemCount, int playersCount)
		{
			float num = Values.BaseTotemRange;
			if (run.IsDeathCurseEnabled)
			{
				float num2 = Values.BaseTotemRange * (float)itemCount * Values.ItemIncreaseRangeFactor;
				num += num2;
			}
			float num3 = Values.BaseTotemRange * Values.IncreaseRangeWithPlayersFactor * (float)playersCount;
			return num + num3;
		}

		public float GetReviveSpeed(Player reviver, int playersInRange)
		{
			//IL_0011: 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)
			int itemCount = reviver.master.master.inventory.GetItemCount(CharonsObol.Index);
			int itemCount2 = reviver.master.master.inventory.GetItemCount(DeadMansHandItem.Index);
			return GetReviveSpeed(itemCount, itemCount2, playersInRange);
		}

		public float GetReviveSpeed(int obolsCount, int reviveEverywhereCount, int playersInRange)
		{
			float num = 1f / Values.ReviveTimeSeconds / (float)playersInRange;
			if (reviveEverywhereCount > 0)
			{
				num /= 2f;
			}
			if (run.IsDeathCurseEnabled)
			{
				float num2 = Values.ReviveTimeSeconds / (Values.ReviveTimeSeconds / Mathf.Pow(Values.ObolReviveFactor, (float)(obolsCount + reviveEverywhereCount)));
				num *= num2;
			}
			return num;
		}

		public float GetReviveIncrease(int obolsCount)
		{
			return Values.ReviveTimeSeconds / Mathf.Pow(Values.ObolReviveFactor, (float)obolsCount);
		}

		public float GetReviveTime(int obolsCount, int reviveEverywhereCount)
		{
			return Values.ReviveTimeSeconds / GetReviveSpeed(obolsCount, reviveEverywhereCount, 1);
		}

		public float GetReviveTimeIncrease(int obolsCount, int reviveEverywhereCount)
		{
			return GetReviveSpeed(obolsCount, 0, 1) / GetReviveSpeed(obolsCount, reviveEverywhereCount, 1);
		}

		public float GetDamageSpeed(float playerMaxHealth, Player dead, int reviverEverywhereObolCount)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			int count = dead.deathTotem.insidePlayerIDs.Count;
			int itemCount = dead.master.master.inventory.GetItemCount(CharonsObol.Index);
			return GetDamageSpeed(count, playerMaxHealth, itemCount, reviverEverywhereObolCount);
		}

		public float GetDamageSpeed(int playersInRange, float playerMaxHealth, int deadPlayerObolsCount, int reviverEverywhereObolCount)
		{
			float num = playerMaxHealth * 0.85f / Values.ReviveTimeSeconds / (float)playersInRange;
			if (run.IsDeathCurseEnabled)
			{
				num *= GetReviveReduceDamageFactor(deadPlayerObolsCount, reviverEverywhereObolCount);
			}
			return num;
		}

		public float GetReviveReduceDamageFactor(int deadPlayerObolsCount, int reviverEverywhereObolCount)
		{
			return 1f / Mathf.Pow(Values.ObolDamageReduceFactor, (float)deadPlayerObolsCount);
		}

		public float GetCurseReduceHpFactor(int reducesCount)
		{
			return Mathf.Pow(Values.ReduceHpFactor, (float)reducesCount) + Values.BaseReduceHpFactor;
		}
	}
	public class ReviveRuleValues
	{
		public float BaseTotemRange { get; set; } = 30f;


		public float IncreaseRangeWithPlayersFactor { get; set; } = 0.4f;


		public float ItemIncreaseRangeFactor { get; set; } = 0.5f;


		public float ReviveTimeSeconds { get; set; } = 6f;


		public float ReduceReviveProgressFactor { get; set; } = 0.05f;


		public float ReviveLinkBuffTimeFactor { get; set; } = 1f;


		public float ObolReviveFactor { get; set; } = 1.125f;


		public float ObolDamageReduceFactor { get; set; } = 1.1f;


		public float PostReviveRegenDurationSec { get; set; } = 4f;


		public float PostReviveRegenFraction { get; set; } = 0.4f;


		public float BaseReduceHpFactor { get; set; } = 0.25f;


		public float ReduceHpFactor { get; set; } = 1.2f;


		public bool ForceDeathCurseRule { get; set; } = false;


		public bool DebugKeepTotem { get; set; } = false;


		public bool ForceEnableDeathCurseForSinglePlayer { get; set; } = false;


		public bool EnableRevivalToken { get; set; } = true;


		public bool CutReviveeHp { get; set; } = true;


		public float DeathCurseChance { get; set; } = 66f;


		public float ReviverDeathCurseChance { get; set; } = 66f;


		public bool RequireHitboxesActive { get; set; } = false;


		public ReviveRuleValues Clone()
		{
			return (ReviveRuleValues)MemberwiseClone();
		}
	}
	public class SetRulesMessage : INetMessage, ISerializableObject
	{
		private readonly ReviveRuleValues ruleValues;

		public SetRulesMessage()
		{
			ruleValues = new ReviveRuleValues();
		}

		public SetRulesMessage(ReviveRuleValues ruleValues)
		{
			this.ruleValues = ruleValues;
		}

		public void Serialize(NetworkWriter writer)
		{
			writer.Write(ruleValues.BaseTotemRange);
			writer.Write(ruleValues.IncreaseRangeWithPlayersFactor);
			writer.Write(ruleValues.ItemIncreaseRangeFactor);
			writer.Write(ruleValues.ReviveTimeSeconds);
			writer.Write(ruleValues.ObolReviveFactor);
			writer.Write(ruleValues.ReduceHpFactor);
			writer.Write(ruleValues.BaseReduceHpFactor);
			writer.Write(ruleValues.ReduceReviveProgressFactor);
			writer.Write(ruleValues.ReviveLinkBuffTimeFactor);
			writer.Write(ruleValues.ObolDamageReduceFactor);
			writer.Write(ruleValues.ForceDeathCurseRule);
			writer.Write(ruleValues.DebugKeepTotem);
			writer.Write(ruleValues.EnableRevivalToken);
			writer.Write(ruleValues.CutReviveeHp);
			writer.Write(ruleValues.PostReviveRegenDurationSec);
			Log.Info("Sending new rule values");
		}

		public void Deserialize(NetworkReader reader)
		{
			ruleValues.BaseTotemRange = reader.ReadSingle();
			ruleValues.IncreaseRangeWithPlayersFactor = reader.ReadSingle();
			ruleValues.ItemIncreaseRangeFactor = reader.ReadSingle();
			ruleValues.ReviveTimeSeconds = reader.ReadSingle();
			ruleValues.ObolReviveFactor = reader.ReadSingle();
			ruleValues.ReduceHpFactor = reader.ReadSingle();
			ruleValues.BaseReduceHpFactor = reader.ReadSingle();
			ruleValues.ReduceReviveProgressFactor = reader.ReadSingle();
			ruleValues.ReviveLinkBuffTimeFactor = reader.ReadSingle();
			ruleValues.ObolDamageReduceFactor = reader.ReadSingle();
			ruleValues.ForceDeathCurseRule = reader.ReadBoolean();
			ruleValues.DebugKeepTotem = reader.ReadBoolean();
			ruleValues.EnableRevivalToken = reader.ReadBoolean();
			ruleValues.CutReviveeHp = reader.ReadBoolean();
			ruleValues.PostReviveRegenDurationSec = reader.ReadSingle();
		}

		public void OnReceived()
		{
			Log.Info("Received new rule values");
			if (NetworkHelper.IsClient())
			{
				ReviveRules.instance.ApplyValues(ruleValues);
				Log.Info("Applied new rule values");
			}
		}
	}
}
namespace TeammateRevive.Resources
{
	public static class CustomResources
	{
		public static GameObject CharonsObolItemPrefab;

		public static GameObject HandItemPrefab;

		public static Sprite CharonsObolItemIcon;

		public static Sprite DeathCurseBuffIcon;

		public static Sprite ReviveLinkBuffIcon;

		public static Sprite LunarHandIcon;

		public static Sprite DeathCurseArtifactEnabledIcon;

		public static Sprite DeathCurseArtifactDisabledIcon;

		public static readonly List<Material> Materials = new List<Material>();

		public static GameObject CurseOrbPrefab;

		public static GameObject progressBarPrefab;

		public static DeathTotemBehavior DeathTotem { get; private set; }

		private static void InitializeDeathTotem(GameObject totemPrefab)
		{
			Log.DebugMethod(null, "InitializeDeathTotem", 17);
			totemPrefab.AddComponent<DeathTotemBehavior>();
			DeathTotem = PrefabAPI.InstantiateClone(totemPrefab, "Death Totem").GetComponent<DeathTotemBehavior>();
			totemPrefab.GetComponent<DeathTotemBehavior>().Setup();
		}

		public static void LoadCustomResources()
		{
			Log.DebugMethod(null, "LoadCustomResources", 25);
			Log.Debug("Loading custom resources...");
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("TeammateRevive.Resources.customresources");
			AssetBundle val = AssetBundle.LoadFromStream(stream);
			ReplaceStubbedShaders(val);
			CharonsObolItemIcon = val.LoadAsset<Sprite>("Assets/CustomAssets/icons/obol.png");
			DeathCurseBuffIcon = val.LoadAsset<Sprite>("Assets/CustomAssets/icons/curse.png");
			ReviveLinkBuffIcon = val.LoadAsset<Sprite>("Assets/CustomAssets/icons/timed_curse.png");
			LunarHandIcon = val.LoadAsset<Sprite>("Assets/CustomAssets/icons/lunar_hand.png");
			DeathCurseArtifactEnabledIcon = val.LoadAsset<Sprite>("Assets/CustomAssets/icons/artifactCurseEnabled.png");
			DeathCurseArtifactDisabledIcon = val.LoadAsset<Sprite>("Assets/CustomAssets/icons/artifactCurseDisabled.png");
			CurseOrbPrefab = val.LoadAsset<GameObject>("Assets/CustomAssets/curseOrb.prefab");
			progressBarPrefab = val.LoadAsset<GameObject>("Assets/CustomAssets/progressBar.prefab");
			CharonsObolItemPrefab = val.LoadAsset<GameObject>("Assets/CustomAssets/obol.prefab");
			HandItemPrefab = val.LoadAsset<GameObject>("Assets/CustomAssets/handItem.prefab");
			InitializeDeathTotem(val.LoadAsset<GameObject>("Assets/CustomAssets/deathTotem.prefab"));
			val.Unload(false);
		}

		private static void ReplaceStubbedShaders(AssetBundle bundle)
		{
			Log.Debug("Replacing the stubbed shaders of the " + ((Object)bundle).name + " asset bundle");
			Material[] array = bundle.LoadAllAssets<Material>();
			Log.Debug($"Found {array.Length} materials in the asset bundle");
			Material[] array2 = array;
			foreach (Material val in array2)
			{
				Log.Debug("Loading the material " + ((Object)val).name);
				if (((Object)val.shader).name.StartsWith("StubbedShader"))
				{
					Log.Debug("Loading the stubbed shared for shader " + ((Object)val.shader).name);
					string text = "shaders" + ((Object)val.shader).name.Substring(13);
					Shader val2 = LegacyResourcesAPI.Load<Shader>(text);
					if (val2 == null)
					{
						Log.Warn("Could not find the shader for material " + ((Object)val).name + " at the path " + text);
					}
					else
					{
						Log.Debug("Loaded the stubbed shared " + ((Object)val2).name + " from the path " + text);
					}
					val.shader = val2;
					Materials.Add(val);
				}
				else
				{
					Log.Debug("The shader was not loaded because it is not a stubbed shader");
				}
			}
		}
	}
}
namespace TeammateRevive.ProgressBar
{
	public class CharArrayBuilder
	{
		private class Part
		{
			public int Start;

			public int Len;

			public Part(int start, int len)
			{
				Start = start;
				Len = len;
			}
		}

		private Part[] parts = Array.Empty<Part>();

		private const char PADDING = '\u200b';

		private const int FRACTION_LEN = 1;

		private const int WHOLE_NUMBER_LEN = 3;

		private const int DIGITS_COUNT = 4;

		private const int DIGITS_MULT = 1000;

		public char[] Buffer { get; private set; } = Array.Empty<char>();


		public int Length { get; set; }

		public CharArrayBuilder(params string[] strs)
		{
			InitParts(strs);
		}

		public void InitParts(params string[] strs)
		{
			Length = 0;
			foreach (string text in strs)
			{
				Length += text.Length;
			}
			if (Buffer.Length < Length)
			{
				Buffer = new char[Length + 7];
			}
			if (parts.Length < strs.Length)
			{
				parts = new Part[strs.Length];
			}
			int num = 0;
			for (int j = 0; j < strs.Length; j++)
			{
				string text2 = strs[j];
				text2.CopyTo(0, Buffer, num, text2.Length);
				parts[j] = new Part(num, text2.Length);
				num += text2.Length;
			}
		}

		public void UpdatePart(int idx, string value)
		{
			Part part = parts[idx];
			UpdatePartLen(part, value.Length, idx);
			value.CopyTo(0, Buffer, part.Start, value.Length);
		}

		private void UpdatePartLen(Part part, int len, int partIdx)
		{
			int num = part.Len - len;
			if (num != 0)
			{
				int num2 = Length - num;
				if (num < 0 && Buffer.Length < num2)
				{
					char[] array = new char[num2];
					Array.Copy(Buffer, array, Length);
					Buffer = array;
				}
				Array.Copy(Buffer, part.Start + part.Len, Buffer, part.Start + part.Len - num, Length - part.Start - part.Len);
				part.Len = len;
				Length -= num;
				for (int i = partIdx + 1; i < parts.Length; i++)
				{
					Part part2 = parts[i];
					part2.Start -= num;
				}
			}
		}

		public void SetPaddedPercentagePart(int partIdx, float value)
		{
			InternalSetPaddedFloatPart(partIdx, (int)(value * 1000f));
		}

		private void InternalSetPaddedFloatPart(int partIdx, int value)
		{
			if (value > 1000)
			{
				value = 1000;
			}
			Part part = parts[partIdx];
			UpdatePartLen(part, 5, partIdx);
			int start = part.Start;
			for (int i = 0; i < 2; i++)
			{
				Buffer[start + i] = '\u200b';
			}
			int num = 10;
			int num2 = 1;
			int num3 = 0;
			bool flag = false;
			for (int j = 0; j < 4; j++)
			{
				int num4 = value % num;
				if (num4 == value)
				{
					flag = true;
				}
				num4 /= num2;
				num *= 10;
				num2 *= 10;
				if (j == 1)
				{
					num3 = 1;
					Buffer[start + 4 - j] = '.';
				}
				Buffer[start + 4 - j - num3] = (char)(48 + num4);
				if (flag && num3 == 1)
				{
					break;
				}
			}
		}

		public override string ToString()
		{
			return new string(Buffer, 0, Length);
		}

		public string TraceParts()
		{
			return string.Join("", parts.Select((Part p, int i) => $"[{i}>" + new string(Buffer, p.Start, p.Len)));
		}
	}
	public class ProgressBarController
	{
		public static ProgressBarController Instance;

		private TextMeshProUGUI textComponent;

		private string currentName = DefaultName;

		private readonly CharArrayBuilder charArrayBuilder;

		public bool showing = false;

		private Slider progressBar;

		public float progress;

		private HUD hudRef;

		private RectTransform healthbarTransform;

		private RectTransform barRootTransform;

		private RectTransform progressBarTransform;

		private static string DefaultName => Language.GetString(LanguageConsts.TEAMMATE_REVIVAL_UI_PLAYER);

		private static string Reviving => Language.GetString(LanguageConsts.TEAMMATE_REVIVAL_UI_PROGRESS_BAR_REVIVING);

		public ProgressBarController()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			Log.Debug("Init ResurrectController");
			HUD.Awake += new hook_Awake(HUDOnAwake);
			Instance = this;
			charArrayBuilder = new CharArrayBuilder("Reviving ", DefaultName, "  -  ", "000.0", "%");
		}

		public void UpdateText(string name, float progress = 0f)
		{
			name = (string.IsNullOrEmpty(name) ? DefaultName : name);
			if (currentName != name)
			{
				charArrayBuilder.UpdatePart(1, name);
				currentName = name;
			}
			charArrayBuilder.SetPaddedPercentagePart(3, progress);
			((TMP_Text)textComponent).SetCharArray(charArrayBuilder.Buffer, 0, charArrayBuilder.Length);
			Show();
		}

		public void SetFraction(float fraction)
		{
			if (!((Object)(object)progressBar == (Object)null))
			{
				progressBar.value = fraction;
				progress = fraction;
				Show();
			}
		}

		public void SetColor(Color color)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)progressBar == (Object)null))
			{
				((Graphic)((Component)progressBar.fillRect).GetComponent<Image>()).color = color;
				Show();
			}
		}

		public (Vector3 bottomLeftOffset, Vector2 size) GetBarPositionAndSize()
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			if (((Object)((Component)progressBar).transform.parent).name != "BottomCenterCluster")
			{
				Transform val = hudRef.mainUIPanel.transform.Find("SpringCanvas/BottomCenterCluster");
				if ((Object)(object)val != (Object)null)
				{
					((Component)progressBar).transform.SetParent(val);
				}
				else
				{
					((Component)progressBar).transform.SetParent(hudRef.mainUIPanel.transform);
				}
			}
			Vector2 parentSize = GetParentSize(progressBarTransform);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor((float)Screen.width / 3.5f, (float)Screen.height / 27f);
			Vector3 item = default(Vector3);
			((Vector3)(ref item))..ctor(parentSize.x / 2f - val2.x / 2f, val2.y * 6f, 0f);
			Transform val3 = hudRef.mainUIPanel.transform.Find("SpringCanvas/BottomLeftCluster/BarRoots/HealthbarRoot");
			Transform val4 = hudRef.mainUIPanel.transform.Find("SpringCanvas/BottomLeftCluster/BarRoots");
			if ((Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null)
			{
				return (item, val2);
			}
			if ((Object)(object)healthbarTransform == (Object)null || (Object)(object)barRootTransform == (Object)null)
			{
				healthbarTransform = ((Component)val3).GetComponent<RectTransform>();
				barRootTransform = ((Component)val4).GetComponent<RectTransform>();
			}
			float num = parentSize.x * 0.8f;
			Rect rect = healthbarTransform.rect;
			((Vector2)(ref val2))..ctor(num, ((Rect)(ref rect)).height);
			rect = barRootTransform.rect;
			float num2 = ((Rect)(ref rect)).width / Mathf.Sin(MathF.PI / 2f);
			Quaternion rotation = val4.parent.rotation;
			float num3 = num2 * Mathf.Sin((0f - ((Quaternion)(ref rotation)).eulerAngles.y) * (MathF.PI / 180f));
			((Vector3)(ref item))..ctor(parentSize.x / 2f - val2.x / 2f, healthbarTransform.GetBottomLeftOffset().y, num3);
			return (item, val2);
		}

		public void UpdatePositionAndSize()
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			var (val, val2) = GetBarPositionAndSize();
			progressBarTransform.SetSizeInPixels(val2.x, val2.y);
			progressBarTransform.SetBottomLeftOffset(val.x, val.y);
			((Transform)progressBarTransform).localScale = Vector3.one;
			((Transform)progressBarTransform).localPosition = ((Transform)progressBarTransform).localPosition.SetZ(val.z);
		}

		public void Hide()
		{
			currentName = DefaultName;
			((Component)progressBar).GetComponent<CanvasGroup>().alpha = 0f;
			showing = false;
		}

		public void Show()
		{
			if (!showing)
			{
				UpdatePositionAndSize();
				showing = true;
				((Component)progressBar).GetComponent<CanvasGroup>().alpha = 1f;
				charArrayBuilder.UpdatePart(0, Reviving);
			}
		}

		public void AttachProgressBar(HUD hud)
		{
			Log.Debug("AttachProgressBar");
			hudRef = hud;
			progressBar = PrefabAPI.InstantiateClone(CustomResources.progressBarPrefab, "Revival Progress Bar").GetComponent<Slider>();
			progressBarTransform = ((Component)progressBar).GetComponent<RectTransform>();
			textComponent = ((Component)progressBar).GetComponentInChildren<TextMeshProUGUI>();
			((TMP_Text)textComponent).font = HGTextMeshProUGUI.defaultLanguageFont;
			Hide();
		}

		public void Destroy()
		{
			Slider obj = progressBar;
			if (Object.op_Implicit((Object)(object)((obj != null) ? ((Component)obj).gameObject : null)))
			{
				Object.Destroy((Object)(object)((Component)progressBar).gameObject);
			}
		}

		private void HUDOnAwake(orig_Awake orig, HUD self)
		{
			Log.Debug("HUDOnAwake");
			orig.Invoke(self);
			AttachProgressBar(self);
		}

		private Vector2 GetParentSize(RectTransform transform)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			Transform parent = ((Transform)transform).parent;
			RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
			Vector2 result;
			if (!((Object)(object)val == (Object)null))
			{
				Rect rect = val.rect;
				result = ((Rect)(ref rect)).size;
			}
			else
			{
				result = Vector2.zero;
			}
			return result;
		}
	}
	public class ReviveProgressBarTracker
	{
		public static readonly Color NegativeProgressColor = new Color(0.84f, 0.2f, 0.28f, 1f);

		public static readonly Color ZeroProgressColor = new Color(0.39f, 0.12f, 0.73f, 1f);

		public static readonly Color FullProgressColor = new Color(0.09f, 0.49f, 0.3f, 1f);

		private readonly ProgressBarController progressBar;

		private readonly PlayersTracker players;

		private readonly DeathTotemTracker deathTotemTracker;

		private readonly ReviveRules rules;

		public DeathTotemBehavior trackingTotem;

		private float queuedToHideAt;

		private SpectatorLabel spectatorLabel;

		public Color PositiveProgressColor => Color.Lerp(ZeroProgressColor, FullProgressColor, progressBar.progress);

		private bool IsQueuedToHide => queuedToHideAt > 0f;

		public ReviveProgressBarTracker(ProgressBarController progressBar, PlayersTracker players, DeathTotemTracker totemTracker, ReviveRules rules)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			this.progressBar = progressBar;
			this.players = players;
			deathTotemTracker = totemTracker;
			this.rules = rules;
			DeathTotemBehavior.GlobalOnDestroy = (Action<DeathTotemBehavior>)Delegate.Combine(DeathTotemBehavior.GlobalOnDestroy, new Action<DeathTotemBehavior>(OnDeathTotemDestroy));
			SpectatorLabel.Awake += new hook_Awake(SpectatorLabelAwake);
		}

		private void SpectatorLabelAwake(orig_Awake orig, SpectatorLabel self)
		{
			orig.Invoke(self);
			spectatorLabel = self;
		}

		private void OnDeathTotemDestroy(DeathTotemBehavior totem)
		{
			if ((Object)(object)trackingTotem == (Object)(object)totem)
			{
				Log.DebugMethod("removing tracking - totem destroyed", "OnDeathTotemDestroy", 57);
				RemoveTracking();
			}
		}

		public void Update()
		{
			//IL_00f8: 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)
			DeathTotemBehavior deathTotemInRange = GetDeathTotemInRange();
			if ((Object)(object)deathTotemInRange == (Object)(object)trackingTotem && (Object)(object)deathTotemInRange == (Object)null)
			{
				if (progressBar.showing)
				{
					Log.DebugMethod("hide - no totem, no tracking", "Update", 71);
					progressBar.Hide();
				}
				return;
			}
			if ((Object)(object)deathTotemInRange != (Object)null && (Object)(object)trackingTotem != (Object)(object)deathTotemInRange)
			{
				Log.DebugMethod("new totem", "Update", 80);
				trackingTotem = deathTotemInRange;
				DequeFromHiding();
				progressBar.UpdateText(deathTotemInRange.PlayerName);
			}
			if ((Object)(object)trackingTotem != (Object)null)
			{
				progressBar.SetFraction(trackingTotem.progress);
				progressBar.SetColor((trackingTotem.fractionPerSecond >= 0f) ? PositiveProgressColor : NegativeProgressColor);
				progressBar.UpdateText(trackingTotem.PlayerName, trackingTotem.progress);
			}
			if ((Object)(object)deathTotemInRange == (Object)null && (Object)(object)trackingTotem != (Object)null && !IsQueuedToHide)
			{
				Log.DebugMethod("queue to hide", "Update", 97);
				QueueToHide();
			}
			if ((Object)(object)trackingTotem != (Object)null && trackingTotem.progress == 0f)
			{
				Log.DebugMethod("removing due to progress is 0", "Update", 104);
				RemoveTracking();
			}
			if (IsQueuedToHide && Time.time > queuedToHideAt)
			{
				Log.DebugMethod($"removing tracking after delay ({Time.time} > {queuedToHideAt})", "Update", 111);
				RemoveTracking();
			}
		}

		private void QueueToHide()
		{
			queuedToHideAt = Time.time + rules.ReviveLinkBuffTime;
			Log.DebugMethod($"Queued to hide at {queuedToHideAt} (current time: {Time.time})", "QueueToHide", 120);
		}

		private void DequeFromHiding()
		{
			queuedToHideAt = 0f;
		}

		private void RemoveTracking()
		{
			DequeFromHiding();
			progressBar.Hide();
			trackingTotem = null;
		}

		public DeathTotemBehavior GetDeathTotemInRange()
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			if (!deathTotemTracker.HasAnyTotems)
			{
				return null;
			}
			NetworkInstanceId? val = players.CurrentUserBodyId ?? GetSpectatingBody();
			if (!val.HasValue)
			{
				return null;
			}
			return deathTotemTracker.GetDeathTotemInRange(val.Value);
		}

		private NetworkInstanceId? GetSpectatingBody()
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			if (IsInSpectatorMode())
			{
				GameObject cachedTarget = spectatorLabel.cachedTarget;
				if (cachedTarget.IsDestroyed())
				{
					return null;
				}
				CharacterBody component = cachedTarget.GetComponent<CharacterBody>();
				if ((Object)(object)component != (Object)null && !component.isPlayerControlled)
				{
					return null;
				}
				return ((NetworkBehaviour)component).netId;
			}
			return null;
		}

		private bool IsInSpectatorMode()
		{
			return (Object)(object)spectatorLabel != (Object)null && !((Component)spectatorLabel).gameObject.IsDestroyed() && !spectatorLabel.labelRoot.IsDestroyed() && spectatorLabel.labelRoot.activeSelf;
		}
	}
}
namespace TeammateRevive.Players
{
	public class Player
	{
		public readonly NetworkUser networkUser;

		public readonly PlayerCharacterMasterController master;

		public DeathTotemBehavior deathTotem = null;

		public Vector3 groundPosition = Vector3.zero;

		public float reviveProgress = 0f;

		public bool isDead = false;

		public readonly Dictionary<Player, float> reviveLinks = new Dictionary<Player, float>();

		public NetworkInstanceId? BodyId
		{
			get
			{
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				CharacterBody body = master.master.GetBody();
				return (body != null) ? new NetworkInstanceId?(((NetworkBehaviour)body).netId) : null;
			}
		}

		public Player(PlayerCharacterMasterController _player)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)_player.networkUser))
			{
				networkUser = _player.networkUser;
			}
			master = _player;
			reviveProgress = 0f;
		}

		public CharacterBody GetBody()
		{
			return master.master.GetBody();
		}

		public bool CheckAlive()
		{
			return Object.op_Implicit((Object)(object)GetBody()) && !master.master.IsDeadAndOutOfLivesServer() && GetBody().healthComponent.alive;
		}

		public bool CheckDead()
		{
			return !Object.op_Implicit((Object)(object)GetBody()) || master.master.IsDeadAndOutOfLivesServer() || !GetBody().healthComponent.alive;
		}

		public void UpdateGroundPosition()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			groundPosition = GetGroundPosition(this);
		}

		public static Vector3 GetGroundPosition(Player player)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: 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_00ac: Unknown result type (might be due to invalid IL or missing references)
			CharacterBody body = player.GetBody();
			if ((Object)(object)body == (Object)null)
			{
				return Vector3.zero;
			}
			RaycastHit val = default(RaycastHit);
			if (Physics.Raycast(body.transform.position, Vector3.down, ref val, 1000f, LayerMask.GetMask(new string[1] { "World" })) && Vector3.Dot(((RaycastHit)(ref val)).normal, Vector3.up) > 0.5f && Vector3.Distance(body.transform.position, player.groundPosition) > Vector3.Distance(body.transform.position, ((RaycastHit)(ref val)).point))
			{
				return ((RaycastHit)(ref val)).point;
			}
			return player.groundPosition;
		}

		public void IncreaseReviveLinkDuration(Player dead, float increase)
		{
			if (!reviveLinks.TryGetValue(dead, out var value))
			{
				value = Time.time + 1f;
			}
			reviveLinks[dead] = value + increase;
		}

		public int RemoveReviveLink(Player dead)
		{
			reviveLinks.Remove(dead);
			return reviveLinks.Count;
		}

		public float GetReviveLinkDuration(Player dead)
		{
			if (reviveLinks.TryGetValue(dead, out var value))
			{
				return value;
			}
			return 0f;
		}

		public void ClearReviveLinks()
		{
			reviveLinks.Clear();
		}

		public int GetPlayersReviveLinks()
		{
			float time = Time.time;
			KeyValuePair<Player, float>[] array = reviveLinks.ToArray();
			for (int i = 0; i < array.Length; i++)
			{
				KeyValuePair<Player, float> keyValuePair = array[i];
				Player key = keyValuePair.Key;
				float value = keyValuePair.Value;
				if (time > value)
				{
					RemoveReviveLink(key);
					Log.Debug($"Removed revive link for revive of {key.networkUser.userName} from {networkUser.userName}. Left: {reviveLinks.Count}");
				}
			}
			return reviveLinks.Count;
		}

		public bool IsLinkedTo(Player player)
		{
			return reviveLinks.ContainsKey(player);
		}
	}
	public static class PlayerExtensions
	{
		public static void GiveItem(this Player player, ItemIndex index, int count = 1)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			player.master.master.inventory.GiveItem(index, count);
		}

		public static void RemoveItem(this Player player, ItemIndex index, int count = 1)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			player.master.master.inventory.RemoveItem(index, count);
		}

		public static int ItemCount(this Player player, ItemIndex index)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			return player.master.master.inventory.GetItemCount(index);
		}
	}
	public class PlayersTracker
	{
		public static PlayersTracker instance;

		private readonly RunTracker run;

		private readonly PluginConfig config;

		private int numPlayersSetup = 0;

		private float playerSetupTimer = 3f;

		public List<Player> Alive = new List<Player>();

		public List<Player> Dead = new List<Player>();

		public List<Player> All = new List<Player>();

		public PlayerCharacterMasterController CurrentUserPlayerCharacterMasterController { get; set; }

		public NetworkInstanceId? CurrentUserBodyId
		{
			get
			{
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				PlayerCharacterMasterController currentUserPlayerCharacterMasterController = CurrentUserPlayerCharacterMasterController;
				NetworkInstanceId? result;
				if (currentUserPlayerCharacterMasterController == null)
				{
					result = null;
				}
				else
				{
					CharacterBody body = currentUserPlayerCharacterMasterController.master.GetBody();
					result = ((body != null) ? new NetworkInstanceId?(((NetworkBehaviour)body).netId) : null);
				}
				return result;
			}
		}

		public int TotalCount { get; set; }

		public bool Setup { get; set; }

		public event Action<Player> OnPlayerDead;

		public event Action<Player> OnPlayerAlive;

		public event Action OnSetupFinished;

		public event Action<Player> OnPlayerRespawned;

		public PlayersTracker(RunTracker run, PluginConfig config)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			instance = this;
			this.run = run;
			this.config = config;
			Run.OnUserRemoved += new hook_OnUserRemoved(hook_OnUserRemoved);
			GlobalEventManager.OnPlayerCharacterDeath += new hook_OnPlayerCharacterDeath(hook_OnPlayerCharacterDeath);
			PlayerCharacterMasterController.OnBodyStart += new hook_OnBodyStart(hook_OnBodyStart);
		}

		public void Respawn(Player player)
		{
			if (NetworkHelper.IsClient() || !Dead.Contains(player))
			{
				return;
			}
			if (player.master.isConnected)
			{
				if (!player.CheckAlive())
				{
					ReviveHelper.RespawnExtraLife(player.master.master);
				}
				else
				{
					Log.Warn("Respawn was called for alive player!");
				}
				PlayerAlive(player);
			}
			this.OnPlayerRespawned?.Invoke(player);
			Log.Info("Player Respawned");
		}

		public void Reset()
		{
			Setup = false;
			Alive.Clear();
			Dead.Clear();
			All.Clear();
			TotalCount = 0;
			numPlayersSetup = 0;
			playerSetupTimer = 0f;
		}

		public Player FindByCharacterMasterControllerId(NetworkInstanceId id)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			foreach (Player item in All)
			{
				if (Object.op_Implicit((Object)(object)item.master) && ((NetworkBehaviour)item.master).netId == id)
				{
					return item;
				}
			}
			return null;
		}

		public Player FindByBodyId(NetworkInstanceId id)
		{
			//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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			foreach (Player item in Alive)
			{
				item.GetBody();
				NetworkInstanceId? bodyId = item.BodyId;
				if (bodyId.HasValue && bodyId.GetValueOrDefault() == id)
				{
					return item;
				}
			}
			return null;
		}

		private void hook_OnUserRemoved(orig_OnUserRemoved orig, Run self, NetworkUser user)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkHelper.IsClient())
			{
				orig.Invoke(self, user);
				return;
			}
			if (!run.IsStarted)
			{
				Log.Info(user.userName + " left while run wasn't in session.");
			}
			Player item = FindByCharacterMasterControllerId(((NetworkBehaviour)user.masterController).netId);
			if (All.Contains(item))
			{
				All.Remove(item);
				if (Dead.Contains(item))
				{
					Dead.Remove(item);
				}
				if (Alive.Contains(item))
				{
					Alive.Remove(item);
				}
				Log.Info(user.userName + " Left!");
			}
			else
			{
				Log.Error(user.userName + " Left - but they were not registered as a player!");
				orig.Invoke(self, user);
			}
		}

		private void hook_OnPlayerCharacterDeath(orig_OnPlayerCharacterDeath orig, GlobalEventManager self, DamageReport damageReport, NetworkUser victimNetworkUser)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkHelper.IsServer)
			{
				Player player = FindByBodyId(((NetworkBehaviour)victimNetworkUser.GetCurrentBody()).netId);
				if (Alive.Contains(player))
				{
					PlayerDead(player);
					Log.Info(victimNetworkUser.userName + " Died!");
				}
				else
				{
					Log.Error("Player Died but they were not alive to begin with!");
				}
			}
			orig.Invoke(self, damageReport, victimNetworkUser);
		}

		private void hook_OnBodyStart(orig_OnBodyStart orig, PlayerCharacterMasterController self)
		{
			orig.Invoke(self);
			if (((NetworkBehaviour)self.networkUser).isLocalPlayer)
			{
				CurrentUserPlayerCharacterMasterController = self;
				Log.Debug($"Set local player body to {CurrentUserBodyId} ({CurrentUserBodyId})");
			}
			if (NetworkHelper.IsClient())
			{
				return;
			}
			if (All.Any((Player p) => (Object)(object)p.master == (Object)(object)self))
			{
				Log.Info("BodyStart: " + self.networkUser.userName + " player already exists.");
				return;
			}
			Player player = new Player(self);
			if (config.GodMode)
			{
				player.GetBody().baseDamage = 120f;
				player.networkUser.GetCurrentBody().baseMoveSpeed = 30f;
				player.GetBody().baseAttackSpeed = 200f;
			}
			Alive.Add(player);
			All.Add(player);
			player.isDead = false;
			numPlayersSetup++;
			Log.Info(self.networkUser.userName + " Setup");
			TotalCount = NetworkManager.singleton.numPlayers;
			playerSetupTimer = 0f;
			if (numPlayersSetup == TotalCount)
			{
				Setup = true;
				Log.Info("All " + TotalCount + " Players Setup Successfully");
				this.OnSetupFinished?.Invoke();
			}
		}

		private void PlayerDead(Player p)
		{
			RemoveDuplicates();
			LogPlayers("Player dead: " + p.networkUser.userName);
			if (Alive.Contains(p))
			{
				Alive.Remove(p);
			}
			if (!Dead.Contains(p))
			{
				Dead.Add(p);
			}
			p.isDead = true;
			p.reviveProgress = 0f;
			if (!NetworkHelper.IsClient())
			{
				this.OnPlayerDead?.Invoke(p);
			}
		}

		public void PlayerAlive(Player p)
		{
			RemoveDuplicates();
			LogPlayers("Player alive: " + p.networkUser.userName);
			if (!Alive.Contains(p))
			{
				Alive.Add(p);
			}
			if (Dead.Contains(p))
			{
				Dead.Remove(p);
			}
			p.isDead = false;
			p.reviveProgress = 0f;
			NetworkServer.Destroy(((Component)p.deathTotem).gameObject);
			this.OnPlayerAlive?.Invoke(p);
		}

		[Conditional("DEBUG")]
		private void RemoveDuplicates()
		{
			Alive = Alive.Distinct().ToList();
			Dead = Dead.Distinct().ToList();
		}

		private void LogPlayers(string prefix)
		{
			string text = string.Join(", ", Alive.Select((Player p) => p.networkUser.userName));
			string text2 = string.Join(", ", Dead.Select((Player p) => p.networkUser.userName));
			Log.Info(prefix + "; Alive: " + text + " | Dead: " + text2);
		}

		public void Update()
		{
			if (NetworkHelper.IsServer && !Setup && numPlayersSetup > 0)
			{
				playerSetupTimer += Time.deltaTime;
				if (playerSetupTimer >= 3f)
				{
					Setup = true;
					Log.Error("The " + TotalCount + " total players were not all setup, falling back. Consider filing an issue on Github.");
				}
			}
		}
	}
	public static class ReviveHelper
	{
		private static readonly Lazy<Action<CharacterMaster>> lazyRespawnDelegate = new Lazy<Action<CharacterMaster>>(CreateRespawnDelegate);

		public static Action<CharacterMaster> RespawnExtraLife => lazyRespawnDelegate.Value;

		public static void Init()
		{
			_ = lazyRespawnDelegate.Value;
		}

		private static Action<CharacterMaster> CreateRespawnDelegate()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			MethodInfo method = typeof(CharacterMaster).GetMethod("RespawnExtraLife");
			try
			{
				DynamicMethodDefinition val = new DynamicMethodDefinition((MethodBase)method);
				ILCursor val2 = new ILCursor(new ILContext(val.Definition));
				if (val2.TryGotoNext(new Func<Instruction, bool>[1]
				{
					(Instruction x) => ILPatternMatchingExt.MatchCall(x, typeof(CharacterMaster), "get_deathFootPosition")
				}))
				{
					int index = val2.Index;
					val2.Index = 0;
					StringBuilder stringBuilder = new StringBuilder("CharacterMaster.RespawnExtraLife removed instructions:").AppendLine();
					foreach (Instruction item in ((IEnumerable<Instruction>)val.Definition.Body.Instructions).Take(index - 1))
					{
						stringBuilder.AppendLine(((object)item).ToString());
					}
					Log.Debug(stringBuilder.ToString());
					val2.RemoveRange(index - 1);
					Action<CharacterMaster> result = Extensions.CreateDelegate<Action<CharacterMaster>>((MethodBase)val.Generate());
					Log.Info("Created patched CharacterMaster.RespawnExtraLife version successfully!");
					return result;
				}
				Log.Warn("Cannot create patched version of RespawnExtraLife!");
			}
			catch (Exception arg)
			{
				Log.Warn($"Error when trying to create patched RespawnExtraLife: {arg}");
			}
			return FallbackRespawnFunction;
		}

		private static void FallbackRespawnFunction(CharacterMaster master)
		{
			master.RespawnExtraLife();
			master.inventory.RemoveItem(Items.ExtraLifeConsumed, 1);
		}
	}
}
namespace TeammateRevive.Logging
{
	public class ChatLogTarget : ILogTarget
	{
		public void Write(LogLevel level, object msg)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Invalid comparison between Unknown and I4
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected I4, but got Unknown
			//IL_0059: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: 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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Invalid comparison between Unknown and I4
			//IL_006d: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			if ((int)level == 32 || !RunTracker.instance.IsStarted)
			{
				return;
			}
			if (1 == 0)
			{
			}
			Color val;
			switch (level - 1)
			{
			default:
				if ((int)level != 16)
				{
					goto case 2;
				}
				val = Color.blue;
				break;
			case 3:
				val = Color.yellow;
				break;
			case 1:
				val = Color.red;
				break;
			case 0:
				val = Color.red;
				break;
			case 2:
				val = Color.blue;
				break;
			}
			if (1 == 0)
			{
			}
			Color val2 = val;
		}
	}
	public class ConsoleLoggerTarget : ILogTarget
	{
		private readonly ManualLogSource log;

		public ConsoleLoggerTarget(ManualLogSource log)
		{
			this.log = log;
		}

		public void Write(LogLevel level, object msg)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			log.Log(level, msg);
		}
	}
	public class DebugFileTarget : ILogTarget
	{
		private static readonly string DefaultPath = Environment.GetEnvironmentVariable("USERPROFILE") + "\\Desktop\\log.txt";

		private readonly string filePath;

		public bool IsEnabled { get; set; } = true;


		public DebugFileTarget(string path, ManualLogSource consoleLogger)
		{
			if (string.IsNullOrEmpty(path))
			{
				path = DefaultPath;
			}
			try
			{
				filePath = NormalizeAndVerifyPath(path);
			}
			catch
			{
				consoleLogger.LogError((object)("Couldn't write to specified file logging path! Will write to \"" + DefaultPath + "\" instead --------------------------------------------"));
				filePath = DefaultPath;
			}
			try
			{
				Write((LogLevel)32, "Log Setup");
			}
			catch
			{
				consoleLogger.LogWarning((object)"Log file location unavailable!");
				IsEnabled = false;
			}
		}

		private string NormalizeAndVerifyPath(string path)
		{
			if (File.Exists(path))
			{
				return path;
			}
			if (Directory.Exists(path) || path.EndsWith("\\"))
			{
				return NormalizeAndVerifyPath(Path.Combine(path, "log.txt"));
			}
			File.WriteAllText(path, "");
			return path;
		}

		public void Write(LogLevel level, object msg)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (!IsEnabled)
			{
				return;
			}
			using StreamWriter streamWriter = new StreamWriter(filePath, append: true);
			streamWriter.WriteLine(string.Format("[{0}] [{1}] {2} \n", ((Enum)level).ToString("G").ToUpper(), DateTime.Now, msg));
		}
	}
	public interface ILogTarget
	{
		void Write(LogLevel level, object msg);
	}
	public class Log
	{
		public static Log Instance;

		public List<ILogTarget> Targets = new List<ILogTarget>();

		public static void Init(PluginConfig config, ManualLogSource log)
		{
			Log log2 = new Log();
			log2.Targets = new ILogTarget[4]
			{
				CreateIf(config.ConsoleLogging, log, () => new ConsoleLoggerTarget(log)),
				CreateIf(config.FileLogging, log, () => new DebugFileTarget(config.FileLoggingPath, log)),
				CreateIf(config.ChatLogging, log, () => new ChatLogTarget()),
				new ServerLogTarget(config.ServerLogging)
			}.Where((ILogTarget t) => t != null).ToList();
			Instance = log2;
		}

		private static ILogTarget CreateIf(bool condition, ManualLogSource consoleLog, Func<ILogTarget> create)
		{
			if (!condition)
			{
				return null;
			}
			try
			{
				return create();
			}
			catch (Exception ex)
			{
				consoleLog.LogWarning((object)("Error on logging target creation: " + ex));
				return null;
			}
		}

		protected Log()
		{
		}

		public static void Info(object msg)
		{
			Instance?.Write((LogLevel)16, msg);
		}

		public static void Warn(object msg)
		{
			Instance?.Write((LogLevel)4, msg);
		}

		public static void WarnMethod(object msg, [CallerMemberName] string callingMember = null, [CallerLineNumber] int lineNo = 0)
		{
			Instance?.Write((LogLevel)4, $"[{NameOfCallingClass()}.{callingMember}:{lineNo}] {msg}");
		}

		public static void Error(object msg)
		{
			Instance?.Write((LogLevel)2, msg);
		}

		[Conditional("DEBUG")]
		public static void Debug(object msg)
		{
			Instance?.Write((LogLevel)32, msg);
		}

		public static void ChatDebug(object msg)
		{
			Instance.Targets.FirstOrDefault((ILogTarget t) => t.GetType() == typeof(ChatLogTarget))?.Write((LogLevel)32, msg);
		}

		[Conditional("DEBUG")]
		public static void DebugMethod(object message = null, [CallerMemberName] string callingMember = null, [CallerLineNumber] int lineNo = 0)
		{
			Instance?.Write((LogLevel)32, string.Format("[{0}.{1}:{2}] {3}", NameOfCallingClass(), callingMember, lineNo, message ?? "called"));
		}

		public static string NameOfCallingClass()
		{
			int num = 2;
			Type type;
			string fullName;
			do
			{
				MethodBase method = new StackFrame(num, needFileInfo: false).GetMethod();
				type = method?.DeclaringType;
				if (type == null)
				{
					return method?.Name ?? "__";
				}
				num++;
				fullName = type.FullName;
			}
			while (type.Module.Name.Equals("mscorlib.dll", StringComparison.OrdinalIgnoreCase));
			return fullName;
		}

		public void Write(LogLevel level, object msg)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			foreach (ILogTarget target in Targets)
			{
				try
				{
					target.Write(level, msg);
				}
				catch
				{
				}
			}
		}
	}
	public class ServerLogTarget : ILogTarget, ILogListener, IDisposable
	{
		private readonly object locker = new object();

		private readonly ServerLoggingConfig config;

		private Task shipTask = Task.CompletedTask;

		private readonly ConcurrentQueue<JSONObject> logsQueue = new ConcurrentQueue<JSONObject>();

		private readonly HttpClient client = new HttpClient();

		public ServerLogTarget(ServerLoggingConfig config)
		{
			this.config = config;
			Logger.Listeners.Add((ILogListener)(object)this);
		}

		public void Write(LogLevel level, object message)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			InternalWrite(level, message, fromHook: false);
		}

		private void InternalWrite(LogLevel level, object message, bool fromHook)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Expected O, but got Unknown
			if (config.IsEnabled && (!config.LogAll || fromHook))
			{
				logsQueue.Enqueue(new JSONObject
				{
					["timestamp"] = JSONNode.op_Implicit((float)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()),
					["level"] = JSONNode.op_Implicit(MapLevel(level)),
					["msg"] = JSONNode.op_Implicit((NetworkHelper.IsClient() ? "C " : "S ") + message),
					["user"] = JSONNode.op_Implicit((NetworkHelper.IsClient() ? "C " : "S ") + config.UserName),
					["room"] = JSONNode.op_Implicit(config.RoomName)
				});
				ShipLogs();
			}
		}

		private string MapLevel(LogLevel level)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Invalid comparison between Unknown and I4
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Invalid comparison between Unknown and I4
			if (1 == 0)
			{
			}
			string result = ((level - 1 <= 1) ? "ERROR" : (((int)level == 4) ? "WARN" : (((int)level != 32) ? "INFO" : "DEBUG")));
			if (1 == 0)
			{
			}
			return result;
		}

		private void ShipLogs()
		{
			if (logsQueue.IsEmpty)
			{
				return;
			}
			lock (locker)
			{
				shipTask = shipTask.ContinueWith((Func<Task, Task>)async delegate
				{
					JSONArray array = GroupEntries();
					if (config.IsEnabled)
					{
						await SendEntries(array);
					}
				});
			}
		}

		private async Task SendEntries(JSONArray entry)
		{
			StringContent content = new StringContent(((object)entry).ToString(), Encoding.UTF8, "application/json");
			try
			{
				await client.PostAsync(config.Url.TrimEnd('/') + "/logs/add", content);
			}
			catch (Exception)
			{
			}
		}

		private JSONArray GroupEntries()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			JSONArray val = new JSONArray();
			int num = 50;
			JSONObject result;
			while (logsQueue.TryDequeue(out result))
			{
				((JSONNode)val).Add((JSONNode)(object)result);
				if (((JSONNode)val).Count == num)
				{
					break;
				}
			}
			return val;
		}

		public void Dispose()
		{
		}

		void ILogListener.LogEvent(object sender, LogEventArgs eventArgs)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if (config.LogAll || ((Enum)eventArgs.Level).HasFlag((Enum)(object)(LogLevel)2))
			{
				InternalWrite(eventArgs.Level, eventArgs.Data.ToString(), fromHook: true);
			}
		}
	}
}
namespace TeammateRevive.Localization
{
	public class LanguageConsts
	{
		public static string ARTIFACT_DEATH_CURSE_NAME = "ARTIFACT_DEATH_CURSE_NAME";

		public static string ARTIFACT_DEATH_CURSE_DESCRIPTION = "ARTIFACT_DEATH_CURSE_DESCRIPTION";

		public static string ARTIFACT_DEATH_CURSE_DISABLED = "ARTIFACT_DEATH_CURSE_DISABLED";

		public static string ARTIFACT_DEATH_CURSE_ENFORCED_BY_SERVER = "ARTIFACT_DEATH_CURSE_ENFORCED_BY_SERVER";

		public static string ITEM_CHARONS_OBOL_NAME = "ITEM_CHARONS_OBOL_NAME";

		public static string ITEM_CHARONS_OBOL_DESCRIPTION = "ITEM_CHARONS_OBOL_DESCRIPTION";

		public static string ITEM_CHARONS_OBOL_PICKUP = "ITEM_CHARONS_OBOL_PICKUP";

		public static string ITEM_REVIVE_EVERYWHERE_NAME = "ITEM_REVIVE_EVERYWHERE_NAME";

		public static string ITEM_REVIVE_EVERYWHERE_DESCRIPTION = "ITEM_REVIVE_EVERYWHERE_DESCRIPTION";

		public static string ITEM_REVIVE_EVERYWHERE_LORE = "ITEM_REVIVE_EVERYWHERE_LORE";

		public static string ITEM_REVIVE_EVERYWHERE_PICKUP = "ITEM_REVIVE_EVERYWHERE_PICKUP";

		public static string ITEM_DEATH_CURSE_NAME = "ITEM_DEATH_CURSE_NAME";

		public static string ITEM_DEATH_CURSE_DESCRIPTION = "ITEM_DEATH_CURSE_DESCRIPTION";

		public static string ITEM_DEATH_CURSE_LORE = "ITEM_DEATH_CURSE_LORE";

		public static string ITEM_DEATH_CURSE_PICKUP = "ITEM_DEATH_CURSE_PICKUP";

		public static string ITEM_REVIVAL_TOKEN_NAME = "ITEM_REVIVAL_TOKEN_NAME";

		public static string ITEM_REVIVAL_TOKEN_DESCRIPTION = "ITEM_REVIVAL_TOKEN_DESCRIPTION";

		public static string BUFF_DEATH_CURSE_DESCRIPTION = "BUFF_DEATH_CURSE_DESCRIPTION";

		public static string BUFF_REVIVE_LINK_NAME = "BUFF_REVIVE_LINK_NAME";

		public static string BUFF_REVIVE_LINK_DESCRIPTION = "BUFF_REVIVE_LINK_DESCRIPTION";

		public static string BUFF_REVIVE_REGEN_NAME = "BUFF_REVIVE_REGEN_NAME";

		public static string BUFF_REVIVE_REGEN_DESCRIPTION = "BUFF_REVIVE_REGEN_DESCRIPTION";

		public static string TEAMMATE_REVIVAL_UI_PLAYER = "TEAMMATE_REVIVAL_UI_PLAYER";

		public static string TEAMMATE_REVIVAL_UI_USE_OBOL = "TEAMMATE_REVIVAL_UI_USE_OBOL";

		public static string TEAMMATE_REVIVAL_UI_NO_OBOL = "TEAMMATE_REVIVAL_UI_NO_OBOL";

		public static string TEAMMATE_REVIVAL_SHIELD_ONLY_POSTFIX = "TEAMMATE_REVIVAL_SHIELD_ONLY_POSTFIX";

		public static string TEAMMATE_REVIVAL_UI_AVOIDED_CURSE = "TEAMMATE_REVIVAL_UI_AVOIDED_CURSE";

		public static string TEAMMATE_REVIVAL_UI_CURSED = "TEAMMATE_REVIVAL_UI_CURSED";

		public static string TEAMMATE_REVIVAL_UI_PROGRESS_BAR_REVIVING = "TEAMMATE_REVIVAL_UI_PROGRESS_BAR_REVIVING";

		public static string ITEM_STAT_CHARON_OBOL_REVIVE_SPEED_INCREASE = "ITEM_STAT_CHARON_OBOL_REVIVE_SPEED_INCREASE";

		public static string ITEM_STAT_CHARON_OBOL_REVIVE_TIME_ALONE = "ITEM_STAT_CHARON_OBOL_REVIVE_TIME_ALONE";

		public static string ITEM_STAT_CHARON_OBOL_REVIVE_CIRCLE_RANGE = "ITEM_STAT_CHARON_OBOL_REVIVE_CIRCLE_RANGE";

		public static string ITEM_STAT_CHARON_OBOL_REVIVE_CIRCLE_DAMAGE = "ITEM_STAT_CHARON_OBOL_REVIVE_CIRCLE_DAMAGE";

		public static string ITEM_STAT_REVIVE_EVERYWHERE_REVIVE_CIRCLE_DAMAGE = "ITEM_STAT_REVIVE_EVERYWHERE_REVIVE_CIRCLE_DAMAGE";
	}
	public class LanguageManager
	{
		public static void RegisterLanguages()
		{
			Language.collectLanguageRootFolders += LanguageOnCollectLanguageRootFolders;
		}

		private static void LanguageOnCollectLanguageRootFolders(List<string> folders)
		{
			folders.Add(Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)MainTeammateRevival.instance).Info.Location), "Localization", "Languages"));
		}
	}
}
namespace TeammateRevive.Integrations
{
	public class InLobbyConfigIntegration
	{
		private readonly PluginConfig pluginConfig;

		public InLobbyConfigIntegration(PluginConfig pluginConfig)
		{
			this.pluginConfig = pluginConfig;
			RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, (Action)delegate
			{
				if (Chainloader.PluginInfos.ContainsKey("com.KingEnderBrine.InLobbyConfig"))
				{
					Register();
				}
			});
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		private void Register()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			try
			{
				ModConfigEntry val = new ModConfigEntry
				{
					DisplayName = "TeammateRevival"
				};
				AddSection(val, pluginConfig.RuleValuesBindCollection);
				AddSection(val, pluginConfig.DebugBindCollection);
				ModConfigCatalog.Add(val);
				Log.Info("InLobbyConfig integration: OK!");
			}
			catch (Exception ex)
			{
				Log.Error("InLobbyConfig integration failed: " + ex);
			}
		}

		private static void AddSection(ModConfigEntry configEntry, BindCollection bindCollection)
		{
			configEntry.SectionFields.Add(bindCollection.Section, GetFieldsFromBindings(bindCollection));
		}

		private static IConfigField[] GetFieldsFromBindings(BindCollection bindCollection)
		{
			Func<ConfigEntryBase, IConfigField> createField = (Func<ConfigEntryBase, IConfigField>)typeof(ConfigFieldUtilities).GetMethod("ProcessConfigRow", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).CreateDelegate(typeof(Func<ConfigEntryBase, IConfigField>));
			return bindCollection.Bindings.Select(delegate(ConfigEntryBase f)
			{
				AcceptableValueBase acceptableValues = f.Description.AcceptableValues;
				AcceptableValueList<string> list = acceptableValues as AcceptableValueList<string>;
				return (IConfigField)((list != null) ? ((object)new SelectListField<string>(f.Definition.Key, f.Description.Description, (Func<ICollection<string>>)(() => new string[1] { (string)f.BoxedValue }), (Action<string, int>)delegate(string s, int i)
				{
					f.BoxedValue = s;
				}, (Action<int>)delegate
				{
				}, (Func<IDictionary<string, string>>)(() => list.AcceptableValues.ToDictionary((string k) => k)))) : ((object)createField(f)));
			}).ToArray();
		}
	}
	public class RiskOfOptionsIntegration
	{
		public const string Guid = "com.rune580.riskofoptions";

		private readonly PluginConfig config;

		public RiskOfOptionsIntegration(PluginConfig config)
		{
			this.config = config;
			RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, (Action)delegate
			{
				if (Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions"))
				{
					try
					{
						RegisterOptions();
					}
					catch (Exception arg)
					{
						Log.Error($"Error during RiskOfOptions integration: {arg}");
					}
				}
			});
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		private void RegisterOptions()
		{
			int num = RegisterBindCollection(config.RuleValuesBindCollection);
			num += RegisterBindCollection(config.MiscBindCollection);
			num += RegisterBindCollection(config.DebugBindCollection);
			Log.Info($"RiskOfOptions integration: OK! (Options: {num})");
		}

		private int RegisterBindCollection(BindCollection bindCollection)
		{
			BaseOption[] array = (from o in bindCollection.Bindi